Commit | Line | Data |
---|---|---|
e693075d FR |
1 | /******************************************************************************* |
2 | * Copyright (c) 2014 École Polytechnique de Montréal | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials are | |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
9 | * Contributors: | |
10 | * François Rajotte - Initial API and implementation | |
11 | * Geneviève Bastien - Revision of the initial implementation | |
12 | *******************************************************************************/ | |
13 | ||
14 | package org.eclipse.linuxtools.lttng2.kernel.core.cpuusage; | |
15 | ||
16 | import java.util.HashMap; | |
17 | import java.util.Map; | |
18 | ||
19 | import org.eclipse.linuxtools.internal.lttng2.kernel.core.Activator; | |
20 | import org.eclipse.linuxtools.internal.lttng2.kernel.core.Attributes; | |
21 | import org.eclipse.linuxtools.internal.lttng2.kernel.core.LttngStrings; | |
e894a508 AM |
22 | import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; |
23 | import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; | |
24 | import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; | |
2bdf0193 AM |
25 | import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; |
26 | import org.eclipse.tracecompass.tmf.core.event.ITmfEventField; | |
27 | import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider; | |
28 | import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; | |
e693075d FR |
29 | |
30 | /** | |
31 | * Creates a state system with the total time spent on CPU for each thread and | |
32 | * for each CPU from a kernel trace. | |
33 | * | |
34 | * This state system in itself keeps the total time on CPU since last time the | |
35 | * process was scheduled out. The state system queries will only be accurate | |
36 | * when the process is not in a running state. To have exact CPU usage when | |
37 | * running, this state system needs to be used along the LTTng Kernel analysis. | |
38 | * | |
39 | * It requires only the 'sched_switch' events enabled on the trace. | |
40 | * | |
41 | * @author François Rajotte | |
42 | * @since 3.0 | |
43 | */ | |
44 | public class LttngKernelCpuStateProvider extends AbstractTmfStateProvider { | |
45 | ||
46 | private static final int VERSION = 1; | |
47 | ||
48 | /* For each CPU, maps the last time a thread was scheduled in */ | |
49 | private final Map<String, Long> fLastStartTimes = new HashMap<>(); | |
50 | private final long fTraceStart; | |
51 | ||
52 | /** | |
53 | * Constructor | |
54 | * | |
55 | * @param trace | |
56 | * The trace from which to get the CPU usage | |
57 | */ | |
58 | public LttngKernelCpuStateProvider(ITmfTrace trace) { | |
59 | super(trace, ITmfEvent.class, "LTTng Kernel CPU usage"); //$NON-NLS-1$ | |
60 | fTraceStart = trace.getStartTime().getValue(); | |
61 | } | |
62 | ||
63 | // ------------------------------------------------------------------------ | |
64 | // ITmfStateProvider | |
65 | // ------------------------------------------------------------------------ | |
66 | ||
67 | @Override | |
68 | public int getVersion() { | |
69 | return VERSION; | |
70 | } | |
71 | ||
72 | @Override | |
73 | public LttngKernelCpuStateProvider getNewInstance() { | |
74 | return new LttngKernelCpuStateProvider(this.getTrace()); | |
75 | } | |
76 | ||
77 | @Override | |
78 | protected void eventHandle(ITmfEvent event) { | |
79 | final String eventName = event.getType().getName(); | |
80 | ||
81 | if (eventName.equals(LttngStrings.SCHED_SWITCH)) { | |
82 | /* | |
83 | * Fields: string prev_comm, int32 prev_tid, int32 prev_prio, int64 | |
84 | * prev_state, string next_comm, int32 next_tid, int32 next_prio | |
85 | */ | |
86 | ||
87 | ITmfEventField content = event.getContent(); | |
88 | long ts = event.getTimestamp().getValue(); | |
89 | String cpu = event.getSource(); | |
90 | ||
91 | Long prevTid = (Long) content.getField(LttngStrings.PREV_TID).getValue(); | |
92 | ||
93 | try { | |
94 | Integer currentCPUNode = ss.getQuarkRelativeAndAdd(getNodeCPUs(), cpu); | |
95 | ||
96 | /* | |
97 | * This quark contains the value of the cumulative time spent on | |
98 | * the source CPU by the currently running thread | |
99 | */ | |
100 | Integer cumulativeTimeQuark = ss.getQuarkRelativeAndAdd(currentCPUNode, prevTid.toString()); | |
101 | Long startTime = fLastStartTimes.get(cpu); | |
102 | /* | |
103 | * If start time is null, we haven't seen the start of the | |
104 | * process, so we assume beginning of the trace | |
105 | */ | |
106 | if (startTime == null) { | |
107 | startTime = fTraceStart; | |
108 | } | |
109 | ||
110 | /* | |
111 | * We add the time from startTime until now to the cumulative | |
112 | * time of the thread | |
113 | */ | |
114 | if (startTime != null) { | |
115 | ITmfStateValue value = ss.queryOngoingState(cumulativeTimeQuark); | |
116 | ||
117 | /* | |
118 | * Modify cumulative time for this CPU/TID combo: The total | |
119 | * time changes when the process is scheduled out. Nothing | |
120 | * happens when the process is scheduled in. | |
121 | */ | |
122 | long prevCumulativeTime = value.unboxLong(); | |
123 | long newCumulativeTime = prevCumulativeTime + (ts - startTime); | |
124 | ||
125 | value = TmfStateValue.newValueLong(newCumulativeTime); | |
126 | ss.modifyAttribute(ts, value, cumulativeTimeQuark); | |
127 | fLastStartTimes.put(cpu, ts); | |
128 | } | |
129 | } catch (AttributeNotFoundException e) { | |
130 | Activator.getDefault().logError("Attribute not found in LttngKernelCpuStateProvider", e); //$NON-NLS-1$ | |
131 | } | |
132 | ||
133 | } | |
134 | } | |
135 | ||
136 | /* Shortcut for the "current CPU" attribute node */ | |
137 | private int getNodeCPUs() { | |
138 | return ss.getQuarkAbsoluteAndAdd(Attributes.CPUS); | |
139 | } | |
140 | ||
141 | } |