bfe5a15094accff9cff5890a0b700513a21307b6
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.os.linux.ui / src / org / eclipse / tracecompass / internal / analysis / os / linux / ui / views / cpuusage / CpuUsageComposite.java
1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 É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
13 package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.cpuusage;
14
15 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Map.Entry;
23 import java.util.Set;
24 import java.util.TreeSet;
25
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.eclipse.jface.viewers.Viewer;
28 import org.eclipse.jface.viewers.ViewerComparator;
29 import org.eclipse.osgi.util.NLS;
30 import org.eclipse.swt.widgets.Composite;
31 import org.eclipse.tracecompass.analysis.os.linux.core.cpuusage.KernelCpuUsageAnalysis;
32 import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
33 import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
34 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
35 import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
36 import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
37 import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
38 import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
39 import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
40 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
41 import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
42 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
43 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
44 import org.eclipse.tracecompass.tmf.ui.viewers.tree.AbstractTmfTreeViewer;
45 import org.eclipse.tracecompass.tmf.ui.viewers.tree.ITmfTreeColumnDataProvider;
46 import org.eclipse.tracecompass.tmf.ui.viewers.tree.ITmfTreeViewerEntry;
47 import org.eclipse.tracecompass.tmf.ui.viewers.tree.TmfTreeColumnData;
48 import org.eclipse.tracecompass.tmf.ui.viewers.tree.TmfTreeColumnData.ITmfColumnPercentageProvider;
49 import org.eclipse.tracecompass.tmf.ui.viewers.tree.TmfTreeViewerEntry;
50
51 /**
52 * Tree viewer to display CPU usage information in a specified time range. It
53 * shows the process's TID, its name, the time spent on the CPU during that
54 * range, in % and absolute value.
55 *
56 * @author Geneviève Bastien
57 */
58 public class CpuUsageComposite extends AbstractTmfTreeViewer {
59
60 // Timeout between to wait for in the updateElements method
61 private static final long BUILD_UPDATE_TIMEOUT = 500;
62
63 private KernelCpuUsageAnalysis fModule = null;
64 private String fSelectedThread = null;
65
66 private static final String[] COLUMN_NAMES = new String[] {
67 Messages.CpuUsageComposite_ColumnTID,
68 Messages.CpuUsageComposite_ColumnProcess,
69 Messages.CpuUsageComposite_ColumnPercent,
70 Messages.CpuUsageComposite_ColumnTime
71 };
72
73 /* A map that saves the mapping of a thread ID to its executable name */
74 private final Map<String, String> fProcessNameMap = new HashMap<>();
75
76 private final @NonNull Set<@NonNull Integer> fCpus = new TreeSet<>();
77
78 /** Provides label for the CPU usage tree viewer cells */
79 protected static class CpuLabelProvider extends TreeLabelProvider {
80
81 @Override
82 public String getColumnText(Object element, int columnIndex) {
83 CpuUsageEntry obj = (CpuUsageEntry) element;
84 if (columnIndex == 0) {
85 return obj.getTid();
86 } else if (columnIndex == 1) {
87 return obj.getProcessName();
88 } else if (columnIndex == 2) {
89 return String.format(Messages.CpuUsageComposite_TextPercent, obj.getPercent());
90 } else if (columnIndex == 3) {
91 return NLS.bind(Messages.CpuUsageComposite_TextTime, obj.getTime());
92 }
93
94 return element.toString();
95 }
96
97 }
98
99 /**
100 * Constructor
101 *
102 * @param parent
103 * The parent composite that holds this viewer
104 */
105 public CpuUsageComposite(Composite parent) {
106 super(parent, false);
107 setLabelProvider(new CpuLabelProvider());
108 }
109
110 @Override
111 protected ITmfTreeColumnDataProvider getColumnDataProvider() {
112 return new ITmfTreeColumnDataProvider() {
113
114 @Override
115 public List<TmfTreeColumnData> getColumnData() {
116 /* All columns are sortable */
117 List<TmfTreeColumnData> columns = new ArrayList<>();
118 TmfTreeColumnData column = new TmfTreeColumnData(COLUMN_NAMES[0]);
119 column.setComparator(new ViewerComparator() {
120 @Override
121 public int compare(Viewer viewer, Object e1, Object e2) {
122 CpuUsageEntry n1 = (CpuUsageEntry) e1;
123 CpuUsageEntry n2 = (CpuUsageEntry) e2;
124
125 return n1.getTid().compareTo(n2.getTid());
126
127 }
128 });
129 columns.add(column);
130 column = new TmfTreeColumnData(COLUMN_NAMES[1]);
131 column.setComparator(new ViewerComparator() {
132 @Override
133 public int compare(Viewer viewer, Object e1, Object e2) {
134 CpuUsageEntry n1 = (CpuUsageEntry) e1;
135 CpuUsageEntry n2 = (CpuUsageEntry) e2;
136
137 return n1.getProcessName().compareTo(n2.getProcessName());
138
139 }
140 });
141 columns.add(column);
142 column = new TmfTreeColumnData(COLUMN_NAMES[2]);
143 column.setComparator(new ViewerComparator() {
144 @Override
145 public int compare(Viewer viewer, Object e1, Object e2) {
146 CpuUsageEntry n1 = (CpuUsageEntry) e1;
147 CpuUsageEntry n2 = (CpuUsageEntry) e2;
148
149 return n1.getPercent().compareTo(n2.getPercent());
150
151 }
152 });
153 column.setPercentageProvider(new ITmfColumnPercentageProvider() {
154
155 @Override
156 public double getPercentage(Object data) {
157 CpuUsageEntry parent = (CpuUsageEntry) data;
158 return parent.getPercent() / 100;
159 }
160 });
161 columns.add(column);
162 column = new TmfTreeColumnData(COLUMN_NAMES[3]);
163 column.setComparator(new ViewerComparator() {
164 @Override
165 public int compare(Viewer viewer, Object e1, Object e2) {
166 CpuUsageEntry n1 = (CpuUsageEntry) e1;
167 CpuUsageEntry n2 = (CpuUsageEntry) e2;
168
169 return n1.getTime().compareTo(n2.getTime());
170
171 }
172 });
173 columns.add(column);
174
175 return columns;
176 }
177
178 };
179 }
180
181 // ------------------------------------------------------------------------
182 // Operations
183 // ------------------------------------------------------------------------
184
185 @Override
186 protected void contentChanged(ITmfTreeViewerEntry rootEntry) {
187 String selectedThread = fSelectedThread;
188 if (selectedThread != null) {
189 /* Find the selected thread among the inputs */
190 for (ITmfTreeViewerEntry entry : rootEntry.getChildren()) {
191 if (entry instanceof CpuUsageEntry) {
192 if (selectedThread.equals(((CpuUsageEntry) entry).getTid())) {
193 List<ITmfTreeViewerEntry> list = Collections.singletonList(entry);
194 super.setSelection(list);
195 return;
196 }
197 }
198 }
199 }
200 }
201
202 @Override
203 public void initializeDataSource() {
204 /* Should not be called while trace is still null */
205 ITmfTrace trace = checkNotNull(getTrace());
206
207 fModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, KernelCpuUsageAnalysis.class, KernelCpuUsageAnalysis.ID);
208 if (fModule == null) {
209 return;
210 }
211 fModule.schedule();
212 fModule.waitForInitialization();
213 fProcessNameMap.clear();
214 }
215
216 @Override
217 protected ITmfTreeViewerEntry updateElements(long start, long end, boolean isSelection) {
218 if (isSelection || (start == end)) {
219 return null;
220 }
221 if (getTrace() == null || fModule == null) {
222 return null;
223 }
224 fModule.waitForInitialization();
225 ITmfStateSystem ss = fModule.getStateSystem();
226 if (ss == null) {
227 return null;
228 }
229
230 boolean complete = false;
231 long currentEnd = Math.max(start, ss.getStartTime());
232
233 while (!complete && currentEnd < end) {
234 complete = ss.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
235 currentEnd = ss.getCurrentEndTime();
236 }
237
238 /* Initialize the data */
239 Map<String, Long> cpuUsageMap = fModule.getCpuUsageInRange(fCpus, Math.max(start, getStartTime()), Math.min(end, getEndTime()));
240
241 TmfTreeViewerEntry root = new TmfTreeViewerEntry(""); //$NON-NLS-1$
242 List<ITmfTreeViewerEntry> entryList = root.getChildren();
243
244 for (Entry<String, Long> entry : cpuUsageMap.entrySet()) {
245 /*
246 * Process only entries representing the total of all CPUs and that
247 * have time on CPU
248 */
249 if (entry.getValue() == 0) {
250 continue;
251 }
252 if (!entry.getKey().startsWith(KernelCpuUsageAnalysis.TOTAL)) {
253 continue;
254 }
255 String[] strings = entry.getKey().split(KernelCpuUsageAnalysis.SPLIT_STRING, 2);
256
257 if ((strings.length > 1) && !(strings[1].equals(KernelCpuUsageAnalysis.TID_ZERO))) {
258 CpuUsageEntry obj = new CpuUsageEntry(strings[1], getProcessName(strings[1]), (double) entry.getValue() / (double) (end - start) * 100, entry.getValue());
259 entryList.add(obj);
260 }
261 }
262
263 return root;
264 }
265
266 /*
267 * Get the process name from its TID by using the LTTng kernel analysis
268 * module
269 */
270 private String getProcessName(String tid) {
271 String execName = fProcessNameMap.get(tid);
272 if (execName != null) {
273 return execName;
274 }
275 ITmfTrace trace = getTrace();
276 if (trace == null) {
277 return tid;
278 }
279 ITmfStateSystem kernelSs = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
280 if (kernelSs == null) {
281 return tid;
282 }
283
284 try {
285 int cpusNode = kernelSs.getQuarkAbsolute(Attributes.THREADS);
286
287 /* Get the quarks for each cpu */
288 List<Integer> cpuNodes = kernelSs.getSubAttributes(cpusNode, false);
289
290 for (Integer tidQuark : cpuNodes) {
291 if (kernelSs.getAttributeName(tidQuark).equals(tid)) {
292 int execNameQuark;
293 List<ITmfStateInterval> execNameIntervals;
294 try {
295 execNameQuark = kernelSs.getQuarkRelative(tidQuark, Attributes.EXEC_NAME);
296 execNameIntervals = StateSystemUtils.queryHistoryRange(kernelSs, execNameQuark, getStartTime(), getEndTime());
297 } catch (TimeRangeException | AttributeNotFoundException e) {
298 /*
299 * No information on this thread (yet?), skip it for now
300 */
301 continue;
302 } catch (StateSystemDisposedException e) {
303 /* State system is closing down, no point continuing */
304 break;
305 }
306
307 for (ITmfStateInterval execNameInterval : execNameIntervals) {
308 if (!execNameInterval.getStateValue().isNull() &&
309 execNameInterval.getStateValue().getType() == ITmfStateValue.Type.STRING) {
310 execName = execNameInterval.getStateValue().unboxStr();
311 fProcessNameMap.put(tid, execName);
312 return execName;
313 }
314 }
315 }
316 }
317
318 } catch (AttributeNotFoundException e) {
319 /* can't find the process name, just return the tid instead */
320 }
321 return tid;
322 }
323
324 /**
325 * Set the currently selected thread ID
326 *
327 * @param tid
328 * The selected thread ID
329 */
330 public void setSelectedThread(String tid) {
331 fSelectedThread = tid;
332 }
333
334 /**
335 * Add a core
336 *
337 * @param core
338 * the core to add
339 * @since 2.0
340 */
341 public void addCpu(int core) {
342 fCpus.add(core);
343 updateContent(getWindowStartTime(), getWindowEndTime(), false);
344 }
345
346 /**
347 * Remove a core
348 *
349 * @param core
350 * the core to remove
351 * @since 2.0
352 */
353 public void removeCpu(int core) {
354 fCpus.remove(core);
355 updateContent(getWindowStartTime(), getWindowEndTime(), false);
356 }
357
358 /**
359 * Clears the cores
360 *
361 * @since 2.0
362 *
363 */
364 public void clearCpu() {
365 fCpus.clear();
366 updateContent(getWindowStartTime(), getWindowEndTime(), false);
367 }
368
369 }
This page took 0.05297 seconds and 4 git commands to generate.