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