1 /*******************************************************************************
2 * Copyright (c) 2014 École Polytechnique de Montréal
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
10 * Geneviève Bastien - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.internal
.lttng2
.kernel
.ui
.views
.cpuusage
;
15 import java
.util
.Arrays
;
16 import java
.util
.HashMap
;
17 import java
.util
.LinkedHashMap
;
19 import java
.util
.Map
.Entry
;
21 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
22 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
23 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
24 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
25 import org
.eclipse
.linuxtools
.internal
.lttng2
.kernel
.ui
.Activator
;
26 import org
.eclipse
.linuxtools
.lttng2
.kernel
.core
.cpuusage
.LttngKernelCpuUsageAnalysis
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateValueTypeException
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.ITmfStateSystem
;
29 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.xycharts
.linecharts
.TmfCommonXLineChartViewer
;
30 import org
.eclipse
.swt
.widgets
.Composite
;
33 * CPU usage viewer with XY line chart. It displays the total CPU usage and that
34 * of the threads selected in the CPU usage tree viewer.
36 * @author Geneviève Bastien
38 public class CpuUsageXYViewer
extends TmfCommonXLineChartViewer
{
40 private LttngKernelCpuUsageAnalysis fModule
= null;
42 /* Maps a thread ID to a list of y values */
43 private final Map
<String
, double[]> fYValues
= new LinkedHashMap
<>();
45 * To avoid up and downs CPU usage when process is in and out of CPU
46 * frequently, use a smaller resolution to get better averages.
48 private static final double RESOLUTION
= 0.4;
50 private long fSelectedThread
= -1;
58 * The tree viewer containing the list of threads with CPU usage.
59 * A listener will be added to that viewer so it can synchronize
60 * with the selection from the viewer.
62 public CpuUsageXYViewer(Composite parent
, CpuUsageComposite treeViewer
) {
63 super(parent
, Messages
.CpuUsageXYViewer_Title
, Messages
.CpuUsageXYViewer_TimeXAxis
, Messages
.CpuUsageXYViewer_CpuYAxis
);
64 setResolution(RESOLUTION
);
66 /* Add selection listener to tree viewer */
67 treeViewer
.addSelectionChangeListener(new ISelectionChangedListener() {
69 public void selectionChanged(SelectionChangedEvent event
) {
70 if (event
.getSelection() instanceof IStructuredSelection
) {
71 Object selection
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
72 if (selection
instanceof CpuUsageEntry
) {
73 CpuUsageEntry entry
= (CpuUsageEntry
) selection
;
74 setSelectedThread(Long
.valueOf(entry
.getTid()));
82 protected void initializeDataSource() {
83 if (getTrace() != null) {
84 fModule
= getTrace().getAnalysisModuleOfClass(LttngKernelCpuUsageAnalysis
.class, LttngKernelCpuUsageAnalysis
.ID
);
85 if (fModule
== null) {
92 private static double[] zeroFill(int nb
) {
93 double[] arr
= new double[nb
];
94 Arrays
.fill(arr
, 0.0);
99 protected void updateData(long start
, long end
, int nb
, IProgressMonitor monitor
) {
101 if (getTrace() == null || fModule
== null) {
104 ITmfStateSystem ss
= fModule
.getStateSystem();
106 * Don't wait for the module completion or initialization, when it's
112 double[] xvalues
= getXAxis(start
, end
, nb
);
113 if (xvalues
.length
== 0) {
118 long traceStart
= getStartTime();
119 long traceEnd
= getEndTime();
120 long offset
= getTimeOffset();
121 long selectedThread
= fSelectedThread
;
123 /* Initialize the data */
124 Map
<String
, Long
> cpuUsageMap
= fModule
.getCpuUsageInRange(Math
.max(start
, traceStart
), Math
.min(end
, traceEnd
));
125 Map
<String
, String
> totalEntries
= new HashMap
<>();
127 fYValues
.put(Messages
.CpuUsageXYViewer_Total
, zeroFill(xvalues
.length
));
128 String stringSelectedThread
= Long
.toString(selectedThread
);
129 if (selectedThread
!= -1) {
130 fYValues
.put(stringSelectedThread
, zeroFill(xvalues
.length
));
133 for (Entry
<String
, Long
> entry
: cpuUsageMap
.entrySet()) {
135 * Process only entries representing the total of all CPUs and
136 * that have time on CPU
138 if (entry
.getValue() == 0) {
141 if (!entry
.getKey().startsWith(LttngKernelCpuUsageAnalysis
.TOTAL
)) {
144 String
[] strings
= entry
.getKey().split(LttngKernelCpuUsageAnalysis
.SPLIT_STRING
, 2);
146 if ((strings
.length
> 1) && !(strings
[1].equals(LttngKernelCpuUsageAnalysis
.TID_ZERO
))) {
147 /* This is the total cpu usage for a thread */
148 totalEntries
.put(strings
[1], entry
.getKey());
152 double prevX
= xvalues
[0];
153 long prevTime
= (long) prevX
+ offset
;
155 * make sure that time is in the trace range after double to long
158 prevTime
= Math
.max(traceStart
, prevTime
);
159 prevTime
= Math
.min(traceEnd
, prevTime
);
160 /* Get CPU usage statistics for each x value */
161 for (int i
= 1; i
< xvalues
.length
; i
++) {
162 if (monitor
.isCanceled()) {
166 double x
= xvalues
[i
];
167 long time
= (long) x
+ offset
;
168 time
= Math
.max(traceStart
, time
);
169 time
= Math
.min(traceEnd
, time
);
171 cpuUsageMap
= fModule
.getCpuUsageInRange(prevTime
, time
);
174 * Calculate the sum of all total entries, and add a data point
175 * to the selected one
177 for (Entry
<String
, String
> entry
: totalEntries
.entrySet()) {
178 Long cpuEntry
= cpuUsageMap
.get(entry
.getValue());
179 cpuEntry
= cpuEntry
!= null ? cpuEntry
: 0L;
181 totalCpu
+= cpuEntry
;
183 if (entry
.getKey().equals(stringSelectedThread
)) {
184 /* This is the total cpu usage for a thread */
185 fYValues
.get(entry
.getKey())[i
] = (double) cpuEntry
/ (double) (time
- prevTime
) * 100;
189 fYValues
.get(Messages
.CpuUsageXYViewer_Total
)[i
] = (double) totalCpu
/ (double) (time
- prevTime
) * 100;
192 for (Entry
<String
, double[]> entry
: fYValues
.entrySet()) {
193 setSeries(entry
.getKey(), entry
.getValue());
195 if (monitor
.isCanceled()) {
199 } catch (StateValueTypeException e
) {
200 Activator
.getDefault().logError("Error updating the data of the CPU usage view", e
); //$NON-NLS-1$
206 * Set the selected thread ID, which will be graphed in this viewer
209 * The selected thread ID
211 public void setSelectedThread(long tid
) {
213 deleteSeries(Long
.toString(fSelectedThread
));
214 fSelectedThread
= tid
;