lttng: Track user/kernel mode and IRQ types under the CPU status
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng2.kernel.core / src / org / eclipse / linuxtools / internal / lttng2 / kernel / core / stateprovider / CtfKernelHandler.java
1 /*******************************************************************************
2 * Copyright (c) 2012 Ericsson
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
5 *
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
10 *
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.internal.lttng2.kernel.core.stateprovider;
14
15 import java.util.HashMap;
16 import java.util.Vector;
17 import java.util.concurrent.BlockingQueue;
18
19 import org.eclipse.linuxtools.internal.lttng2.kernel.core.Attributes;
20 import org.eclipse.linuxtools.internal.lttng2.kernel.core.StateValues;
21 import org.eclipse.linuxtools.lttng2.kernel.core.trace.LttngStrings;
22 import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfEvent;
23 import org.eclipse.linuxtools.tmf.core.event.ITmfEventField;
24 import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
25 import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
26 import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
27 import org.eclipse.linuxtools.tmf.core.statesystem.IStateSystemBuilder;
28 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
29 import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
30
31 /**
32 * This is the reference "state provider" for LTTng 2.0 kernel traces.
33 *
34 * @author alexmont
35 *
36 */
37 class CtfKernelHandler implements Runnable {
38
39 private final BlockingQueue<CtfTmfEvent> inQueue;
40 private IStateSystemBuilder ss;
41
42 private CtfTmfEvent currentEvent;
43
44 /*
45 * We can keep handles to some Attribute Nodes so these don't need to be
46 * re-found (re-hashed Strings etc.) every new event
47 */
48 Vector<Integer> currentCPUNodes;
49 Vector<Integer> currentThreadNodes;
50
51 /* Event names HashMap. TODO: This can be discarded once we move to Java 7 */
52 private final HashMap<String, Integer> knownEventNames;
53
54 /* Common locations in the attribute tree */
55 private int cpusNode = -1;
56 private int threadsNode = -1;
57 private int irqsNode = -1;
58 private int softIrqsNode = -1;
59
60 CtfKernelHandler(BlockingQueue<CtfTmfEvent> eventsQueue) {
61 assert (eventsQueue != null);
62 this.inQueue = eventsQueue;
63 currentCPUNodes = new Vector<Integer>();
64 currentThreadNodes = new Vector<Integer>();
65
66 knownEventNames = fillEventNames();
67 }
68
69 void assignStateSystem(IStateSystemBuilder targetSS) {
70 this.ss = targetSS;
71 }
72
73 @Override
74 public void run() {
75 if (ss == null) {
76 System.err.println("Cannot run event manager without assigning a target state system first!"); //$NON-NLS-1$
77 return;
78 }
79 CtfTmfEvent event;
80 setupCommonLocations();
81
82 try {
83 event = inQueue.take();
84 while (event.getTimestampValue() != -1) {
85 processEvent(event);
86 event = inQueue.take();
87 }
88 /* We've received the last event, clean up */
89 closeStateSystem();
90 return;
91 } catch (InterruptedException e) {
92 /* We've been interrupted abnormally */
93 System.out.println("Event handler interrupted!"); //$NON-NLS-1$
94 e.printStackTrace();
95 }
96 }
97
98 private void closeStateSystem() {
99 /* Close the History system, if there is one */
100 if (currentEvent == null) {
101 return;
102 }
103 try {
104 ss.closeHistory(currentEvent.getTimestamp().getValue());
105 } catch (TimeRangeException e) {
106 /*
107 * Since we're using currentEvent.getTimestamp, this shouldn't
108 * cause any problem
109 */
110 e.printStackTrace();
111 }
112 }
113
114 private void processEvent(CtfTmfEvent event) {
115 currentEvent = event;
116 ITmfEventField content = event.getContent();
117 String eventName = event.getEventName();
118
119 long ts = event.getTimestamp().getValue();
120 int quark;
121 ITmfStateValue value;
122 Integer eventCpu = event.getCPU();
123 Integer currentCPUNode, currentThreadNode, tidNode;
124
125 /* Adjust the current nodes Vectors if we see a new CPU in an event */
126 if (eventCpu >= currentCPUNodes.size()) {
127 /* We need to add this node to the vector */
128 for (Integer i = currentCPUNodes.size(); i < eventCpu + 1; i++) {
129 quark = ss.getQuarkRelativeAndAdd(cpusNode, i.toString());
130 currentCPUNodes.add(quark);
131
132 quark = ss.getQuarkRelativeAndAdd(threadsNode, Attributes.UNKNOWN);
133 currentThreadNodes.add(quark);
134 }
135 }
136
137 currentCPUNode = currentCPUNodes.get(eventCpu);
138 currentThreadNode = currentThreadNodes.get(eventCpu);
139 assert (currentCPUNode != null);
140 assert (currentThreadNode != null);
141
142 try {
143 /*
144 * Feed event to the history system if it's known to cause a state
145 * transition.
146 */
147 switch (getEventIndex(eventName)) {
148
149 case 1: // "exit_syscall":
150 /* Fields: int64 ret */
151 {
152 /* Clear the current system call on the process */
153 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
154 value = TmfStateValue.nullValue();
155 ss.modifyAttribute(ts, value, quark);
156
157 /* Put the process' status back to user mode */
158 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
159 value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_RUN_USERMODE);
160 ss.modifyAttribute(ts, value, quark);
161 }
162 break;
163
164 case 2: // "irq_handler_entry":
165 /* Fields: int32 irq, string name */
166 {
167 Integer irqId = ((Long) content.getField(LttngStrings.IRQ).getValue()).intValue();
168
169 /* Mark this IRQ as active in the resource tree.
170 * The state value = the CPU on which this IRQ is sitting */
171 quark = ss.getQuarkRelativeAndAdd(irqsNode, irqId.toString());
172 value = TmfStateValue.newValueInt(event.getCPU());
173 ss.modifyAttribute(ts, value, quark);
174
175 /* Change the status of the running process to interrupted */
176 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
177 value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_INTERRUPTED);
178 ss.modifyAttribute(ts, value, quark);
179
180 /* Change the status of the CPU to interrupted */
181 quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS);
182 value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_IRQ);
183 ss.modifyAttribute(ts, value, quark);
184 }
185 break;
186
187 case 3: // "irq_handler_exit":
188 /* Fields: int32 irq, int32 ret */
189 {
190 Integer irqId = ((Long) content.getField(LttngStrings.IRQ).getValue()).intValue();
191
192 /* Put this IRQ back to inactive in the resource tree */
193 quark = ss.getQuarkRelativeAndAdd(irqsNode, irqId.toString());
194 value = TmfStateValue.nullValue();
195 ss.modifyAttribute(ts, value, quark);
196
197 /* Set the previous process back to running */
198 setProcessToRunning(ts, currentThreadNode);
199
200 /* Set the CPU status back to running or "idle" */
201 cpuExitInterrupt(ts, currentCPUNode, currentThreadNode);
202 }
203 break;
204
205 case 4: // "softirq_entry":
206 /* Fields: int32 vec */
207 {
208 Integer softIrqId = ((Long) content.getField(LttngStrings.VEC).getValue()).intValue();
209
210 /* Mark this SoftIRQ as active in the resource tree.
211 * The state value = the CPU on which this SoftIRQ is processed */
212 quark = ss.getQuarkRelativeAndAdd(softIrqsNode, softIrqId.toString());
213 value = TmfStateValue.newValueInt(event.getCPU());
214 ss.modifyAttribute(ts, value, quark);
215
216 /* Change the status of the running process to interrupted */
217 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
218 value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_INTERRUPTED);
219 ss.modifyAttribute(ts, value, quark);
220
221 /* Change the status of the CPU to interrupted */
222 quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS);
223 value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_SOFTIRQ);
224 ss.modifyAttribute(ts, value, quark);
225 }
226 break;
227
228 case 5: // "softirq_exit":
229 /* Fields: int32 vec */
230 {
231 Integer softIrqId = ((Long) content.getField(LttngStrings.VEC).getValue()).intValue();
232
233 /* Put this SoftIRQ back to inactive (= -1) in the resource tree */
234 quark = ss.getQuarkRelativeAndAdd(softIrqsNode, softIrqId.toString());
235 value = TmfStateValue.nullValue();
236 ss.modifyAttribute(ts, value, quark);
237
238 /* Set the previous process back to running */
239 setProcessToRunning(ts, currentThreadNode);
240
241 /* Set the CPU status back to "busy" or "idle" */
242 cpuExitInterrupt(ts, currentCPUNode, currentThreadNode);
243 }
244 break;
245
246 case 6: // "softirq_raise":
247 /* Fields: int32 vec */
248 {
249 Integer softIrqId = ((Long) content.getField(LttngStrings.VEC).getValue()).intValue();
250
251 /* Mark this SoftIRQ as *raised* in the resource tree.
252 * State value = -2 */
253 quark = ss.getQuarkRelativeAndAdd(softIrqsNode, softIrqId.toString());
254 value = TmfStateValue.newValueInt(StateValues.SOFT_IRQ_RAISED);
255 ss.modifyAttribute(ts, value, quark);
256 }
257 break;
258
259 case 7: // "sched_switch":
260 /*
261 * Fields: string prev_comm, int32 prev_tid, int32 prev_prio, int64 prev_state,
262 * string next_comm, int32 next_tid, int32 next_prio
263 */
264 {
265 Integer prevTid = ((Long) content.getField(LttngStrings.PREV_TID).getValue()).intValue();
266 //Long prevState = (Long) content.getField(LttngStrings.PREV_STATE).getValue();
267
268 String nextProcessName = (String) content.getField(LttngStrings.NEXT_COMM).getValue();
269 Integer nextTid = ((Long) content.getField(LttngStrings.NEXT_TID).getValue()).intValue();
270
271 /* Update the currentThreadNodes pointer */
272 Integer newCurrentThreadNode = ss.getQuarkRelativeAndAdd(threadsNode, nextTid.toString());
273 currentThreadNodes.set(eventCpu, newCurrentThreadNode);
274
275 /*
276 * Set the status of the process that got scheduled out, but
277 * only in the case where that process is currently active.
278 */
279 Integer formerThreadNode = ss.getQuarkRelativeAndAdd(threadsNode, prevTid.toString());
280 quark = ss.getQuarkRelativeAndAdd(formerThreadNode, Attributes.EXEC_NAME);
281 value = ss.queryOngoingState(quark);
282 if (!value.isNull()) {
283 quark = ss.getQuarkRelativeAndAdd(formerThreadNode, Attributes.STATUS);
284 value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_WAIT);
285 ss.modifyAttribute(ts, value, quark);
286 }
287
288 /* Set the status of the new scheduled process */
289 setProcessToRunning(ts, newCurrentThreadNode);
290
291 /* Set the exec name of the new process */
292 quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.EXEC_NAME);
293 value = TmfStateValue.newValueString(nextProcessName);
294 ss.modifyAttribute(ts, value, quark);
295
296 /*
297 * Check if we need to set the syscall state and the PPID of
298 * the new process (in case we haven't seen this process before)
299 */
300 quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.SYSTEM_CALL);
301 if (quark == ss.getNbAttributes()) { /* Did we just add this attribute? */
302 value = TmfStateValue.nullValue();
303 ss.modifyAttribute(ts, value, quark);
304 }
305 quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.PPID);
306 if (quark == ss.getNbAttributes()) {
307 value = TmfStateValue.nullValue();
308 ss.modifyAttribute(ts, value, quark);
309 }
310
311 /* Set the current scheduled process on the relevant CPU */
312 quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.CURRENT_THREAD);
313 value = TmfStateValue.newValueInt(nextTid);
314 ss.modifyAttribute(ts, value, quark);
315
316 /* Set the status of the CPU itself */
317 if (nextTid > 0) {
318 /* Check if the entering process is in kernel or user mode */
319 quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.SYSTEM_CALL);
320 if (ss.queryOngoingState(quark).isNull()) {
321 value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_RUN_USERMODE);
322 } else {
323 value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_RUN_SYSCALL);
324 }
325 } else {
326 value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_IDLE);
327 }
328 quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS);
329 ss.modifyAttribute(ts, value, quark);
330 }
331 break;
332
333 case 8: // "sched_process_fork":
334 /* Fields: string parent_comm, int32 parent_tid,
335 * string child_comm, int32 child_tid */
336 {
337 // String parentProcessName = (String)
338 // event.getFieldValue("parent_comm");
339 String childProcessName;
340 childProcessName = (String) content.getField(LttngStrings.CHILD_COMM).getValue();
341 // assert ( parentProcessName.equals(childProcessName) );
342
343 Integer parentTid = ((Long) content.getField(LttngStrings.PARENT_TID).getValue()).intValue();
344 Integer childTid = ((Long) content.getField(LttngStrings.CHILD_TID).getValue()).intValue();
345
346 tidNode = ss.getQuarkRelativeAndAdd(threadsNode, childTid.toString());
347
348 /* Assign the PPID to the new process */
349 quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.PPID);
350 value = TmfStateValue.newValueInt(parentTid);
351 ss.modifyAttribute(ts, value, quark);
352
353 /* Set the new process' exec_name */
354 quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.EXEC_NAME);
355 value = TmfStateValue.newValueString(childProcessName);
356 ss.modifyAttribute(ts, value, quark);
357
358 /* Set the new process' status */
359 quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.STATUS);
360 value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_WAIT);
361 ss.modifyAttribute(ts, value, quark);
362
363 /* Set the process' syscall state */
364 quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.SYSTEM_CALL);
365 value = TmfStateValue.nullValue();
366 ss.modifyAttribute(ts, value, quark);
367 }
368 break;
369
370 case 9: // "sched_process_exit":
371 /* Fields: string comm, int32 tid, int32 prio */
372 {
373 String processName = (String) content.getField(LttngStrings.COMM).getValue();
374 Integer tid = ((Long) content.getField(LttngStrings.TID).getValue()).intValue();
375
376 /* Update the process' name, if we don't have it */
377 quark = ss.getQuarkRelativeAndAdd(threadsNode, tid.toString(), Attributes.EXEC_NAME);
378 value = TmfStateValue.newValueString(processName);
379 ss.updateOngoingState(value, quark);
380
381 /*
382 * Remove the process and all its sub-attributes from the
383 * current state
384 */
385 quark = ss.getQuarkRelativeAndAdd(threadsNode, tid.toString());
386 ss.removeAttribute(ts, quark);
387 }
388 break;
389
390 case 10: // "sched_process_free":
391 /* Fields: string comm, int32 tid, int32 prio */
392 break;
393
394 // FIXME In CTF it's as "syscall_exec". Will have to be adapted.
395 // case LTT_EVENT_EXEC:
396 // filename = new String((byte[]) event.getField(0));
397 //
398 // /* Change the Exec_name of the process */
399 // quark = ss.getQuarkRelativePath(true, currentThreadNode,
400 // "Exec_name");
401 // ss.modifyAttribute(ts, filename, quark);
402 // break;
403
404 default:
405 /* Other event types not covered by the main switch */
406 {
407 if (eventName.startsWith(LttngStrings.SYSCALL_PREFIX)
408 || eventName.startsWith(LttngStrings.COMPAT_SYSCALL_PREFIX)) {
409 /*
410 * This is a replacement for the old sys_enter event. Now
411 * syscall names are listed into the event type
412 */
413
414 /* Assign the new system call to the process */
415 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
416 value = TmfStateValue.newValueString(eventName);
417 ss.modifyAttribute(ts, value, quark);
418
419 /* Put the process in system call mode */
420 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
421 value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_RUN_SYSCALL);
422 ss.modifyAttribute(ts, value, quark);
423 }
424 }
425 break;
426 } // End of big switch
427
428 /*
429 * Statistics
430 */
431
432 /* Number of events of each type, globally */
433 // quark = ss.getQuarkAbsoluteAndAdd(Attributes.STATISTICS,
434 // Attributes.EVENT_TYPES, eventName);
435 // ss.incrementAttribute(ts, quark);
436
437 /* Number of events per CPU */
438 // quark = ss.getQuarkRelativeAndAdd(currentCPUNode,
439 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
440 // ss.incrementAttribute(ts, quark);
441
442 /* Number of events per process */
443 // quark = ss.getQuarkRelativeAndAdd(currentThreadNode,
444 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
445 // ss.incrementAttribute(ts, quark);
446
447 } catch (AttributeNotFoundException ae) {
448 /*
449 * This would indicate a problem with the logic of the manager here,
450 * so it shouldn't happen.
451 */
452 ae.printStackTrace();
453
454 } catch (TimeRangeException tre) {
455 /*
456 * This would happen if the events in the trace aren't ordered
457 * chronologically, which should never be the case ...
458 */
459 System.err.println("TimeRangeExcpetion caught in the state system's event manager."); //$NON-NLS-1$
460 System.err.println("Are the events in the trace correctly ordered?"); //$NON-NLS-1$
461 tre.printStackTrace();
462
463 } catch (StateValueTypeException sve) {
464 /*
465 * This would happen if we were trying to push/pop attributes not of
466 * type integer. Which, once again, should never happen.
467 */
468 sve.printStackTrace();
469 }
470 }
471
472 private void setupCommonLocations() {
473 cpusNode = ss.getQuarkAbsoluteAndAdd(Attributes.CPUS);
474 threadsNode = ss.getQuarkAbsoluteAndAdd(Attributes.THREADS);
475 irqsNode = ss.getQuarkAbsoluteAndAdd(Attributes.RESOURCES, Attributes.IRQS);
476 softIrqsNode = ss.getQuarkAbsoluteAndAdd(Attributes.RESOURCES, Attributes.SOFT_IRQS);
477 }
478
479 private static HashMap<String, Integer> fillEventNames() {
480 /*
481 * TODO Replace with straight strings in the switch/case once we move to
482 * Java 7
483 */
484 HashMap<String, Integer> map = new HashMap<String, Integer>();
485
486 map.put(LttngStrings.EXIT_SYSCALL, 1);
487 map.put(LttngStrings.IRQ_HANDLER_ENTRY, 2);
488 map.put(LttngStrings.IRQ_HANDLER_EXIT, 3);
489 map.put(LttngStrings.SOFTIRQ_ENTRY, 4);
490 map.put(LttngStrings.SOFTIRQ_EXIT, 5);
491 map.put(LttngStrings.SOFTIRQ_RAISE, 6);
492 map.put(LttngStrings.SCHED_SWITCH, 7);
493 map.put(LttngStrings.SCHED_PROCESS_FORK, 8);
494 map.put(LttngStrings.SCHED_PROCESS_EXIT, 9);
495 map.put(LttngStrings.SCHED_PROCESS_FREE, 10);
496
497 return map;
498 }
499
500 private int getEventIndex(String eventName) {
501 Integer ret = knownEventNames.get(eventName);
502 return (ret != null) ? ret : -1;
503 }
504
505 /**
506 * When we want to set a process back to a "running" state, first check
507 * its current System_call attribute. If there is a system call active, we
508 * put the process back in the syscall state. If not, we put it back in
509 * user mode state.
510 */
511 private void setProcessToRunning(long ts, int currentThreadNode)
512 throws AttributeNotFoundException, TimeRangeException,
513 StateValueTypeException {
514 int quark;
515 ITmfStateValue value;
516
517 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
518 if (ss.queryOngoingState(quark).isNull()) {
519 /* We were in user mode before the interruption */
520 value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_RUN_USERMODE);
521 } else {
522 /* We were previously in kernel mode */
523 value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_RUN_SYSCALL);
524 }
525 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
526 ss.modifyAttribute(ts, value, quark);
527 }
528
529 /**
530 * Similar logic as above, but to set the CPU's status when it's coming out
531 * of an interruption.
532 * @throws AttributeNotFoundException
533 * @throws StateValueTypeException
534 * @throws TimeRangeException
535 */
536 private void cpuExitInterrupt(long ts, int currentCpuNode, int currentThreadNode)
537 throws StateValueTypeException, AttributeNotFoundException,
538 TimeRangeException {
539 int quark;
540 ITmfStateValue value;
541
542 quark = ss.getQuarkRelativeAndAdd(currentCpuNode, Attributes.CURRENT_THREAD);
543 if (ss.queryOngoingState(quark).unboxInt() > 0) {
544 /* There was a process on the CPU */
545 quark = ss.getQuarkRelative(currentThreadNode, Attributes.SYSTEM_CALL);
546 if (ss.queryOngoingState(quark).isNull()) {
547 /* That process was in user mode */
548 value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_RUN_USERMODE);
549 } else {
550 /* That process was in a system call */
551 value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_RUN_SYSCALL);
552 }
553 } else {
554 /* There was no real process scheduled, CPU was idle */
555 value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_IDLE);
556 }
557 quark = ss.getQuarkRelativeAndAdd(currentCpuNode, Attributes.STATUS);
558 ss.modifyAttribute(ts, value, quark);
559 }
560 }
This page took 0.046816 seconds and 6 git commands to generate.