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