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
.Nullable
;
18 import org
.eclipse
.osgi
.util
.NLS
;
19 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.Activator
;
20 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystemBuilder
;
21 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
22 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
23 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
24 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.AbstractTmfStateProvider
;
25 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.ITmfStateProvider
;
26 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
29 * The state provider for traces that support the Call Stack view.
31 * The attribute tree should have the following structure:
38 * | | +-- CallStack (stack-attribute)
44 * | +-- CallStack (stack-attribute)
52 * +-- CallStack (stack-attribute)
61 * <li>(PID n) is an attribute whose name is the display name of the process.
62 * Optionally, its value can be an int representing the process id. Otherwise,
63 * the attribute name can be set to the process id formatted as a string.</li>
64 * <li>(TID n) is an attribute whose name is the display name of the thread.
65 * Optionally, its value can be a long representing the thread id. Otherwise,
66 * the attribute name can be set to the thread id formatted as a string.</li>
67 * <li>"CallStack" is a stack-attribute whose pushed values are either a string,
68 * int or long representing the function name or address in the call stack. The
69 * type of value used must be constant for a particular CallStack.</li>
72 * @author Patrick Tasse
74 public abstract class CallStackStateProvider
extends AbstractTmfStateProvider
{
81 public static final String PROCESSES
= "Processes"; //$NON-NLS-1$
83 /** CallStack stack-attribute */
84 public static final String CALL_STACK
= "CallStack"; //$NON-NLS-1$
91 public static final int UNKNOWN_PID
= -1;
98 public static final String UNKNOWN
= "UNKNOWN"; //$NON-NLS-1$
100 /** CallStack state system ID */
101 private static final String ID
= "org.eclipse.linuxtools.tmf.callstack"; //$NON-NLS-1$
104 * Default constructor
107 * The trace for which we build this state system
109 public CallStackStateProvider(ITmfTrace trace
) {
114 protected void eventHandle(ITmfEvent event
) {
115 if (!considerEvent(event
)) {
119 ITmfStateSystemBuilder ss
= checkNotNull(getStateSystemBuilder());
121 /* Check if the event is a function entry */
122 ITmfStateValue functionEntryName
= functionEntry(event
);
123 if (functionEntryName
!= null) {
124 long timestamp
= event
.getTimestamp().toNanos();
126 String processName
= getProcessName(event
);
127 int processId
= getProcessId(event
);
128 if (processName
== null) {
129 processName
= (processId
== UNKNOWN_PID
) ? UNKNOWN
: Integer
.toString(processId
);
131 int processQuark
= ss
.getQuarkAbsoluteAndAdd(PROCESSES
, processName
);
132 ss
.updateOngoingState(TmfStateValue
.newValueInt(processId
), processQuark
);
134 String threadName
= getThreadName(event
);
135 long threadId
= getThreadId(event
);
136 if (threadName
== null) {
137 threadName
= Long
.toString(threadId
);
139 int threadQuark
= ss
.getQuarkRelativeAndAdd(processQuark
, threadName
);
140 ss
.updateOngoingState(TmfStateValue
.newValueLong(threadId
), threadQuark
);
142 int callStackQuark
= ss
.getQuarkRelativeAndAdd(threadQuark
, CALL_STACK
);
143 ITmfStateValue value
= functionEntryName
;
144 ss
.pushAttribute(timestamp
, value
, callStackQuark
);
148 /* Check if the event is a function exit */
149 ITmfStateValue functionExitState
= functionExit(event
);
150 if (functionExitState
!= null) {
151 long timestamp
= event
.getTimestamp().toNanos();
152 String processName
= getProcessName(event
);
153 if (processName
== null) {
154 int processId
= getProcessId(event
);
155 processName
= (processId
== UNKNOWN_PID
) ? UNKNOWN
: Integer
.toString(processId
);
157 String threadName
= getThreadName(event
);
158 if (threadName
== null) {
159 threadName
= Long
.toString(getThreadId(event
));
161 int quark
= ss
.getQuarkAbsoluteAndAdd(PROCESSES
, processName
, threadName
, CALL_STACK
);
162 ITmfStateValue poppedValue
= ss
.popAttribute(timestamp
, quark
);
164 * Verify that the value we are popping matches the one in the
165 * event field, unless the latter is undefined.
167 if (!functionExitState
.isNull() && !functionExitState
.equals(poppedValue
)) {
168 Activator
.logWarning(NLS
.bind(
169 Messages
.CallStackStateProvider_UnmatchedPoppedValue
,
177 * Restrict the return type for {@link ITmfStateProvider#getNewInstance}.
182 public abstract CallStackStateProvider
getNewInstance();
185 * Check if this event should be considered at all for function entry/exit
186 * analysis. This check is only run once per event, before
187 * {@link #functionEntry} and {@link #functionExit} (to avoid repeating
188 * checks in those methods).
192 * @return If false, the event will be ignored by the state provider. If
193 * true processing will continue.
195 protected abstract boolean considerEvent(ITmfEvent event
);
198 * Check an event if it indicates a function entry.
201 * An event to check for function entry
202 * @return The state value representing the function being entered, or null
203 * if not a function entry
206 protected abstract @Nullable ITmfStateValue
functionEntry(ITmfEvent event
);
209 * Check an event if it indicates a function exit.
212 * An event to check for function exit
213 * @return The state value representing the function being exited, or
214 * TmfStateValue#nullValue() if the exited function is undefined,
215 * or null if not a function exit.
218 protected abstract @Nullable ITmfStateValue
functionExit(ITmfEvent event
);
221 * Return the process ID of a function entry event.
223 * Use {@link #UNKNOWN_PID} if it is not known.
227 * @return The process ID
230 protected abstract int getProcessId(ITmfEvent event
);
233 * Return the process name of a function entry event.
237 * @return The process name (as will be shown in the view) or null to use
238 * the process ID formatted as a string (or {@link #UNKNOWN})
241 protected @Nullable String
getProcessName(ITmfEvent event
) {
242 /* Override to provide a process name */
247 * Return the thread id of a function entry event.
251 * @return The thread id
254 protected abstract long getThreadId(ITmfEvent event
);
257 * Return the thread name of a function entry or exit event.
261 * @return The thread name (as will be shown in the view) or null to use the
262 * thread id formatted as a string
264 protected @Nullable String
getThreadName(ITmfEvent event
) {
265 /* Override to provide a thread name */