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 | |
b3867ecc MAL |
156 | Integer cpu = TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event); |
157 | if (cpu == null) { | |
1786026d | 158 | /* We couldn't find any CPU information, ignore this event */ |
e1de2fd4 AM |
159 | return; |
160 | } | |
79e0a1df | 161 | |
e3d50cf4 | 162 | final String eventName = event.getName(); |
79e0a1df AM |
163 | final long ts = event.getTimestamp().getValue(); |
164 | ||
2c2f900e | 165 | try { |
e363eae1 AM |
166 | final ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder()); |
167 | ||
79e0a1df | 168 | /* Shortcut for the "current CPU" attribute node */ |
d0c7e4ba | 169 | final int currentCPUNode = ss.getQuarkRelativeAndAdd(getNodeCPUs(ss), cpu.toString()); |
79e0a1df AM |
170 | |
171 | /* | |
172 | * Shortcut for the "current thread" attribute node. It requires | |
173 | * querying the current CPU's current thread. | |
174 | */ | |
3ae73cfa AM |
175 | int quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.CURRENT_THREAD); |
176 | ITmfStateValue value = ss.queryOngoingState(quark); | |
359eeba0 | 177 | int thread = value.isNull() ? -1 : value.unboxInt(); |
d0c7e4ba | 178 | final int currentThreadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), String.valueOf(thread)); |
79e0a1df AM |
179 | |
180 | /* | |
181 | * Feed event to the history system if it's known to cause a state | |
182 | * transition. | |
183 | */ | |
7411cd67 AM |
184 | Integer idx = fEventNames.get(eventName); |
185 | int intval = (idx == null ? -1 : idx.intValue()); | |
186 | switch (intval) { | |
79e0a1df | 187 | |
7411cd67 | 188 | case IRQ_HANDLER_ENTRY_INDEX: |
79e0a1df | 189 | { |
7411cd67 | 190 | Integer irqId = ((Long) event.getContent().getField(fLayout.fieldIrq()).getValue()).intValue(); |
79e0a1df AM |
191 | |
192 | /* Mark this IRQ as active in the resource tree. | |
193 | * The state value = the CPU on which this IRQ is sitting */ | |
d0c7e4ba | 194 | quark = ss.getQuarkRelativeAndAdd(getNodeIRQs(ss), irqId.toString()); |
1786026d | 195 | value = TmfStateValue.newValueInt(cpu.intValue()); |
79e0a1df AM |
196 | ss.modifyAttribute(ts, value, quark); |
197 | ||
198 | /* Change the status of the running process to interrupted */ | |
199 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS); | |
dfb27cee | 200 | value = StateValues.PROCESS_STATUS_INTERRUPTED_VALUE; |
79e0a1df AM |
201 | ss.modifyAttribute(ts, value, quark); |
202 | ||
203 | /* Change the status of the CPU to interrupted */ | |
204 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS); | |
dfb27cee | 205 | value = StateValues.CPU_STATUS_IRQ_VALUE; |
79e0a1df AM |
206 | ss.modifyAttribute(ts, value, quark); |
207 | } | |
208 | break; | |
209 | ||
7411cd67 | 210 | case IRQ_HANDLER_EXIT_INDEX: |
79e0a1df | 211 | { |
7411cd67 | 212 | Integer irqId = ((Long) event.getContent().getField(fLayout.fieldIrq()).getValue()).intValue(); |
79e0a1df AM |
213 | |
214 | /* Put this IRQ back to inactive in the resource tree */ | |
d0c7e4ba | 215 | quark = ss.getQuarkRelativeAndAdd(getNodeIRQs(ss), irqId.toString()); |
79e0a1df AM |
216 | value = TmfStateValue.nullValue(); |
217 | ss.modifyAttribute(ts, value, quark); | |
218 | ||
219 | /* Set the previous process back to running */ | |
d0c7e4ba | 220 | setProcessToRunning(ss, ts, currentThreadNode); |
79e0a1df AM |
221 | |
222 | /* Set the CPU status back to running or "idle" */ | |
d0c7e4ba | 223 | cpuExitInterrupt(ss, ts, currentCPUNode, currentThreadNode); |
79e0a1df AM |
224 | } |
225 | break; | |
226 | ||
7411cd67 | 227 | case SOFT_IRQ_ENTRY_INDEX: |
79e0a1df | 228 | { |
7411cd67 | 229 | Integer softIrqId = ((Long) event.getContent().getField(fLayout.fieldVec()).getValue()).intValue(); |
79e0a1df AM |
230 | |
231 | /* Mark this SoftIRQ as active in the resource tree. | |
232 | * The state value = the CPU on which this SoftIRQ is processed */ | |
d0c7e4ba | 233 | quark = ss.getQuarkRelativeAndAdd(getNodeSoftIRQs(ss), softIrqId.toString()); |
1786026d | 234 | value = TmfStateValue.newValueInt(cpu.intValue()); |
79e0a1df AM |
235 | ss.modifyAttribute(ts, value, quark); |
236 | ||
237 | /* Change the status of the running process to interrupted */ | |
238 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS); | |
dfb27cee | 239 | value = StateValues.PROCESS_STATUS_INTERRUPTED_VALUE; |
79e0a1df AM |
240 | ss.modifyAttribute(ts, value, quark); |
241 | ||
242 | /* Change the status of the CPU to interrupted */ | |
243 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS); | |
dfb27cee | 244 | value = StateValues.CPU_STATUS_SOFTIRQ_VALUE; |
79e0a1df AM |
245 | ss.modifyAttribute(ts, value, quark); |
246 | } | |
247 | break; | |
248 | ||
7411cd67 | 249 | case SOFT_IRQ_EXIT_INDEX: |
79e0a1df | 250 | { |
7411cd67 | 251 | Integer softIrqId = ((Long) event.getContent().getField(fLayout.fieldVec()).getValue()).intValue(); |
79e0a1df AM |
252 | |
253 | /* Put this SoftIRQ back to inactive (= -1) in the resource tree */ | |
d0c7e4ba | 254 | quark = ss.getQuarkRelativeAndAdd(getNodeSoftIRQs(ss), softIrqId.toString()); |
79e0a1df AM |
255 | value = TmfStateValue.nullValue(); |
256 | ss.modifyAttribute(ts, value, quark); | |
257 | ||
258 | /* Set the previous process back to running */ | |
d0c7e4ba | 259 | setProcessToRunning(ss, ts, currentThreadNode); |
79e0a1df AM |
260 | |
261 | /* Set the CPU status back to "busy" or "idle" */ | |
d0c7e4ba | 262 | cpuExitInterrupt(ss, ts, currentCPUNode, currentThreadNode); |
79e0a1df AM |
263 | } |
264 | break; | |
265 | ||
7411cd67 | 266 | case SOFT_IRQ_RAISE_INDEX: |
79e0a1df AM |
267 | /* Fields: int32 vec */ |
268 | { | |
7411cd67 | 269 | Integer softIrqId = ((Long) event.getContent().getField(fLayout.fieldVec()).getValue()).intValue(); |
79e0a1df AM |
270 | |
271 | /* Mark this SoftIRQ as *raised* in the resource tree. | |
272 | * State value = -2 */ | |
d0c7e4ba | 273 | quark = ss.getQuarkRelativeAndAdd(getNodeSoftIRQs(ss), softIrqId.toString()); |
dfb27cee | 274 | value = StateValues.SOFT_IRQ_RAISED_VALUE; |
79e0a1df AM |
275 | ss.modifyAttribute(ts, value, quark); |
276 | } | |
277 | break; | |
278 | ||
7411cd67 | 279 | case SCHED_SWITCH_INDEX: |
79e0a1df | 280 | { |
7a2f04a6 | 281 | ITmfEventField content = event.getContent(); |
7411cd67 AM |
282 | Integer prevTid = ((Long) content.getField(fLayout.fieldPrevTid()).getValue()).intValue(); |
283 | Long prevState = (Long) content.getField(fLayout.fieldPrevState()).getValue(); | |
284 | String nextProcessName = (String) content.getField(fLayout.fieldNextComm()).getValue(); | |
285 | Integer nextTid = ((Long) content.getField(fLayout.fieldNextTid()).getValue()).intValue(); | |
3bf563da | 286 | Integer nextPrio = ((Long) content.getField(fLayout.fieldNextPrio()).getValue()).intValue(); |
79e0a1df | 287 | |
d0c7e4ba AM |
288 | Integer formerThreadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), prevTid.toString()); |
289 | Integer newCurrentThreadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), nextTid.toString()); | |
79e0a1df | 290 | |
6b1f08f1 GB |
291 | /* |
292 | * Empirical observations and look into the linux code have | |
293 | * shown that the TASK_STATE_MAX flag is used internally and | |
294 | * |'ed with other states, most often the running state, so it | |
295 | * is ignored from the prevState value. | |
296 | */ | |
297 | prevState = prevState & ~(LinuxValues.TASK_STATE_MAX); | |
298 | ||
79e0a1df | 299 | /* Set the status of the process that got scheduled out. */ |
2f693965 AM |
300 | switch (prevState.intValue()) { |
301 | case LinuxValues.TASK_STATE_RUNNING: | |
dfb27cee | 302 | value = StateValues.PROCESS_STATUS_WAIT_FOR_CPU_VALUE; |
2f693965 AM |
303 | break; |
304 | case LinuxValues.TASK_INTERRUPTIBLE: | |
305 | case LinuxValues.TASK_UNINTERRUPTIBLE: | |
306 | value = StateValues.PROCESS_STATUS_WAIT_BLOCKED_VALUE; | |
307 | break; | |
308 | case LinuxValues.TASK_DEAD: | |
309 | value = TmfStateValue.nullValue(); | |
310 | break; | |
311 | default: | |
312 | value = StateValues.PROCESS_STATUS_WAIT_UNKNOWN_VALUE; | |
313 | break; | |
f2338178 | 314 | } |
2f693965 AM |
315 | |
316 | quark = ss.getQuarkRelativeAndAdd(formerThreadNode, Attributes.STATUS); | |
79e0a1df AM |
317 | ss.modifyAttribute(ts, value, quark); |
318 | ||
319 | /* Set the status of the new scheduled process */ | |
d0c7e4ba | 320 | setProcessToRunning(ss, ts, newCurrentThreadNode); |
79e0a1df AM |
321 | |
322 | /* Set the exec name of the new process */ | |
323 | quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.EXEC_NAME); | |
324 | value = TmfStateValue.newValueString(nextProcessName); | |
325 | ss.modifyAttribute(ts, value, quark); | |
326 | ||
3bf563da CM |
327 | /* Set the current prio for the new process */ |
328 | quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.PRIO); | |
329 | value = TmfStateValue.newValueInt(nextPrio); | |
330 | ss.modifyAttribute(ts, value, quark); | |
331 | ||
25e43749 AM |
332 | /* Make sure the PPID and system_call sub-attributes exist */ |
333 | ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.SYSTEM_CALL); | |
334 | ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.PPID); | |
79e0a1df AM |
335 | |
336 | /* Set the current scheduled process on the relevant CPU */ | |
337 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.CURRENT_THREAD); | |
338 | value = TmfStateValue.newValueInt(nextTid); | |
339 | ss.modifyAttribute(ts, value, quark); | |
340 | ||
341 | /* Set the status of the CPU itself */ | |
342 | if (nextTid > 0) { | |
343 | /* Check if the entering process is in kernel or user mode */ | |
344 | quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.SYSTEM_CALL); | |
345 | if (ss.queryOngoingState(quark).isNull()) { | |
dfb27cee | 346 | value = StateValues.CPU_STATUS_RUN_USERMODE_VALUE; |
79e0a1df | 347 | } else { |
dfb27cee | 348 | value = StateValues.CPU_STATUS_RUN_SYSCALL_VALUE; |
79e0a1df AM |
349 | } |
350 | } else { | |
dfb27cee | 351 | value = StateValues.CPU_STATUS_IDLE_VALUE; |
79e0a1df AM |
352 | } |
353 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS); | |
354 | ss.modifyAttribute(ts, value, quark); | |
355 | } | |
356 | break; | |
357 | ||
3bf563da CM |
358 | case SCHED_PI_SETPRIO_INDEX: |
359 | { | |
360 | ITmfEventField content = event.getContent(); | |
361 | Integer tid = ((Long) content.getField(fLayout.fieldTid()).getValue()).intValue(); | |
362 | Integer prio = ((Long) content.getField(fLayout.fieldNewPrio()).getValue()).intValue(); | |
363 | ||
364 | Integer updateThreadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), tid.toString()); | |
365 | ||
366 | /* Set the current prio for the new process */ | |
367 | quark = ss.getQuarkRelativeAndAdd(updateThreadNode, Attributes.PRIO); | |
368 | value = TmfStateValue.newValueInt(prio); | |
369 | ss.modifyAttribute(ts, value, quark); | |
370 | } | |
371 | break; | |
372 | ||
7411cd67 | 373 | case SCHED_PROCESS_FORK_INDEX: |
79e0a1df | 374 | { |
7a2f04a6 | 375 | ITmfEventField content = event.getContent(); |
79e0a1df | 376 | // String parentProcessName = (String) event.getFieldValue("parent_comm"); |
7411cd67 | 377 | String childProcessName = (String) content.getField(fLayout.fieldChildComm()).getValue(); |
79e0a1df AM |
378 | // assert ( parentProcessName.equals(childProcessName) ); |
379 | ||
7411cd67 AM |
380 | Integer parentTid = ((Long) content.getField(fLayout.fieldParentTid()).getValue()).intValue(); |
381 | Integer childTid = ((Long) content.getField(fLayout.fieldChildTid()).getValue()).intValue(); | |
79e0a1df | 382 | |
d0c7e4ba AM |
383 | Integer parentTidNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), parentTid.toString()); |
384 | Integer childTidNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), childTid.toString()); | |
79e0a1df AM |
385 | |
386 | /* Assign the PPID to the new process */ | |
387 | quark = ss.getQuarkRelativeAndAdd(childTidNode, Attributes.PPID); | |
388 | value = TmfStateValue.newValueInt(parentTid); | |
389 | ss.modifyAttribute(ts, value, quark); | |
390 | ||
391 | /* Set the new process' exec_name */ | |
392 | quark = ss.getQuarkRelativeAndAdd(childTidNode, Attributes.EXEC_NAME); | |
393 | value = TmfStateValue.newValueString(childProcessName); | |
394 | ss.modifyAttribute(ts, value, quark); | |
395 | ||
396 | /* Set the new process' status */ | |
397 | quark = ss.getQuarkRelativeAndAdd(childTidNode, Attributes.STATUS); | |
dfb27cee | 398 | value = StateValues.PROCESS_STATUS_WAIT_FOR_CPU_VALUE; |
79e0a1df AM |
399 | ss.modifyAttribute(ts, value, quark); |
400 | ||
401 | /* Set the process' syscall name, to be the same as the parent's */ | |
402 | quark = ss.getQuarkRelativeAndAdd(parentTidNode, Attributes.SYSTEM_CALL); | |
403 | value = ss.queryOngoingState(quark); | |
b46ea93c AM |
404 | if (value.isNull()) { |
405 | /* | |
406 | * Maybe we were missing info about the parent? At least we | |
407 | * will set the child right. Let's suppose "sys_clone". | |
408 | */ | |
7411cd67 | 409 | value = TmfStateValue.newValueString(fLayout.eventSyscallEntryPrefix() + IKernelAnalysisEventLayout.INITIAL_SYSCALL_NAME); |
b46ea93c | 410 | } |
79e0a1df AM |
411 | quark = ss.getQuarkRelativeAndAdd(childTidNode, Attributes.SYSTEM_CALL); |
412 | ss.modifyAttribute(ts, value, quark); | |
413 | } | |
414 | break; | |
415 | ||
7411cd67 | 416 | case SCHED_PROCESS_EXIT_INDEX: |
79e0a1df AM |
417 | break; |
418 | ||
7411cd67 | 419 | case SCHED_PROCESS_FREE_INDEX: |
79e0a1df | 420 | { |
7411cd67 | 421 | Integer tid = ((Long) event.getContent().getField(fLayout.fieldTid()).getValue()).intValue(); |
79e0a1df AM |
422 | /* |
423 | * Remove the process and all its sub-attributes from the | |
424 | * current state | |
425 | */ | |
d0c7e4ba | 426 | quark = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), tid.toString()); |
79e0a1df AM |
427 | ss.removeAttribute(ts, quark); |
428 | } | |
429 | break; | |
430 | ||
7411cd67 AM |
431 | case STATEDUMP_PROCESS_STATE_INDEX: |
432 | /* LTTng-specific */ | |
79e0a1df | 433 | { |
7a2f04a6 | 434 | ITmfEventField content = event.getContent(); |
7411cd67 AM |
435 | int tid = ((Long) content.getField("tid").getValue()).intValue(); //$NON-NLS-1$ |
436 | int pid = ((Long) content.getField("pid").getValue()).intValue(); //$NON-NLS-1$ | |
437 | int ppid = ((Long) content.getField("ppid").getValue()).intValue(); //$NON-NLS-1$ | |
438 | int status = ((Long) content.getField("status").getValue()).intValue(); //$NON-NLS-1$ | |
439 | String name = (String) content.getField("name").getValue(); //$NON-NLS-1$ | |
79e0a1df AM |
440 | /* |
441 | * "mode" could be interesting too, but it doesn't seem to be | |
442 | * populated with anything relevant for now. | |
443 | */ | |
444 | ||
d0c7e4ba | 445 | int curThreadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), String.valueOf(tid)); |
79e0a1df AM |
446 | |
447 | /* Set the process' name */ | |
448 | quark = ss.getQuarkRelativeAndAdd(curThreadNode, Attributes.EXEC_NAME); | |
449 | if (ss.queryOngoingState(quark).isNull()) { | |
450 | /* If the value didn't exist previously, set it */ | |
451 | value = TmfStateValue.newValueString(name); | |
452 | ss.modifyAttribute(ts, value, quark); | |
453 | } | |
454 | ||
455 | /* Set the process' PPID */ | |
456 | quark = ss.getQuarkRelativeAndAdd(curThreadNode, Attributes.PPID); | |
457 | if (ss.queryOngoingState(quark).isNull()) { | |
bc19bff3 AM |
458 | if (pid == tid) { |
459 | /* We have a process. Use the 'PPID' field. */ | |
460 | value = TmfStateValue.newValueInt(ppid); | |
461 | } else { | |
462 | /* We have a thread, use the 'PID' field for the parent. */ | |
463 | value = TmfStateValue.newValueInt(pid); | |
464 | } | |
79e0a1df AM |
465 | ss.modifyAttribute(ts, value, quark); |
466 | } | |
467 | ||
468 | /* Set the process' status */ | |
469 | quark = ss.getQuarkRelativeAndAdd(curThreadNode, Attributes.STATUS); | |
470 | if (ss.queryOngoingState(quark).isNull()) { | |
a810c240 | 471 | switch (status) { |
03bd936a | 472 | case LinuxValues.STATEDUMP_PROCESS_STATUS_WAIT_CPU: |
dfb27cee | 473 | value = StateValues.PROCESS_STATUS_WAIT_FOR_CPU_VALUE; |
a810c240 | 474 | break; |
03bd936a AM |
475 | case LinuxValues.STATEDUMP_PROCESS_STATUS_WAIT: |
476 | /* | |
477 | * We have no information on what the process is waiting | |
478 | * on (unlike a sched_switch for example), so we will | |
479 | * use the WAIT_UNKNOWN state instead of the "normal" | |
480 | * WAIT_BLOCKED state. | |
481 | */ | |
a810c240 AM |
482 | value = StateValues.PROCESS_STATUS_WAIT_UNKNOWN_VALUE; |
483 | break; | |
484 | default: | |
dfb27cee | 485 | value = StateValues.PROCESS_STATUS_UNKNOWN_VALUE; |
79e0a1df AM |
486 | } |
487 | ss.modifyAttribute(ts, value, quark); | |
488 | } | |
489 | } | |
490 | break; | |
491 | ||
7411cd67 | 492 | case SCHED_WAKEUP_INDEX: |
d1b933e7 | 493 | { |
7411cd67 | 494 | final int tid = ((Long) event.getContent().getField(fLayout.fieldTid()).getValue()).intValue(); |
3bf563da | 495 | final int prio = ((Long) event.getContent().getField(fLayout.fieldPrio()).getValue()).intValue(); |
d0c7e4ba | 496 | final int threadNode = ss.getQuarkRelativeAndAdd(getNodeThreads(ss), String.valueOf(tid)); |
d1b933e7 AM |
497 | |
498 | /* | |
499 | * The process indicated in the event's payload is now ready to | |
3d6e6112 FR |
500 | * run. Assign it to the "wait for cpu" state, but only if it |
501 | * was not already running. | |
d1b933e7 AM |
502 | */ |
503 | quark = ss.getQuarkRelativeAndAdd(threadNode, Attributes.STATUS); | |
3d6e6112 FR |
504 | int status = ss.queryOngoingState(quark).unboxInt(); |
505 | ||
506 | if (status != StateValues.PROCESS_STATUS_RUN_SYSCALL && | |
507 | status != StateValues.PROCESS_STATUS_RUN_USERMODE) { | |
508 | value = StateValues.PROCESS_STATUS_WAIT_FOR_CPU_VALUE; | |
509 | ss.modifyAttribute(ts, value, quark); | |
510 | } | |
3bf563da CM |
511 | |
512 | /* | |
513 | * When a user changes a threads prio (e.g. with pthread_setschedparam), | |
514 | * it shows in ftrace with a sched_wakeup. | |
515 | */ | |
516 | quark = ss.getQuarkRelativeAndAdd(threadNode, Attributes.PRIO); | |
517 | value = TmfStateValue.newValueInt(prio); | |
518 | ss.modifyAttribute(ts, value, quark); | |
d1b933e7 AM |
519 | } |
520 | break; | |
521 | ||
79e0a1df AM |
522 | default: |
523 | /* Other event types not covered by the main switch */ | |
524 | { | |
7411cd67 AM |
525 | if (eventName.startsWith(fLayout.eventSyscallEntryPrefix()) |
526 | || eventName.startsWith(fLayout.eventCompatSyscallEntryPrefix())) { | |
79e0a1df AM |
527 | |
528 | /* Assign the new system call to the process */ | |
529 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL); | |
530 | value = TmfStateValue.newValueString(eventName); | |
531 | ss.modifyAttribute(ts, value, quark); | |
532 | ||
533 | /* Put the process in system call mode */ | |
534 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS); | |
dfb27cee | 535 | value = StateValues.PROCESS_STATUS_RUN_SYSCALL_VALUE; |
79e0a1df AM |
536 | ss.modifyAttribute(ts, value, quark); |
537 | ||
538 | /* Put the CPU in system call (kernel) mode */ | |
539 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS); | |
dfb27cee | 540 | value = StateValues.CPU_STATUS_RUN_SYSCALL_VALUE; |
79e0a1df | 541 | ss.modifyAttribute(ts, value, quark); |
acba092b AM |
542 | |
543 | } else if (eventName.startsWith(fLayout.eventSyscallExitPrefix())) { | |
544 | ||
545 | /* Clear the current system call on the process */ | |
546 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL); | |
547 | value = TmfStateValue.nullValue(); | |
548 | ss.modifyAttribute(ts, value, quark); | |
549 | ||
550 | /* Put the process' status back to user mode */ | |
551 | quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS); | |
552 | value = StateValues.PROCESS_STATUS_RUN_USERMODE_VALUE; | |
553 | ss.modifyAttribute(ts, value, quark); | |
554 | ||
555 | /* Put the CPU's status back to user mode */ | |
556 | quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS); | |
557 | value = StateValues.CPU_STATUS_RUN_USERMODE_VALUE; | |
558 | ss.modifyAttribute(ts, value, quark); | |
79e0a1df | 559 | } |
acba092b | 560 | |
79e0a1df AM |
561 | } |
562 | break; | |
563 | } // End of big switch | |
564 | ||
79e0a1df AM |
565 | } catch (AttributeNotFoundException ae) { |
566 | /* | |
567 | * This would indicate a problem with the logic of the manager here, | |
568 | * so it shouldn't happen. | |
569 | */ | |
570 | ae.printStackTrace(); | |
571 | ||
572 | } catch (TimeRangeException tre) { | |
573 | /* | |
574 | * This would happen if the events in the trace aren't ordered | |
575 | * chronologically, which should never be the case ... | |
576 | */ | |
577 | System.err.println("TimeRangeExcpetion caught in the state system's event manager."); //$NON-NLS-1$ | |
578 | System.err.println("Are the events in the trace correctly ordered?"); //$NON-NLS-1$ | |
579 | tre.printStackTrace(); | |
580 | ||
581 | } catch (StateValueTypeException sve) { | |
582 | /* | |
583 | * This would happen if we were trying to push/pop attributes not of | |
584 | * type integer. Which, once again, should never happen. | |
585 | */ | |
586 | sve.printStackTrace(); | |
2c2f900e AM |
587 | } |
588 | } | |
589 | ||
6383e95d AM |
590 | // ------------------------------------------------------------------------ |
591 | // Convenience methods for commonly-used attribute tree locations | |
592 | // ------------------------------------------------------------------------ | |
593 | ||
d0c7e4ba AM |
594 | private static int getNodeCPUs(ITmfStateSystemBuilder ssb) { |
595 | return ssb.getQuarkAbsoluteAndAdd(Attributes.CPUS); | |
79e0a1df AM |
596 | } |
597 | ||
d0c7e4ba AM |
598 | private static int getNodeThreads(ITmfStateSystemBuilder ssb) { |
599 | return ssb.getQuarkAbsoluteAndAdd(Attributes.THREADS); | |
6383e95d AM |
600 | } |
601 | ||
d0c7e4ba AM |
602 | private static int getNodeIRQs(ITmfStateSystemBuilder ssb) { |
603 | return ssb.getQuarkAbsoluteAndAdd(Attributes.RESOURCES, Attributes.IRQS); | |
6383e95d AM |
604 | } |
605 | ||
d0c7e4ba AM |
606 | private static int getNodeSoftIRQs(ITmfStateSystemBuilder ssb) { |
607 | return ssb.getQuarkAbsoluteAndAdd(Attributes.RESOURCES, Attributes.SOFT_IRQS); | |
6383e95d AM |
608 | } |
609 | ||
6383e95d AM |
610 | // ------------------------------------------------------------------------ |
611 | // Advanced state-setting methods | |
612 | // ------------------------------------------------------------------------ | |
613 | ||
79e0a1df AM |
614 | /** |
615 | * When we want to set a process back to a "running" state, first check | |
616 | * its current System_call attribute. If there is a system call active, we | |
617 | * put the process back in the syscall state. If not, we put it back in | |
618 | * user mode state. | |
619 | */ | |
d0c7e4ba | 620 | private static void setProcessToRunning(ITmfStateSystemBuilder ssb, long ts, int currentThreadNode) |
79e0a1df AM |
621 | throws AttributeNotFoundException, TimeRangeException, |
622 | StateValueTypeException { | |
623 | int quark; | |
624 | ITmfStateValue value; | |
625 | ||
d0c7e4ba AM |
626 | quark = ssb.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL); |
627 | if (ssb.queryOngoingState(quark).isNull()) { | |
79e0a1df | 628 | /* We were in user mode before the interruption */ |
dfb27cee | 629 | value = StateValues.PROCESS_STATUS_RUN_USERMODE_VALUE; |
79e0a1df AM |
630 | } else { |
631 | /* We were previously in kernel mode */ | |
dfb27cee | 632 | value = StateValues.PROCESS_STATUS_RUN_SYSCALL_VALUE; |
79e0a1df | 633 | } |
d0c7e4ba AM |
634 | quark = ssb.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS); |
635 | ssb.modifyAttribute(ts, value, quark); | |
79e0a1df AM |
636 | } |
637 | ||
638 | /** | |
639 | * Similar logic as above, but to set the CPU's status when it's coming out | |
640 | * of an interruption. | |
641 | */ | |
d0c7e4ba AM |
642 | private static void cpuExitInterrupt(ITmfStateSystemBuilder ssb, long ts, |
643 | int currentCpuNode, int currentThreadNode) | |
79e0a1df AM |
644 | throws StateValueTypeException, AttributeNotFoundException, |
645 | TimeRangeException { | |
646 | int quark; | |
647 | ITmfStateValue value; | |
648 | ||
d0c7e4ba AM |
649 | quark = ssb.getQuarkRelativeAndAdd(currentCpuNode, Attributes.CURRENT_THREAD); |
650 | if (ssb.queryOngoingState(quark).unboxInt() > 0) { | |
79e0a1df | 651 | /* There was a process on the CPU */ |
d0c7e4ba AM |
652 | quark = ssb.getQuarkRelative(currentThreadNode, Attributes.SYSTEM_CALL); |
653 | if (ssb.queryOngoingState(quark).isNull()) { | |
79e0a1df | 654 | /* That process was in user mode */ |
dfb27cee | 655 | value = StateValues.CPU_STATUS_RUN_USERMODE_VALUE; |
79e0a1df AM |
656 | } else { |
657 | /* That process was in a system call */ | |
dfb27cee | 658 | value = StateValues.CPU_STATUS_RUN_SYSCALL_VALUE; |
79e0a1df AM |
659 | } |
660 | } else { | |
661 | /* There was no real process scheduled, CPU was idle */ | |
dfb27cee | 662 | value = StateValues.CPU_STATUS_IDLE_VALUE; |
2c2f900e | 663 | } |
d0c7e4ba AM |
664 | quark = ssb.getQuarkRelativeAndAdd(currentCpuNode, Attributes.STATUS); |
665 | ssb.modifyAttribute(ts, value, quark); | |
efc403bb AM |
666 | } |
667 | } |