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 CtfKernelHandler(BlockingQueue
<CtfTmfEvent
> eventsQueue
) {
54 assert (eventsQueue
!= null);
55 this.inQueue
= eventsQueue
;
56 currentCPUNodes
= new Vector
<Integer
>();
57 currentThreadNodes
= new Vector
<Integer
>();
59 knownEventNames
= fillEventNames();
62 void assignStateSystem(IStateSystemBuilder targetSS
) {
69 System
.err
.println("Cannot run event manager without assigning a target state system first!"); //$NON-NLS-1$
75 event
= inQueue
.take();
76 while (event
.getTimestampValue() != -1) {
78 event
= inQueue
.take();
80 /* We've received the last event, clean up */
83 } catch (InterruptedException e
) {
84 /* We've been interrupted abnormally */
85 System
.out
.println("Event handler interrupted!"); //$NON-NLS-1$
90 private void closeStateSystem() {
91 /* Close the History system, if there is one */
93 ss
.closeHistory(currentEvent
.getTimestamp().getValue());
94 } catch (TimeRangeException e
) {
96 * Since we're using currentEvent.getTimestamp, this shouldn't
103 private void processEvent(CtfTmfEvent event
) {
104 currentEvent
= event
;
105 ITmfEventField content
= event
.getContent();
106 String eventName
= event
.getEventName();
108 long ts
= event
.getTimestamp().getValue();
110 ITmfStateValue value
;
111 Integer eventCpu
= event
.getCPU();
112 Integer currentCPUNode
, currentThreadNode
, tidNode
;
114 /* Adjust the current nodes Vectors if we see a new CPU in an event */
115 if (eventCpu
>= currentCPUNodes
.size()) {
116 /* We need to add this node to the vector */
117 for (Integer i
= currentCPUNodes
.size(); i
< eventCpu
+ 1; i
++) {
118 quark
= ss
.getQuarkAbsoluteAndAdd(Attributes
.CPUS
, i
.toString());
119 currentCPUNodes
.add(quark
);
121 quark
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, Attributes
.UNKNOWN
);
122 currentThreadNodes
.add(quark
);
126 currentCPUNode
= currentCPUNodes
.get(eventCpu
);
127 currentThreadNode
= currentThreadNodes
.get(eventCpu
);
128 assert (currentCPUNode
!= null);
129 assert (currentThreadNode
!= null);
133 * Feed event to the history system if it's known to cause a state
135 * https://projectwiki.dorsal.polymtl.ca/index.php/State_transitions
137 switch (getEventIndex(eventName
)) {
139 case 1: // "exit_syscall":
140 /* Fields: int64 ret */
141 /* Pop "syscall" from the Exec_mode_stack */
142 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_MODE_STACK
);
144 ss
.popAttribute(ts
, quark
);
145 } catch (AttributeNotFoundException e1
) {
147 * meh, can happen if we're missing events, we'll just
148 * silently ignore it.
150 System
.err
.println(event
.getTimestamp()
151 + " Popping empty attribute: " + e1
.getMessage()); //$NON-NLS-1$
155 case 2: // "irq_handler_entry":
156 /* Fields: int32 irq, string name */
157 Integer irqId
= ((Long
) content
.getField(LttngStrings
.IRQ
).getValue()).intValue();
159 /* Push the IRQ to the CPU's IRQ_stack */
160 quark
= ss
.getQuarkRelativeAndAdd(currentCPUNode
, Attributes
.IRQ_STACK
);
161 value
= TmfStateValue
.newValueInt(irqId
);
162 ss
.pushAttribute(ts
, value
, quark
);
164 /* Change the status of the running process to interrupted */
165 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
166 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_WAIT_CPU
);
167 ss
.modifyAttribute(ts
, value
, quark
);
170 case 3: // "irq_handler_exit":
171 /* Fields: int32 irq, int32 ret */
174 /* Pop the IRQ from the CPU's IRQ_stack */
175 quark
= ss
.getQuarkRelativeAndAdd(currentCPUNode
, Attributes
.IRQ_STACK
);
177 ss
.popAttribute(ts
, quark
);
178 } catch (AttributeNotFoundException e1
) {
179 System
.err
.print(event
.getTimestamp()
180 + " Popping empty attribute: " + e1
.getMessage()); //$NON-NLS-1$
184 * If this was the last IRQ on the stack, set the process back
187 /* 'quark' should still be valid */
189 stackDepth
= ss
.queryOngoingState(quark
).unboxInt();
190 } catch (StateValueTypeException e
) {
191 /* IRQ_stack SHOULD be of int type, this shouldn't happen */
194 if (stackDepth
== 0) {
195 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
196 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_RUN
);
197 ss
.modifyAttribute(ts
, value
, quark
);
201 case 4: // "softirq_entry":
202 /* Fields: int32 vec */
205 case 5: // "softirq_exit":
206 /* Fields: int32 vec */
209 case 6: // "softirq_raise":
210 /* Fields: int32 vec */
213 case 7: // "sched_switch":
215 * Fields: string prev_comm, int32 prev_tid, int32 prev_prio,
216 * int64 prev_state, string next_comm, int32 next_tid, int32
220 Integer prevTid
= ((Long
) content
.getField(LttngStrings
.PREV_TID
).getValue()).intValue();
221 Long prevState
= (Long
) content
.getField(LttngStrings
.PREV_STATE
).getValue();
223 String nextProcessName
= (String
) content
.getField(LttngStrings
.NEXT_COMM
).getValue();
224 Integer nextTid
= ((Long
) content
.getField(LttngStrings
.NEXT_TID
).getValue()).intValue();
226 /* Update the currentThreadNodes pointer */
227 Integer newCurrentThreadNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, nextTid
.toString());
228 initThreadNode(newCurrentThreadNode
);
229 currentThreadNodes
.set(eventCpu
, newCurrentThreadNode
);
231 /* Set the status of the new scheduled process */
232 quark
= ss
.getQuarkRelative(newCurrentThreadNode
, Attributes
.STATUS
);
233 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_RUN
);
234 ss
.modifyAttribute(ts
, value
, quark
);
236 /* Set the exec name of the new process */
237 quark
= ss
.getQuarkRelative(newCurrentThreadNode
, Attributes
.EXEC_NAME
);
238 value
= TmfStateValue
.newValueString(nextProcessName
);
239 ss
.modifyAttribute(ts
, value
, quark
);
241 /* Set the status of the process that got scheduled out */
242 quark
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, prevTid
.toString(), Attributes
.STATUS
);
243 value
= TmfStateValue
.newValueInt(prevState
.intValue());
244 ss
.modifyAttribute(ts
, value
, quark
);
246 /* Set the current scheduled process on the relevant CPU */
247 quark
= ss
.getQuarkRelativeAndAdd(currentCPUNode
, Attributes
.CURRENT_THREAD
);
248 value
= TmfStateValue
.newValueInt(nextTid
);
249 ss
.modifyAttribute(ts
, value
, quark
);
252 case 8: // "sched_process_fork":
254 * Fields: string parent_comm, int32 parent_tid, string
255 * child_comm, int32 child_tid
258 // String parentProcessName = (String)
259 // event.getFieldValue("parent_comm");
260 String childProcessName
;
261 childProcessName
= (String
) content
.getField(LttngStrings
.CHILD_COMM
).getValue();
262 // assert ( parentProcessName.equals(childProcessName) );
264 Integer parentTid
= ((Long
) content
.getField(LttngStrings
.PARENT_TID
).getValue()).intValue();
265 Integer childTid
= ((Long
) content
.getField(LttngStrings
.CHILD_TID
).getValue()).intValue();
267 tidNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, childTid
.toString());
268 initThreadNode(tidNode
);
271 * Add the new process with its known TID, PPID, and initial
274 quark
= ss
.getQuarkRelative(tidNode
, Attributes
.PPID
);
275 value
= TmfStateValue
.newValueInt(parentTid
);
276 ss
.modifyAttribute(ts
, value
, quark
);
278 /* Set the new process' exec_name */
279 quark
= ss
.getQuarkRelative(tidNode
, Attributes
.EXEC_NAME
);
280 value
= TmfStateValue
.newValueString(childProcessName
);
281 ss
.modifyAttribute(ts
, value
, quark
);
284 case 9: // "sched_process_exit":
285 /* Fields: string comm, int32 tid, int32 prio */
286 String processName
= (String
) content
.getField(LttngStrings
.COMM
).getValue();
287 Integer tid
= ((Long
) content
.getField(LttngStrings
.TID
).getValue()).intValue();
289 /* Update the process' name, if we don't have it */
290 quark
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, tid
.toString(), Attributes
.EXEC_NAME
);
291 value
= TmfStateValue
.newValueString(processName
);
292 ss
.updateOngoingState(value
, quark
);
295 * Remove the process and all its sub-attributes from the
298 quark
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, tid
.toString());
299 ss
.removeAttribute(ts
, quark
);
302 case 10: // "sched_process_free":
303 /* Fields: string comm, int32 tid, int32 prio */
306 // FIXME In CTF it's as "syscall_exec". Will have to be adapted.
307 // case LTT_EVENT_EXEC:
308 // filename = new String((byte[]) event.getField(0));
310 // /* Change the Exec_name of the process */
311 // quark = ss.getQuarkRelativePath(true, currentThreadNode,
313 // ss.modifyAttribute(ts, filename, quark);
317 /* Other event types not covered by the main switch */
319 if (eventName
.startsWith(LttngStrings
.SYSCALL_PREFIX
)
320 || eventName
.startsWith(LttngStrings
.COMPAT_SYSCALL_PREFIX
)) {
322 * This is a replacement for the old sys_enter event. Now
323 * syscall names are listed into the event type
327 * Push the syscall name on the Exec_mode_stack of the
330 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_MODE_STACK
);
331 value
= TmfStateValue
.newValueString(eventName
);
332 ss
.pushAttribute(ts
, value
, quark
);
342 /* Number of events of each type, globally */
343 // quark = ss.getQuarkAbsoluteAndAdd(Attributes.STATISTICS,
344 // Attributes.EVENT_TYPES, eventName);
345 // ss.incrementAttribute(ts, quark);
347 /* Number of events per CPU */
348 // quark = ss.getQuarkRelativeAndAdd(currentCPUNode,
349 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
350 // ss.incrementAttribute(ts, quark);
352 /* Number of events per process */
353 // quark = ss.getQuarkRelativeAndAdd(currentThreadNode,
354 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
355 // ss.incrementAttribute(ts, quark);
357 } catch (AttributeNotFoundException ae
) {
359 * This would indicate a problem with the logic of the manager here,
360 * so it shouldn't happen.
362 ae
.printStackTrace();
364 } catch (TimeRangeException tre
) {
366 * This would happen if the events in the trace aren't ordered
367 * chronologically, which should never be the case ...
369 System
.err
.println("TimeRangeExcpetion caught in the state system's event manager."); //$NON-NLS-1$
370 System
.err
.println("Are the events in the trace correctly ordered?"); //$NON-NLS-1$
371 tre
.printStackTrace();
373 } catch (StateValueTypeException sve
) {
375 * This would happen if we were trying to push/pop attributes not of
376 * type integer. Which, once again, should never happen.
378 sve
.printStackTrace();
383 * Ensure we always have some sub-attributes available for every "TID" node.
385 private void initThreadNode(int currentThreadNode
) {
386 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.PPID
);
387 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_NAME
);
388 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_MODE_STACK
);
389 ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.STATUS
);
392 private static HashMap
<String
, Integer
> fillEventNames() {
394 * TODO Replace with straight strings in the switch/case once we move to
397 HashMap
<String
, Integer
> map
= new HashMap
<String
, Integer
>();
399 map
.put(LttngStrings
.EXIT_SYSCALL
, 1);
400 map
.put(LttngStrings
.IRQ_HANDLER_ENTRY
, 2);
401 map
.put(LttngStrings
.IRQ_HANDLER_EXIT
, 3);
402 map
.put(LttngStrings
.SOFTIRQ_ENTRY
, 4);
403 map
.put(LttngStrings
.SOFTIRQ_EXIT
, 5);
404 map
.put(LttngStrings
.SOFTIRQ_RAISE
, 6);
405 map
.put(LttngStrings
.SCHED_SWITCH
, 7);
406 map
.put(LttngStrings
.SCHED_PROCESS_FORK
, 8);
407 map
.put(LttngStrings
.SCHED_PROCESS_EXIT
, 9);
408 map
.put(LttngStrings
.SCHED_PROCESS_FREE
, 10);
413 private int getEventIndex(String eventName
) {
414 Integer ret
= knownEventNames
.get(eventName
);
415 return (ret
!= null) ? ret
: -1;