Commit | Line | Data |
---|---|---|
efc403bb | 1 | /******************************************************************************* |
ed902a2b | 2 | * Copyright (c) 2012, 2015 Ericsson |
efc403bb AM |
3 | * Copyright (c) 2010, 2011 École Polytechnique de Montréal |
4 | * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com> | |
d85d2a6d | 5 | * |
efc403bb AM |
6 | * All rights reserved. This program and the accompanying materials are |
7 | * made available under the terms of the Eclipse Public License v1.0 which | |
8 | * accompanies this distribution, and is available at | |
9 | * http://www.eclipse.org/legal/epl-v10.html | |
d85d2a6d | 10 | * |
efc403bb AM |
11 | *******************************************************************************/ |
12 | ||
6d16f5a9 | 13 | package org.eclipse.tracecompass.internal.analysis.os.linux.core.kernelanalysis; |
efc403bb | 14 | |
d0c7e4ba AM |
15 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
16 | ||
7411cd67 AM |
17 | import java.util.Map; |
18 | ||
e363eae1 | 19 | import org.eclipse.jdt.annotation.Nullable; |
6d16f5a9 | 20 | import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.Attributes; |
af7f72ce | 21 | import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.LinuxValues; |
6d16f5a9 | 22 | import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.StateValues; |
e363eae1 | 23 | import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout; |
e894a508 AM |
24 | import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; |
25 | import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; | |
26 | import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException; | |
27 | import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException; | |
28 | import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; | |
29 | import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; | |
2bdf0193 AM |
30 | import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; |
31 | import org.eclipse.tracecompass.tmf.core.event.ITmfEventField; | |
1786026d | 32 | import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect; |
2bdf0193 AM |
33 | import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider; |
34 | import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; | |
1786026d | 35 | import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; |
efc403bb | 36 | |
7411cd67 AM |
37 | import com.google.common.collect.ImmutableMap; |
38 | ||
efc403bb AM |
39 | /** |
40 | * This is the state change input plugin for TMF's state system which handles | |
41 | * the LTTng 2.0 kernel traces in CTF format. | |
d85d2a6d | 42 | * |
efc403bb | 43 | * It uses the reference handler defined in CTFKernelHandler.java. |
d85d2a6d | 44 | * |
efc403bb | 45 | * @author alexmont |
d85d2a6d | 46 | * |
efc403bb | 47 | */ |
e363eae1 | 48 | public class KernelStateProvider extends AbstractTmfStateProvider { |
efc403bb | 49 | |
7411cd67 AM |
50 | // ------------------------------------------------------------------------ |
51 | // Static fields | |
52 | // ------------------------------------------------------------------------ | |
53 | ||
a96cc6be AM |
54 | /** |
55 | * Version number of this state provider. Please bump this if you modify the | |
56 | * contents of the generated state history in some way. | |
57 | */ | |
2f693965 | 58 | private static final int VERSION = 9; |
a96cc6be | 59 | |
7411cd67 AM |
60 | private static final int IRQ_HANDLER_ENTRY_INDEX = 1; |
61 | private static final int IRQ_HANDLER_EXIT_INDEX = 2; | |
62 | private static final int SOFT_IRQ_ENTRY_INDEX = 3; | |
63 | private static final int SOFT_IRQ_EXIT_INDEX = 4; | |
64 | private static final int SOFT_IRQ_RAISE_INDEX = 5; | |
65 | private static final int SCHED_SWITCH_INDEX = 6; | |
66 | private static final int SCHED_PROCESS_FORK_INDEX = 7; | |
67 | private static final int SCHED_PROCESS_EXIT_INDEX = 8; | |
68 | private static final int SCHED_PROCESS_FREE_INDEX = 9; | |
69 | private static final int STATEDUMP_PROCESS_STATE_INDEX = 10; | |
70 | private static final int SCHED_WAKEUP_INDEX = 11; | |
3bf563da | 71 | private static final int SCHED_PI_SETPRIO_INDEX = 12; |
7411cd67 AM |
72 | |
73 | ||
74 | // ------------------------------------------------------------------------ | |
75 | // Fields | |
76 | // ------------------------------------------------------------------------ | |
77 | ||
78 | private final Map<String, Integer> fEventNames; | |
e363eae1 | 79 | private final IKernelAnalysisEventLayout fLayout; |
7411cd67 | 80 | |
6383e95d AM |
81 | // ------------------------------------------------------------------------ |
82 | // Constructor | |
83 | // ------------------------------------------------------------------------ | |
efc403bb AM |
84 | |
85 | /** | |
86 | * Instantiate a new state provider plugin. | |
d85d2a6d AM |
87 | * |
88 | * @param trace | |
efc403bb | 89 | * The LTTng 2.0 kernel trace directory |
7411cd67 AM |
90 | * @param layout |
91 | * The event layout to use for this state provider. Usually | |
92 | * depending on the tracer implementation. | |
efc403bb | 93 | */ |
e363eae1 | 94 | public KernelStateProvider(ITmfTrace trace, IKernelAnalysisEventLayout layout) { |
e2bcc8a5 | 95 | super(trace, "Kernel"); //$NON-NLS-1$ |
7411cd67 AM |
96 | fLayout = layout; |
97 | fEventNames = buildEventNames(layout); | |
98 | } | |
99 | ||
100 | // ------------------------------------------------------------------------ | |
101 | // Event names management | |
102 | // ------------------------------------------------------------------------ | |
103 | ||
104 | private static Map<String, Integer> buildEventNames(IKernelAnalysisEventLayout layout) { | |
105 | ImmutableMap.Builder<String, Integer> builder = ImmutableMap.builder(); | |
106 | ||
7411cd67 AM |
107 | builder.put(layout.eventIrqHandlerEntry(), IRQ_HANDLER_ENTRY_INDEX); |
108 | builder.put(layout.eventIrqHandlerExit(), IRQ_HANDLER_EXIT_INDEX); | |
109 | builder.put(layout.eventSoftIrqEntry(), SOFT_IRQ_ENTRY_INDEX); | |
110 | builder.put(layout.eventSoftIrqExit(), SOFT_IRQ_EXIT_INDEX); | |
111 | builder.put(layout.eventSoftIrqRaise(), SOFT_IRQ_RAISE_INDEX); | |
112 | builder.put(layout.eventSchedSwitch(), SCHED_SWITCH_INDEX); | |
3bf563da | 113 | builder.put(layout.eventSchedPiSetprio(), SCHED_PI_SETPRIO_INDEX); |
7411cd67 AM |
114 | builder.put(layout.eventSchedProcessFork(), SCHED_PROCESS_FORK_INDEX); |
115 | builder.put(layout.eventSchedProcessExit(), SCHED_PROCESS_EXIT_INDEX); | |
116 | builder.put(layout.eventSchedProcessFree(), SCHED_PROCESS_FREE_INDEX); | |
bd0e2f70 | 117 | |
1224c7d2 MK |
118 | final String eventStatedumpProcessState = layout.eventStatedumpProcessState(); |
119 | if (eventStatedumpProcessState != null) { | |
120 | builder.put(eventStatedumpProcessState, STATEDUMP_PROCESS_STATE_INDEX); | |
bd0e2f70 | 121 | } |
7411cd67 AM |
122 | |
123 | for (String eventSchedWakeup : layout.eventsSchedWakeup()) { | |
124 | builder.put(eventSchedWakeup, SCHED_WAKEUP_INDEX); | |
125 | } | |
126 | ||
e363eae1 | 127 | return checkNotNull(builder.build()); |
2c2f900e | 128 | } |
efc403bb | 129 | |
6383e95d AM |
130 | // ------------------------------------------------------------------------ |
131 | // IStateChangeInput | |
132 | // ------------------------------------------------------------------------ | |
133 | ||
a96cc6be AM |
134 | @Override |
135 | public int getVersion() { | |
136 | return VERSION; | |
137 | } | |
138 | ||
2c2f900e | 139 | @Override |
f1f86dfb | 140 | public void assignTargetStateSystem(ITmfStateSystemBuilder ssb) { |
79e0a1df AM |
141 | /* We can only set up the locations once the state system is assigned */ |
142 | super.assignTargetStateSystem(ssb); | |
2c2f900e | 143 | } |
efc403bb | 144 | |
e96ab5c4 | 145 | @Override |
e363eae1 AM |
146 | public KernelStateProvider getNewInstance() { |
147 | return new KernelStateProvider(this.getTrace(), fLayout); | |
e96ab5c4 AM |
148 | } |
149 | ||
efc403bb | 150 | @Override |
e363eae1 AM |
151 | protected void eventHandle(@Nullable ITmfEvent event) { |
152 | if (event == null) { | |
153 | return; | |
154 | } | |
d0c7e4ba | 155 | |
b1aad44e GB |
156 | Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event); |
157 | if (cpuObj == null) { | |
1786026d | 158 | /* We couldn't find any CPU information, ignore this event */ |
e1de2fd4 AM |
159 | return; |
160 | } | |
b1aad44e | 161 | Integer cpu = (Integer) cpuObj; |
79e0a1df | 162 | |
e3d50cf4 | 163 | final String eventName = event.getName(); |
79e0a1df AM |
164 | final long ts = event.getTimestamp().getValue(); |
165 | ||
2c2f900e | 166 | try { |
e363eae1 AM |
167 | final ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder()); |
168 | ||
79e0a1df | 169 | /* Shortcut for the "current CPU" attribute node */ |
d0c7e4ba | 170 | final int currentCPUNode = ss.getQuarkRelativeAndAdd(getNodeCPUs(ss), cpu.toString()); |
79e0a1df AM |
171 | |
172 | /* | |
173 | * Shortcut for the "current thread" attribute node. It requires | |
174 | * querying the current CPU's current thread. | |
175 | */ | |
3ae73cfa AM |
176 | int quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.CURRENT_THREAD); |
177 | ITmfStateValue value = ss.queryOngoingState(quark); | |
359eeba0 | 178 | int thread = value.isNull() ? -1 : value.unboxInt(); |
d0c7e4ba | 179 | final int currentThreadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), String.valueOf(thread)); |
79e0a1df AM |
180 | |
181 | /* | |
182 | * Feed event to the history system if it's known to cause a state | |
183 | * transition. | |
184 | */ | |
7411cd67 AM |
185 | Integer idx = fEventNames.get(eventName); |
186 | int intval = (idx == null ? -1 : idx.intValue()); | |
187 | switch (intval) { | |
79e0a1df | 188 | |
7411cd67 | 189 | case IRQ_HANDLER_ENTRY_INDEX: |
79e0a1df | 190 | { |
7411cd67 | 191 | Integer irqId = ((Long) event.getContent().getField(fLayout.fieldIrq()).getValue()).intValue(); |
79e0a1df AM |
192 | |
193 | /* Mark this IRQ as active in the resource tree. | |
194 | * The state value = the CPU on which this IRQ is sitting */ | |
d0c7e4ba | 195 | quark = ss.getQuarkRelativeAndAdd(getNodeIRQs(ss), irqId.toString()); |
1786026d | 196 | value = TmfStateValue.newValueInt(cpu.intValue()); |
79e0a1df AM |
197 | ss.modifyAttribute(ts, value, quark); |
198 | ||
199 | /* Change the status of the running process to interrupted */ | |
200 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS); | |
dfb27cee | 201 | value = StateValues.PROCESS_STATUS_INTERRUPTED_VALUE; |
79e0a1df AM |
202 | ss.modifyAttribute(ts, value, quark); |
203 | ||
204 | /* Change the status of the CPU to interrupted */ | |
205 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS); | |
dfb27cee | 206 | value = StateValues.CPU_STATUS_IRQ_VALUE; |
79e0a1df AM |
207 | ss.modifyAttribute(ts, value, quark); |
208 | } | |
209 | break; | |
210 | ||
7411cd67 | 211 | case IRQ_HANDLER_EXIT_INDEX: |
79e0a1df | 212 | { |
7411cd67 | 213 | Integer irqId = ((Long) event.getContent().getField(fLayout.fieldIrq()).getValue()).intValue(); |
79e0a1df AM |
214 | |
215 | /* Put this IRQ back to inactive in the resource tree */ | |
d0c7e4ba | 216 | quark = ss.getQuarkRelativeAndAdd(getNodeIRQs(ss), irqId.toString()); |
79e0a1df AM |
217 | value = TmfStateValue.nullValue(); |
218 | ss.modifyAttribute(ts, value, quark); | |
219 | ||
220 | /* Set the previous process back to running */ | |
d0c7e4ba | 221 | setProcessToRunning(ss, ts, currentThreadNode); |
79e0a1df AM |
222 | |
223 | /* Set the CPU status back to running or "idle" */ | |
d0c7e4ba | 224 | cpuExitInterrupt(ss, ts, currentCPUNode, currentThreadNode); |
79e0a1df AM |
225 | } |
226 | break; | |
227 | ||
7411cd67 | 228 | case SOFT_IRQ_ENTRY_INDEX: |
79e0a1df | 229 | { |
7411cd67 | 230 | Integer softIrqId = ((Long) event.getContent().getField(fLayout.fieldVec()).getValue()).intValue(); |
79e0a1df AM |
231 | |
232 | /* Mark this SoftIRQ as active in the resource tree. | |
233 | * The state value = the CPU on which this SoftIRQ is processed */ | |
d0c7e4ba | 234 | quark = ss.getQuarkRelativeAndAdd(getNodeSoftIRQs(ss), softIrqId.toString()); |
1786026d | 235 | value = TmfStateValue.newValueInt(cpu.intValue()); |
79e0a1df AM |
236 | ss.modifyAttribute(ts, value, quark); |
237 | ||
238 | /* Change the status of the running process to interrupted */ | |
239 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS); | |
dfb27cee | 240 | value = StateValues.PROCESS_STATUS_INTERRUPTED_VALUE; |
79e0a1df AM |
241 | ss.modifyAttribute(ts, value, quark); |
242 | ||
243 | /* Change the status of the CPU to interrupted */ | |
244 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS); | |
dfb27cee | 245 | value = StateValues.CPU_STATUS_SOFTIRQ_VALUE; |
79e0a1df AM |
246 | ss.modifyAttribute(ts, value, quark); |
247 | } | |
248 | break; | |
249 | ||
7411cd67 | 250 | case SOFT_IRQ_EXIT_INDEX: |
79e0a1df | 251 | { |
7411cd67 | 252 | Integer softIrqId = ((Long) event.getContent().getField(fLayout.fieldVec()).getValue()).intValue(); |
79e0a1df AM |
253 | |
254 | /* Put this SoftIRQ back to inactive (= -1) in the resource tree */ | |
d0c7e4ba | 255 | quark = ss.getQuarkRelativeAndAdd(getNodeSoftIRQs(ss), softIrqId.toString()); |
79e0a1df AM |
256 | value = TmfStateValue.nullValue(); |
257 | ss.modifyAttribute(ts, value, quark); | |
258 | ||
259 | /* Set the previous process back to running */ | |
d0c7e4ba | 260 | setProcessToRunning(ss, ts, currentThreadNode); |
79e0a1df AM |
261 | |
262 | /* Set the CPU status back to "busy" or "idle" */ | |
d0c7e4ba | 263 | cpuExitInterrupt(ss, ts, currentCPUNode, currentThreadNode); |
79e0a1df AM |
264 | } |
265 | break; | |
266 | ||
7411cd67 | 267 | case SOFT_IRQ_RAISE_INDEX: |
79e0a1df AM |
268 | /* Fields: int32 vec */ |
269 | { | |
7411cd67 | 270 | Integer softIrqId = ((Long) event.getContent().getField(fLayout.fieldVec()).getValue()).intValue(); |
79e0a1df AM |
271 | |
272 | /* Mark this SoftIRQ as *raised* in the resource tree. | |
273 | * State value = -2 */ | |
d0c7e4ba | 274 | quark = ss.getQuarkRelativeAndAdd(getNodeSoftIRQs(ss), softIrqId.toString()); |
dfb27cee | 275 | value = StateValues.SOFT_IRQ_RAISED_VALUE; |
79e0a1df AM |
276 | ss.modifyAttribute(ts, value, quark); |
277 | } | |
278 | break; | |
279 | ||
7411cd67 | 280 | case SCHED_SWITCH_INDEX: |
79e0a1df | 281 | { |
7a2f04a6 | 282 | ITmfEventField content = event.getContent(); |
7411cd67 AM |
283 | Integer prevTid = ((Long) content.getField(fLayout.fieldPrevTid()).getValue()).intValue(); |
284 | Long prevState = (Long) content.getField(fLayout.fieldPrevState()).getValue(); | |
285 | String nextProcessName = (String) content.getField(fLayout.fieldNextComm()).getValue(); | |
286 | Integer nextTid = ((Long) content.getField(fLayout.fieldNextTid()).getValue()).intValue(); | |
3bf563da | 287 | Integer nextPrio = ((Long) content.getField(fLayout.fieldNextPrio()).getValue()).intValue(); |
79e0a1df | 288 | |
d0c7e4ba AM |
289 | Integer formerThreadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), prevTid.toString()); |
290 | Integer newCurrentThreadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), nextTid.toString()); | |
79e0a1df | 291 | |
6b1f08f1 GB |
292 | /* |
293 | * Empirical observations and look into the linux code have | |
294 | * shown that the TASK_STATE_MAX flag is used internally and | |
295 | * |'ed with other states, most often the running state, so it | |
296 | * is ignored from the prevState value. | |
297 | */ | |
298 | prevState = prevState & ~(LinuxValues.TASK_STATE_MAX); | |
299 | ||
79e0a1df | 300 | /* Set the status of the process that got scheduled out. */ |
2f693965 AM |
301 | switch (prevState.intValue()) { |
302 | case LinuxValues.TASK_STATE_RUNNING: | |
dfb27cee | 303 | value = StateValues.PROCESS_STATUS_WAIT_FOR_CPU_VALUE; |
2f693965 AM |
304 | break; |
305 | case LinuxValues.TASK_INTERRUPTIBLE: | |
306 | case LinuxValues.TASK_UNINTERRUPTIBLE: | |
307 | value = StateValues.PROCESS_STATUS_WAIT_BLOCKED_VALUE; | |
308 | break; | |
309 | case LinuxValues.TASK_DEAD: | |
310 | value = TmfStateValue.nullValue(); | |
311 | break; | |
312 | default: | |
313 | value = StateValues.PROCESS_STATUS_WAIT_UNKNOWN_VALUE; | |
314 | break; | |
f2338178 | 315 | } |
2f693965 AM |
316 | |
317 | quark = ss.getQuarkRelativeAndAdd(formerThreadNode, Attributes.STATUS); | |
79e0a1df AM |
318 | ss.modifyAttribute(ts, value, quark); |
319 | ||
320 | /* Set the status of the new scheduled process */ | |
d0c7e4ba | 321 | setProcessToRunning(ss, ts, newCurrentThreadNode); |
79e0a1df AM |
322 | |
323 | /* Set the exec name of the new process */ | |
324 | quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.EXEC_NAME); | |
325 | value = TmfStateValue.newValueString(nextProcessName); | |
326 | ss.modifyAttribute(ts, value, quark); | |
327 | ||
3bf563da CM |
328 | /* Set the current prio for the new process */ |
329 | quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.PRIO); | |
330 | value = TmfStateValue.newValueInt(nextPrio); | |
331 | ss.modifyAttribute(ts, value, quark); | |
332 | ||
25e43749 AM |
333 | /* Make sure the PPID and system_call sub-attributes exist */ |
334 | ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.SYSTEM_CALL); | |
335 | ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.PPID); | |
79e0a1df AM |
336 | |
337 | /* Set the current scheduled process on the relevant CPU */ | |
338 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.CURRENT_THREAD); | |
339 | value = TmfStateValue.newValueInt(nextTid); | |
340 | ss.modifyAttribute(ts, value, quark); | |
341 | ||
342 | /* Set the status of the CPU itself */ | |
343 | if (nextTid > 0) { | |
344 | /* Check if the entering process is in kernel or user mode */ | |
345 | quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.SYSTEM_CALL); | |
346 | if (ss.queryOngoingState(quark).isNull()) { | |
dfb27cee | 347 | value = StateValues.CPU_STATUS_RUN_USERMODE_VALUE; |
79e0a1df | 348 | } else { |
dfb27cee | 349 | value = StateValues.CPU_STATUS_RUN_SYSCALL_VALUE; |
79e0a1df AM |
350 | } |
351 | } else { | |
dfb27cee | 352 | value = StateValues.CPU_STATUS_IDLE_VALUE; |
79e0a1df AM |
353 | } |
354 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS); | |
355 | ss.modifyAttribute(ts, value, quark); | |
356 | } | |
357 | break; | |
358 | ||
3bf563da CM |
359 | case SCHED_PI_SETPRIO_INDEX: |
360 | { | |
361 | ITmfEventField content = event.getContent(); | |
362 | Integer tid = ((Long) content.getField(fLayout.fieldTid()).getValue()).intValue(); | |
363 | Integer prio = ((Long) content.getField(fLayout.fieldNewPrio()).getValue()).intValue(); | |
364 | ||
365 | Integer updateThreadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), tid.toString()); | |
366 | ||
367 | /* Set the current prio for the new process */ | |
368 | quark = ss.getQuarkRelativeAndAdd(updateThreadNode, Attributes.PRIO); | |
369 | value = TmfStateValue.newValueInt(prio); | |
370 | ss.modifyAttribute(ts, value, quark); | |
371 | } | |
372 | break; | |
373 | ||
7411cd67 | 374 | case SCHED_PROCESS_FORK_INDEX: |
79e0a1df | 375 | { |
7a2f04a6 | 376 | ITmfEventField content = event.getContent(); |
79e0a1df | 377 | // String parentProcessName = (String) event.getFieldValue("parent_comm"); |
7411cd67 | 378 | String childProcessName = (String) content.getField(fLayout.fieldChildComm()).getValue(); |
79e0a1df AM |
379 | // assert ( parentProcessName.equals(childProcessName) ); |
380 | ||
7411cd67 AM |
381 | Integer parentTid = ((Long) content.getField(fLayout.fieldParentTid()).getValue()).intValue(); |
382 | Integer childTid = ((Long) content.getField(fLayout.fieldChildTid()).getValue()).intValue(); | |
79e0a1df | 383 | |
d0c7e4ba AM |
384 | Integer parentTidNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), parentTid.toString()); |
385 | Integer childTidNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), childTid.toString()); | |
79e0a1df AM |
386 | |
387 | /* Assign the PPID to the new process */ | |
388 | quark = ss.getQuarkRelativeAndAdd(childTidNode, Attributes.PPID); | |
389 | value = TmfStateValue.newValueInt(parentTid); | |
390 | ss.modifyAttribute(ts, value, quark); | |
391 | ||
392 | /* Set the new process' exec_name */ | |
393 | quark = ss.getQuarkRelativeAndAdd(childTidNode, Attributes.EXEC_NAME); | |
394 | value = TmfStateValue.newValueString(childProcessName); | |
395 | ss.modifyAttribute(ts, value, quark); | |
396 | ||
397 | /* Set the new process' status */ | |
398 | quark = ss.getQuarkRelativeAndAdd(childTidNode, Attributes.STATUS); | |
dfb27cee | 399 | value = StateValues.PROCESS_STATUS_WAIT_FOR_CPU_VALUE; |
79e0a1df AM |
400 | ss.modifyAttribute(ts, value, quark); |
401 | ||
402 | /* Set the process' syscall name, to be the same as the parent's */ | |
403 | quark = ss.getQuarkRelativeAndAdd(parentTidNode, Attributes.SYSTEM_CALL); | |
404 | value = ss.queryOngoingState(quark); | |
b46ea93c AM |
405 | if (value.isNull()) { |
406 | /* | |
407 | * Maybe we were missing info about the parent? At least we | |
408 | * will set the child right. Let's suppose "sys_clone". | |
409 | */ | |
7411cd67 | 410 | value = TmfStateValue.newValueString(fLayout.eventSyscallEntryPrefix() + IKernelAnalysisEventLayout.INITIAL_SYSCALL_NAME); |
b46ea93c | 411 | } |
79e0a1df AM |
412 | quark = ss.getQuarkRelativeAndAdd(childTidNode, Attributes.SYSTEM_CALL); |
413 | ss.modifyAttribute(ts, value, quark); | |
414 | } | |
415 | break; | |
416 | ||
7411cd67 | 417 | case SCHED_PROCESS_EXIT_INDEX: |
79e0a1df AM |
418 | break; |
419 | ||
7411cd67 | 420 | case SCHED_PROCESS_FREE_INDEX: |
79e0a1df | 421 | { |
7411cd67 | 422 | Integer tid = ((Long) event.getContent().getField(fLayout.fieldTid()).getValue()).intValue(); |
79e0a1df AM |
423 | /* |
424 | * Remove the process and all its sub-attributes from the | |
425 | * current state | |
426 | */ | |
d0c7e4ba | 427 | quark = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), tid.toString()); |
79e0a1df AM |
428 | ss.removeAttribute(ts, quark); |
429 | } | |
430 | break; | |
431 | ||
7411cd67 AM |
432 | case STATEDUMP_PROCESS_STATE_INDEX: |
433 | /* LTTng-specific */ | |
79e0a1df | 434 | { |
7a2f04a6 | 435 | ITmfEventField content = event.getContent(); |
7411cd67 AM |
436 | int tid = ((Long) content.getField("tid").getValue()).intValue(); //$NON-NLS-1$ |
437 | int pid = ((Long) content.getField("pid").getValue()).intValue(); //$NON-NLS-1$ | |
438 | int ppid = ((Long) content.getField("ppid").getValue()).intValue(); //$NON-NLS-1$ | |
439 | int status = ((Long) content.getField("status").getValue()).intValue(); //$NON-NLS-1$ | |
440 | String name = (String) content.getField("name").getValue(); //$NON-NLS-1$ | |
79e0a1df AM |
441 | /* |
442 | * "mode" could be interesting too, but it doesn't seem to be | |
443 | * populated with anything relevant for now. | |
444 | */ | |
445 | ||
d0c7e4ba | 446 | int curThreadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), String.valueOf(tid)); |
79e0a1df AM |
447 | |
448 | /* Set the process' name */ | |
449 | quark = ss.getQuarkRelativeAndAdd(curThreadNode, Attributes.EXEC_NAME); | |
450 | if (ss.queryOngoingState(quark).isNull()) { | |
451 | /* If the value didn't exist previously, set it */ | |
452 | value = TmfStateValue.newValueString(name); | |
453 | ss.modifyAttribute(ts, value, quark); | |
454 | } | |
455 | ||
456 | /* Set the process' PPID */ | |
457 | quark = ss.getQuarkRelativeAndAdd(curThreadNode, Attributes.PPID); | |
458 | if (ss.queryOngoingState(quark).isNull()) { | |
bc19bff3 AM |
459 | if (pid == tid) { |
460 | /* We have a process. Use the 'PPID' field. */ | |
461 | value = TmfStateValue.newValueInt(ppid); | |
462 | } else { | |
463 | /* We have a thread, use the 'PID' field for the parent. */ | |
464 | value = TmfStateValue.newValueInt(pid); | |
465 | } | |
79e0a1df AM |
466 | ss.modifyAttribute(ts, value, quark); |
467 | } | |
468 | ||
469 | /* Set the process' status */ | |
470 | quark = ss.getQuarkRelativeAndAdd(curThreadNode, Attributes.STATUS); | |
471 | if (ss.queryOngoingState(quark).isNull()) { | |
a810c240 | 472 | switch (status) { |
03bd936a | 473 | case LinuxValues.STATEDUMP_PROCESS_STATUS_WAIT_CPU: |
dfb27cee | 474 | value = StateValues.PROCESS_STATUS_WAIT_FOR_CPU_VALUE; |
a810c240 | 475 | break; |
03bd936a AM |
476 | case LinuxValues.STATEDUMP_PROCESS_STATUS_WAIT: |
477 | /* | |
478 | * We have no information on what the process is waiting | |
479 | * on (unlike a sched_switch for example), so we will | |
480 | * use the WAIT_UNKNOWN state instead of the "normal" | |
481 | * WAIT_BLOCKED state. | |
482 | */ | |
a810c240 AM |
483 | value = StateValues.PROCESS_STATUS_WAIT_UNKNOWN_VALUE; |
484 | break; | |
485 | default: | |
dfb27cee | 486 | value = StateValues.PROCESS_STATUS_UNKNOWN_VALUE; |
79e0a1df AM |
487 | } |
488 | ss.modifyAttribute(ts, value, quark); | |
489 | } | |
490 | } | |
491 | break; | |
492 | ||
7411cd67 | 493 | case SCHED_WAKEUP_INDEX: |
d1b933e7 | 494 | { |
7411cd67 | 495 | final int tid = ((Long) event.getContent().getField(fLayout.fieldTid()).getValue()).intValue(); |
3bf563da | 496 | final int prio = ((Long) event.getContent().getField(fLayout.fieldPrio()).getValue()).intValue(); |
d0c7e4ba | 497 | final int threadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), String.valueOf(tid)); |
d1b933e7 AM |
498 | |
499 | /* | |
500 | * The process indicated in the event's payload is now ready to | |
3d6e6112 FR |
501 | * run. Assign it to the "wait for cpu" state, but only if it |
502 | * was not already running. | |
d1b933e7 AM |
503 | */ |
504 | quark = ss.getQuarkRelativeAndAdd(threadNode, Attributes.STATUS); | |
3d6e6112 FR |
505 | int status = ss.queryOngoingState(quark).unboxInt(); |
506 | ||
507 | if (status != StateValues.PROCESS_STATUS_RUN_SYSCALL && | |
508 | status != StateValues.PROCESS_STATUS_RUN_USERMODE) { | |
509 | value = StateValues.PROCESS_STATUS_WAIT_FOR_CPU_VALUE; | |
510 | ss.modifyAttribute(ts, value, quark); | |
511 | } | |
3bf563da CM |
512 | |
513 | /* | |
514 | * When a user changes a threads prio (e.g. with pthread_setschedparam), | |
515 | * it shows in ftrace with a sched_wakeup. | |
516 | */ | |
517 | quark = ss.getQuarkRelativeAndAdd(threadNode, Attributes.PRIO); | |
518 | value = TmfStateValue.newValueInt(prio); | |
519 | ss.modifyAttribute(ts, value, quark); | |
d1b933e7 AM |
520 | } |
521 | break; | |
522 | ||
79e0a1df AM |
523 | default: |
524 | /* Other event types not covered by the main switch */ | |
525 | { | |
7411cd67 AM |
526 | if (eventName.startsWith(fLayout.eventSyscallEntryPrefix()) |
527 | || eventName.startsWith(fLayout.eventCompatSyscallEntryPrefix())) { | |
79e0a1df AM |
528 | |
529 | /* Assign the new system call to the process */ | |
530 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL); | |
531 | value = TmfStateValue.newValueString(eventName); | |
532 | ss.modifyAttribute(ts, value, quark); | |
533 | ||
534 | /* Put the process in system call mode */ | |
535 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS); | |
dfb27cee | 536 | value = StateValues.PROCESS_STATUS_RUN_SYSCALL_VALUE; |
79e0a1df AM |
537 | ss.modifyAttribute(ts, value, quark); |
538 | ||
539 | /* Put the CPU in system call (kernel) mode */ | |
540 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS); | |
dfb27cee | 541 | value = StateValues.CPU_STATUS_RUN_SYSCALL_VALUE; |
79e0a1df | 542 | ss.modifyAttribute(ts, value, quark); |
acba092b AM |
543 | |
544 | } else if (eventName.startsWith(fLayout.eventSyscallExitPrefix())) { | |
545 | ||
546 | /* Clear the current system call on the process */ | |
547 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL); | |
548 | value = TmfStateValue.nullValue(); | |
549 | ss.modifyAttribute(ts, value, quark); | |
550 | ||
551 | /* Put the process' status back to user mode */ | |
552 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS); | |
553 | value = StateValues.PROCESS_STATUS_RUN_USERMODE_VALUE; | |
554 | ss.modifyAttribute(ts, value, quark); | |
555 | ||
556 | /* Put the CPU's status back to user mode */ | |
557 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS); | |
558 | value = StateValues.CPU_STATUS_RUN_USERMODE_VALUE; | |
559 | ss.modifyAttribute(ts, value, quark); | |
79e0a1df | 560 | } |
acba092b | 561 | |
79e0a1df AM |
562 | } |
563 | break; | |
564 | } // End of big switch | |
565 | ||
79e0a1df AM |
566 | } catch (AttributeNotFoundException ae) { |
567 | /* | |
568 | * This would indicate a problem with the logic of the manager here, | |
569 | * so it shouldn't happen. | |
570 | */ | |
571 | ae.printStackTrace(); | |
572 | ||
573 | } catch (TimeRangeException tre) { | |
574 | /* | |
575 | * This would happen if the events in the trace aren't ordered | |
576 | * chronologically, which should never be the case ... | |
577 | */ | |
578 | System.err.println("TimeRangeExcpetion caught in the state system's event manager."); //$NON-NLS-1$ | |
579 | System.err.println("Are the events in the trace correctly ordered?"); //$NON-NLS-1$ | |
580 | tre.printStackTrace(); | |
581 | ||
582 | } catch (StateValueTypeException sve) { | |
583 | /* | |
584 | * This would happen if we were trying to push/pop attributes not of | |
585 | * type integer. Which, once again, should never happen. | |
586 | */ | |
587 | sve.printStackTrace(); | |
2c2f900e AM |
588 | } |
589 | } | |
590 | ||
6383e95d AM |
591 | // ------------------------------------------------------------------------ |
592 | // Convenience methods for commonly-used attribute tree locations | |
593 | // ------------------------------------------------------------------------ | |
594 | ||
d0c7e4ba AM |
595 | private static int getNodeCPUs(ITmfStateSystemBuilder ssb) { |
596 | return ssb.getQuarkAbsoluteAndAdd(Attributes.CPUS); | |
79e0a1df AM |
597 | } |
598 | ||
d0c7e4ba AM |
599 | private static int getNodeThreads(ITmfStateSystemBuilder ssb) { |
600 | return ssb.getQuarkAbsoluteAndAdd(Attributes.THREADS); | |
6383e95d AM |
601 | } |
602 | ||
d0c7e4ba AM |
603 | private static int getNodeIRQs(ITmfStateSystemBuilder ssb) { |
604 | return ssb.getQuarkAbsoluteAndAdd(Attributes.RESOURCES, Attributes.IRQS); | |
6383e95d AM |
605 | } |
606 | ||
d0c7e4ba AM |
607 | private static int getNodeSoftIRQs(ITmfStateSystemBuilder ssb) { |
608 | return ssb.getQuarkAbsoluteAndAdd(Attributes.RESOURCES, Attributes.SOFT_IRQS); | |
6383e95d AM |
609 | } |
610 | ||
6383e95d AM |
611 | // ------------------------------------------------------------------------ |
612 | // Advanced state-setting methods | |
613 | // ------------------------------------------------------------------------ | |
614 | ||
79e0a1df AM |
615 | /** |
616 | * When we want to set a process back to a "running" state, first check | |
617 | * its current System_call attribute. If there is a system call active, we | |
618 | * put the process back in the syscall state. If not, we put it back in | |
619 | * user mode state. | |
620 | */ | |
d0c7e4ba | 621 | private static void setProcessToRunning(ITmfStateSystemBuilder ssb, long ts, int currentThreadNode) |
79e0a1df AM |
622 | throws AttributeNotFoundException, TimeRangeException, |
623 | StateValueTypeException { | |
624 | int quark; | |
625 | ITmfStateValue value; | |
626 | ||
d0c7e4ba AM |
627 | quark = ssb.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL); |
628 | if (ssb.queryOngoingState(quark).isNull()) { | |
79e0a1df | 629 | /* We were in user mode before the interruption */ |
dfb27cee | 630 | value = StateValues.PROCESS_STATUS_RUN_USERMODE_VALUE; |
79e0a1df AM |
631 | } else { |
632 | /* We were previously in kernel mode */ | |
dfb27cee | 633 | value = StateValues.PROCESS_STATUS_RUN_SYSCALL_VALUE; |
79e0a1df | 634 | } |
d0c7e4ba AM |
635 | quark = ssb.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS); |
636 | ssb.modifyAttribute(ts, value, quark); | |
79e0a1df AM |
637 | } |
638 | ||
639 | /** | |
640 | * Similar logic as above, but to set the CPU's status when it's coming out | |
641 | * of an interruption. | |
642 | */ | |
d0c7e4ba AM |
643 | private static void cpuExitInterrupt(ITmfStateSystemBuilder ssb, long ts, |
644 | int currentCpuNode, int currentThreadNode) | |
79e0a1df AM |
645 | throws StateValueTypeException, AttributeNotFoundException, |
646 | TimeRangeException { | |
647 | int quark; | |
648 | ITmfStateValue value; | |
649 | ||
d0c7e4ba AM |
650 | quark = ssb.getQuarkRelativeAndAdd(currentCpuNode, Attributes.CURRENT_THREAD); |
651 | if (ssb.queryOngoingState(quark).unboxInt() > 0) { | |
79e0a1df | 652 | /* There was a process on the CPU */ |
d0c7e4ba AM |
653 | quark = ssb.getQuarkRelative(currentThreadNode, Attributes.SYSTEM_CALL); |
654 | if (ssb.queryOngoingState(quark).isNull()) { | |
79e0a1df | 655 | /* That process was in user mode */ |
dfb27cee | 656 | value = StateValues.CPU_STATUS_RUN_USERMODE_VALUE; |
79e0a1df AM |
657 | } else { |
658 | /* That process was in a system call */ | |
dfb27cee | 659 | value = StateValues.CPU_STATUS_RUN_SYSCALL_VALUE; |
79e0a1df AM |
660 | } |
661 | } else { | |
662 | /* There was no real process scheduled, CPU was idle */ | |
dfb27cee | 663 | value = StateValues.CPU_STATUS_IDLE_VALUE; |
2c2f900e | 664 | } |
d0c7e4ba AM |
665 | quark = ssb.getQuarkRelativeAndAdd(currentCpuNode, Attributes.STATUS); |
666 | ssb.modifyAttribute(ts, value, quark); | |
efc403bb AM |
667 | } |
668 | } |