tmf: Split StateHistorySystem into two interfaces
[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.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;
29
30 /**
31 * This is the reference "state provider" for LTTng 2.0 kernel traces.
32 *
33 * @author alexmont
34 *
35 */
36 class CtfKernelHandler implements Runnable {
37
38 private final BlockingQueue<CtfTmfEvent> inQueue;
39 private IStateSystemBuilder ss;
40
41 private CtfTmfEvent currentEvent;
42
43 /*
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
46 */
47 Vector<Integer> currentCPUNodes;
48 Vector<Integer> currentThreadNodes;
49
50 /* Event names HashMap. TODO: This can be discarded once we move to Java 7 */
51 private final HashMap<String, Integer> knownEventNames;
52
53 CtfKernelHandler(BlockingQueue<CtfTmfEvent> eventsQueue) {
54 assert (eventsQueue != null);
55 this.inQueue = eventsQueue;
56 currentCPUNodes = new Vector<Integer>();
57 currentThreadNodes = new Vector<Integer>();
58
59 knownEventNames = fillEventNames();
60 }
61
62 void assignStateSystem(IStateSystemBuilder targetSS) {
63 this.ss = targetSS;
64 }
65
66 @Override
67 public void run() {
68 if (ss == null) {
69 System.err.println("Cannot run event manager without assigning a target state system first!"); //$NON-NLS-1$
70 return;
71 }
72 CtfTmfEvent event;
73
74 try {
75 event = inQueue.take();
76 while (event.getTimestampValue() != -1) {
77 processEvent(event);
78 event = inQueue.take();
79 }
80 /* We've received the last event, clean up */
81 closeStateSystem();
82 return;
83 } catch (InterruptedException e) {
84 /* We've been interrupted abnormally */
85 System.out.println("Event handler interrupted!"); //$NON-NLS-1$
86 e.printStackTrace();
87 }
88 }
89
90 private void closeStateSystem() {
91 /* Close the History system, if there is one */
92 try {
93 ss.closeHistory(currentEvent.getTimestamp().getValue());
94 } catch (TimeRangeException e) {
95 /*
96 * Since we're using currentEvent.getTimestamp, this shouldn't
97 * cause any problem
98 */
99 e.printStackTrace();
100 }
101 }
102
103 private void processEvent(CtfTmfEvent event) {
104 currentEvent = event;
105 ITmfEventField content = event.getContent();
106 String eventName = event.getEventName();
107
108 long ts = event.getTimestamp().getValue();
109 int quark;
110 ITmfStateValue value;
111 Integer eventCpu = event.getCPU();
112 Integer currentCPUNode, currentThreadNode, tidNode;
113
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);
120
121 quark = ss.getQuarkAbsoluteAndAdd(Attributes.THREADS, Attributes.UNKNOWN);
122 currentThreadNodes.add(quark);
123 }
124 }
125
126 currentCPUNode = currentCPUNodes.get(eventCpu);
127 currentThreadNode = currentThreadNodes.get(eventCpu);
128 assert (currentCPUNode != null);
129 assert (currentThreadNode != null);
130
131 try {
132 /*
133 * Feed event to the history system if it's known to cause a state
134 * transition See:
135 * https://projectwiki.dorsal.polymtl.ca/index.php/State_transitions
136 */
137 switch (getEventIndex(eventName)) {
138
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);
143 try {
144 ss.popAttribute(ts, quark);
145 } catch (AttributeNotFoundException e1) {
146 /*
147 * meh, can happen if we're missing events, we'll just
148 * silently ignore it.
149 */
150 System.err.println(event.getTimestamp()
151 + " Popping empty attribute: " + e1.getMessage()); //$NON-NLS-1$
152 }
153 break;
154
155 case 2: // "irq_handler_entry":
156 /* Fields: int32 irq, string name */
157 Integer irqId = ((Long) content.getField(LttngStrings.IRQ).getValue()).intValue();
158
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);
163
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);
168 break;
169
170 case 3: // "irq_handler_exit":
171 /* Fields: int32 irq, int32 ret */
172 int stackDepth = 0;
173
174 /* Pop the IRQ from the CPU's IRQ_stack */
175 quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.IRQ_STACK);
176 try {
177 ss.popAttribute(ts, quark);
178 } catch (AttributeNotFoundException e1) {
179 System.err.print(event.getTimestamp()
180 + " Popping empty attribute: " + e1.getMessage()); //$NON-NLS-1$
181 }
182
183 /*
184 * If this was the last IRQ on the stack, set the process back
185 * to running
186 */
187 /* 'quark' should still be valid */
188 try {
189 stackDepth = ss.queryOngoingState(quark).unboxInt();
190 } catch (StateValueTypeException e) {
191 /* IRQ_stack SHOULD be of int type, this shouldn't happen */
192 e.printStackTrace();
193 }
194 if (stackDepth == 0) {
195 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
196 value = TmfStateValue.newValueInt(Attributes.STATUS_RUN);
197 ss.modifyAttribute(ts, value, quark);
198 }
199 break;
200
201 case 4: // "softirq_entry":
202 /* Fields: int32 vec */
203 break;
204
205 case 5: // "softirq_exit":
206 /* Fields: int32 vec */
207 break;
208
209 case 6: // "softirq_raise":
210 /* Fields: int32 vec */
211 break;
212
213 case 7: // "sched_switch":
214 /*
215 * Fields: string prev_comm, int32 prev_tid, int32 prev_prio,
216 * int64 prev_state, string next_comm, int32 next_tid, int32
217 * next_prio
218 */
219
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();
224
225 String nextProcessName = (String) content.getField(LttngStrings.NEXT_COMM).getValue();
226 Integer nextTid = ((Long) content.getField(LttngStrings.NEXT_TID).getValue()).intValue();
227
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);
232
233 /* Update the currentThreadNodes pointer */
234 Integer newCurrentThreadNode = ss.getQuarkAbsoluteAndAdd(Attributes.THREADS, nextTid.toString());
235 currentThreadNodes.set(eventCpu, newCurrentThreadNode);
236
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);
241
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);
246
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);
251
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);
256 break;
257
258 case 8: // "sched_process_fork":
259 /*
260 * Fields: string parent_comm, int32 parent_tid, string
261 * child_comm, int32 child_tid
262 */
263
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) );
269
270 Integer parentTid = ((Long) content.getField(LttngStrings.PARENT_TID).getValue()).intValue();
271 Integer childTid = ((Long) content.getField(LttngStrings.CHILD_TID).getValue()).intValue();
272
273 tidNode = ss.getQuarkAbsoluteAndAdd(Attributes.THREADS, childTid.toString());
274
275 /*
276 * Add the new process with its known TID, PPID, and initial
277 * Exec_name
278 */
279 quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.PPID);
280 value = TmfStateValue.newValueInt(parentTid);
281 ss.modifyAttribute(ts, value, quark);
282
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);
287 break;
288
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();
293
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);
298
299 /*
300 * Remove the process and all its sub-attributes from the
301 * current state
302 */
303 quark = ss.getQuarkAbsoluteAndAdd(Attributes.THREADS, tid.toString());
304 ss.removeAttribute(ts, quark);
305 break;
306
307 case 10: // "sched_process_free":
308 /* Fields: string comm, int32 tid, int32 prio */
309 break;
310
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));
314 //
315 // /* Change the Exec_name of the process */
316 // quark = ss.getQuarkRelativePath(true, currentThreadNode,
317 // "Exec_name");
318 // ss.modifyAttribute(ts, filename, quark);
319 // break;
320
321 default:
322 /* Other event types not covered by the main switch */
323
324 if (eventName.startsWith(LttngStrings.SYSCALL_PREFIX)
325 || eventName.startsWith(LttngStrings.COMPAT_SYSCALL_PREFIX)) {
326 /*
327 * This is a replacement for the old sys_enter event. Now
328 * syscall names are listed into the event type
329 */
330
331 /*
332 * Push the syscall name on the Exec_mode_stack of the
333 * relevant PID
334 */
335 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.EXEC_MODE_STACK);
336 value = TmfStateValue.newValueString(eventName);
337 ss.pushAttribute(ts, value, quark);
338 }
339
340 break;
341 } // End of switch
342
343 /*
344 * Statistics
345 */
346
347 /* Number of events of each type, globally */
348 // quark = ss.getQuarkAbsoluteAndAdd(Attributes.STATISTICS,
349 // Attributes.EVENT_TYPES, eventName);
350 // ss.incrementAttribute(ts, quark);
351
352 /* Number of events per CPU */
353 // quark = ss.getQuarkRelativeAndAdd(currentCPUNode,
354 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
355 // ss.incrementAttribute(ts, quark);
356
357 /* Number of events per process */
358 // quark = ss.getQuarkRelativeAndAdd(currentThreadNode,
359 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
360 // ss.incrementAttribute(ts, quark);
361
362 } catch (AttributeNotFoundException ae) {
363 /*
364 * This would indicate a problem with the logic of the manager here,
365 * so it shouldn't happen.
366 */
367 ae.printStackTrace();
368
369 } catch (TimeRangeException tre) {
370 /*
371 * This would happen if the events in the trace aren't ordered
372 * chronologically, which should never be the case ...
373 */
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();
377
378 } catch (StateValueTypeException sve) {
379 /*
380 * This would happen if we were trying to push/pop attributes not of
381 * type integer. Which, once again, should never happen.
382 */
383 sve.printStackTrace();
384 }
385
386 }
387
388 private static HashMap<String, Integer> fillEventNames() {
389 /*
390 * TODO Replace with straight strings in the switch/case once we move to
391 * Java 7
392 */
393 HashMap<String, Integer> map = new HashMap<String, Integer>();
394
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);
405
406 return map;
407 }
408
409 private int getEventIndex(String eventName) {
410 Integer ret = knownEventNames.get(eventName);
411 return (ret != null) ? ret : -1;
412 }
413 }
This page took 0.04157 seconds and 6 git commands to generate.