lttng: Add a view for the CPU usage analysis
authorGeneviève Bastien <gbastien+lttng@versatic.net>
Mon, 17 Feb 2014 15:32:00 +0000 (10:32 -0500)
committerGenevieve Bastien <gbastien+lttng@versatic.net>
Thu, 17 Apr 2014 14:42:50 +0000 (10:42 -0400)
This view contains a tree viewer to show all threads spending time on the CPU
in the time range, and an XY chart viewer to display the total CPU of all
threads and the CPU usage of the currently selected from the tree viewer.

Change-Id: Id96fa1005623601539fad10e28949691b70ea1df
Signed-off-by: Geneviève Bastien <gbastien+lttng@versatic.net>
Reviewed-on: https://git.eclipse.org/r/22522
Tested-by: Hudson CI
Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/lttng2/kernel/core/cpuusage/LttngKernelCpuUsageAnalysis.java
org.eclipse.linuxtools.lttng2.kernel.ui/.settings/org.eclipse.jdt.core.prefs
org.eclipse.linuxtools.lttng2.kernel.ui/META-INF/MANIFEST.MF
org.eclipse.linuxtools.lttng2.kernel.ui/plugin.properties
org.eclipse.linuxtools.lttng2.kernel.ui/plugin.xml
org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageComposite.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageEntry.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageView.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageXYViewer.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/Messages.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/messages.properties [new file with mode: 0644]

index 174b5da005b02f5a9e3deaff28ac72b0a78f5244..6a8a9f3c584342701627ec2c70b3a54478a8a8a3 100644 (file)
@@ -105,7 +105,9 @@ public class LttngKernelCpuUsageAnalysis extends TmfStateSystemAnalysisModule {
          * don't get TimeRange exceptions.
          */
         long startTime = Math.max(start, cpuSs.getStartTime());
+        startTime = Math.max(startTime, kernelSs.getStartTime());
         long endTime = Math.min(end, cpuSs.getCurrentEndTime());
+        endTime = Math.min(endTime, kernelSs.getCurrentEndTime());
         long totalTime = 0;
         if (endTime < startTime) {
             return map;
index 5009ad9f24f70c48ea9036d2a68336ed11b82408..b50d517d73a2a10bc4de868fc2e91b8cf673bb3b 100644 (file)
@@ -21,7 +21,7 @@ org.eclipse.jdt.core.compiler.problem.deadCode=error
 org.eclipse.jdt.core.compiler.problem.deprecation=warning
 org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled
 org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
-org.eclipse.jdt.core.compiler.problem.discouragedReference=error
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=error
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
 org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=error
index cd20f1627b5996384c689eb6dade290eaf6d2418..8764a3b2ee6ffcf4b4f0e235c678c5aaef0f2597 100644 (file)
@@ -21,4 +21,5 @@ Export-Package: org.eclipse.linuxtools.internal.lttng2.kernel.ui;x-friends:="org
  org.eclipse.linuxtools.internal.lttng2.kernel.ui.viewers.events;x-internal:=true,
  org.eclipse.linuxtools.internal.lttng2.kernel.ui.views;x-friends:="org.eclipse.linuxtools.lttng2.kernel.ui.swtbot.tests",
  org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.controlflow;x-friends:="org.eclipse.linuxtools.lttng2.kernel.ui.swtbot.tests",
+ org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.cpuusage;x-friends:="org.eclipse.linuxtools.lttng2.kernel.ui.swtbot.tests",
  org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.resources;x-friends:="org.eclipse.linuxtools.lttng2.kernel.ui.swtbot.tests"
index 2d929a044cf463a8c91d5380005c3a4c8eca869b..0a53a64e67b398168729a4fdb7b85585c4097907 100644 (file)
@@ -18,6 +18,7 @@ kernel.perspective.name = LTTng Kernel
 
 controlflow.view.name = Control Flow
 resources.view.name = Resources
+cpuusage.view.name = CPU Usage
 
 tracetype.type.kernel = LTTng Kernel Trace
 analysis.lttngkernel = LTTng Kernel Analysis
index 7416106ce267071d4bace8e4de8cb0b3898875a0..de8ad0300926a062b5bef052c9b2593ebd3cece9 100644 (file)
             name="%resources.view.name"
             restorable="true">
       </view>
+      <view
+            allowMultiple="false"
+            category="org.eclipse.linuxtools.lttng2.ui.views.category"
+            class="org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.cpuusage.CpuUsageView"
+            id="org.eclipse.linuxtools.lttng2.kernel.ui.views.cpuusage"
+            name="%cpuusage.view.name"
+            restorable="true">
+      </view>
    </extension>
    <extension
          point="org.eclipse.ui.navigator.navigatorContent">
                id="org.eclipse.linuxtools.lttng2.kernel.analysis">
          </analysisId>
       </output>
+      <output
+            class="org.eclipse.linuxtools.tmf.ui.analysis.TmfAnalysisViewOutput"
+            id="org.eclipse.linuxtools.lttng2.kernel.ui.views.cpuusage">
+         <analysisId
+               id="org.eclipse.linuxtools.lttng2.kernel.core.cpuusage">
+         </analysisId>
+      </output>
    </extension>
    <extension
          point="org.eclipse.linuxtools.tmf.ui.tracetypeui">
diff --git a/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageComposite.java b/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageComposite.java
new file mode 100644 (file)
index 0000000..27c88ef
--- /dev/null
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.cpuusage;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.linuxtools.internal.lttng2.kernel.core.Attributes;
+import org.eclipse.linuxtools.lttng2.kernel.core.analysis.LttngKernelAnalysisModule;
+import org.eclipse.linuxtools.lttng2.kernel.core.cpuusage.LttngKernelCpuUsageAnalysis;
+import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
+import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
+import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
+import org.eclipse.linuxtools.tmf.core.statesystem.TmfStateSystemAnalysisModule;
+import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
+import org.eclipse.linuxtools.tmf.ui.viewers.tree.AbstractTmfTreeViewer;
+import org.eclipse.linuxtools.tmf.ui.viewers.tree.ITmfTreeColumnDataProvider;
+import org.eclipse.linuxtools.tmf.ui.viewers.tree.ITmfTreeViewerEntry;
+import org.eclipse.linuxtools.tmf.ui.viewers.tree.TmfTreeColumnData;
+import org.eclipse.linuxtools.tmf.ui.viewers.tree.TmfTreeColumnData.ITmfColumnPercentageProvider;
+import org.eclipse.linuxtools.tmf.ui.viewers.tree.TmfTreeViewerEntry;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Tree viewer to display CPU usage information in a specified time range. It
+ * shows the process's TID, its name, the time spent on the CPU during that
+ * range, in % and absolute value.
+ *
+ * @author Geneviève Bastien
+ */
+public class CpuUsageComposite extends AbstractTmfTreeViewer {
+
+    private LttngKernelCpuUsageAnalysis fModule = null;
+
+    private static final String[] COLUMN_NAMES = new String[] {
+            Messages.CpuUsageComposite_ColumnTID,
+            Messages.CpuUsageComposite_ColumnProcess,
+            Messages.CpuUsageComposite_ColumnPercent,
+            Messages.CpuUsageComposite_ColumnTime
+    };
+
+    /* A map that saves the mapping of a thread ID to its executable name */
+    private final Map<String, String> fProcessNameMap = new HashMap<>();
+
+    /** Provides label for the CPU usage tree viewer cells */
+    protected static class CpuLabelProvider extends TreeLabelProvider {
+
+        @Override
+        public String getColumnText(Object element, int columnIndex) {
+            CpuUsageEntry obj = (CpuUsageEntry) element;
+            if (columnIndex == 0) {
+                return obj.getTid();
+            } else if (columnIndex == 1) {
+                return obj.getProcessName();
+            } else if (columnIndex == 2) {
+                return String.format(Messages.CpuUsageComposite_TextPercent, obj.getPercent());
+            } else if (columnIndex == 3) {
+                return NLS.bind(Messages.CpuUsageComposite_TextTime, obj.getTime());
+            }
+
+            return element.toString();
+        }
+
+    }
+
+    /**
+     * Constructor
+     *
+     * @param parent
+     *            The parent composite that holds this viewer
+     */
+    public CpuUsageComposite(Composite parent) {
+        super(parent, false);
+        setLabelProvider(new CpuLabelProvider());
+    }
+
+    @Override
+    protected ITmfTreeColumnDataProvider getColumnDataProvider() {
+        return new ITmfTreeColumnDataProvider() {
+
+            @Override
+            public List<TmfTreeColumnData> getColumnData() {
+                /* All columns are sortable */
+                List<TmfTreeColumnData> columns = new ArrayList<>();
+                TmfTreeColumnData column = new TmfTreeColumnData(COLUMN_NAMES[0]);
+                column.setComparator(new ViewerComparator() {
+                    @Override
+                    public int compare(Viewer viewer, Object e1, Object e2) {
+                        CpuUsageEntry n1 = (CpuUsageEntry) e1;
+                        CpuUsageEntry n2 = (CpuUsageEntry) e2;
+
+                        return n1.getTid().compareTo(n2.getTid());
+
+                    }
+                });
+                columns.add(column);
+                column = new TmfTreeColumnData(COLUMN_NAMES[1]);
+                column.setComparator(new ViewerComparator() {
+                    @Override
+                    public int compare(Viewer viewer, Object e1, Object e2) {
+                        CpuUsageEntry n1 = (CpuUsageEntry) e1;
+                        CpuUsageEntry n2 = (CpuUsageEntry) e2;
+
+                        return n1.getProcessName().compareTo(n2.getProcessName());
+
+                    }
+                });
+                columns.add(column);
+                column = new TmfTreeColumnData(COLUMN_NAMES[2]);
+                column.setComparator(new ViewerComparator() {
+                    @Override
+                    public int compare(Viewer viewer, Object e1, Object e2) {
+                        CpuUsageEntry n1 = (CpuUsageEntry) e1;
+                        CpuUsageEntry n2 = (CpuUsageEntry) e2;
+
+                        return n1.getPercent().compareTo(n2.getPercent());
+
+                    }
+                });
+                column.setPercentageProvider(new ITmfColumnPercentageProvider() {
+
+                    @Override
+                    public double getPercentage(Object data) {
+                        CpuUsageEntry parent = (CpuUsageEntry) data;
+                        return parent.getPercent() / 100;
+                    }
+                });
+                columns.add(column);
+                column = new TmfTreeColumnData(COLUMN_NAMES[3]);
+                column.setComparator(new ViewerComparator() {
+                    @Override
+                    public int compare(Viewer viewer, Object e1, Object e2) {
+                        CpuUsageEntry n1 = (CpuUsageEntry) e1;
+                        CpuUsageEntry n2 = (CpuUsageEntry) e2;
+
+                        return n1.getTime().compareTo(n2.getTime());
+
+                    }
+                });
+                columns.add(column);
+
+                return columns;
+            }
+
+        };
+    }
+
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    @Override
+    public void initializeDataSource() {
+        fModule = getTrace().getAnalysisModuleOfClass(LttngKernelCpuUsageAnalysis.class, LttngKernelCpuUsageAnalysis.ID);
+        if (fModule == null) {
+            return;
+        }
+        fModule.schedule();
+        fModule.waitForInitialization();
+        fProcessNameMap.clear();
+    }
+
+    @Override
+    protected ITmfTreeViewerEntry updateElements(long start, long end, boolean isSelection) {
+        if (isSelection || (start == end)) {
+            return null;
+        }
+        if (getTrace() == null || fModule == null) {
+            return null;
+        }
+        ITmfStateSystem ss = fModule.getStateSystem();
+        /* Don't wait for the module completion, when it's ready, we'll know */
+        if (ss == null) {
+            return null;
+        }
+
+        /* Initialize the data */
+        Map<String, Long> cpuUsageMap = fModule.getCpuUsageInRange(Math.max(start, getStartTime()), Math.min(end, getEndTime()));
+
+        TmfTreeViewerEntry root = new TmfTreeViewerEntry(""); //$NON-NLS-1$
+        List<ITmfTreeViewerEntry> entryList = root.getChildren();
+
+        for (Entry<String, Long> entry : cpuUsageMap.entrySet()) {
+            /*
+             * Process only entries representing the total of all CPUs and that
+             * have time on CPU
+             */
+            if (entry.getValue() == 0) {
+                continue;
+            }
+            if (!entry.getKey().startsWith(LttngKernelCpuUsageAnalysis.TOTAL)) {
+                continue;
+            }
+            String[] strings = entry.getKey().split(LttngKernelCpuUsageAnalysis.SPLIT_STRING, 2);
+
+            if ((strings.length > 1) && !(strings[1].equals(LttngKernelCpuUsageAnalysis.TID_ZERO))) {
+                CpuUsageEntry obj = new CpuUsageEntry(strings[1], getProcessName(strings[1]), (double) entry.getValue() / (double) (end - start) * 100, entry.getValue());
+                entryList.add(obj);
+            }
+        }
+
+        return root;
+    }
+
+    /*
+     * Get the process name from its TID by using the LTTng kernel analysis
+     * module
+     */
+    private String getProcessName(String tid) {
+        String execName = fProcessNameMap.get(tid);
+        if (execName != null) {
+            return execName;
+        }
+        TmfStateSystemAnalysisModule module = getTrace().getAnalysisModuleOfClass(TmfStateSystemAnalysisModule.class, LttngKernelAnalysisModule.ID);
+        if (module == null) {
+            return tid;
+        }
+        /*
+         * Do not schedule the analysis here. It should have been executed when
+         * the CPU usage analysis was executed. If it's not available, there
+         * might be a good reason (disk space?) so don't force it.
+         */
+        ITmfStateSystem kernelSs = module.getStateSystem();
+        if (kernelSs == null) {
+            return tid;
+        }
+
+        try {
+            int cpusNode = kernelSs.getQuarkAbsolute(Attributes.THREADS);
+
+            /* Get the quarks for each cpu */
+            List<Integer> cpuNodes = kernelSs.getSubAttributes(cpusNode, false);
+
+            for (Integer tidQuark : cpuNodes) {
+                if (kernelSs.getAttributeName(tidQuark).equals(tid)) {
+                    int execNameQuark;
+                    List<ITmfStateInterval> execNameIntervals;
+                    try {
+                        execNameQuark = kernelSs.getQuarkRelative(tidQuark, Attributes.EXEC_NAME);
+                        execNameIntervals = kernelSs.queryHistoryRange(execNameQuark, getStartTime(), getEndTime());
+                    } catch (AttributeNotFoundException e) {
+                        /* No information on this thread (yet?), skip it for now */
+                        continue;
+                    } catch (StateSystemDisposedException e) {
+                        /* State system is closing down, no point continuing */
+                        break;
+                    }
+
+                    for (ITmfStateInterval execNameInterval : execNameIntervals) {
+                        if (!execNameInterval.getStateValue().isNull() &&
+                                execNameInterval.getStateValue().getType() == ITmfStateValue.Type.STRING) {
+                            execName = execNameInterval.getStateValue().unboxStr();
+                            fProcessNameMap.put(tid, execName);
+                            return execName;
+                        }
+                    }
+                }
+            }
+
+        } catch (AttributeNotFoundException e) {
+            /* can't find the process name, just return the tid instead */
+        }
+        return tid;
+    }
+
+}
diff --git a/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageEntry.java b/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageEntry.java
new file mode 100644 (file)
index 0000000..79bb0ce
--- /dev/null
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.cpuusage;
+
+import org.eclipse.linuxtools.tmf.ui.viewers.tree.TmfTreeViewerEntry;
+
+/**
+ * Represents an entry in the tree viewer of the CPU usage view. An entry is a
+ * thread that occupied part of the CPU in the selected time range.
+ *
+ * @author Geneviève Bastien
+ */
+public class CpuUsageEntry extends TmfTreeViewerEntry {
+    private final String fTid;
+    private final String fProcessName;
+    private final Double fPercent;
+    private final Long fTime;
+
+    /**
+     * Constructor
+     *
+     * @param tid
+     *            The TID of the process
+     * @param name
+     *            The thread's name
+     * @param percent
+     *            The percentage CPU usage
+     * @param time
+     *            The total amount of time spent on CPU
+     */
+    public CpuUsageEntry(String tid, String name, double percent, long time) {
+        super(tid);
+        fTid = tid;
+        fProcessName = name;
+        fPercent = percent;
+        fTime = time;
+    }
+
+    /**
+     * Get the TID of the thread represented by this entry
+     *
+     * @return The thread's TID
+     */
+    public String getTid() {
+        return fTid;
+    }
+
+    /**
+     * Get the process name
+     *
+     * @return The process name
+     */
+    public String getProcessName() {
+        return fProcessName;
+    }
+
+    /**
+     * Get the percentage of time spent on CPU in the time interval represented
+     * by this entry.
+     *
+     * @return The percentage of time spent on CPU
+     */
+    public Double getPercent() {
+        return fPercent;
+    }
+
+    /**
+     * Get the total time spent on CPU in the time interval represented by this
+     * entry.
+     *
+     * @return The total time spent on CPU
+     */
+    public Long getTime() {
+        return fTime;
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageView.java b/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageView.java
new file mode 100644 (file)
index 0000000..f69648e
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.cpuusage;
+
+import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.ui.viewers.xycharts.TmfXYChartViewer;
+import org.eclipse.linuxtools.tmf.ui.views.TmfView;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * CPU usage view. It contains 2 viewers: one tree viewer showing all the
+ * threads who were on the CPU in the time range, and one XY chart viewer
+ * plotting the total time spent on CPU and the time of the threads selected in
+ * the tree viewer.
+ *
+ * @author Geneviève Bastien
+ */
+public class CpuUsageView extends TmfView {
+
+    /** ID string */
+    public static final String ID = "org.eclipse.linuxtools.lttng2.kernel.ui.views.cpuusage"; //$NON-NLS-1$
+
+    /**
+     * Constructor
+     */
+    public CpuUsageView() {
+        super(Messages.CpuUsageView_Title);
+    }
+
+    @Override
+    public void createPartControl(Composite parent) {
+
+        final SashForm sash = new SashForm(parent, SWT.NONE);
+
+        CpuUsageComposite treeViewer = new CpuUsageComposite(sash);
+
+        /* Build the XY chart part of the view */
+        TmfXYChartViewer xyViewer = new CpuUsageXYViewer(sash, treeViewer);
+
+        sash.setLayout(new FillLayout());
+
+        /* Initialize the viewers with the currently selected trace */
+        ITmfTrace trace = getActiveTrace();
+        if (trace != null) {
+            TmfTraceSelectedSignal signal = new TmfTraceSelectedSignal(this, trace);
+            treeViewer.traceSelected(signal);
+            xyViewer.traceSelected(signal);
+        }
+
+    }
+
+    @Override
+    public void setFocus() {
+    }
+
+}
diff --git a/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageXYViewer.java b/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/CpuUsageXYViewer.java
new file mode 100644 (file)
index 0000000..a87c5f6
--- /dev/null
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.cpuusage;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.linuxtools.internal.lttng2.kernel.ui.Activator;
+import org.eclipse.linuxtools.lttng2.kernel.core.cpuusage.LttngKernelCpuUsageAnalysis;
+import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
+import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
+import org.eclipse.linuxtools.tmf.ui.viewers.xycharts.linecharts.TmfCommonXLineChartViewer;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * CPU usage viewer with XY line chart. It displays the total CPU usage and that
+ * of the threads selected in the CPU usage tree viewer.
+ *
+ * @author Geneviève Bastien
+ */
+public class CpuUsageXYViewer extends TmfCommonXLineChartViewer {
+
+    private LttngKernelCpuUsageAnalysis fModule = null;
+
+    /* Maps a thread ID to a list of y values */
+    private final Map<String, double[]> fYValues = new LinkedHashMap<>();
+    /*
+     * To avoid up and downs CPU usage when process is in and out of CPU
+     * frequently, use a smaller resolution to get better averages.
+     */
+    private static final double RESOLUTION = 0.4;
+
+    private long fSelectedThread = -1;
+
+    /**
+     * Constructor
+     *
+     * @param parent
+     *            parent composite
+     * @param treeViewer
+     *            The tree viewer containing the list of threads with CPU usage.
+     *            A listener will be added to that viewer so it can synchronize
+     *            with the selection from the viewer.
+     */
+    public CpuUsageXYViewer(Composite parent, CpuUsageComposite treeViewer) {
+        super(parent, Messages.CpuUsageXYViewer_Title, Messages.CpuUsageXYViewer_TimeXAxis, Messages.CpuUsageXYViewer_CpuYAxis);
+        setResolution(RESOLUTION);
+
+        /* Add selection listener to tree viewer */
+        treeViewer.addSelectionChangeListener(new ISelectionChangedListener() {
+            @Override
+            public void selectionChanged(SelectionChangedEvent event) {
+                if (event.getSelection() instanceof IStructuredSelection) {
+                    Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
+                    if (selection instanceof CpuUsageEntry) {
+                        CpuUsageEntry entry = (CpuUsageEntry) selection;
+                        setSelectedThread(Long.valueOf(entry.getTid()));
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    protected void initializeDataSource() {
+        if (getTrace() != null) {
+            fModule = getTrace().getAnalysisModuleOfClass(LttngKernelCpuUsageAnalysis.class, LttngKernelCpuUsageAnalysis.ID);
+            if (fModule == null) {
+                return;
+            }
+            fModule.schedule();
+        }
+    }
+
+    private static double[] zeroFill(int nb) {
+        double[] arr = new double[nb];
+        Arrays.fill(arr, 0.0);
+        return arr;
+    }
+
+    @Override
+    protected void updateData(long start, long end, int nb, IProgressMonitor monitor) {
+        try {
+            if (getTrace() == null || fModule == null) {
+                return;
+            }
+            ITmfStateSystem ss = fModule.getStateSystem();
+            /*
+             * Don't wait for the module completion or initialization, when it's
+             * ready, we'll know
+             */
+            if (ss == null) {
+                return;
+            }
+            double[] xvalues = getXAxis(start, end, nb);
+            if (xvalues.length == 0) {
+                return;
+            }
+            setXAxis(xvalues);
+
+            long traceStart = getStartTime();
+            long traceEnd = getEndTime();
+            long offset = getTimeOffset();
+            long selectedThread = fSelectedThread;
+
+            /* Initialize the data */
+            Map<String, Long> cpuUsageMap = fModule.getCpuUsageInRange(Math.max(start, traceStart), Math.min(end, traceEnd));
+            Map<String, String> totalEntries = new HashMap<>();
+            fYValues.clear();
+            fYValues.put(Messages.CpuUsageXYViewer_Total, zeroFill(xvalues.length));
+            String stringSelectedThread = Long.toString(selectedThread);
+            if (selectedThread != -1) {
+                fYValues.put(stringSelectedThread, zeroFill(xvalues.length));
+            }
+
+            for (Entry<String, Long> entry : cpuUsageMap.entrySet()) {
+                /*
+                 * Process only entries representing the total of all CPUs and
+                 * that have time on CPU
+                 */
+                if (entry.getValue() == 0) {
+                    continue;
+                }
+                if (!entry.getKey().startsWith(LttngKernelCpuUsageAnalysis.TOTAL)) {
+                    continue;
+                }
+                String[] strings = entry.getKey().split(LttngKernelCpuUsageAnalysis.SPLIT_STRING, 2);
+
+                if ((strings.length > 1) && !(strings[1].equals(LttngKernelCpuUsageAnalysis.TID_ZERO))) {
+                    /* This is the total cpu usage for a thread */
+                    totalEntries.put(strings[1], entry.getKey());
+                }
+            }
+
+            double prevX = xvalues[0];
+            long prevTime = (long) prevX + offset;
+            /*
+             * make sure that time is in the trace range after double to long
+             * conversion
+             */
+            prevTime = Math.max(traceStart, prevTime);
+            prevTime = Math.min(traceEnd, prevTime);
+            /* Get CPU usage statistics for each x value */
+            for (int i = 1; i < xvalues.length; i++) {
+                if (monitor.isCanceled()) {
+                    return;
+                }
+                long totalCpu = 0;
+                double x = xvalues[i];
+                long time = (long) x + offset;
+                time = Math.max(traceStart, time);
+                time = Math.min(traceEnd, time);
+
+                cpuUsageMap = fModule.getCpuUsageInRange(prevTime, time);
+
+                /*
+                 * Calculate the sum of all total entries, and add a data point
+                 * to the selected one
+                 */
+                for (Entry<String, String> entry : totalEntries.entrySet()) {
+                    Long cpuEntry = cpuUsageMap.get(entry.getValue());
+                    cpuEntry = cpuEntry != null ? cpuEntry : 0L;
+
+                    totalCpu += cpuEntry;
+
+                    if (entry.getKey().equals(stringSelectedThread)) {
+                        /* This is the total cpu usage for a thread */
+                        fYValues.get(entry.getKey())[i] = (double) cpuEntry / (double) (time - prevTime) * 100;
+                    }
+
+                }
+                fYValues.get(Messages.CpuUsageXYViewer_Total)[i] = (double) totalCpu / (double) (time - prevTime) * 100;
+                prevTime = time;
+            }
+            for (Entry<String, double[]> entry : fYValues.entrySet()) {
+                setSeries(entry.getKey(), entry.getValue());
+            }
+            if (monitor.isCanceled()) {
+                return;
+            }
+            updateDisplay();
+        } catch (StateValueTypeException e) {
+            Activator.getDefault().logError("Error updating the data of the CPU usage view", e); //$NON-NLS-1$
+        }
+
+    }
+
+    /**
+     * Set the selected thread ID, which will be graphed in this viewer
+     *
+     * @param tid
+     *            The selected thread ID
+     */
+    public void setSelectedThread(long tid) {
+        cancelUpdate();
+        deleteSeries(Long.toString(fSelectedThread));
+        fSelectedThread = tid;
+        updateContent();
+    }
+
+}
diff --git a/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/Messages.java b/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/Messages.java
new file mode 100644 (file)
index 0000000..6b70d8c
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.cpuusage;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages used in the LTTng kernel CPU usage view and viewers.
+ *
+ * @author Geneviève Bastien
+ */
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+    private static final String BUNDLE_NAME = "org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.cpuusage.messages"; //$NON-NLS-1$
+    public static String CpuUsageComposite_ColumnPercent;
+    public static String CpuUsageComposite_ColumnProcess;
+    public static String CpuUsageComposite_ColumnTID;
+    public static String CpuUsageComposite_ColumnTime;
+    public static String CpuUsageComposite_TextPercent;
+    public static String CpuUsageComposite_TextTime;
+    public static String CpuUsageView_Title;
+    public static String CpuUsageXYViewer_CpuYAxis;
+    public static String CpuUsageXYViewer_TimeXAxis;
+    public static String CpuUsageXYViewer_Title;
+    public static String CpuUsageXYViewer_Total;
+    static {
+        // initialize resource bundle
+        NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+    }
+
+    private Messages() {
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/messages.properties b/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/cpuusage/messages.properties
new file mode 100644 (file)
index 0000000..bca6d6a
--- /dev/null
@@ -0,0 +1,23 @@
+###############################################################################
+# Copyright (c) 2014 École Polytechnique de Montréal
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     Geneviève Bastien - Initial API and implementation
+###############################################################################
+
+CpuUsageComposite_ColumnPercent=%
+CpuUsageComposite_ColumnProcess=Process
+CpuUsageComposite_ColumnTID=TID
+CpuUsageComposite_ColumnTime=Time
+CpuUsageComposite_TextPercent=%1$.3f %%
+CpuUsageComposite_TextTime={0} ns
+CpuUsageView_Title=CPU Usage
+CpuUsageXYViewer_CpuYAxis=% CPU
+CpuUsageXYViewer_TimeXAxis=Time
+CpuUsageXYViewer_Title=CPU usage
+CpuUsageXYViewer_Total=Total
This page took 0.042207 seconds and 5 git commands to generate.