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.ArrayList;
16
import java.util.HashMap;
17
import java.util.List;
18
import java.util.concurrent.BlockingQueue;
20
import org.eclipse.linuxtools.internal.lttng2.kernel.core.Attributes;
21
import org.eclipse.linuxtools.internal.lttng2.kernel.core.LttngStrings;
22
import org.eclipse.linuxtools.internal.lttng2.kernel.core.StateValues;
23
import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfEvent;
24
import org.eclipse.linuxtools.tmf.core.event.ITmfEventField;
25
import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
26
import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
27
import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
28
import org.eclipse.linuxtools.tmf.core.statesystem.IStateSystemBuilder;
29
import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
30
import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
33
* This is the reference "state provider" for LTTng 2.0 kernel traces.
38
class CtfKernelHandler implements Runnable {
40
private final BlockingQueue<CtfTmfEvent> inQueue;
41
private IStateSystemBuilder ss;
43
private CtfTmfEvent currentEvent;
46
* We can keep handles to some Attribute Nodes so these don't need to be
47
* re-found (re-hashed Strings etc.) every new event
49
List<Integer> currentCPUNodes;
50
List<Integer> currentThreadNodes;
52
/* Event names HashMap. TODO: This can be discarded once we move to Java 7 */
53
private final HashMap<String, Integer> knownEventNames;
55
/* Common locations in the attribute tree */
56
private int cpusNode = -1;
57
private int threadsNode = -1;
58
private int irqsNode = -1;
59
private int softIrqsNode = -1;
61
CtfKernelHandler(BlockingQueue<CtfTmfEvent> eventsQueue) {
62
assert (eventsQueue != null);
63
this.inQueue = eventsQueue;
64
currentCPUNodes = new ArrayList<Integer>();
65
currentThreadNodes = new ArrayList<Integer>();
67
knownEventNames = fillEventNames();
70
void assignStateSystem(IStateSystemBuilder targetSS) {
77
System.err.println("Cannot run event manager without assigning a target state system first!"); //$NON-NLS-1$
81
setupCommonLocations();
84
event = inQueue.take();
85
while (event.getTimestampValue() != -1) {
87
event = inQueue.take();
89
/* We've received the last event, clean up */
92
} catch (InterruptedException e) {
93
/* We've been interrupted abnormally */
94
System.out.println("Event handler interrupted!"); //$NON-NLS-1$
99
private void closeStateSystem() {
100
/* Close the History system, if there is one */
101
if (currentEvent == null) {
105
ss.closeHistory(currentEvent.getTimestamp().getValue());
106
} catch (TimeRangeException e) {
108
* Since we're using currentEvent.getTimestamp, this shouldn't
115
private void processEvent(CtfTmfEvent event) {
116
currentEvent = event;
117
ITmfEventField content = event.getContent();
118
String eventName = event.getEventName();
120
long ts = event.getTimestamp().getValue();
122
ITmfStateValue value;
123
Integer eventCpu = event.getCPU();
124
Integer currentCPUNode, currentThreadNode, tidNode;
126
/* Adjust the current nodes Vectors if we see a new CPU in an event */
127
if (eventCpu >= currentCPUNodes.size()) {
128
/* We need to add this node to the vector */
129
for (Integer i = currentCPUNodes.size(); i < eventCpu + 1; i++) {
130
quark = ss.getQuarkRelativeAndAdd(cpusNode, i.toString());
131
currentCPUNodes.add(quark);
133
quark = ss.getQuarkRelativeAndAdd(threadsNode, Attributes.UNKNOWN);
134
currentThreadNodes.add(quark);
138
currentCPUNode = currentCPUNodes.get(eventCpu);
139
currentThreadNode = currentThreadNodes.get(eventCpu);
140
assert (currentCPUNode != null);
141
assert (currentThreadNode != null);
145
* Feed event to the history system if it's known to cause a state
148
switch (getEventIndex(eventName)) {
150
case 1: // "exit_syscall":
151
/* Fields: int64 ret */
153
/* Clear the current system call on the process */
154
quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
155
value = TmfStateValue.nullValue();
156
ss.modifyAttribute(ts, value, quark);
158
/* Put the process' status back to user mode */
159
quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
160
value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_RUN_USERMODE);
161
ss.modifyAttribute(ts, value, quark);
163
/* Put the CPU's status back to user mode */
164
quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS);
165
value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_RUN_USERMODE);
166
ss.modifyAttribute(ts, value, quark);
170
case 2: // "irq_handler_entry":
171
/* Fields: int32 irq, string name */
173
Integer irqId = ((Long) content.getField(LttngStrings.IRQ).getValue()).intValue();
175
/* Mark this IRQ as active in the resource tree.
176
* The state value = the CPU on which this IRQ is sitting */
177
quark = ss.getQuarkRelativeAndAdd(irqsNode, irqId.toString());
178
value = TmfStateValue.newValueInt(event.getCPU());
179
ss.modifyAttribute(ts, value, quark);
181
/* Change the status of the running process to interrupted */
182
quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
183
value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_INTERRUPTED);
184
ss.modifyAttribute(ts, value, quark);
186
/* Change the status of the CPU to interrupted */
187
quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS);
188
value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_IRQ);
189
ss.modifyAttribute(ts, value, quark);
193
case 3: // "irq_handler_exit":
194
/* Fields: int32 irq, int32 ret */
196
Integer irqId = ((Long) content.getField(LttngStrings.IRQ).getValue()).intValue();
198
/* Put this IRQ back to inactive in the resource tree */
199
quark = ss.getQuarkRelativeAndAdd(irqsNode, irqId.toString());
200
value = TmfStateValue.nullValue();
201
ss.modifyAttribute(ts, value, quark);
203
/* Set the previous process back to running */
204
setProcessToRunning(ts, currentThreadNode);
206
/* Set the CPU status back to running or "idle" */
207
cpuExitInterrupt(ts, currentCPUNode, currentThreadNode);
211
case 4: // "softirq_entry":
212
/* Fields: int32 vec */
214
Integer softIrqId = ((Long) content.getField(LttngStrings.VEC).getValue()).intValue();
216
/* Mark this SoftIRQ as active in the resource tree.
217
* The state value = the CPU on which this SoftIRQ is processed */
218
quark = ss.getQuarkRelativeAndAdd(softIrqsNode, softIrqId.toString());
219
value = TmfStateValue.newValueInt(event.getCPU());
220
ss.modifyAttribute(ts, value, quark);
222
/* Change the status of the running process to interrupted */
223
quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
224
value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_INTERRUPTED);
225
ss.modifyAttribute(ts, value, quark);
227
/* Change the status of the CPU to interrupted */
228
quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS);
229
value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_SOFTIRQ);
230
ss.modifyAttribute(ts, value, quark);
234
case 5: // "softirq_exit":
235
/* Fields: int32 vec */
237
Integer softIrqId = ((Long) content.getField(LttngStrings.VEC).getValue()).intValue();
239
/* Put this SoftIRQ back to inactive (= -1) in the resource tree */
240
quark = ss.getQuarkRelativeAndAdd(softIrqsNode, softIrqId.toString());
241
value = TmfStateValue.nullValue();
242
ss.modifyAttribute(ts, value, quark);
244
/* Set the previous process back to running */
245
setProcessToRunning(ts, currentThreadNode);
247
/* Set the CPU status back to "busy" or "idle" */
248
cpuExitInterrupt(ts, currentCPUNode, currentThreadNode);
252
case 6: // "softirq_raise":
253
/* Fields: int32 vec */
255
Integer softIrqId = ((Long) content.getField(LttngStrings.VEC).getValue()).intValue();
257
/* Mark this SoftIRQ as *raised* in the resource tree.
258
* State value = -2 */
259
quark = ss.getQuarkRelativeAndAdd(softIrqsNode, softIrqId.toString());
260
value = TmfStateValue.newValueInt(StateValues.SOFT_IRQ_RAISED);
261
ss.modifyAttribute(ts, value, quark);
265
case 7: // "sched_switch":
267
* Fields: string prev_comm, int32 prev_tid, int32 prev_prio, int64 prev_state,
268
* string next_comm, int32 next_tid, int32 next_prio
271
Integer prevTid = ((Long) content.getField(LttngStrings.PREV_TID).getValue()).intValue();
272
//Long prevState = (Long) content.getField(LttngStrings.PREV_STATE).getValue();
274
String nextProcessName = (String) content.getField(LttngStrings.NEXT_COMM).getValue();
275
Integer nextTid = ((Long) content.getField(LttngStrings.NEXT_TID).getValue()).intValue();
277
/* Update the currentThreadNodes pointer */
278
Integer newCurrentThreadNode = ss.getQuarkRelativeAndAdd(threadsNode, nextTid.toString());
279
currentThreadNodes.set(eventCpu, newCurrentThreadNode);
282
* Set the status of the process that got scheduled out, but
283
* only in the case where that process is currently active.
285
Integer formerThreadNode = ss.getQuarkRelativeAndAdd(threadsNode, prevTid.toString());
286
quark = ss.getQuarkRelativeAndAdd(formerThreadNode, Attributes.EXEC_NAME);
287
value = ss.queryOngoingState(quark);
288
if (!value.isNull()) {
289
quark = ss.getQuarkRelativeAndAdd(formerThreadNode, Attributes.STATUS);
290
value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_WAIT);
291
ss.modifyAttribute(ts, value, quark);
294
/* Set the status of the new scheduled process */
295
setProcessToRunning(ts, newCurrentThreadNode);
297
/* Set the exec name of the new process */
298
quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.EXEC_NAME);
299
value = TmfStateValue.newValueString(nextProcessName);
300
ss.modifyAttribute(ts, value, quark);
303
* Check if we need to set the syscall state and the PPID of
304
* the new process (in case we haven't seen this process before)
306
quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.SYSTEM_CALL);
307
if (quark == ss.getNbAttributes()) { /* Did we just add this attribute? */
308
value = TmfStateValue.nullValue();
309
ss.modifyAttribute(ts, value, quark);
311
quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.PPID);
312
if (quark == ss.getNbAttributes()) {
313
value = TmfStateValue.nullValue();
314
ss.modifyAttribute(ts, value, quark);
317
/* Set the current scheduled process on the relevant CPU */
318
quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.CURRENT_THREAD);
319
value = TmfStateValue.newValueInt(nextTid);
320
ss.modifyAttribute(ts, value, quark);
322
/* Set the status of the CPU itself */
324
/* Check if the entering process is in kernel or user mode */
325
quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.SYSTEM_CALL);
326
if (ss.queryOngoingState(quark).isNull()) {
327
value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_RUN_USERMODE);
329
value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_RUN_SYSCALL);
332
value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_IDLE);
334
quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS);
335
ss.modifyAttribute(ts, value, quark);
339
case 8: // "sched_process_fork":
340
/* Fields: string parent_comm, int32 parent_tid,
341
* string child_comm, int32 child_tid */
343
// String parentProcessName = (String)
344
// event.getFieldValue("parent_comm");
345
String childProcessName;
346
childProcessName = (String) content.getField(LttngStrings.CHILD_COMM).getValue();
347
// assert ( parentProcessName.equals(childProcessName) );
349
Integer parentTid = ((Long) content.getField(LttngStrings.PARENT_TID).getValue()).intValue();
350
Integer childTid = ((Long) content.getField(LttngStrings.CHILD_TID).getValue()).intValue();
352
tidNode = ss.getQuarkRelativeAndAdd(threadsNode, childTid.toString());
354
/* Assign the PPID to the new process */
355
quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.PPID);
356
value = TmfStateValue.newValueInt(parentTid);
357
ss.modifyAttribute(ts, value, quark);
359
/* Set the new process' exec_name */
360
quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.EXEC_NAME);
361
value = TmfStateValue.newValueString(childProcessName);
362
ss.modifyAttribute(ts, value, quark);
364
/* Set the new process' status */
365
quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.STATUS);
366
value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_WAIT);
367
ss.modifyAttribute(ts, value, quark);
369
/* Set the process' syscall state */
370
quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.SYSTEM_CALL);
371
value = TmfStateValue.nullValue();
372
ss.modifyAttribute(ts, value, quark);
376
case 9: // "sched_process_exit":
377
/* Fields: string comm, int32 tid, int32 prio */
379
String processName = (String) content.getField(LttngStrings.COMM).getValue();
380
Integer tid = ((Long) content.getField(LttngStrings.TID).getValue()).intValue();
382
/* Update the process' name, if we don't have it */
383
quark = ss.getQuarkRelativeAndAdd(threadsNode, tid.toString(), Attributes.EXEC_NAME);
384
value = TmfStateValue.newValueString(processName);
385
ss.updateOngoingState(value, quark);
388
* Remove the process and all its sub-attributes from the
391
quark = ss.getQuarkRelativeAndAdd(threadsNode, tid.toString());
392
ss.removeAttribute(ts, quark);
396
case 10: // "sched_process_free":
397
/* Fields: string comm, int32 tid, int32 prio */
400
// FIXME In CTF it's as "syscall_exec". Will have to be adapted.
401
// case LTT_EVENT_EXEC:
402
// filename = new String((byte[]) event.getField(0));
404
// /* Change the Exec_name of the process */
405
// quark = ss.getQuarkRelativePath(true, currentThreadNode,
407
// ss.modifyAttribute(ts, filename, quark);
411
/* Other event types not covered by the main switch */
413
if (eventName.startsWith(LttngStrings.SYSCALL_PREFIX)
414
|| eventName.startsWith(LttngStrings.COMPAT_SYSCALL_PREFIX)) {
416
* This is a replacement for the old sys_enter event. Now
417
* syscall names are listed into the event type
420
/* Assign the new system call to the process */
421
quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
422
value = TmfStateValue.newValueString(eventName);
423
ss.modifyAttribute(ts, value, quark);
425
/* Put the process in system call mode */
426
quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
427
value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_RUN_SYSCALL);
428
ss.modifyAttribute(ts, value, quark);
430
/* Put the CPU in system call (kernel) mode */
431
quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS);
432
value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_RUN_SYSCALL);
433
ss.modifyAttribute(ts, value, quark);
437
} // End of big switch
443
/* Number of events of each type, globally */
444
// quark = ss.getQuarkAbsoluteAndAdd(Attributes.STATISTICS,
445
// Attributes.EVENT_TYPES, eventName);
446
// ss.incrementAttribute(ts, quark);
448
/* Number of events per CPU */
449
// quark = ss.getQuarkRelativeAndAdd(currentCPUNode,
450
// Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
451
// ss.incrementAttribute(ts, quark);
453
/* Number of events per process */
454
// quark = ss.getQuarkRelativeAndAdd(currentThreadNode,
455
// Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
456
// ss.incrementAttribute(ts, quark);
458
} catch (AttributeNotFoundException ae) {
460
* This would indicate a problem with the logic of the manager here,
461
* so it shouldn't happen.
463
ae.printStackTrace();
465
} catch (TimeRangeException tre) {
467
* This would happen if the events in the trace aren't ordered
468
* chronologically, which should never be the case ...
470
System.err.println("TimeRangeExcpetion caught in the state system's event manager."); //$NON-NLS-1$
471
System.err.println("Are the events in the trace correctly ordered?"); //$NON-NLS-1$
472
tre.printStackTrace();
474
} catch (StateValueTypeException sve) {
476
* This would happen if we were trying to push/pop attributes not of
477
* type integer. Which, once again, should never happen.
479
sve.printStackTrace();
483
private void setupCommonLocations() {
484
cpusNode = ss.getQuarkAbsoluteAndAdd(Attributes.CPUS);
485
threadsNode = ss.getQuarkAbsoluteAndAdd(Attributes.THREADS);
486
irqsNode = ss.getQuarkAbsoluteAndAdd(Attributes.RESOURCES, Attributes.IRQS);
487
softIrqsNode = ss.getQuarkAbsoluteAndAdd(Attributes.RESOURCES, Attributes.SOFT_IRQS);
490
private static HashMap<String, Integer> fillEventNames() {
492
* TODO Replace with straight strings in the switch/case once we move to
495
HashMap<String, Integer> map = new HashMap<String, Integer>();
497
map.put(LttngStrings.EXIT_SYSCALL, 1);
498
map.put(LttngStrings.IRQ_HANDLER_ENTRY, 2);
499
map.put(LttngStrings.IRQ_HANDLER_EXIT, 3);
500
map.put(LttngStrings.SOFTIRQ_ENTRY, 4);
501
map.put(LttngStrings.SOFTIRQ_EXIT, 5);
502
map.put(LttngStrings.SOFTIRQ_RAISE, 6);
503
map.put(LttngStrings.SCHED_SWITCH, 7);
504
map.put(LttngStrings.SCHED_PROCESS_FORK, 8);
505
map.put(LttngStrings.SCHED_PROCESS_EXIT, 9);
506
map.put(LttngStrings.SCHED_PROCESS_FREE, 10);
511
private int getEventIndex(String eventName) {
512
Integer ret = knownEventNames.get(eventName);
513
return (ret != null) ? ret : -1;
517
* When we want to set a process back to a "running" state, first check
518
* its current System_call attribute. If there is a system call active, we
519
* put the process back in the syscall state. If not, we put it back in
522
private void setProcessToRunning(long ts, int currentThreadNode)
523
throws AttributeNotFoundException, TimeRangeException,
524
StateValueTypeException {
526
ITmfStateValue value;
528
quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
529
if (ss.queryOngoingState(quark).isNull()) {
530
/* We were in user mode before the interruption */
531
value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_RUN_USERMODE);
533
/* We were previously in kernel mode */
534
value = TmfStateValue.newValueInt(StateValues.PROCESS_STATUS_RUN_SYSCALL);
536
quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
537
ss.modifyAttribute(ts, value, quark);
541
* Similar logic as above, but to set the CPU's status when it's coming out
542
* of an interruption.
543
* @throws AttributeNotFoundException
544
* @throws StateValueTypeException
545
* @throws TimeRangeException
547
private void cpuExitInterrupt(long ts, int currentCpuNode, int currentThreadNode)
548
throws StateValueTypeException, AttributeNotFoundException,
551
ITmfStateValue value;
553
quark = ss.getQuarkRelativeAndAdd(currentCpuNode, Attributes.CURRENT_THREAD);
554
if (ss.queryOngoingState(quark).unboxInt() > 0) {
555
/* There was a process on the CPU */
556
quark = ss.getQuarkRelative(currentThreadNode, Attributes.SYSTEM_CALL);
557
if (ss.queryOngoingState(quark).isNull()) {
558
/* That process was in user mode */
559
value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_RUN_USERMODE);
561
/* That process was in a system call */
562
value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_RUN_SYSCALL);
565
/* There was no real process scheduled, CPU was idle */
566
value = TmfStateValue.newValueInt(StateValues.CPU_STATUS_IDLE);
568
quark = ss.getQuarkRelativeAndAdd(currentCpuNode, Attributes.STATUS);
569
ss.modifyAttribute(ts, value, quark);