tmf.ctf: Rework the event aspects of CTF traces
[deliverable/tracecompass.git] / org.eclipse.tracecompass.lttng2.kernel.core / src / org / eclipse / tracecompass / lttng2 / kernel / core / analysis / cpuusage / LttngKernelCpuUsageAnalysis.java
CommitLineData
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 * Geneviève Bastien - Initial API and implementation
11 *******************************************************************************/
12
42d5b5f2 13package org.eclipse.tracecompass.lttng2.kernel.core.analysis.cpuusage;
e693075d
FR
14
15import java.util.HashMap;
16import java.util.List;
17import java.util.Map;
18import java.util.Map.Entry;
19
20import org.eclipse.core.runtime.IProgressMonitor;
9bc60be7
AM
21import org.eclipse.tracecompass.internal.lttng2.kernel.core.Activator;
22import org.eclipse.tracecompass.internal.lttng2.kernel.core.Attributes;
7411cd67
AM
23import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.IKernelAnalysisEventLayout;
24import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.LttngEventLayout;
42d5b5f2 25import org.eclipse.tracecompass.lttng2.kernel.core.analysis.kernel.LttngKernelAnalysis;
7411cd67 26import org.eclipse.tracecompass.lttng2.kernel.core.trace.LttngKernelTrace;
e894a508
AM
27import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
28import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
29import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
30import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
31import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
32import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
2bdf0193
AM
33import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
34import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
35import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
e693075d
FR
36
37/**
38 * This analysis module computes the CPU usage of a system from a kernel trace.
39 * It requires the LTTng Kernel analysis module to have accurate CPU usage data.
40 *
41 * @author Geneviève Bastien
42 * @since 3.0
43 */
44public class LttngKernelCpuUsageAnalysis extends TmfStateSystemAnalysisModule {
45
46 /** The ID of this analysis */
47 public static final String ID = "org.eclipse.linuxtools.lttng2.kernel.core.cpuusage"; //$NON-NLS-1$
48
49 /** Text used to identify 'total' entries in the returned maps */
50 public static final String TOTAL = "total"; //$NON-NLS-1$
51 /** String used to separate elements in the returned maps */
52 public static final String SPLIT_STRING = "/"; //$NON-NLS-1$
53 /** Idle process thread ID */
54 public static final String TID_ZERO = "0"; //$NON-NLS-1$
55
56 @Override
57 protected ITmfStateProvider createStateProvider() {
7411cd67
AM
58 ITmfTrace trace = getTrace();
59 IKernelAnalysisEventLayout layout;
60
61 if (trace instanceof LttngKernelTrace) {
62 layout = ((LttngKernelTrace) trace).getEventLayout();
63 } else {
64 /* Fall-back to the base LttngEventLayout */
65 layout = LttngEventLayout.getInstance();
66 }
67
68 return new LttngKernelCpuUsageStateProvider(trace, layout);
e693075d
FR
69 }
70
71 @Override
72 protected StateSystemBackendType getBackendType() {
73 return StateSystemBackendType.FULL;
74 }
75
76 @Override
77 protected boolean executeAnalysis(IProgressMonitor monitor) {
ba27dd38
GB
78 ITmfTrace trace = getTrace();
79 if (trace == null) {
80 throw new IllegalStateException();
81 }
e693075d
FR
82 /*
83 * This analysis depends on the LTTng kernel analysis, so we'll start
84 * that build at the same time
85 */
ba27dd38 86 LttngKernelAnalysis module = trace.getAnalysisModuleOfClass(LttngKernelAnalysis.class, LttngKernelAnalysis.ID);
e693075d
FR
87 if (module != null) {
88 module.schedule();
89 }
90 return super.executeAnalysis(monitor);
91 }
92
93 /**
94 * Get a map of time spent on CPU by various threads during a time range.
95 *
96 * @param start
97 * Start time of requested range
98 * @param end
99 * End time of requested range
100 * @return A map of TID -> time spent on CPU in the [start, end] interval
101 */
102 public Map<String, Long> getCpuUsageInRange(long start, long end) {
103 Map<String, Long> map = new HashMap<>();
104 Map<String, Long> totalMap = new HashMap<>();
105
72221aa4 106 ITmfTrace trace = getTrace();
e693075d 107 ITmfStateSystem cpuSs = getStateSystem();
72221aa4 108 if (trace == null || cpuSs == null) {
e693075d
FR
109 return map;
110 }
42d5b5f2 111 ITmfStateSystem kernelSs = TmfStateSystemAnalysisModule.getStateSystem(trace, LttngKernelAnalysis.ID);
e693075d
FR
112 if (kernelSs == null) {
113 return map;
114 }
115
116 /*
117 * Make sure the start/end times are within the state history, so we
118 * don't get TimeRange exceptions.
119 */
120 long startTime = Math.max(start, cpuSs.getStartTime());
dffc234f 121 startTime = Math.max(startTime, kernelSs.getStartTime());
e693075d 122 long endTime = Math.min(end, cpuSs.getCurrentEndTime());
dffc234f 123 endTime = Math.min(endTime, kernelSs.getCurrentEndTime());
e693075d
FR
124 long totalTime = 0;
125 if (endTime < startTime) {
126 return map;
127 }
128
129 try {
130 /* Get the list of quarks for each CPU and CPU's TIDs */
131 int cpusNode = cpuSs.getQuarkAbsolute(Attributes.CPUS);
132 Map<Integer, List<Integer>> tidsPerCpu = new HashMap<>();
133 for (int cpuNode : cpuSs.getSubAttributes(cpusNode, false)) {
134 tidsPerCpu.put(cpuNode, cpuSs.getSubAttributes(cpuNode, false));
135 }
136
137 /* Query full states at start and end times */
138 List<ITmfStateInterval> kernelEndState = kernelSs.queryFullState(endTime);
139 List<ITmfStateInterval> endState = cpuSs.queryFullState(endTime);
140 List<ITmfStateInterval> kernelStartState = kernelSs.queryFullState(startTime);
141 List<ITmfStateInterval> startState = cpuSs.queryFullState(startTime);
142
143 long countAtStart, countAtEnd;
144
145 for (Entry<Integer, List<Integer>> entry : tidsPerCpu.entrySet()) {
146 int cpuNode = entry.getKey();
147 List<Integer> tidNodes = entry.getValue();
148
149 String curCpuName = cpuSs.getAttributeName(cpuNode);
150 long cpuTotal = 0;
151
152 /* Get the quark of the thread running on this CPU */
153 int currentThreadQuark = kernelSs.getQuarkAbsolute(Attributes.CPUS, curCpuName, Attributes.CURRENT_THREAD);
154 /* Get the currently running thread on this CPU */
155 int startThread = kernelStartState.get(currentThreadQuark).getStateValue().unboxInt();
156 int endThread = kernelEndState.get(currentThreadQuark).getStateValue().unboxInt();
157
158 for (int tidNode : tidNodes) {
159 String curTidName = cpuSs.getAttributeName(tidNode);
160 int tid = Integer.parseInt(curTidName);
161
162 countAtEnd = endState.get(tidNode).getStateValue().unboxLong();
163 countAtStart = startState.get(tidNode).getStateValue().unboxLong();
164 if (countAtStart == -1) {
165 countAtStart = 0;
166 }
167 if (countAtEnd == -1) {
168 countAtEnd = 0;
169 }
170
171 /*
172 * Interpolate start and end time of threads running at
173 * those times
174 */
175 if (tid == startThread || startThread == -1) {
176 long runningTime = kernelStartState.get(currentThreadQuark).getEndTime() - kernelStartState.get(currentThreadQuark).getStartTime();
177 long runningEnd = kernelStartState.get(currentThreadQuark).getEndTime();
178
179 countAtStart = interpolateCount(countAtStart, startTime, runningEnd, runningTime);
180 }
181 if (tid == endThread) {
182 long runningTime = kernelEndState.get(currentThreadQuark).getEndTime() - kernelEndState.get(currentThreadQuark).getStartTime();
183 long runningEnd = kernelEndState.get(currentThreadQuark).getEndTime();
184
185 countAtEnd = interpolateCount(countAtEnd, endTime, runningEnd, runningTime);
186 }
187 /*
188 * If startThread is -1, we made the hypothesis that the
189 * process running at start was the current one. If the
190 * count is negative, we were wrong in this hypothesis. Also
191 * if the time at end is 0, it either means the process
192 * hasn't been on the CPU or that we still don't know who is
193 * running. In both cases, that invalidates the hypothesis.
194 */
195 if ((startThread == -1) && ((countAtEnd - countAtStart < 0) || (countAtEnd == 0))) {
196 countAtStart = 0;
197 }
198
199 long currentCount = countAtEnd - countAtStart;
200 if (currentCount < 0) {
201 Activator.getDefault().logWarning(String.format("Negative count: start %d, end %d", countAtStart, countAtEnd)); //$NON-NLS-1$
202 currentCount = 0;
203 } else if (currentCount > endTime - startTime) {
204 Activator.getDefault().logWarning(String.format("CPU Usage: Spent more time on CPU than allowed: %s spent %d when max should be %d", curTidName, currentCount, endTime - startTime)); //$NON-NLS-1$
205 currentCount = 0;
206 }
207 cpuTotal += currentCount;
208 map.put(curCpuName + SPLIT_STRING + curTidName, currentCount);
209 addToMap(totalMap, curTidName, currentCount);
210 totalTime += (currentCount);
211 }
212 map.put(curCpuName, cpuTotal);
213 }
214
215 /* Add the totals to the map */
216 for (Entry<String, Long> entry : totalMap.entrySet()) {
217 map.put(TOTAL + SPLIT_STRING + entry.getKey(), entry.getValue());
218 }
219 map.put(TOTAL, totalTime);
220
221 } catch (TimeRangeException | AttributeNotFoundException e) {
222 /*
223 * Assume there is no events or the attribute does not exist yet,
224 * nothing will be put in the map.
225 */
226 } catch (StateValueTypeException | StateSystemDisposedException e) {
227 /*
228 * These other exception types would show a logic problem, so they
229 * should not happen.
230 */
231 Activator.getDefault().logError("Error getting CPU usage in a time range", e); //$NON-NLS-1$
232 }
233
234 return map;
235 }
236
237 private static long interpolateCount(long count, long ts, long runningEnd, long runningTime) {
238 long newCount = count;
239
240 /* sanity check */
241 if (runningTime > 0) {
242
243 long runningStart = runningEnd - runningTime;
244
245 if (ts < runningStart) {
246 /*
247 * This interval was not started, this can happen if the current
248 * running thread is unknown and we execute this method. It just
249 * means that this process was not the one running
250 */
251 return newCount;
252 }
253 newCount += (ts - runningStart);
254 }
255 return newCount;
256 }
257
258 /*
259 * Add the value to the previous value in the map. If the key was not set,
260 * assume 0
261 */
262 private static void addToMap(Map<String, Long> map, String key, Long value) {
263 Long addTo = map.get(key);
264 if (addTo == null) {
265 map.put(key, value);
266 } else {
267 map.put(key, addTo + value);
268 }
269 }
270
271}
This page took 0.048388 seconds and 5 git commands to generate.