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