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 /* Pop "syscall" from the Exec_mode_stack */
149 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_MODE_STACK
);
151 ss
.popAttribute(ts
, quark
);
152 } catch (AttributeNotFoundException e1
) {
154 * meh, can happen if we're missing events, we'll just
155 * silently ignore it.
157 System
.err
.println(event
.getTimestamp()
158 + " Popping empty attribute: " + e1
.getMessage()); //$NON-NLS-1$
163 case 2: // "irq_handler_entry":
164 /* Fields: int32 irq, string name */
166 Integer irqId
= ((Long
) content
.getField(LttngStrings
.IRQ
).getValue()).intValue();
168 /* Mark this IRQ as active in the resource tree.
169 * The state value = the CPU on which this IRQ is sitting */
170 quark
= ss
.getQuarkRelativeAndAdd(irqsNode
, irqId
.toString());
171 value
= TmfStateValue
.newValueInt(event
.getCPU());
172 ss
.modifyAttribute(ts
, value
, quark
);
174 /* Change the status of the running process to interrupted */
175 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
176 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_INTERRUPTED
);
177 ss
.modifyAttribute(ts
, value
, quark
);
181 case 3: // "irq_handler_exit":
182 /* Fields: int32 irq, int32 ret */
184 Integer irqId
= ((Long
) content
.getField(LttngStrings
.IRQ
).getValue()).intValue();
186 /* Put this IRQ back to inactive in the resource tree */
187 quark
= ss
.getQuarkRelativeAndAdd(irqsNode
, irqId
.toString());
188 value
= TmfStateValue
.nullValue();
189 ss
.modifyAttribute(ts
, value
, quark
);
191 /* Set the previous process back to running */
192 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
193 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_RUN
);
194 ss
.modifyAttribute(ts
, value
, quark
);
198 case 4: // "softirq_entry":
199 /* Fields: int32 vec */
201 Integer softIrqId
= ((Long
) content
.getField(LttngStrings
.VEC
).getValue()).intValue();
203 /* Mark this SoftIRQ as active in the resource tree.
204 * The state value = the CPU on which this SoftIRQ is processed */
205 quark
= ss
.getQuarkRelativeAndAdd(softIrqsNode
, softIrqId
.toString());
206 value
= TmfStateValue
.newValueInt(event
.getCPU());
207 ss
.modifyAttribute(ts
, value
, quark
);
209 /* Change the status of the running process to interrupted */
210 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
211 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_INTERRUPTED
);
212 ss
.modifyAttribute(ts
, value
, quark
);
216 case 5: // "softirq_exit":
217 /* Fields: int32 vec */
219 Integer softIrqId
= ((Long
) content
.getField(LttngStrings
.VEC
).getValue()).intValue();
221 /* Put this SoftIRQ back to inactive (= -1) in the resource tree */
222 quark
= ss
.getQuarkRelativeAndAdd(softIrqsNode
, softIrqId
.toString());
223 value
= TmfStateValue
.nullValue();
224 ss
.modifyAttribute(ts
, value
, quark
);
226 /* Set the previous process back to running */
227 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
228 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_RUN
);
229 ss
.modifyAttribute(ts
, value
, quark
);
233 case 6: // "softirq_raise":
234 /* Fields: int32 vec */
236 Integer softIrqId
= ((Long
) content
.getField(LttngStrings
.VEC
).getValue()).intValue();
238 /* Mark this SoftIRQ as *raised* in the resource tree.
239 * State value = -2 */
240 quark
= ss
.getQuarkRelativeAndAdd(softIrqsNode
, softIrqId
.toString());
241 value
= TmfStateValue
.newValueInt(-2);
242 ss
.modifyAttribute(ts
, value
, quark
);
246 case 7: // "sched_switch":
248 * Fields: string prev_comm, int32 prev_tid, int32 prev_prio, int64 prev_state,
249 * string next_comm, int32 next_tid, int32 next_prio
253 Integer prevTid
= ((Long
) content
.getField(LttngStrings
.PREV_TID
).getValue()).intValue();
254 Long prevState
= (Long
) content
.getField(LttngStrings
.PREV_STATE
).getValue();
256 String nextProcessName
= (String
) content
.getField(LttngStrings
.NEXT_COMM
).getValue();
257 Integer nextTid
= ((Long
) content
.getField(LttngStrings
.NEXT_TID
).getValue()).intValue();
259 /* Update the currentThreadNodes pointer */
260 Integer newCurrentThreadNode
= ss
.getQuarkRelativeAndAdd(threadsNode
, nextTid
.toString());
261 initThreadNode(newCurrentThreadNode
);
262 currentThreadNodes
.set(eventCpu
, newCurrentThreadNode
);
264 /* Set the status of the new scheduled process */
265 quark
= ss
.getQuarkRelative(newCurrentThreadNode
, Attributes
.STATUS
);
266 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_RUN
);
267 ss
.modifyAttribute(ts
, value
, quark
);
269 /* Set the exec name of the new process */
270 quark
= ss
.getQuarkRelative(newCurrentThreadNode
, Attributes
.EXEC_NAME
);
271 value
= TmfStateValue
.newValueString(nextProcessName
);
272 ss
.modifyAttribute(ts
, value
, quark
);
274 /* Set the status of the process that got scheduled out */
275 quark
= ss
.getQuarkRelativeAndAdd(threadsNode
, prevTid
.toString(), Attributes
.STATUS
);
276 value
= TmfStateValue
.newValueInt(prevState
.intValue());
277 ss
.modifyAttribute(ts
, value
, quark
);
279 /* Set the current scheduled process on the relevant CPU */
280 quark
= ss
.getQuarkRelativeAndAdd(currentCPUNode
, Attributes
.CURRENT_THREAD
);
281 value
= TmfStateValue
.newValueInt(nextTid
);
282 ss
.modifyAttribute(ts
, value
, quark
);
286 case 8: // "sched_process_fork":
287 /* Fields: string parent_comm, int32 parent_tid,
288 * string child_comm, int32 child_tid */
290 // String parentProcessName = (String)
291 // event.getFieldValue("parent_comm");
292 String childProcessName
;
293 childProcessName
= (String
) content
.getField(LttngStrings
.CHILD_COMM
).getValue();
294 // assert ( parentProcessName.equals(childProcessName) );
296 Integer parentTid
= ((Long
) content
.getField(LttngStrings
.PARENT_TID
).getValue()).intValue();
297 Integer childTid
= ((Long
) content
.getField(LttngStrings
.CHILD_TID
).getValue()).intValue();
299 tidNode
= ss
.getQuarkRelativeAndAdd(threadsNode
, childTid
.toString());
300 initThreadNode(tidNode
);
303 * Add the new process with its known TID, PPID, and initial
306 quark
= ss
.getQuarkRelative(tidNode
, Attributes
.PPID
);
307 value
= TmfStateValue
.newValueInt(parentTid
);
308 ss
.modifyAttribute(ts
, value
, quark
);
310 /* Set the new process' exec_name */
311 quark
= ss
.getQuarkRelative(tidNode
, Attributes
.EXEC_NAME
);
312 value
= TmfStateValue
.newValueString(childProcessName
);
313 ss
.modifyAttribute(ts
, value
, quark
);
317 case 9: // "sched_process_exit":
318 /* Fields: string comm, int32 tid, int32 prio */
320 String processName
= (String
) content
.getField(LttngStrings
.COMM
).getValue();
321 Integer tid
= ((Long
) content
.getField(LttngStrings
.TID
).getValue()).intValue();
323 /* Update the process' name, if we don't have it */
324 quark
= ss
.getQuarkRelativeAndAdd(threadsNode
, tid
.toString(), Attributes
.EXEC_NAME
);
325 value
= TmfStateValue
.newValueString(processName
);
326 ss
.updateOngoingState(value
, quark
);
329 * Remove the process and all its sub-attributes from the
332 quark
= ss
.getQuarkRelativeAndAdd(threadsNode
, tid
.toString());
333 ss
.removeAttribute(ts
, quark
);
337 case 10: // "sched_process_free":
338 /* Fields: string comm, int32 tid, int32 prio */
341 // FIXME In CTF it's as "syscall_exec". Will have to be adapted.
342 // case LTT_EVENT_EXEC:
343 // filename = new String((byte[]) event.getField(0));
345 // /* Change the Exec_name of the process */
346 // quark = ss.getQuarkRelativePath(true, currentThreadNode,
348 // ss.modifyAttribute(ts, filename, quark);
352 /* Other event types not covered by the main switch */
354 if (eventName
.startsWith(LttngStrings
.SYSCALL_PREFIX
)
355 || eventName
.startsWith(LttngStrings
.COMPAT_SYSCALL_PREFIX
)) {
357 * This is a replacement for the old sys_enter event. Now
358 * syscall names are listed into the event type
362 * Push the syscall name on the Exec_mode_stack of the
365 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_MODE_STACK
);
366 value
= TmfStateValue
.newValueString(eventName
);
367 ss
.pushAttribute(ts
, value
, quark
);
371 } // End of big switch
377 /* Number of events of each type, globally */
378 // quark = ss.getQuarkAbsoluteAndAdd(Attributes.STATISTICS,
379 // Attributes.EVENT_TYPES, eventName);
380 // ss.incrementAttribute(ts, quark);
382 /* Number of events per CPU */
383 // quark = ss.getQuarkRelativeAndAdd(currentCPUNode,
384 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
385 // ss.incrementAttribute(ts, quark);
387 /* Number of events per process */
388 // quark = ss.getQuarkRelativeAndAdd(currentThreadNode,
389 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
390 // ss.incrementAttribute(ts, quark);
392 } catch (AttributeNotFoundException ae
) {
394 * This would indicate a problem with the logic of the manager here,
395 * so it shouldn't happen.
397 ae
.printStackTrace();
399 } catch (TimeRangeException tre
) {
401 * This would happen if the events in the trace aren't ordered
402 * chronologically, which should never be the case ...
404 System
.err
.println("TimeRangeExcpetion caught in the state system's event manager."); //$NON-NLS-1$
405 System
.err
.println("Are the events in the trace correctly ordered?"); //$NON-NLS-1$
406 tre
.printStackTrace();
408 } catch (StateValueTypeException sve
) {
410 * This would happen if we were trying to push/pop attributes not of
411 * type integer. Which, once again, should never happen.
413 sve
.printStackTrace();
418 * Ensure we always have some sub-attributes available for every "TID" node.
420 private void initThreadNode(int currentThreadNode
) {
421 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.PPID
);
422 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_NAME
);
423 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_MODE_STACK
);
424 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
427 private void setupCommonLocations() {
428 cpusNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.CPUS
);
429 threadsNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
);
430 irqsNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.RESOURCES
, Attributes
.IRQS
);
431 softIrqsNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.RESOURCES
, Attributes
.SOFT_IRQS
);
434 private static HashMap
<String
, Integer
> fillEventNames() {
436 * TODO Replace with straight strings in the switch/case once we move to
439 HashMap
<String
, Integer
> map
= new HashMap
<String
, Integer
>();
441 map
.put(LttngStrings
.EXIT_SYSCALL
, 1);
442 map
.put(LttngStrings
.IRQ_HANDLER_ENTRY
, 2);
443 map
.put(LttngStrings
.IRQ_HANDLER_EXIT
, 3);
444 map
.put(LttngStrings
.SOFTIRQ_ENTRY
, 4);
445 map
.put(LttngStrings
.SOFTIRQ_EXIT
, 5);
446 map
.put(LttngStrings
.SOFTIRQ_RAISE
, 6);
447 map
.put(LttngStrings
.SCHED_SWITCH
, 7);
448 map
.put(LttngStrings
.SCHED_PROCESS_FORK
, 8);
449 map
.put(LttngStrings
.SCHED_PROCESS_EXIT
, 9);
450 map
.put(LttngStrings
.SCHED_PROCESS_FREE
, 10);
455 private int getEventIndex(String eventName
) {
456 Integer ret
= knownEventNames
.get(eventName
);
457 return (ret
!= null) ? ret
: -1;