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>
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
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.internal
.lttng2
.kernel
.core
.stateprovider
;
15 import java
.util
.HashMap
;
16 import java
.util
.Vector
;
17 import java
.util
.concurrent
.BlockingQueue
;
19 import org
.eclipse
.linuxtools
.lttng2
.kernel
.core
.trace
.Attributes
;
20 import org
.eclipse
.linuxtools
.lttng2
.kernel
.core
.trace
.LttngStrings
;
21 import org
.eclipse
.linuxtools
.tmf
.core
.ctfadaptor
.CtfTmfEvent
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEventField
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.AttributeNotFoundException
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateValueTypeException
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TimeRangeException
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.IStateSystemBuilder
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.ITmfStateValue
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.TmfStateValue
;
31 * This is the reference "state provider" for LTTng 2.0 kernel traces.
36 class CtfKernelHandler
implements Runnable
{
38 private final BlockingQueue
<CtfTmfEvent
> inQueue
;
39 private IStateSystemBuilder ss
;
41 private CtfTmfEvent currentEvent
;
44 * We can keep handles to some Attribute Nodes so these don't need to be
45 * re-found (re-hashed Strings etc.) every new event
47 Vector
<Integer
> currentCPUNodes
;
48 Vector
<Integer
> currentThreadNodes
;
50 /* Event names HashMap. TODO: This can be discarded once we move to Java 7 */
51 private final HashMap
<String
, Integer
> knownEventNames
;
53 /* Common locations in the attribute tree */
54 private int cpusNode
= -1;
55 private int threadsNode
= -1;
56 private int irqsNode
= -1;
57 private int softIrqsNode
= -1;
59 CtfKernelHandler(BlockingQueue
<CtfTmfEvent
> eventsQueue
) {
60 assert (eventsQueue
!= null);
61 this.inQueue
= eventsQueue
;
62 currentCPUNodes
= new Vector
<Integer
>();
63 currentThreadNodes
= new Vector
<Integer
>();
65 knownEventNames
= fillEventNames();
68 void assignStateSystem(IStateSystemBuilder targetSS
) {
75 System
.err
.println("Cannot run event manager without assigning a target state system first!"); //$NON-NLS-1$
79 setupCommonLocations();
82 event
= inQueue
.take();
83 while (event
.getTimestampValue() != -1) {
85 event
= inQueue
.take();
87 /* We've received the last event, clean up */
90 } catch (InterruptedException e
) {
91 /* We've been interrupted abnormally */
92 System
.out
.println("Event handler interrupted!"); //$NON-NLS-1$
97 private void closeStateSystem() {
98 /* Close the History system, if there is one */
100 ss
.closeHistory(currentEvent
.getTimestamp().getValue());
101 } catch (TimeRangeException e
) {
103 * Since we're using currentEvent.getTimestamp, this shouldn't
110 private void processEvent(CtfTmfEvent event
) {
111 currentEvent
= event
;
112 ITmfEventField content
= event
.getContent();
113 String eventName
= event
.getEventName();
115 long ts
= event
.getTimestamp().getValue();
117 ITmfStateValue value
;
118 Integer eventCpu
= event
.getCPU();
119 Integer currentCPUNode
, currentThreadNode
, tidNode
;
121 /* Adjust the current nodes Vectors if we see a new CPU in an event */
122 if (eventCpu
>= currentCPUNodes
.size()) {
123 /* We need to add this node to the vector */
124 for (Integer i
= currentCPUNodes
.size(); i
< eventCpu
+ 1; i
++) {
125 quark
= ss
.getQuarkRelativeAndAdd(cpusNode
, i
.toString());
126 currentCPUNodes
.add(quark
);
128 quark
= ss
.getQuarkRelativeAndAdd(threadsNode
, Attributes
.UNKNOWN
);
129 currentThreadNodes
.add(quark
);
133 currentCPUNode
= currentCPUNodes
.get(eventCpu
);
134 currentThreadNode
= currentThreadNodes
.get(eventCpu
);
135 assert (currentCPUNode
!= null);
136 assert (currentThreadNode
!= null);
140 * Feed event to the history system if it's known to cause a state
143 switch (getEventIndex(eventName
)) {
145 case 1: // "exit_syscall":
146 /* Fields: int64 ret */
148 /* Clear the current system call on the process */
149 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.SYSTEM_CALL
);
150 value
= TmfStateValue
.nullValue();
151 ss
.modifyAttribute(ts
, value
, quark
);
153 /* Put the process' status back to user mode */
154 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
155 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_RUN_USERMODE
);
156 ss
.modifyAttribute(ts
, value
, quark
);
160 case 2: // "irq_handler_entry":
161 /* Fields: int32 irq, string name */
163 Integer irqId
= ((Long
) content
.getField(LttngStrings
.IRQ
).getValue()).intValue();
165 /* Mark this IRQ as active in the resource tree.
166 * The state value = the CPU on which this IRQ is sitting */
167 quark
= ss
.getQuarkRelativeAndAdd(irqsNode
, irqId
.toString());
168 value
= TmfStateValue
.newValueInt(event
.getCPU());
169 ss
.modifyAttribute(ts
, value
, quark
);
171 /* Change the status of the running process to interrupted */
172 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
173 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_INTERRUPTED
);
174 ss
.modifyAttribute(ts
, value
, quark
);
178 case 3: // "irq_handler_exit":
179 /* Fields: int32 irq, int32 ret */
181 Integer irqId
= ((Long
) content
.getField(LttngStrings
.IRQ
).getValue()).intValue();
183 /* Put this IRQ back to inactive in the resource tree */
184 quark
= ss
.getQuarkRelativeAndAdd(irqsNode
, irqId
.toString());
185 value
= TmfStateValue
.nullValue();
186 ss
.modifyAttribute(ts
, value
, quark
);
188 /* Set the previous process back to running */
189 setProcessToRunning(ts
, currentThreadNode
);
193 case 4: // "softirq_entry":
194 /* Fields: int32 vec */
196 Integer softIrqId
= ((Long
) content
.getField(LttngStrings
.VEC
).getValue()).intValue();
198 /* Mark this SoftIRQ as active in the resource tree.
199 * The state value = the CPU on which this SoftIRQ is processed */
200 quark
= ss
.getQuarkRelativeAndAdd(softIrqsNode
, softIrqId
.toString());
201 value
= TmfStateValue
.newValueInt(event
.getCPU());
202 ss
.modifyAttribute(ts
, value
, quark
);
204 /* Change the status of the running process to interrupted */
205 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
206 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_INTERRUPTED
);
207 ss
.modifyAttribute(ts
, value
, quark
);
211 case 5: // "softirq_exit":
212 /* Fields: int32 vec */
214 Integer softIrqId
= ((Long
) content
.getField(LttngStrings
.VEC
).getValue()).intValue();
216 /* Put this SoftIRQ back to inactive (= -1) in the resource tree */
217 quark
= ss
.getQuarkRelativeAndAdd(softIrqsNode
, softIrqId
.toString());
218 value
= TmfStateValue
.nullValue();
219 ss
.modifyAttribute(ts
, value
, quark
);
221 /* Set the previous process back to running */
222 setProcessToRunning(ts
, currentThreadNode
);
226 case 6: // "softirq_raise":
227 /* Fields: int32 vec */
229 Integer softIrqId
= ((Long
) content
.getField(LttngStrings
.VEC
).getValue()).intValue();
231 /* Mark this SoftIRQ as *raised* in the resource tree.
232 * State value = -2 */
233 quark
= ss
.getQuarkRelativeAndAdd(softIrqsNode
, softIrqId
.toString());
234 value
= TmfStateValue
.newValueInt(Attributes
.SOFT_IRQ_RAISED
);
235 ss
.modifyAttribute(ts
, value
, quark
);
239 case 7: // "sched_switch":
241 * Fields: string prev_comm, int32 prev_tid, int32 prev_prio, int64 prev_state,
242 * string next_comm, int32 next_tid, int32 next_prio
246 Integer prevTid
= ((Long
) content
.getField(LttngStrings
.PREV_TID
).getValue()).intValue();
247 //Long prevState = (Long) content.getField(LttngStrings.PREV_STATE).getValue();
249 String nextProcessName
= (String
) content
.getField(LttngStrings
.NEXT_COMM
).getValue();
250 Integer nextTid
= ((Long
) content
.getField(LttngStrings
.NEXT_TID
).getValue()).intValue();
252 /* Update the currentThreadNodes pointer */
253 Integer newCurrentThreadNode
= ss
.getQuarkRelativeAndAdd(threadsNode
, nextTid
.toString());
254 initThreadNode(newCurrentThreadNode
);
255 currentThreadNodes
.set(eventCpu
, newCurrentThreadNode
);
257 /* Set the status of the new scheduled process */
258 setProcessToRunning(ts
, newCurrentThreadNode
);
260 /* Set the exec name of the new process */
261 quark
= ss
.getQuarkRelative(newCurrentThreadNode
, Attributes
.EXEC_NAME
);
262 value
= TmfStateValue
.newValueString(nextProcessName
);
263 ss
.modifyAttribute(ts
, value
, quark
);
265 /* Set the status of the process that got scheduled out */
266 quark
= ss
.getQuarkRelativeAndAdd(threadsNode
, prevTid
.toString(), Attributes
.STATUS
);
267 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_WAIT
);
268 ss
.modifyAttribute(ts
, value
, quark
);
270 /* Set the current scheduled process on the relevant CPU */
271 quark
= ss
.getQuarkRelativeAndAdd(currentCPUNode
, Attributes
.CURRENT_THREAD
);
272 value
= TmfStateValue
.newValueInt(nextTid
);
273 ss
.modifyAttribute(ts
, value
, quark
);
277 case 8: // "sched_process_fork":
278 /* Fields: string parent_comm, int32 parent_tid,
279 * string child_comm, int32 child_tid */
281 // String parentProcessName = (String)
282 // event.getFieldValue("parent_comm");
283 String childProcessName
;
284 childProcessName
= (String
) content
.getField(LttngStrings
.CHILD_COMM
).getValue();
285 // assert ( parentProcessName.equals(childProcessName) );
287 Integer parentTid
= ((Long
) content
.getField(LttngStrings
.PARENT_TID
).getValue()).intValue();
288 Integer childTid
= ((Long
) content
.getField(LttngStrings
.CHILD_TID
).getValue()).intValue();
290 tidNode
= ss
.getQuarkRelativeAndAdd(threadsNode
, childTid
.toString());
291 initThreadNode(tidNode
);
294 * Add the new process with its known TID, PPID, and initial
297 quark
= ss
.getQuarkRelative(tidNode
, Attributes
.PPID
);
298 value
= TmfStateValue
.newValueInt(parentTid
);
299 ss
.modifyAttribute(ts
, value
, quark
);
301 /* Set the new process' exec_name */
302 quark
= ss
.getQuarkRelative(tidNode
, Attributes
.EXEC_NAME
);
303 value
= TmfStateValue
.newValueString(childProcessName
);
304 ss
.modifyAttribute(ts
, value
, quark
);
308 case 9: // "sched_process_exit":
309 /* Fields: string comm, int32 tid, int32 prio */
311 String processName
= (String
) content
.getField(LttngStrings
.COMM
).getValue();
312 Integer tid
= ((Long
) content
.getField(LttngStrings
.TID
).getValue()).intValue();
314 /* Update the process' name, if we don't have it */
315 quark
= ss
.getQuarkRelativeAndAdd(threadsNode
, tid
.toString(), Attributes
.EXEC_NAME
);
316 value
= TmfStateValue
.newValueString(processName
);
317 ss
.updateOngoingState(value
, quark
);
320 * Remove the process and all its sub-attributes from the
323 quark
= ss
.getQuarkRelativeAndAdd(threadsNode
, tid
.toString());
324 ss
.removeAttribute(ts
, quark
);
328 case 10: // "sched_process_free":
329 /* Fields: string comm, int32 tid, int32 prio */
332 // FIXME In CTF it's as "syscall_exec". Will have to be adapted.
333 // case LTT_EVENT_EXEC:
334 // filename = new String((byte[]) event.getField(0));
336 // /* Change the Exec_name of the process */
337 // quark = ss.getQuarkRelativePath(true, currentThreadNode,
339 // ss.modifyAttribute(ts, filename, quark);
343 /* Other event types not covered by the main switch */
345 if (eventName
.startsWith(LttngStrings
.SYSCALL_PREFIX
)
346 || eventName
.startsWith(LttngStrings
.COMPAT_SYSCALL_PREFIX
)) {
348 * This is a replacement for the old sys_enter event. Now
349 * syscall names are listed into the event type
352 /* Assign the new system call to the process */
353 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.SYSTEM_CALL
);
354 value
= TmfStateValue
.newValueString(eventName
);
355 ss
.modifyAttribute(ts
, value
, quark
);
357 /* Put the process in system call mode */
358 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
359 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_RUN_SYSCALL
);
360 ss
.modifyAttribute(ts
, value
, quark
);
364 } // End of big switch
370 /* Number of events of each type, globally */
371 // quark = ss.getQuarkAbsoluteAndAdd(Attributes.STATISTICS,
372 // Attributes.EVENT_TYPES, eventName);
373 // ss.incrementAttribute(ts, quark);
375 /* Number of events per CPU */
376 // quark = ss.getQuarkRelativeAndAdd(currentCPUNode,
377 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
378 // ss.incrementAttribute(ts, quark);
380 /* Number of events per process */
381 // quark = ss.getQuarkRelativeAndAdd(currentThreadNode,
382 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
383 // ss.incrementAttribute(ts, quark);
385 } catch (AttributeNotFoundException ae
) {
387 * This would indicate a problem with the logic of the manager here,
388 * so it shouldn't happen.
390 ae
.printStackTrace();
392 } catch (TimeRangeException tre
) {
394 * This would happen if the events in the trace aren't ordered
395 * chronologically, which should never be the case ...
397 System
.err
.println("TimeRangeExcpetion caught in the state system's event manager."); //$NON-NLS-1$
398 System
.err
.println("Are the events in the trace correctly ordered?"); //$NON-NLS-1$
399 tre
.printStackTrace();
401 } catch (StateValueTypeException sve
) {
403 * This would happen if we were trying to push/pop attributes not of
404 * type integer. Which, once again, should never happen.
406 sve
.printStackTrace();
411 * Ensure we always have some sub-attributes available for every "TID" node.
413 private void initThreadNode(int currentThreadNode
) {
414 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.PPID
);
415 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_NAME
);
416 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.SYSTEM_CALL
);
417 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
420 private void setupCommonLocations() {
421 cpusNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.CPUS
);
422 threadsNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
);
423 irqsNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.RESOURCES
, Attributes
.IRQS
);
424 softIrqsNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.RESOURCES
, Attributes
.SOFT_IRQS
);
427 private static HashMap
<String
, Integer
> fillEventNames() {
429 * TODO Replace with straight strings in the switch/case once we move to
432 HashMap
<String
, Integer
> map
= new HashMap
<String
, Integer
>();
434 map
.put(LttngStrings
.EXIT_SYSCALL
, 1);
435 map
.put(LttngStrings
.IRQ_HANDLER_ENTRY
, 2);
436 map
.put(LttngStrings
.IRQ_HANDLER_EXIT
, 3);
437 map
.put(LttngStrings
.SOFTIRQ_ENTRY
, 4);
438 map
.put(LttngStrings
.SOFTIRQ_EXIT
, 5);
439 map
.put(LttngStrings
.SOFTIRQ_RAISE
, 6);
440 map
.put(LttngStrings
.SCHED_SWITCH
, 7);
441 map
.put(LttngStrings
.SCHED_PROCESS_FORK
, 8);
442 map
.put(LttngStrings
.SCHED_PROCESS_EXIT
, 9);
443 map
.put(LttngStrings
.SCHED_PROCESS_FREE
, 10);
448 private int getEventIndex(String eventName
) {
449 Integer ret
= knownEventNames
.get(eventName
);
450 return (ret
!= null) ? ret
: -1;
454 * When we want to set a process back to a "running" state, first check
455 * its current System_call attribute. If there is a system call active, we
456 * put the process back in the syscall state. If not, we put it back in
459 private void setProcessToRunning(long ts
, int currentThreadNode
)
460 throws AttributeNotFoundException
, TimeRangeException
,
461 StateValueTypeException
{
463 ITmfStateValue value
;
465 quark
= ss
.getQuarkRelative(currentThreadNode
, Attributes
.SYSTEM_CALL
);
466 if (ss
.queryOngoingState(quark
).isNull()) {
467 /* We were in user mode before the interruption */
468 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_RUN_USERMODE
);
470 /* We were previously in kernel mode */
471 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_RUN_SYSCALL
);
473 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
474 ss
.modifyAttribute(ts
, value
, quark
);