1 /*******************************************************************************
2 * Copyright (c) 2013, 2016 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.tmf
.core
.callstack
;
15 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
17 import org
.eclipse
.jdt
.annotation
.NonNullByDefault
;
18 import org
.eclipse
.jdt
.annotation
.Nullable
;
19 import org
.eclipse
.osgi
.util
.NLS
;
20 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.Activator
;
21 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystemBuilder
;
22 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
23 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
24 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
25 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.AbstractTmfStateProvider
;
26 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.ITmfStateProvider
;
27 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
30 * The state provider for traces that support the Call Stack view.
32 * The attribute tree should have the following structure:
39 * | | +-- CallStack (stack-attribute)
45 * | +-- CallStack (stack-attribute)
53 * +-- CallStack (stack-attribute)
62 * <li>(PID n) is an attribute whose name is the display name of the process.
63 * Optionally, its value can be an int representing the process id. Otherwise,
64 * the attribute name can be set to the process id formatted as a string.</li>
65 * <li>(TID n) is an attribute whose name is the display name of the thread.
66 * Optionally, its value can be a long representing the thread id. Otherwise,
67 * the attribute name can be set to the thread id formatted as a string.</li>
68 * <li>"CallStack" is a stack-attribute whose pushed values are either a string,
69 * int or long representing the function name or address in the call stack. The
70 * type of value used must be constant for a particular CallStack.</li>
73 * @author Patrick Tasse
76 public abstract class CallStackStateProvider
extends AbstractTmfStateProvider
{
83 public static final String PROCESSES
= "Processes"; //$NON-NLS-1$
85 /** CallStack stack-attribute */
86 public static final String CALL_STACK
= "CallStack"; //$NON-NLS-1$
93 public static final int UNKNOWN_PID
= -1;
100 public static final String UNKNOWN
= "UNKNOWN"; //$NON-NLS-1$
102 /** CallStack state system ID */
103 private static final String ID
= "org.eclipse.linuxtools.tmf.callstack"; //$NON-NLS-1$
106 * Default constructor
109 * The trace for which we build this state system
111 public CallStackStateProvider(ITmfTrace trace
) {
116 protected void eventHandle(ITmfEvent event
) {
117 if (!considerEvent(event
)) {
121 ITmfStateSystemBuilder ss
= checkNotNull(getStateSystemBuilder());
123 /* Check if the event is a function entry */
124 ITmfStateValue functionEntryName
= functionEntry(event
);
125 if (functionEntryName
!= null) {
126 long timestamp
= event
.getTimestamp().toNanos();
128 String processName
= getProcessName(event
);
129 int processId
= getProcessId(event
);
130 if (processName
== null) {
131 processName
= (processId
== UNKNOWN_PID
) ? UNKNOWN
: Integer
.toString(processId
);
133 int processQuark
= ss
.getQuarkAbsoluteAndAdd(PROCESSES
, processName
);
134 ss
.updateOngoingState(TmfStateValue
.newValueInt(processId
), processQuark
);
136 String threadName
= getThreadName(event
);
137 long threadId
= getThreadId(event
);
138 if (threadName
== null) {
139 threadName
= Long
.toString(threadId
);
141 int threadQuark
= ss
.getQuarkRelativeAndAdd(processQuark
, threadName
);
142 ss
.updateOngoingState(TmfStateValue
.newValueLong(threadId
), threadQuark
);
144 int callStackQuark
= ss
.getQuarkRelativeAndAdd(threadQuark
, CALL_STACK
);
145 ITmfStateValue value
= functionEntryName
;
146 ss
.pushAttribute(timestamp
, value
, callStackQuark
);
150 /* Check if the event is a function exit */
151 ITmfStateValue functionExitState
= functionExit(event
);
152 if (functionExitState
!= null) {
153 long timestamp
= event
.getTimestamp().toNanos();
154 String processName
= getProcessName(event
);
155 if (processName
== null) {
156 int processId
= getProcessId(event
);
157 processName
= (processId
== UNKNOWN_PID
) ? UNKNOWN
: Integer
.toString(processId
);
159 String threadName
= getThreadName(event
);
160 if (threadName
== null) {
161 threadName
= Long
.toString(getThreadId(event
));
163 int quark
= ss
.getQuarkAbsoluteAndAdd(PROCESSES
, processName
, threadName
, CALL_STACK
);
164 ITmfStateValue poppedValue
= ss
.popAttribute(timestamp
, quark
);
166 * Verify that the value we are popping matches the one in the
167 * event field, unless the latter is undefined.
169 if (!functionExitState
.isNull() && !functionExitState
.equals(poppedValue
)) {
170 Activator
.logWarning(NLS
.bind(
171 Messages
.CallStackStateProvider_UnmatchedPoppedValue
,
179 * Restrict the return type for {@link ITmfStateProvider#getNewInstance}.
184 public abstract CallStackStateProvider
getNewInstance();
187 * Check if this event should be considered at all for function entry/exit
188 * analysis. This check is only run once per event, before
189 * {@link #functionEntry} and {@link #functionExit} (to avoid repeating
190 * checks in those methods).
194 * @return If false, the event will be ignored by the state provider. If
195 * true processing will continue.
197 protected abstract boolean considerEvent(ITmfEvent event
);
200 * Check an event if it indicates a function entry.
203 * An event to check for function entry
204 * @return The state value representing the function being entered, or null
205 * if not a function entry
208 protected abstract @Nullable ITmfStateValue
functionEntry(ITmfEvent event
);
211 * Check an event if it indicates a function exit.
214 * An event to check for function exit
215 * @return The state value representing the function being exited, or
216 * TmfStateValue#nullValue() if the exited function is undefined,
217 * or null if not a function exit.
220 protected abstract @Nullable ITmfStateValue
functionExit(ITmfEvent event
);
223 * Return the process ID of a function entry event.
225 * Use {@link #UNKNOWN_PID} if it is not known.
229 * @return The process ID
232 protected abstract int getProcessId(ITmfEvent event
);
235 * Return the process name of a function entry event.
239 * @return The process name (as will be shown in the view) or null to use
240 * the process ID formatted as a string (or {@link #UNKNOWN})
243 protected @Nullable String
getProcessName(ITmfEvent event
) {
244 /* Override to provide a process name */
249 * Return the thread id of a function entry event.
253 * @return The thread id
256 protected abstract long getThreadId(ITmfEvent event
);
259 * Return the thread name of a function entry or exit event.
263 * @return The thread name (as will be shown in the view) or null to use the
264 * thread id formatted as a string
266 protected @Nullable String
getThreadName(ITmfEvent event
) {
267 /* Override to provide a thread name */