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
.statesystem
.AttributeNotFoundException
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.TimeRangeException
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.helpers
.IStateSystemBuilder
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.ITmfStateValue
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.StateValueTypeException
;
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 // prev_comm doesn't seem to get populated...
221 String prevProcessName
= (String
) content
.getField(LttngStrings
.PREV_COMM
).getValue();
222 Integer prevTid
= ((Long
) content
.getField(LttngStrings
.PREV_TID
).getValue()).intValue();
223 Long prevState
= (Long
) content
.getField(LttngStrings
.PREV_STATE
).getValue();
225 String nextProcessName
= (String
) content
.getField(LttngStrings
.NEXT_COMM
).getValue();
226 Integer nextTid
= ((Long
) content
.getField(LttngStrings
.NEXT_TID
).getValue()).intValue();
228 /* Update the name of the process going out (if needed) */
229 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_NAME
);
230 value
= TmfStateValue
.newValueString(prevProcessName
);
231 ss
.updateOngoingState(value
, quark
);
233 /* Update the currentThreadNodes pointer */
234 Integer newCurrentThreadNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, nextTid
.toString());
235 currentThreadNodes
.set(eventCpu
, newCurrentThreadNode
);
237 /* Set the status of the new scheduled process */
238 quark
= ss
.getQuarkRelativeAndAdd(newCurrentThreadNode
, Attributes
.STATUS
);
239 value
= TmfStateValue
.newValueInt(Attributes
.STATUS_RUN
);
240 ss
.modifyAttribute(ts
, value
, quark
);
242 /* Set the exec name of the new process */
243 quark
= ss
.getQuarkRelativeAndAdd(newCurrentThreadNode
, Attributes
.EXEC_NAME
);
244 value
= TmfStateValue
.newValueString(nextProcessName
);
245 ss
.modifyAttribute(ts
, value
, quark
);
247 /* Set the status of the process that got scheduled out */
248 quark
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, prevTid
.toString(), Attributes
.STATUS
);
249 value
= TmfStateValue
.newValueInt(prevState
.intValue());
250 ss
.modifyAttribute(ts
, value
, quark
);
252 /* Set the current scheduled process on the relevant CPU */
253 quark
= ss
.getQuarkRelativeAndAdd(currentCPUNode
, Attributes
.CURRENT_THREAD
);
254 value
= TmfStateValue
.newValueInt(nextTid
);
255 ss
.modifyAttribute(ts
, value
, quark
);
258 case 8: // "sched_process_fork":
260 * Fields: string parent_comm, int32 parent_tid, string
261 * child_comm, int32 child_tid
264 // String parentProcessName = (String)
265 // event.getFieldValue("parent_comm");
266 String childProcessName
;
267 childProcessName
= (String
) content
.getField(LttngStrings
.CHILD_COMM
).getValue();
268 // assert ( parentProcessName.equals(childProcessName) );
270 Integer parentTid
= ((Long
) content
.getField(LttngStrings
.PARENT_TID
).getValue()).intValue();
271 Integer childTid
= ((Long
) content
.getField(LttngStrings
.CHILD_TID
).getValue()).intValue();
273 tidNode
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, childTid
.toString());
276 * Add the new process with its known TID, PPID, and initial
279 quark
= ss
.getQuarkRelativeAndAdd(tidNode
, Attributes
.PPID
);
280 value
= TmfStateValue
.newValueInt(parentTid
);
281 ss
.modifyAttribute(ts
, value
, quark
);
283 /* Set the new process' exec_name */
284 quark
= ss
.getQuarkRelativeAndAdd(tidNode
, Attributes
.EXEC_NAME
);
285 value
= TmfStateValue
.newValueString(childProcessName
);
286 ss
.modifyAttribute(ts
, value
, quark
);
289 case 9: // "sched_process_exit":
290 /* Fields: string comm, int32 tid, int32 prio */
291 String processName
= (String
) content
.getField(LttngStrings
.COMM
).getValue();
292 Integer tid
= ((Long
) content
.getField(LttngStrings
.TID
).getValue()).intValue();
294 /* Update the process' name, if we don't have it */
295 quark
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, tid
.toString(), Attributes
.EXEC_NAME
);
296 value
= TmfStateValue
.newValueString(processName
);
297 ss
.updateOngoingState(value
, quark
);
300 * Remove the process and all its sub-attributes from the
303 quark
= ss
.getQuarkAbsoluteAndAdd(Attributes
.THREADS
, tid
.toString());
304 ss
.removeAttribute(ts
, quark
);
307 case 10: // "sched_process_free":
308 /* Fields: string comm, int32 tid, int32 prio */
311 // FIXME In CTF it's as "syscall_exec". Will have to be adapted.
312 // case LTT_EVENT_EXEC:
313 // filename = new String((byte[]) event.getField(0));
315 // /* Change the Exec_name of the process */
316 // quark = ss.getQuarkRelativePath(true, currentThreadNode,
318 // ss.modifyAttribute(ts, filename, quark);
322 /* Other event types not covered by the main switch */
324 if (eventName
.startsWith(LttngStrings
.SYSCALL_PREFIX
)
325 || eventName
.startsWith(LttngStrings
.COMPAT_SYSCALL_PREFIX
)) {
327 * This is a replacement for the old sys_enter event. Now
328 * syscall names are listed into the event type
332 * Push the syscall name on the Exec_mode_stack of the
335 quark
= ss
.getQuarkRelativeAndAdd(currentThreadNode
, Attributes
.EXEC_MODE_STACK
);
336 value
= TmfStateValue
.newValueString(eventName
);
337 ss
.pushAttribute(ts
, value
, quark
);
347 /* Number of events of each type, globally */
348 // quark = ss.getQuarkAbsoluteAndAdd(Attributes.STATISTICS,
349 // Attributes.EVENT_TYPES, eventName);
350 // ss.incrementAttribute(ts, quark);
352 /* Number of events per CPU */
353 // quark = ss.getQuarkRelativeAndAdd(currentCPUNode,
354 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
355 // ss.incrementAttribute(ts, quark);
357 /* Number of events per process */
358 // quark = ss.getQuarkRelativeAndAdd(currentThreadNode,
359 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
360 // ss.incrementAttribute(ts, quark);
362 } catch (AttributeNotFoundException ae
) {
364 * This would indicate a problem with the logic of the manager here,
365 * so it shouldn't happen.
367 ae
.printStackTrace();
369 } catch (TimeRangeException tre
) {
371 * This would happen if the events in the trace aren't ordered
372 * chronologically, which should never be the case ...
374 System
.err
.println("TimeRangeExcpetion caught in the state system's event manager."); //$NON-NLS-1$
375 System
.err
.println("Are the events in the trace correctly ordered?"); //$NON-NLS-1$
376 tre
.printStackTrace();
378 } catch (StateValueTypeException sve
) {
380 * This would happen if we were trying to push/pop attributes not of
381 * type integer. Which, once again, should never happen.
383 sve
.printStackTrace();
388 private static HashMap
<String
, Integer
> fillEventNames() {
390 * TODO Replace with straight strings in the switch/case once we move to
393 HashMap
<String
, Integer
> map
= new HashMap
<String
, Integer
>();
395 map
.put(LttngStrings
.EXIT_SYSCALL
, 1);
396 map
.put(LttngStrings
.IRQ_HANDLER_ENTRY
, 2);
397 map
.put(LttngStrings
.IRQ_HANDLER_EXIT
, 3);
398 map
.put(LttngStrings
.SOFTIRQ_ENTRY
, 4);
399 map
.put(LttngStrings
.SOFTIRQ_EXIT
, 5);
400 map
.put(LttngStrings
.SOFTIRQ_RAISE
, 6);
401 map
.put(LttngStrings
.SCHED_SWITCH
, 7);
402 map
.put(LttngStrings
.SCHED_PROCESS_FORK
, 8);
403 map
.put(LttngStrings
.SCHED_PROCESS_EXIT
, 9);
404 map
.put(LttngStrings
.SCHED_PROCESS_FREE
, 10);
409 private int getEventIndex(String eventName
) {
410 Integer ret
= knownEventNames
.get(eventName
);
411 return (ret
!= null) ? ret
: -1;