tmf: Introduce the notion of PID to the Callstack analysis
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / callstack / CallStackStateProvider.java
1 /*******************************************************************************
2 * Copyright (c) 2013, 2015 Ericsson
3 *
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
8 *
9 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.tmf.core.callstack;
14
15 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
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.exceptions.AttributeNotFoundException;
23 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
24 import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
25 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
26 import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider;
27 import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
28 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
29
30 /**
31 * The state provider for traces that support the Call Stack view.
32 *
33 * The attribute tree should have the following structure:
34 *
35 * <pre>
36 * (root)
37 * +-- Processes
38 * +-- (PID 1000)
39 * | +-- (TID 1000)
40 * | | +-- CallStack (stack-attribute)
41 * | | +-- 1
42 * | | +-- 2
43 * | | ...
44 * | | +-- n
45 * | +-- (TID 1001)
46 * | +-- CallStack (stack-attribute)
47 * | +-- 1
48 * | +-- 2
49 * | ...
50 * | +-- n
51 * |
52 * +-- (PID 2000)
53 * +-- (TID 2000)
54 * +-- CallStack (stack-attribute)
55 * +-- 1
56 * +-- 2
57 * ...
58 * +-- n
59 * </pre>
60 *
61 * where:
62 * <ul>
63 * <li>(PID n) is an attribute name representing a unique process identifier.
64 * </li>
65 * <li>(TID n) is an attribute whose name is the display name of the thread.
66 * Optionally, its value is a long representing the thread id, used for sorting.
67 * </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>
71 * </ul>
72 *
73 * @author Patrick Tasse
74 */
75 @NonNullByDefault
76 public abstract class CallStackStateProvider extends AbstractTmfStateProvider {
77
78 /** Thread attribute
79 * @since 2.0 */
80 public static final String PROCESSES = "Processes"; //$NON-NLS-1$
81
82 /** CallStack stack-attribute */
83 public static final String CALL_STACK = "CallStack"; //$NON-NLS-1$
84
85 /** Undefined process ID
86 * @since 2.0 */
87 protected static final int UNDEFINED_PID = -1;
88
89 /** Undefined function exit name */
90 protected static final String UNDEFINED = "UNDEFINED"; //$NON-NLS-1$
91
92 /** CallStack state system ID */
93 private static final String ID = "org.eclipse.linuxtools.tmf.callstack"; //$NON-NLS-1$
94
95 /** Dummy function name for when no function is expected */
96 private static final String NO_FUNCTION = "no function"; //$NON-NLS-1$
97
98 /**
99 * Default constructor
100 *
101 * @param trace
102 * The trace for which we build this state system
103 */
104 public CallStackStateProvider(ITmfTrace trace) {
105 super(trace, ID);
106 }
107
108 @Override
109 protected void eventHandle(ITmfEvent event) {
110 if (!considerEvent(event)) {
111 return;
112 }
113
114 ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder());
115
116 try {
117 /* Check if the event is a function entry */
118 String functionEntryName = functionEntry(event);
119 if (functionEntryName != null) {
120 long timestamp = event.getTimestamp().toNanos();
121 int pid = getProcessId(event);
122 String threadName = getThreadName(event);
123 int threadQuark = ss.getQuarkAbsoluteAndAdd(PROCESSES, Integer.toString(pid), threadName);
124
125 long threadId = getThreadId(event);
126 ss.updateOngoingState(TmfStateValue.newValueLong(threadId), threadQuark);
127
128 int callStackQuark = ss.getQuarkRelativeAndAdd(threadQuark, CALL_STACK);
129 ITmfStateValue value = TmfStateValue.newValueString(functionEntryName);
130 ss.pushAttribute(timestamp, value, callStackQuark);
131 return;
132 }
133
134 /* Check if the event is a function exit */
135 String functionExitName = functionExit(event);
136 if (functionExitName != null) {
137 long timestamp = event.getTimestamp().toNanos();
138 int pid = getProcessId(event);
139 String thread = getThreadName(event);
140 int quark = ss.getQuarkAbsoluteAndAdd(PROCESSES, Integer.toString(pid), thread, CALL_STACK);
141 ITmfStateValue poppedValue = ss.popAttribute(timestamp, quark);
142 String poppedName = (poppedValue == null ? NO_FUNCTION : poppedValue.unboxStr());
143
144 /*
145 * Verify that the value we are popping matches the one in the
146 * event field, unless the latter is undefined.
147 */
148 if (!functionExitName.equals(UNDEFINED) &&
149 !functionExitName.equals(poppedName)) {
150 Activator.logWarning(NLS.bind(
151 Messages.CallStackStateProvider_UnmatchedPoppedValue,
152 functionExitName,
153 poppedName));
154 }
155 }
156
157 } catch (AttributeNotFoundException e) {
158 e.printStackTrace();
159 }
160 }
161
162 /**
163 * Restrict the return type for {@link ITmfStateProvider#getNewInstance}.
164 *
165 * @since 2.0
166 */
167 @Override
168 public abstract CallStackStateProvider getNewInstance();
169
170 /**
171 * Check if this event should be considered at all for function entry/exit
172 * analysis. This check is only run once per event, before
173 * {@link #functionEntry} and {@link #functionExit} (to avoid repeating
174 * checks in those methods).
175 *
176 * @param event
177 * The event to check
178 * @return If false, the event will be ignored by the state provider. If
179 * true processing will continue.
180 */
181 protected abstract boolean considerEvent(ITmfEvent event);
182
183 /**
184 * Check an event if it indicates a function entry.
185 *
186 * @param event
187 * An event to check for function entry
188 * @return The function name of the function entry, or null if not a
189 * function entry.
190 */
191 protected abstract @Nullable String functionEntry(ITmfEvent event);
192
193 /**
194 * Check an event if it indicates a function exit.
195 *
196 * @param event
197 * An event to check for function exit
198 * @return The function name, or UNDEFINED, for a function exit, or null if
199 * not a function exit.
200 */
201 protected abstract @Nullable String functionExit(ITmfEvent event);
202
203 /**
204 * Return the process ID of a function entry event.
205 *
206 * Use {@link #UNDEFINED_PID} if it is not known.
207 *
208 * @param event
209 * The event
210 * @return The process ID
211 * @since 2.0
212 */
213 protected abstract int getProcessId(ITmfEvent event);
214
215 /**
216 * Return the thread id of a function entry event.
217 *
218 * @param event
219 * The event
220 * @return The thread id
221 * @since 2.0
222 */
223 protected abstract long getThreadId(ITmfEvent event);
224
225 /**
226 * Return the thread name of a function entry or exit event.
227 *
228 * @param event
229 * The event
230 * @return The thread name (as will be shown in the view)
231 */
232 protected abstract String getThreadName(ITmfEvent event);
233 }
This page took 0.039718 seconds and 6 git commands to generate.