summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Dumais2013-02-28 08:17:19 (EST)
committer Marc Khouzam2013-02-28 11:05:22 (EST)
commit91de3531687c4da12b74c7a8c83cb422c4f061df (patch)
tree8f05761f4f55e190a23028d48c080339c174814f
parent52c0edd492391f725d3cf5f6da113dd7924688fe (diff)
downloadorg.eclipse.cdt-91de3531687c4da12b74c7a8c83cb422c4f061df.zip
org.eclipse.cdt-91de3531687c4da12b74c7a8c83cb422c4f061df.tar.gz
org.eclipse.cdt-91de3531687c4da12b74c7a8c83cb422c4f061df.tar.bz2
Bug 396268 - [Visualizer] Add CPU/core load information to the multicorerefs/changes/77/10077/13
visualizer Change-Id: I28432354b497732b4ecf7924bb7227e0b8d25508 Reviewed-on: https://git.eclipse.org/r/10077 Reviewed-by: William Swanson <traveler@tilera.com> Reviewed-by: Marc Khouzam <marc.khouzam@ericsson.com> IP-Clean: Marc Khouzam <marc.khouzam@ericsson.com> Tested-by: Marc Khouzam <marc.khouzam@ericsson.com>
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/resources/messages.properties13
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/actions/EnableLoadMetersAction.java77
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/actions/SetLoadMeterPeriodAction.java62
-rwxr-xr-xdsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerCPU.java24
-rwxr-xr-xdsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerCore.java24
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerLoadInfo.java71
-rwxr-xr-xdsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerModel.java24
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/IMulticoreVisualizerConstants.java36
-rwxr-xr-xdsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizer.java264
-rwxr-xr-xdsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCPU.java61
-rwxr-xr-xdsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCanvas.java81
-rwxr-xr-xdsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCore.java33
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerLoadMeter.java223
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/DSFDebugModel.java63
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/DSFDebugModelListener.java14
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatCoreLoads.java42
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatCounters.java140
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatParser.java100
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBHardwareAndOS.java303
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBHardwareAndOS2.java27
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/Suite_Sessionless_Tests.java5
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/ProcStatParserTest.java220
-rwxr-xr-xvisualizer/org.eclipse.cdt.visualizer.ui/src/org/eclipse/cdt/visualizer/ui/VisualizerAction.java6
23 files changed, 1891 insertions, 22 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/resources/messages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/resources/messages.properties
index 0103a53..62b3b75 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/resources/messages.properties
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/resources/messages.properties
@@ -7,6 +7,7 @@
#
# Contributors:
# William R. Swanson (Tilera Corporation)
+# Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
# =============================================================================
# -----------------------------------------------------------------------------
@@ -19,3 +20,15 @@ MulticoreVisualizer.actions.SelectAll.description=Select all thread(s)
MulticoreVisualizer.actions.Refresh.text=Refresh@F5
MulticoreVisualizer.actions.Refresh.description=Refresh the visualizer display
+
+MulticoreVisualizer.actions.EnableLoadMeter.Enable.text=Enable Load Meters
+MulticoreVisualizer.actions.EnableLoadMeter.Disable.text=Disable Load Meters
+MulticoreVisualizer.actions.EnableLoadMeter.description=Enable or disable the load meters
+
+MulticoreVisualizer.actions.SetLoadMeterPeriod.fast.text=Fast
+MulticoreVisualizer.actions.SetLoadMeterPeriod.medium.text=Medium
+MulticoreVisualizer.actions.SetLoadMeterPeriod.slow.text=Slow
+MulticoreVisualizer.actions.SetLoadMeterPeriod.description=Choose the refresh speed for load meters
+
+MulticoreVisualizer.actions.LoadMeterSubmenu.text=Load Meters
+MulticoreVisualizer.actions.LoadMetersRefreshSubSubmenu.text=Refresh Speed
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/actions/EnableLoadMetersAction.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/actions/EnableLoadMetersAction.java
new file mode 100644
index 0000000..d4061ff
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/actions/EnableLoadMetersAction.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ * 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:
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.actions;
+
+import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.MulticoreVisualizerUIPlugin;
+import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.view.MulticoreVisualizer;
+import org.eclipse.cdt.visualizer.ui.VisualizerAction;
+
+/**
+ * @since 1.1
+ */
+public class EnableLoadMetersAction extends VisualizerAction {
+
+ /** Visualizer instance we're associated with. */
+ MulticoreVisualizer m_visualizer = null;
+
+ boolean m_enabled = false;
+
+ public EnableLoadMetersAction(boolean enable) {
+ m_enabled = enable;
+ setText(getTextToDisplay());
+ setDescription(MulticoreVisualizerUIPlugin.getString(
+ "MulticoreVisualizer.actions.EnableLoadMeter.description")); //$NON-NLS-1$
+ }
+
+ /** Dispose method. */
+ @Override
+ public void dispose()
+ {
+ m_visualizer = null;
+ super.dispose();
+ }
+
+ // --- init methods ---
+
+ /** Initializes this action for the specified view. */
+ public void init(MulticoreVisualizer visualizer)
+ {
+ m_visualizer = visualizer;
+ }
+
+
+ // --- methods ---
+
+ private String getTextToDisplay() {
+ if(m_enabled) {
+ return MulticoreVisualizerUIPlugin.getString(
+ "MulticoreVisualizer.actions.EnableLoadMeter.Disable.text"); //$NON-NLS-1$
+ }
+ else {
+ return MulticoreVisualizerUIPlugin.getString(
+ "MulticoreVisualizer.actions.EnableLoadMeter.Enable.text"); //$NON-NLS-1$
+ }
+ }
+
+ /** Invoked when action is triggered. */
+ @Override
+ public void run() {
+ if (m_visualizer != null) {
+ // toggle enabled state
+ m_enabled = !m_enabled;
+ m_visualizer.setLoadMetersEnabled(m_enabled);
+ m_visualizer.refresh();
+
+ setText(getTextToDisplay());
+ }
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/actions/SetLoadMeterPeriodAction.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/actions/SetLoadMeterPeriodAction.java
new file mode 100644
index 0000000..5e4be80
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/actions/SetLoadMeterPeriodAction.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ * 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:
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.actions;
+
+import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.MulticoreVisualizerUIPlugin;
+import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.view.MulticoreVisualizer;
+import org.eclipse.cdt.visualizer.ui.VisualizerAction;
+
+/**
+ * @since 1.1
+ */
+public class SetLoadMeterPeriodAction extends VisualizerAction {
+
+
+ /** Visualizer instance we're associated with. */
+ MulticoreVisualizer m_visualizer = null;
+
+ final int m_period;
+
+ public SetLoadMeterPeriodAction(String label, int period) {
+ super(label, AS_RADIO_BUTTON);
+ m_period = period;
+
+ setDescription(MulticoreVisualizerUIPlugin.getString(
+ "MulticoreVisualizer.actions.SetLoadMeterPeriod.description")); //$NON-NLS-1$
+ }
+
+ /** Dispose method. */
+ @Override
+ public void dispose()
+ {
+ m_visualizer = null;
+ super.dispose();
+ }
+
+ // --- init methods ---
+
+ /** Initializes this action for the specified view. */
+ public void init(MulticoreVisualizer visualizer)
+ {
+ m_visualizer = visualizer;
+ }
+
+ /** Invoked when action is triggered. */
+ @Override
+ public void run() {
+ if (!isChecked()) return;
+
+ if (m_visualizer != null) {
+ m_visualizer.setLoadMeterTimerPeriod(m_period);
+ }
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerCPU.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerCPU.java
index 1f92161..c70117b 100755
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerCPU.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerCPU.java
@@ -7,6 +7,7 @@
*
* Contributors:
* William R. Swanson (Tilera Corporation) - initial API and implementation
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model;
@@ -29,6 +30,11 @@ public class VisualizerCPU
/** ID of this core. */
public int m_id;
+ /** Contains load information
+ * @since 1.1
+ */
+ protected VisualizerLoadInfo m_loadinfo;
+
/** List of cores */
protected ArrayList<VisualizerCore> m_cores;
@@ -55,6 +61,7 @@ public class VisualizerCPU
m_coreMap = null;
m_cores.clear();
m_cores = null;
+ m_loadinfo = null;
}
}
@@ -75,6 +82,23 @@ public class VisualizerCPU
return m_id;
}
+ /** sets the load info for this CPU
+ * @since 1.1*/
+ public synchronized void setLoadInfo (VisualizerLoadInfo info) {
+ m_loadinfo = info;
+ }
+
+ /** Gets the CPU usage load of this CPU.
+ * @since 1.1*/
+ public synchronized Integer getLoad() {
+ return (m_loadinfo == null) ? null : m_loadinfo.getLoad();
+ }
+
+ /** get the highest recorded load for this CPU
+ * @since 1.1*/
+ public synchronized Integer getHighLoadWatermark() {
+ return (m_loadinfo == null) ? null : m_loadinfo.getHighLoadWaterMark();
+ }
// --- methods ---
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerCore.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerCore.java
index 87bc1c5..4d2e657 100755
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerCore.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerCore.java
@@ -7,6 +7,7 @@
*
* Contributors:
* William R. Swanson (Tilera Corporation) - initial API and implementation
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model;
@@ -23,6 +24,10 @@ public class VisualizerCore
/** Linux CPU ID of this core. */
public int m_id = 0;
+ /** Contains load information
+ * @since 1.1
+ */
+ protected VisualizerLoadInfo m_loadinfo;
// --- constructors/destructors ---
@@ -34,6 +39,7 @@ public class VisualizerCore
/** Dispose method */
public void dispose() {
+ m_loadinfo = null;
}
@@ -57,6 +63,24 @@ public class VisualizerCore
public int getID() {
return m_id;
}
+
+ /** sets the load info for this core
+ * @since 1.1*/
+ public synchronized void setLoadInfo (VisualizerLoadInfo info) {
+ m_loadinfo = info;
+ }
+
+ /** Gets the CPU usage load of this core.
+ * @since 1.1*/
+ public synchronized Integer getLoad() {
+ return (m_loadinfo == null) ? null : m_loadinfo.getLoad();
+ }
+
+ /** get the highest recorded load for this core
+ * @since 1.1*/
+ public synchronized Integer getHighLoadWatermark() {
+ return (m_loadinfo == null) ? null : m_loadinfo.getHighLoadWaterMark();
+ }
// --- methods ---
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerLoadInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerLoadInfo.java
new file mode 100644
index 0000000..f6cef40
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerLoadInfo.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ * 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:
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model;
+
+
+//----------------------------------------------------------------------------
+//VisualizerLoadInfo
+//----------------------------------------------------------------------------
+
+/**
+ * @since 1.1
+ */
+public class VisualizerLoadInfo {
+
+ // --- members ---
+
+ /** load */
+ protected Integer m_load = null;
+
+ /** the high load water-mark */
+ protected Integer m_highLoadWatermark = null;
+
+
+ // --- constructors/destructors ---
+
+ /** constructor */
+ public VisualizerLoadInfo (Integer load) {
+ m_load = load;
+ }
+
+ public VisualizerLoadInfo (Integer load, Integer highLoadWatermark) {
+ this(load);
+ m_highLoadWatermark = highLoadWatermark;
+ }
+
+
+ // --- Object methods ---
+
+ /** Returns string representation. */
+ @Override
+ public String toString() {
+ if(m_highLoadWatermark != null) {
+ return "Load:" + m_load + ", high water-mark:" + m_highLoadWatermark; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ else {
+ return "Load:" + m_load + ", high water-mark: not defined"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ // --- accessors ---
+
+ /** Gets the CPU usage load of this core. */
+ public Integer getLoad() {
+ return m_load;
+ }
+
+ /** get the high load water-mark */
+ public Integer getHighLoadWaterMark() {
+ return m_highLoadWatermark;
+ }
+
+
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerModel.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerModel.java
index d62a714..bdddd3b 100755
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerModel.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/model/VisualizerModel.java
@@ -7,6 +7,7 @@
*
* Contributors:
* William R. Swanson (Tilera Corporation) - initial API and implementation
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model;
@@ -38,12 +39,17 @@ public class VisualizerModel
/** Completion state tracker. */
protected Todo m_todo;
+ /** Completion state tracker for load meters. */
+ protected Todo m_loadTodo;
+
// Setting to remove exited threads, or keep them shown.
// If we are to support this, we should have a preference
// and a way to for the user to clean up old threads,
// or maybe a timeout to remove them.
private boolean m_keepExitedThreads = false;
+ protected boolean m_loadMetersEnabled = false;
+
// --- constructors/destructors ---
/** Constructor */
@@ -52,6 +58,7 @@ public class VisualizerModel
m_cpuMap = new Hashtable<Integer, VisualizerCPU>();
m_threads = new ArrayList<VisualizerThread>();
m_todo = new Todo();
+ m_loadTodo = new Todo();
}
/** Dispose method */
@@ -76,6 +83,10 @@ public class VisualizerModel
m_todo.dispose();
m_todo = null;
}
+ if (m_loadTodo != null) {
+ m_loadTodo.dispose();
+ m_loadTodo = null;
+ }
}
@@ -86,6 +97,19 @@ public class VisualizerModel
return m_todo;
}
+ /** Gets completion state tracker. */
+ public Todo getLoadTodo() {
+ return m_loadTodo;
+ }
+
+ public void setLoadMetersEnabled (boolean enable) {
+ m_loadMetersEnabled = enable;
+ }
+
+ public boolean getLoadMetersEnabled () {
+ return m_loadMetersEnabled;
+ }
+
// --- methods ---
/** Sorts cores, cpus, etc. by IDs. */
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/IMulticoreVisualizerConstants.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/IMulticoreVisualizerConstants.java
index 5b3a280..6ec0634 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/IMulticoreVisualizerConstants.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/IMulticoreVisualizerConstants.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Marc Khouzam (Ericsson) - initial API and implementation
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.view;
@@ -49,6 +50,17 @@ public class IMulticoreVisualizerConstants
public static final Color COLOR_CRASHED_CORE_FG = Colors.RED;
public static final Color COLOR_CRASHED_CORE_BG = Colors.DARK_RED;
+ // Colors for drawing CPUs
+
+ /**
+ * @since 1.1
+ */
+ public static final Color COLOR_CPU_FG = Colors.GREEN;
+ /**
+ * @since 1.1
+ */
+ public static final Color COLOR_CPU_BG = Colors.getColor(0,64,0);
+
// Colors for text
/** Color to be used to draw a the text for a thread */
@@ -58,4 +70,28 @@ public class IMulticoreVisualizerConstants
/** Color to be used to draw a the text for a core */
public static final Color COLOR_CORE_TEXT_FG = Colors.WHITE;
public static final Color COLOR_CORE_TEXT_BG = Colors.BLACK;
+
+ /** Color to be used to draw the load text
+ * @since 1.1
+ */
+ public static final Color COLOR_LOAD_TEXT = Colors.GREEN;
+
+ // Colors for load meters
+
+ /**
+ * @since 1.1
+ */
+ public static final Color COLOR_LOAD_LOADBAR_NORMAL = Colors.GREEN;
+ /**
+ * @since 1.1
+ */
+ public static final Color COLOR_LOAD_LOADBAR_OVERLOAD = Colors.RED;
+ /**
+ * @since 1.1
+ */
+ public static final Color COLOR_LOAD_UNDERBAR_FG = Colors.getColor(0,200,0);
+ /**
+ * @since 1.1
+ */
+ public static final Color COLOR_LOAD_UNDERBAR_BG_DEFAULT = Colors.getColor(0,64,0);
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizer.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizer.java
index f9ea96a..76910a4 100755
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizer.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizer.java
@@ -9,10 +9,12 @@
* William R. Swanson (Tilera Corporation) - initial API and implementation
* IBM Corporation
* Marc Dumais (Ericsson) - Bug 399281
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.view;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -24,11 +26,15 @@ import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMData;
import org.eclipse.cdt.dsf.gdb.launching.GDBProcess;
import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
+import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.MulticoreVisualizerUIPlugin;
+import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.actions.EnableLoadMetersAction;
import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.actions.RefreshAction;
import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.actions.SelectAllAction;
+import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.actions.SetLoadMeterPeriodAction;
import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model.VisualizerCPU;
import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model.VisualizerCore;
import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model.VisualizerExecutionState;
+import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model.VisualizerLoadInfo;
import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model.VisualizerModel;
import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model.VisualizerThread;
import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils.DSFDebugModel;
@@ -37,6 +43,7 @@ import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils.DSFSessionStat
import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils.DebugViewUtils;
import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.ICPUDMContext;
import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.ICoreDMContext;
+import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2.ILoadInfo;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
@@ -46,6 +53,7 @@ import org.eclipse.cdt.visualizer.ui.plugin.CDTVisualizerUIPlugin;
import org.eclipse.cdt.visualizer.ui.util.Colors;
import org.eclipse.cdt.visualizer.ui.util.GUIUtils;
import org.eclipse.cdt.visualizer.ui.util.SelectionUtils;
+import org.eclipse.cdt.visualizer.ui.util.Timer;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.internal.ui.commands.actions.DropToFrameCommandAction;
@@ -63,6 +71,7 @@ import org.eclipse.debug.internal.ui.views.launch.LaunchView;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
@@ -107,6 +116,39 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
/** Model changed listener, attached to Debug View. */
protected IModelChangedListener m_modelChangedListener = null;
+ // These two arrays are used to cache the CPU and core
+ // contexts, each time the model is recreated. This way
+ // we can avoid asking the backend for the CPU/core
+ // geometry each time we want to update the load information.
+ /**
+ * @since 1.1
+ */
+ protected ICPUDMContext[] m_cpuContextsCache = null;
+ /**
+ * @since 1.1
+ */
+ protected ICoreDMContext[] m_coreContextsCache = null;
+
+ /**
+ * Main switch that determines if we should display the load meters
+ * @since 1.1
+ */
+ protected boolean m_loadMetersEnabled = false;
+ /**
+ * Timer used to trigger the update of the CPU/core load meters
+ * @since 1.1
+ */
+ protected Timer m_updateLoadMeterTimer = null;
+ /**
+ * @since 1.1
+ */
+ protected int m_loadMeterTimerPeriod = LOAD_METER_TIMER_MEDIUM; // default 1000ms
+ // Load meters refresh periods, in ms
+ private static final int LOAD_METER_TIMER_MIN = 100;
+ private static final int LOAD_METER_TIMER_FAST = 500;
+ private static final int LOAD_METER_TIMER_MEDIUM = 1000;
+ private static final int LOAD_METER_TIMER_SLOW = 5000;
+
// --- UI members ---
@@ -143,6 +185,17 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
/** Toolbar / menu action */
RefreshAction m_refreshAction = null;
+ /** Sub-menu */
+ IMenuManager m_loadMetersSubMenu = null;
+ /** Sub-sub menu */
+ IMenuManager m_loadMetersRefreshSubSubmenu = null;
+
+ /** Menu action */
+ EnableLoadMetersAction m_enableLoadMetersAction = null;
+
+ /** Menu action */
+ List<SetLoadMeterPeriodAction> m_setLoadMeterPeriodActions = null;
+
// --- constructors/destructors ---
@@ -158,6 +211,7 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
super.dispose();
removeDebugViewerListener();
disposeActions();
+ disposeLoadMeterTimer();
}
@@ -169,6 +223,26 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
fEventListener = new MulticoreVisualizerEventListener(this);
}
+ /**
+ * @since 1.1
+ */
+ protected void initializeLoadMeterTimer() {
+ if (!m_loadMetersEnabled) return;
+ m_updateLoadMeterTimer = DSFDebugModel.getLoadTimer(m_sessionState, m_loadMeterTimerPeriod, this);
+ // one-shot timer (re-scheduled upon successful triggering)
+ m_updateLoadMeterTimer.setRepeating(false);
+ }
+
+ /**
+ * @since 1.1
+ */
+ protected void disposeLoadMeterTimer() {
+ if(m_updateLoadMeterTimer != null) {
+ m_updateLoadMeterTimer.dispose();
+ m_updateLoadMeterTimer = null;
+ }
+ }
+
/** Invoked when visualizer is disposed, to permit any cleanup. */
@Override
public void disposeVisualizer()
@@ -198,6 +272,28 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
return Messages.MulticoreVisualizer_tooltip;
}
+ /**
+ * @since 1.1
+ */
+ public void setLoadMeterTimerPeriod(int p) {
+ assert (p > LOAD_METER_TIMER_MIN);
+ if (m_loadMeterTimerPeriod == p) return;
+ m_loadMeterTimerPeriod = p > LOAD_METER_TIMER_MIN ? p : LOAD_METER_TIMER_MIN;
+ disposeLoadMeterTimer();
+ initializeLoadMeterTimer();
+ }
+
+ /**
+ * @since 1.1
+ */
+ public void setLoadMetersEnabled(boolean enabled) {
+ if (m_loadMetersEnabled == enabled) return;
+ m_loadMetersEnabled = enabled;
+ // save load meter enablement in model
+ fDataModel.setLoadMetersEnabled(m_loadMetersEnabled);
+ disposeLoadMeterTimer();
+ initializeLoadMeterTimer();
+ }
// --- canvas management ---
@@ -219,6 +315,7 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
m_canvas.dispose();
m_canvas = null;
}
+ disposeLoadMeterTimer();
}
/** Invoked after visualizer control creation, */
@@ -285,6 +382,37 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
m_refreshAction = new RefreshAction();
m_refreshAction.init(this);
+
+ // create load meters sub-menu and associated actions
+ m_loadMetersSubMenu = new MenuManager(MulticoreVisualizerUIPlugin.getString(
+ "MulticoreVisualizer.actions.LoadMeterSubmenu.text")); //$NON-NLS-1$
+ m_loadMetersRefreshSubSubmenu = new MenuManager(MulticoreVisualizerUIPlugin.getString(
+ "MulticoreVisualizer.actions.LoadMetersRefreshSubSubmenu.text")); //$NON-NLS-1$
+
+ m_enableLoadMetersAction = new EnableLoadMetersAction(m_loadMetersEnabled);
+ m_enableLoadMetersAction.init(this);
+ // enable the load meter sub-menu
+ m_enableLoadMetersAction.setEnabled(true);
+
+ m_setLoadMeterPeriodActions = new ArrayList<SetLoadMeterPeriodAction>();
+ m_setLoadMeterPeriodActions.add(new SetLoadMeterPeriodAction(
+ MulticoreVisualizerUIPlugin.getString("MulticoreVisualizer.actions.SetLoadMeterPeriod.fast.text"), //$NON-NLS-1$
+ LOAD_METER_TIMER_FAST));
+
+ SetLoadMeterPeriodAction defaultAction = new SetLoadMeterPeriodAction(
+ MulticoreVisualizerUIPlugin.getString("MulticoreVisualizer.actions.SetLoadMeterPeriod.medium.text"), //$NON-NLS-1$
+ LOAD_METER_TIMER_MEDIUM);
+ m_setLoadMeterPeriodActions.add(defaultAction);
+
+ m_setLoadMeterPeriodActions.add(new SetLoadMeterPeriodAction(
+ MulticoreVisualizerUIPlugin.getString("MulticoreVisualizer.actions.SetLoadMeterPeriod.slow.text"), //$NON-NLS-1$
+ LOAD_METER_TIMER_SLOW));
+ for (SetLoadMeterPeriodAction act : m_setLoadMeterPeriodActions) {
+ act.init(this);
+ act.setEnabled(true);
+ }
+ defaultAction.setChecked(true);
+ defaultAction.run();
// Note: debug view may not be initialized at startup,
// so we'll pretend the actions are not yet updated,
@@ -301,6 +429,10 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
m_selectAllAction.setEnabled(enabled);
m_refreshAction.setEnabled(enabled);
+ // show the load meter refresh speed sub-menu only
+ // if the load meters are enabled
+ m_loadMetersRefreshSubSubmenu.setVisible(m_loadMetersEnabled);
+
// We should not change the enablement of the debug view
// actions, as they are automatically enabled/disabled
// by the platform.
@@ -358,6 +490,30 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
m_refreshAction = null;
}
+
+ if (m_loadMetersSubMenu != null) {
+ m_loadMetersSubMenu.dispose();
+ m_loadMetersSubMenu = null;
+ }
+
+ if (m_loadMetersRefreshSubSubmenu != null) {
+ m_loadMetersRefreshSubSubmenu.dispose();
+ m_loadMetersRefreshSubSubmenu = null;
+ }
+
+ if (m_enableLoadMetersAction != null ) {
+ m_enableLoadMetersAction.dispose();
+ m_enableLoadMetersAction = null;
+ }
+
+ if (m_setLoadMeterPeriodActions != null) {
+ for (SetLoadMeterPeriodAction act : m_setLoadMeterPeriodActions) {
+ act.dispose();
+ }
+ m_setLoadMeterPeriodActions.clear();
+ m_setLoadMeterPeriodActions = null;
+ }
+
m_actionsInitialized = false;
}
@@ -420,6 +576,21 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
menuManager.add(m_selectAllAction);
menuManager.add(m_refreshAction);
+ menuManager.add(m_separatorAction);
+
+ // add load meters sub-menus and actions
+ m_loadMetersSubMenu.removeAll();
+ m_loadMetersRefreshSubSubmenu.removeAll();
+
+ menuManager.add(m_loadMetersSubMenu);
+
+ m_loadMetersSubMenu.add(m_enableLoadMetersAction);
+ m_loadMetersSubMenu.add(m_loadMetersRefreshSubSubmenu);
+
+ for (SetLoadMeterPeriodAction act : m_setLoadMeterPeriodActions) {
+ m_loadMetersRefreshSubSubmenu.add(act);
+ }
+
updateActions();
Point location = m_viewer.getContextMenuLocation();
updateContextMenuActions(location);
@@ -663,6 +834,11 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
if (m_sessionState != null &&
! m_sessionState.getSessionID().equals(sessionId))
{
+ // stop timer that updates the load meters
+ disposeLoadMeterTimer();
+ m_cpuContextsCache = null;
+ m_coreContextsCache = null;
+
m_sessionState.removeServiceEventListener(fEventListener);
m_sessionState.dispose();
m_sessionState = null;
@@ -674,6 +850,8 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
{
m_sessionState = new DSFSessionState(sessionId);
m_sessionState.addServiceEventListener(fEventListener);
+ // start timer that updates the load meters
+ initializeLoadMeterTimer();
changed = true;
}
@@ -762,6 +940,8 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
/** Invoked when getModel() request completes. */
@ConfinedToDsfExecutor("getSession().getExecutor()")
public void getVisualizerModelDone(VisualizerModel model) {
+ fDataModel.setLoadMetersEnabled(m_loadMetersEnabled);
+ updateLoads();
model.sort();
setCanvasModel(model);
}
@@ -774,6 +954,8 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
@ConfinedToDsfExecutor("getSession().getExecutor()")
public void getCPUsDone(ICPUDMContext[] cpuContexts, Object arg)
{
+ // save CPU contexts
+ m_cpuContextsCache = cpuContexts;
VisualizerModel model = (VisualizerModel) arg;
if (cpuContexts == null || cpuContexts.length == 0) {
@@ -811,6 +993,8 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
ICoreDMContext[] coreContexts,
Object arg)
{
+ // save core contexts
+ m_coreContextsCache = coreContexts;
VisualizerModel model = (VisualizerModel) arg;
if (coreContexts == null || coreContexts.length == 0) {
@@ -924,6 +1108,70 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
done(1, model);
}
+
+ /**
+ * @since 1.1
+ */
+ @ConfinedToDsfExecutor("getSession().getExecutor()")
+ @Override
+ public void updateLoads() {
+ if (m_cpuContextsCache == null || m_coreContextsCache == null) {
+ // not ready to get load info yet
+ return;
+ }
+ // if meters not enabled, do not query backend
+ if (!m_loadMetersEnabled) {
+ return;
+ }
+
+ VisualizerModel model = fDataModel;
+
+ // keep track of how many loads we expect
+ int count = m_cpuContextsCache.length + m_coreContextsCache.length;
+ model.getLoadTodo().dispose();
+ model.getLoadTodo().add(count);
+
+ // ask load for each CPU
+ for (ICPUDMContext cpuCtx : m_cpuContextsCache) {
+ DSFDebugModel.getLoad(m_sessionState, cpuCtx, this, model);
+ }
+ // ask load for each core
+ for (ICoreDMContext coreCtx : m_coreContextsCache) {
+ DSFDebugModel.getLoad(m_sessionState, coreCtx, this, model);
+ }
+ }
+
+ /**
+ * Invoked when a getLoad() request completes.
+ * @since 1.1*/
+ @Override
+ @ConfinedToDsfExecutor("getSession().getExecutor()")
+ public void getLoadDone(IDMContext context, ILoadInfo load, Object arg)
+ {
+ VisualizerModel model = (VisualizerModel) arg;
+ Integer l = null;
+
+ if (load != null) {
+ l = Integer.valueOf(load.getLoad());
+ }
+
+ // CPU context? Update the correct CPU in the model
+ if (context instanceof ICPUDMContext) {
+ ICPUDMContext cpuContext = (ICPUDMContext) context;
+ VisualizerCPU cpu = model.getCPU(Integer.parseInt(cpuContext.getId()));
+ cpu.setLoadInfo(new VisualizerLoadInfo(l));
+ }
+ // Core context? Update the correct core in the model
+ else if(context instanceof ICoreDMContext) {
+ ICoreDMContext coreContext = (ICoreDMContext) context;
+ VisualizerCore core = model.getCore(Integer.parseInt(coreContext.getId()));
+ core.setLoadInfo(new VisualizerLoadInfo(l));
+ }
+
+ loadDone(1, model);
+ }
+
+
/** Update "done" count for current visualizer model. */
protected void done(int n, VisualizerModel model) {
model.getTodo().done(n);
@@ -931,5 +1179,21 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer
getVisualizerModelDone(model);
}
}
+
+ /** Update "done" count for current visualizer model. */
+ protected void loadDone(int n, VisualizerModel model) {
+ model.getLoadTodo().done(n);
+ if (model.getLoadTodo().isDone()) {
+ // canvas may have been disposed since the transaction has started
+ if (m_canvas != null) {
+ m_canvas.refreshLoadMeters();
+ m_canvas.requestUpdate();
+ }
+ if (m_updateLoadMeterTimer != null) {
+ // re-start timer
+ m_updateLoadMeterTimer.start();
+ }
+ }
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCPU.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCPU.java
index fc0cf24..423610b 100755
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCPU.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCPU.java
@@ -7,6 +7,7 @@
*
* Contributors:
* William R. Swanson (Tilera Corporation) - initial API and implementation
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.view;
@@ -14,7 +15,6 @@ package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.view;
import java.util.ArrayList;
import java.util.List;
-import org.eclipse.cdt.visualizer.ui.util.Colors;
import org.eclipse.cdt.visualizer.ui.util.GUIUtils;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
@@ -32,6 +32,22 @@ public class MulticoreVisualizerCPU extends MulticoreVisualizerGraphicObject
/** Child cores. */
protected ArrayList<MulticoreVisualizerCore> m_cores;
+ /**
+ * Load meter associated to this CPU
+ * @since 1.1
+ */
+ protected MulticoreVisualizerLoadMeter m_loadMeter;
+
+ /**
+ * @since 1.1
+ */
+ protected static final Color BG_COLOR = IMulticoreVisualizerConstants.COLOR_CPU_BG;
+
+ /**
+ * @since 1.1
+ */
+ protected static final Color FG_COLOR = IMulticoreVisualizerConstants.COLOR_CPU_FG;
+
// --- constructors/destructors ---
@@ -40,12 +56,18 @@ public class MulticoreVisualizerCPU extends MulticoreVisualizerGraphicObject
{
m_id = id;
m_cores = new ArrayList<MulticoreVisualizerCore>();
+
+ // default load meter
+ m_loadMeter = new MulticoreVisualizerLoadMeter(null, null);
}
/** Dispose method */
@Override
public void dispose() {
super.dispose();
+ if (m_loadMeter != null) {
+ m_loadMeter.dispose();
+ }
}
@@ -77,17 +99,30 @@ public class MulticoreVisualizerCPU extends MulticoreVisualizerGraphicObject
return m_cores;
}
+ /**
+ * @since 1.1
+ */
+ public void setLoadMeter (MulticoreVisualizerLoadMeter meter) {
+ m_loadMeter = meter;
+ }
+
+ /**
+ * @since 1.1
+ */
+ public MulticoreVisualizerLoadMeter getLoadMeter() {
+ return m_loadMeter;
+ }
// --- paint methods ---
/** Invoked to allow element to paint itself on the viewer canvas */
@Override
public void paintContent(GC gc) {
- Color fg, bg;
- fg = Colors.getColor(0,255,0);
- bg = Colors.getColor(0,64,0);
- gc.setForeground(fg);
- gc.setBackground(bg);
+ gc.setForeground(FG_COLOR);
+ gc.setBackground(BG_COLOR);
+
+ // We want the load meter to share the same BG color
+ m_loadMeter.setParentBgColor(BG_COLOR);
gc.fillRectangle(m_bounds);
gc.drawRectangle(m_bounds);
@@ -103,15 +138,13 @@ public class MulticoreVisualizerCPU extends MulticoreVisualizerGraphicObject
@Override
public void paintDecorations(GC gc) {
if (m_bounds.height > 20) {
- Color fg, bg;
- fg = Colors.getColor(0,255,0);
- bg = Colors.getColor(0,64,0);
- gc.setForeground(fg);
- gc.setBackground(bg);
+ gc.setForeground(IMulticoreVisualizerConstants.COLOR_CPU_FG);
+ gc.setBackground(IMulticoreVisualizerConstants.COLOR_CPU_BG);
- int text_indent = 6;
- int tx = m_bounds.x + m_bounds.width - text_indent;
- int ty = m_bounds.y + m_bounds.height - text_indent;
+ int text_indent_x = 6;
+ int text_indent_y = 2;
+ int tx = m_bounds.x + m_bounds.width - text_indent_x;
+ int ty = m_bounds.y + m_bounds.height - text_indent_y;
GUIUtils.drawTextAligned(gc, Integer.toString(m_id), tx, ty, false, false);
}
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCanvas.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCanvas.java
index 093501c..9ba43fe 100755
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCanvas.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCanvas.java
@@ -12,11 +12,13 @@
* Marc Dumais (Ericsson) - Bug 396200
* Marc Dumais (Ericsson) - Bug 396293
* Marc Dumais (Ericsson) - Bug 399281
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.view;
import java.util.ArrayList;
+import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
@@ -76,6 +78,12 @@ public class MulticoreVisualizerCanvas extends GraphicCanvas
*/
protected boolean m_recacheSizes = true;
+ /**
+ * Whether the load information has changed and we need to update the load meters
+ * @since 1.1
+ */
+ protected boolean m_recacheLoadMeters = true;
+
/** Whether we need to repaint the canvas */
protected boolean m_update = true;
@@ -283,6 +291,13 @@ public class MulticoreVisualizerCanvas extends GraphicCanvas
requestUpdate();
}
+ /**
+ * only update the load meters
+ * @since 1.1
+ */
+ public void refreshLoadMeters() {
+ requestRecache(false, false, true);
+ }
// --- resize methods ---
@@ -316,16 +331,26 @@ public class MulticoreVisualizerCanvas extends GraphicCanvas
/** Requests that next paint call should recache state and/or size information */
// synchronized so we don't change recache flags while doing a recache
public synchronized void requestRecache() {
- requestRecache(true, true);
+ requestRecache(true, true, true);
}
/** Requests that next paint call should recache state and/or size information */
// synchronized so we don't change recache flags while doing a recache
public synchronized void requestRecache(boolean state, boolean sizes) {
+ requestRecache(state, sizes, true);
+ }
+
+ /**
+ * Requests that the next paing call should recache state and/or size and/or load information
+ * @since 1.1
+ */
+ // synchronized so we don't change recache flags while doing a recache
+ public synchronized void requestRecache(boolean state, boolean sizes, boolean load) {
m_recache = true;
// NOTE: we intentionally OR these flags with any pending request(s)
m_recacheState |= state;
m_recacheSizes |= sizes;
+ m_recacheLoadMeters |= load;
}
/** Fits n square items into a rectangle of the specified size.
@@ -372,6 +397,7 @@ public class MulticoreVisualizerCanvas extends GraphicCanvas
m_threads.clear();
m_cpuMap.clear();
m_coreMap.clear();
+ m_threadMap.clear();
// For debugging purposes only, allows us to force a CPU count.
//int cpu_count = 0;
@@ -399,11 +425,40 @@ public class MulticoreVisualizerCanvas extends GraphicCanvas
}
*/
- // we've recached state, which implies recacheing sizes too
+ // we've recached state, which implies recacheing sizes and load meters
m_recacheState = false;
+ m_recacheLoadMeters = true;
m_recacheSizes = true;
}
+ if (m_recacheLoadMeters) {
+ // refresh the visualizer CPU and core load meters
+ if (m_model != null) {
+ Enumeration<VisualizerCPU> modelCpus = m_cpuMap.keys();
+ while (modelCpus.hasMoreElements()) {
+ VisualizerCPU modelCpu = modelCpus.nextElement();
+ MulticoreVisualizerCPU visualizerCpu = m_cpuMap.get(modelCpu);
+ // update CPUs load meter
+ MulticoreVisualizerLoadMeter meter = visualizerCpu.getLoadMeter();
+ meter.setEnabled(m_model.getLoadMetersEnabled());
+ meter.setLoad(modelCpu.getLoad());
+ meter.setHighLoadWatermark(modelCpu.getHighLoadWatermark());
+
+ for (VisualizerCore modelCore : modelCpu.getCores()) {
+ MulticoreVisualizerCore visualizerCore = m_coreMap.get(modelCore);
+ // update cores load meter
+ meter = visualizerCore.getLoadMeter();
+ meter.setEnabled(m_model.getLoadMetersEnabled());
+ meter.setLoad(modelCore.getLoad());
+ meter.setHighLoadWatermark(modelCore.getHighLoadWatermark());
+ }
+ }
+ }
+
+ m_recacheSizes = true;
+ m_recacheLoadMeters = false;
+ }
+
if (m_recacheSizes) {
// avoid doing resize calculations if the model is not ready
if (m_model == null ) {
@@ -416,9 +471,14 @@ public class MulticoreVisualizerCanvas extends GraphicCanvas
int cpu_margin = 8; // margin around edges of CPU grid
int cpu_separation = 6; // spacing between CPUS
- int core_margin = 4; // margin around cores in a CPU
- int core_separation = 2; // spacing between cores
+ // make room when load meters are present, else use a more compact layout
+ int core_margin = m_model.getLoadMetersEnabled() ? 20 : 4; // margin around cores in a CPU
+ int core_separation = m_model.getLoadMetersEnabled() ? 4 : 2; // spacing between cores
+ int loadMeterWidth = core_margin*3/5;
+ int loadMeterHMargin = core_margin/5;
+ int loadMeterHCoreMargin = loadMeterHMargin + 5;
+
// Get overall area we have for laying out content.
Rectangle bounds = getClientArea();
GUIUtils.inset(bounds, cpu_margin);
@@ -442,6 +502,8 @@ public class MulticoreVisualizerCanvas extends GraphicCanvas
int x = bounds.x, y = bounds.y;
for (MulticoreVisualizerCPU cpu : m_cpus) {
cpu.setBounds(x, y, cpu_size-1, cpu_size-1);
+ // put cpu meter in the right margin of the CPU
+ cpu.getLoadMeter().setBounds(x + cpu_size - 2*cpu_margin, y + 2*core_margin, loadMeterWidth, cpu_size-3*core_margin);
int left = x + core_margin;
int cx = left, cy = y + core_margin;
@@ -449,6 +511,13 @@ public class MulticoreVisualizerCanvas extends GraphicCanvas
{
core.setBounds(cx, cy, core_size, core_size);
+ core.getLoadMeter().setBounds(
+ cx + core_size - loadMeterHCoreMargin - loadMeterWidth,
+ cy + core_size * 1 / 3,
+ loadMeterWidth,
+ core_size * 2 / 3 - loadMeterHCoreMargin
+ );
+
cx += core_size + core_separation;
if (cx + core_size + core_margin > x + cpu_size) {
cx = left;
@@ -564,11 +633,15 @@ public class MulticoreVisualizerCanvas extends GraphicCanvas
// paint cpus
for (MulticoreVisualizerCPU cpu : m_cpus) {
cpu.paintContent(gc);
+ cpu.getLoadMeter().paintContent(gc);
+ cpu.getLoadMeter().paintDecorations(gc);
}
// paint cores
for (MulticoreVisualizerCore core : m_cores) {
core.paintContent(gc);
+ core.getLoadMeter().paintContent(gc);
+ core.getLoadMeter().paintDecorations(gc);
}
// paint cpus IDs on top of cores
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCore.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCore.java
index 2772a05..37359cc 100755
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCore.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerCore.java
@@ -7,6 +7,7 @@
*
* Contributors:
* William R. Swanson (Tilera Corporation) - initial API and implementation
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.view;
@@ -36,6 +37,12 @@ public class MulticoreVisualizerCore extends MulticoreVisualizerGraphicObject
/** List of threads currently on this core. */
protected ArrayList<MulticoreVisualizerThread> m_threads;
+ /**
+ * Load meter associated to this core
+ * @since 1.1
+ */
+ protected MulticoreVisualizerLoadMeter m_loadMeter;
+
// --- constructors/destructors ---
/** Constructor */
@@ -44,6 +51,9 @@ public class MulticoreVisualizerCore extends MulticoreVisualizerGraphicObject
if (m_cpu != null) m_cpu.addCore(this);
m_id = id;
m_threads = new ArrayList<MulticoreVisualizerThread>();
+
+ // default load meter
+ m_loadMeter = new MulticoreVisualizerLoadMeter(null, null);
}
/** Dispose method */
@@ -54,6 +64,9 @@ public class MulticoreVisualizerCore extends MulticoreVisualizerGraphicObject
m_threads.clear();
m_threads = null;
}
+ if (m_loadMeter != null) {
+ m_loadMeter.dispose();
+ }
}
@@ -95,6 +108,20 @@ public class MulticoreVisualizerCore extends MulticoreVisualizerGraphicObject
{
return m_threads;
}
+
+ /**
+ * @since 1.1
+ */
+ public void setLoadMeter (MulticoreVisualizerLoadMeter meter) {
+ m_loadMeter = meter;
+ }
+
+ /**
+ * @since 1.1
+ */
+ public MulticoreVisualizerLoadMeter getLoadMeter() {
+ return m_loadMeter;
+ }
/**
* A core state is based on its thread states.
@@ -149,8 +176,12 @@ public class MulticoreVisualizerCore extends MulticoreVisualizerGraphicObject
/** Invoked to allow element to paint itself on the viewer canvas */
@Override
public void paintContent(GC gc) {
+ Color bg = getCoreStateColor(false);
+
gc.setForeground(getCoreStateColor(true));
- gc.setBackground(getCoreStateColor(false));
+ gc.setBackground(bg);
+ // We want the load meter to share the same BG color
+ m_loadMeter.setParentBgColor(bg);
gc.fillRectangle(m_bounds);
gc.drawRectangle(m_bounds);
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerLoadMeter.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerLoadMeter.java
new file mode 100644
index 0000000..9a55a98
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizerLoadMeter.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ * 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:
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.view;
+
+import org.eclipse.cdt.visualizer.ui.util.Colors;
+import org.eclipse.cdt.visualizer.ui.util.GUIUtils;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Rectangle;
+
+/**
+ * @since 1.1
+ */
+public class MulticoreVisualizerLoadMeter extends MulticoreVisualizerGraphicObject {
+
+ // --- members ---
+
+ /** Is this load meter enabled? */
+ protected boolean m_enabled = false;
+
+ /** The current CPU/core load */
+ protected Integer m_currentLoad = null;
+
+ /** the high load water-mark */
+ protected Integer m_highLoadWatermark = null;
+
+ /** second rectangle, that will be displayed to show the load */
+ protected Rectangle m_loadRect = null;
+
+ /** to display the high load water-mark */
+ protected Rectangle m_highWatermarkRect = null;
+
+ /** Switch that permits to hide the load meter when not in overload */
+ protected Boolean m_showOnlyIfOverload = false;
+
+ /** Default overload threshold */
+ protected int m_overloadThreshold = 75;
+
+ /** Permits to have the load meter use the same BG color as its parent */
+ protected Color m_parentBgColor = null;
+
+
+ // --- constructors/destructors ---
+
+ /** Constructor */
+
+ public MulticoreVisualizerLoadMeter(Integer load) {
+ m_currentLoad = load;
+ }
+
+ /** Constructor witch includes the high load water-mark */
+ public MulticoreVisualizerLoadMeter(Integer load, Integer highWatermark) {
+ this(load);
+ m_highLoadWatermark = highWatermark;
+ }
+
+ /** Dispose method */
+ @Override
+ public void dispose() {
+ super.dispose();
+ }
+
+
+ // --- accessors ---
+
+ public void setEnabled (boolean enabled) {
+ m_enabled = enabled;
+ }
+
+ public boolean getEnabled() {
+ return m_enabled;
+ }
+
+ public void setLoad(Integer load) {
+ m_currentLoad = load;
+ }
+
+ /**
+ * @return the load value. If the value is undefined (null), zero is
+ * returned. Method isLoadDefined() can be used to determine is the load
+ * value is defined, in the cases where the difference is important
+ * if needed.
+ */
+ public int getLoad() {
+ return (m_currentLoad != null) ? m_currentLoad : 0;
+ }
+
+ /**
+ * @return true if load is a non-null value, otherwise false.
+ */
+ public boolean isLoadDefined() {
+ return (m_currentLoad != null);
+ }
+
+ public void setHighLoadWatermark(Integer wm) {
+ m_highLoadWatermark = wm;
+ }
+
+ public void setOverloadThreshold (int t) {
+ m_overloadThreshold = t;
+ }
+
+ public void setShowyOnlyIfOverload (Boolean o) {
+ m_showOnlyIfOverload = o;
+ }
+
+ public void setParentBgColor(Color c) {
+ m_parentBgColor = c;
+ }
+
+ // --- paint methods ---
+
+ /** get a color that corresponds to the current load */
+ private Color getLoadColor() {
+
+ if (getLoad() < m_overloadThreshold) {
+ return IMulticoreVisualizerConstants.COLOR_LOAD_LOADBAR_NORMAL;
+ }
+ else {
+ return IMulticoreVisualizerConstants.COLOR_LOAD_LOADBAR_OVERLOAD;
+ }
+ }
+
+ /** Invoked to allow element to paint itself on the viewer canvas */
+ @Override
+ public void paintContent(GC gc) {
+ if (!m_enabled) {
+ return;
+ }
+
+ if (getLoad() < m_overloadThreshold && m_showOnlyIfOverload)
+ return;
+
+ // Show meter only if there is enough space
+ if (m_bounds.height < 30) {
+ return;
+ }
+
+ if (m_parentBgColor == null) {
+ // use default bg color
+ m_parentBgColor = IMulticoreVisualizerConstants.COLOR_LOAD_UNDERBAR_BG_DEFAULT;
+ }
+
+ // Display complete-length load bar
+ gc.setForeground(IMulticoreVisualizerConstants.COLOR_LOAD_UNDERBAR_FG);
+ gc.setBackground(m_parentBgColor);
+ gc.fillRectangle(m_bounds);
+ gc.drawRectangle(m_bounds);
+
+ // Create/display shorter bar over to show current load
+ int x,y,w,h;
+ x = m_bounds.x;
+ y = (int) (m_bounds.y + m_bounds.height * ((100.0f - getLoad()) / 100.0f));
+ w = m_bounds.width;
+ h = (int) (m_bounds.height - m_bounds.height * ((100.0f - getLoad()) / 100.0f));
+
+ m_loadRect = new Rectangle(x, y, w, h);
+ gc.setBackground(getLoadColor());
+ gc.fillRectangle(m_loadRect);
+ gc.drawRectangle(m_loadRect);
+
+ // Display high water-mark, if defined
+ if ( m_highLoadWatermark != null) {
+ x = m_bounds.x - 5;
+ y = (int) (m_bounds.y + m_bounds.height * ((100.0f - m_highLoadWatermark) / 100.0f));
+ w = m_bounds.width + 7;
+ h = 2;
+
+ m_highWatermarkRect = new Rectangle(x, y, w, h);
+ gc.setBackground(Colors.BLACK);
+ gc.setForeground(Colors.DARK_RED);
+ gc.fillRectangle(m_highWatermarkRect);
+ gc.drawRectangle(m_highWatermarkRect);
+ }
+
+ }
+
+ /** Returns true if object has decorations to paint. */
+ @Override
+ public boolean hasDecorations() {
+ return true;
+ }
+
+ /** Invoked to allow element to paint decorations on top of anything drawn on it */
+ @Override
+ public void paintDecorations(GC gc) {
+ String load;
+
+ // display nothing if load meter is not enabled
+ if (!m_enabled)
+ return;
+ // "display only if overload" mode applicable?
+ if (getLoad() < m_overloadThreshold && m_showOnlyIfOverload)
+ return;
+
+ // is there an actual value to display yet?
+ if (isLoadDefined()) {
+ load = Integer.toString(getLoad());
+ }
+ // no
+ else {
+ load = "n/a"; //$NON-NLS-1$
+ }
+
+ // Show load text only if there is enough space
+ if (m_bounds.height > 50) {
+ // Display load in text above the load monitor bar
+ gc.setForeground(IMulticoreVisualizerConstants.COLOR_LOAD_TEXT);
+ int tx = m_bounds.x;
+ int ty = m_bounds.y;
+ GUIUtils.drawTextAligned(gc, load, tx, ty, true, false);
+ }
+ }
+
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/DSFDebugModel.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/DSFDebugModel.java
index d7b65a1..add78f5 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/DSFDebugModel.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/DSFDebugModel.java
@@ -7,6 +7,7 @@
*
* Contributors:
* William R. Swanson (Tilera Corporation) - initial API and implementation
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils;
@@ -14,6 +15,7 @@ package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils;
import java.util.ArrayList;
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
import org.eclipse.cdt.dsf.concurrent.ImmediateCountingRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
@@ -34,8 +36,12 @@ import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS;
import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.ICPUDMContext;
import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.ICoreDMContext;
import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.IHardwareTargetDMContext;
+import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2;
+import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2.ILoadInfo;
import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses.IGdbThreadDMData;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.visualizer.ui.util.Timer;
/** Debugger state information accessors.
@@ -81,6 +87,31 @@ public class DSFDebugModel {
);
}
+
+ /** Request load information for a single CPU or core
+ * @since 1.1*/
+ @ConfinedToDsfExecutor("getSession().getExecutor()")
+ public static void getLoad(DSFSessionState sessionState,
+ final IDMContext context,
+ final DSFDebugModelListener listener,
+ final Object arg)
+ {
+ IGDBHardwareAndOS2 hwService = sessionState.getService(IGDBHardwareAndOS2.class);
+ if (hwService == null) {
+ listener.getLoadDone(context, null, arg);
+ return;
+ }
+
+ hwService.getLoadInfo(context,
+ new ImmediateDataRequestMonitor<ILoadInfo>() {
+ @Override
+ protected void handleCompleted() {
+ listener.getLoadDone(context, getData(), arg);
+ }
+ }
+ );
+ }
+
/** Requests list of Cores.
* Calls back to getCoresDone() on listener. */
@ConfinedToDsfExecutor("getSession().getExecutor()")
@@ -337,4 +368,36 @@ public class DSFDebugModel {
return false;
}
+
+ /**
+ * Creates and returns a timer that refreshes the load meters
+ * @since 1.1
+ */
+ public static Timer getLoadTimer(final DSFSessionState sessionState,
+ final int timeout,
+ final DSFDebugModelListener listener)
+ {
+
+ Timer t = new Timer(timeout) {
+ @Override
+ public void run() {
+ if (sessionState != null) {
+ DsfSession session = DsfSession.getSession(sessionState.getSessionID());
+ if (session != null) {
+ DsfExecutor executor = session.getExecutor();
+ if (executor != null) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ listener.updateLoads();
+ }
+ });
+ }
+ }
+ }
+ }
+ };
+
+ return t;
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/DSFDebugModelListener.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/DSFDebugModelListener.java
index f55a259..2336d6d 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/DSFDebugModelListener.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/DSFDebugModelListener.java
@@ -7,6 +7,7 @@
*
* Contributors:
* William R. Swanson (Tilera Corporation) - initial API and implementation
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils;
@@ -17,6 +18,7 @@ import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMData;
import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model.VisualizerExecutionState;
import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.ICPUDMContext;
import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.ICoreDMContext;
+import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2.ILoadInfo;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
/** Interface for classes that interact with DSFDebugModel.
@@ -64,5 +66,17 @@ public interface DSFDebugModelListener {
IThreadDMData threadData,
VisualizerExecutionState state,
Object arg);
+
+ /**
+ * Invoked when getLoad() request completes.
+ * @since 1.1
+ */
+ public void getLoadDone(IDMContext context, ILoadInfo loads, Object arg);
+ /**
+ * Invoked when the load timer triggers
+ * @since 1.1
+ */
+ public void updateLoads();
+
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatCoreLoads.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatCoreLoads.java
new file mode 100644
index 0000000..fb19f8c
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatCoreLoads.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ * 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:
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class provides a container to store the computed
+ * loads for the various CPU cores.
+ *
+ */
+public class ProcStatCoreLoads {
+ private Map<String, Float> m_coreLoads;
+
+ public ProcStatCoreLoads() {
+ m_coreLoads = new HashMap<String,Float>();
+ }
+
+ public void put(String coreId, Float load) {
+ m_coreLoads.put(coreId,load);
+ }
+
+ /**
+ * @param cpuId: the cpu/core id, as listed in /proc/cpuinfo.
+ * For example, for the core labelled "cpu0" in /proc/stat,
+ * use id "0".
+ * @return The measured load for that core
+ */
+ public Float getLoad(String cpuId) {
+ return m_coreLoads.get("cpu"+cpuId); //$NON-NLS-1$
+ }
+}
+
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatCounters.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatCounters.java
new file mode 100644
index 0000000..c0e1259
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatCounters.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ * 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:
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.gdb.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A class that holds one set of /proc/stat counters.
+ * TODO: extend to more than the tick counters.
+ */
+public class ProcStatCounters {
+ private Map<String,OneCoreTickCounters> fTickCounters = new HashMap<String,OneCoreTickCounters>();
+
+ /**
+ * An object of this class holds one set of core/CPU tick counter values, for a single CPU core
+ */
+ private class OneCoreTickCounters {
+ private int fUser;
+ private int fNice;
+ private int fSystem;
+ private int fIdle;
+ private int fIowait;
+ private int fIrq;
+ private int fSoftirq;
+
+ public OneCoreTickCounters(Integer[] c) {
+ // sanity checks
+ assert (c != null && c.length >= 7);
+ if (c == null || c.length < 7) return;
+
+ fUser = c[0];
+ fNice = c[1];
+ fSystem = c[2];
+ fIdle = c[3];
+ fIowait = c[4];
+ fIrq = c[5];
+ fSoftirq = c[6];
+ }
+
+ /**
+ * @return The sum of all "active" (i.e. non-idle) tick counters
+ */
+ private int getActiveTicks() {
+ return fUser + fNice + fSystem + fIowait + fIrq + fSoftirq;
+ }
+
+ /**
+ * @return The "idle" tick counter
+ */
+ private int getIdleTicks() {
+ return fIdle;
+ }
+ }
+
+ /**
+ *
+ */
+ public ProcStatCounters() {
+ fTickCounters = new HashMap<String,OneCoreTickCounters>();
+ }
+
+ /**
+ * Saves the tick counters for one core
+ * @param core: the core id, as seen in /proc/stat.
+ * @param ticks: Array of tick counters, as read from a CPU/core line in /proc/stat
+ */
+ public void addTickCounters(String core, Integer[] ticks) {
+ fTickCounters.put(core, new OneCoreTickCounters(ticks));
+ }
+
+ /**
+ * Note: It was discovered during testing that sometimes, the counters in
+ * /proc/stat are not updated for a given core, between two measurements.
+ * The cause seems to be that with CPUs such as the i5 and i7, some power-
+ * saving modes can put a core to sleep for a short time. When all counters
+ * for a core are the same for 2 measurements, it can cause a division by
+ * zero below, in the load computing code. Given that this can legitimately
+ * happen, we handle the case and assign a load of zero, when it does.
+ *
+ * @param old: another ProcStatCounters object. If null, will compute the
+ * average load from boot time (i.e. historical load).
+ * @return the load, for each CPU core, computed from the two
+ * sets of counters.
+ */
+ public final ProcStatCoreLoads computeLoads(final ProcStatCounters old) {
+ ProcStatCoreLoads loads = new ProcStatCoreLoads();
+
+ // for each core
+ for(String coreId: fTickCounters.keySet()) {
+ OneCoreTickCounters coreCountersNew = fTickCounters.get(coreId);
+ // Do we have 2 sets of counters to compute the load from?
+ if (old != null) {
+ OneCoreTickCounters coreCountersOld = old.fTickCounters.get(coreId);
+ int diffIdle = coreCountersNew.getIdleTicks() - coreCountersOld.getIdleTicks();
+ int diffActive = coreCountersNew.getActiveTicks() - coreCountersOld.getActiveTicks();
+
+ // Sanity check - we do not expect that the counter should decrease
+ assert(diffIdle >= 0);
+ assert(diffActive >= 0);
+
+ if (diffIdle < 0 || diffActive < 0) {
+ return null;
+ }
+
+ float load;
+ if (diffIdle + diffActive != 0) {
+ load = diffActive / (float)(diffActive + diffIdle);
+ }
+ // Here we catch the cases where a core has been asleep for the whole
+ // measurement period. See note above this method.
+ else {
+ load = 0;
+ }
+ loads.put(coreId, load * 100.0f);
+ }
+ // we have only one set of counters; we will effectively compute the historical load,
+ // from boot time until now.
+ else {
+ int diffIdle = coreCountersNew.getIdleTicks();
+ int diffActive = coreCountersNew.getActiveTicks();
+ assert (diffActive + diffIdle != 0);
+ float load = diffActive / (float)(diffActive + diffIdle);
+ loads.put(coreId, load * 100.0f);
+ }
+ }
+
+ return loads;
+ }
+
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatParser.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatParser.java
new file mode 100644
index 0000000..a69d5cb
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/ProcStatParser.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ * 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:
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.internal;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Marc Dumais
+ * TODO: extend to more than the tick counters.
+ * @see also http://www.linuxhowtos.org/System/procstat.htm
+ */
+public class ProcStatParser {
+
+ private ProcStatCounters cpuCoreCounters;
+ private ProcStatCounters cpuCoreCountersOld;
+
+ public ProcStatParser() {
+
+ }
+
+ /**
+ * Read and parse the /proc/stat file given as param
+ * @param fileName
+ */
+ public void parseStatFile(String fileName) throws FileNotFoundException, NumberFormatException {
+ cpuCoreCountersOld = cpuCoreCounters;
+
+ File statFile = new File(fileName);
+ if (!statFile.exists()) {
+ throw new FileNotFoundException();
+ }
+
+ cpuCoreCounters = new ProcStatCounters();
+ BufferedReader reader = null;
+ try {
+ String coreId;
+ Reader r = new InputStreamReader(new FileInputStream(statFile));
+ reader = new BufferedReader(r);
+ String line;
+ // ex: "cpu0 2048635 3195 385292 66149962 895977 22 36130 0 0 0"
+ // note: we intentionally do not catch the "cpu" (without a core number) line.
+ Pattern patternCpu = Pattern.compile("^(cpu[0-9]+)(.*)$"); //$NON-NLS-1$
+
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+
+ // catch "cpu" lines from /proc/stat
+ Matcher matcherCpu = patternCpu.matcher(line);
+ if (matcherCpu.find()) {
+ Vector<Integer> ticks = new Vector<Integer>();
+ coreId = matcherCpu.group(1);
+ // extract the counters for current cpu line
+ for (String tick : matcherCpu.group(2).trim().split("\\s+")) { //$NON-NLS-1$
+ ticks.add(Integer.parseInt(tick));
+ }
+
+ cpuCoreCounters.addTickCounters(coreId, ticks.toArray(new Integer[ticks.size()]));
+ }
+ }
+
+ } catch (IOException e) {
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ } catch (IOException e) {/* Don't care */}
+ reader = null;
+ }
+
+ }
+
+ /**
+ * @return a Map of the computed CPU/core loads. The load of individual
+ * CPUs/cores can be found with keys "cpuN", where N is the CPU/core
+ * number, starting with 0, as found in /proc/stat .
+ *
+ */
+ public ProcStatCoreLoads getCpuLoad() {
+ return cpuCoreCounters.computeLoads(cpuCoreCountersOld);
+ }
+
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBHardwareAndOS.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBHardwareAndOS.java
index 5a80347..6a69334 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBHardwareAndOS.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBHardwareAndOS.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012 Ericsson and others.
+ * Copyright (c) 2012-2013 Ericsson and others.
* 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
@@ -8,17 +8,22 @@
* Contributors:
* Marc Khouzam (Ericsson) - initial API and implementation
* Marc Khouzam (Ericsson) - Updated to use /proc/cpuinfo for remote targets (Bug 374024)
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.Vector;
+import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
@@ -27,6 +32,7 @@ import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.Immutable;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.DataModelInitializedEvent;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.datamodel.IDMData;
@@ -42,6 +48,8 @@ import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
import org.eclipse.cdt.dsf.gdb.internal.CoreInfo;
import org.eclipse.cdt.dsf.gdb.internal.CoreList;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
+import org.eclipse.cdt.dsf.gdb.internal.ProcStatCoreLoads;
+import org.eclipse.cdt.dsf.gdb.internal.ProcStatParser;
import org.eclipse.cdt.dsf.gdb.internal.service.command.commands.MIMetaGetCPUInfo;
import org.eclipse.cdt.dsf.gdb.internal.service.command.output.MIMetaGetCPUInfoInfo;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
@@ -65,7 +73,7 @@ import org.osgi.framework.BundleContext;
*
* @since 4.1
*/
-public class GDBHardwareAndOS extends AbstractDsfService implements IGDBHardwareAndOS, ICachingService {
+public class GDBHardwareAndOS extends AbstractDsfService implements IGDBHardwareAndOS2, ICachingService {
@Immutable
protected static class GDBCPUDMC extends AbstractDMContext
@@ -152,6 +160,34 @@ public class GDBHardwareAndOS extends AbstractDsfService implements IGDBHardware
}
+ /**
+ * @since 4.2
+ */
+ @Immutable
+ protected class GDBLoadInfo implements ILoadInfo {
+ private String fLoad;
+ private Map<String,String> fDetailedLoad;
+
+ public GDBLoadInfo(String load, Map<String,String> detailedLoad) {
+ fLoad = load;
+ fDetailedLoad = detailedLoad;
+ }
+ public GDBLoadInfo(String load) {
+ this(load, null);
+ }
+ @Override
+ public String getLoad() {
+ return fLoad;
+ }
+ @Override
+ public Map<String,String> getDetailedLoad() {
+ return fDetailedLoad;
+ }
+ }
+
+ // to save queued load info requests for later processing
+ private Map<IDMContext, DataRequestMonitor<ILoadInfo>> fLoadInfoRequestCache;
+
private IGDBControl fCommandControl;
private IGDBBackend fBackend;
private CommandFactory fCommandFactory;
@@ -170,6 +206,19 @@ public class GDBHardwareAndOS extends AbstractDsfService implements IGDBHardware
// Bug 374293
private boolean fSessionInitializationComplete;
+ // used to keep track when we last computed the load
+ private long fLastCpuLoadRefresh = 0;
+ // to keep track if we are already seeking to get the load
+ private boolean fLoadRequestOngoing = false;
+ // Length of the measured sample in ms
+ private final static int LOAD_SAMPLE_DELAY = 250;
+ // To avoid bombarding the remote GDB server, we cache the measured load
+ // and serve it again if requested within a short period of time.
+ private ProcStatCoreLoads fCachedLoads = null;
+ // lifetime of the load cache, in ms
+ private final static int LOAD_CACHE_LIFETIME = 500;
+
+
public GDBHardwareAndOS(DsfSession session) {
super(session);
}
@@ -211,11 +260,13 @@ public class GDBHardwareAndOS extends AbstractDsfService implements IGDBHardware
// handle getting the required cpu info
fFetchCPUInfoCache = new CommandCache(getSession(), new CPUInfoManager());
fFetchCPUInfoCache.setContextAvailable(fCommandControl.getContext(), true);
+ fLoadInfoRequestCache = new HashMap<IDMContext, DataRequestMonitor<ILoadInfo>>();
getSession().addServiceEventListener(this, null);
// Register this service.
register(new String[] { IGDBHardwareAndOS.class.getName(),
+ IGDBHardwareAndOS2.class.getName(),
GDBHardwareAndOS.class.getName() },
new Hashtable<String, String>());
@@ -234,6 +285,7 @@ public class GDBHardwareAndOS extends AbstractDsfService implements IGDBHardware
public void shutdown(RequestMonitor requestMonitor) {
getSession().removeServiceEventListener(this);
fFetchCPUInfoCache.reset();
+ fLoadInfoRequestCache.clear();
unregister();
super.shutdown(requestMonitor);
}
@@ -502,4 +554,251 @@ public class GDBHardwareAndOS extends AbstractDsfService implements IGDBHardware
public void removeCommand(ICommandToken token) { assert false : "Not supported"; } //$NON-NLS-1$
}
+
+ /**
+ * @since 4.2
+ */
+ @Override
+ public boolean isAvailable() {
+ return false;
+ }
+
+ /**
+ * @since 4.2
+ */
+ @Override
+ public void getResourceClasses(IDMContext dmc,
+ DataRequestMonitor<IResourceClass[]> rm) {
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Operation not supported", null)); //$NON-NLS-1$
+ }
+
+ /**
+ * @since 4.2
+ */
+ @Override
+ public void getResourcesInformation(IDMContext dmc, String resourceClassId,
+ DataRequestMonitor<IResourcesInformation> rm) {
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Operation not supported", null)); //$NON-NLS-1$
+ }
+
+
+ /**
+ * This method processes "load info" requests. The load is computed using a
+ * sampling method; two readings of a local or remote /proc/stat file are done
+ * with a delay in between. Then the load is computed from the two samples,
+ * for all CPUs/cores known in the system.
+ *
+ * Because of the method used, it's possible that fast variations in CPU usage will
+ * be missed. However longer load trends should be reflected in the results.
+ *
+ * To avoid generating too much load in the remote case, there is a cache that will
+ * return the already computed load, if requested multiple times in a short period.
+ * There is also a mechanism to queue subsequent requests if one is ongoing. Upon
+ * completion of the ongoing request, any queued request is answered with the load
+ * that was just computed.
+ *
+ * @since 4.2
+ */
+ @Override
+ public void getLoadInfo(final IDMContext context, final DataRequestMonitor<ILoadInfo> rm) {
+ if (!(context instanceof ICoreDMContext) && !(context instanceof ICPUDMContext)) {
+ // we only support getting the load for a CPU or a core
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Load information not supported for this context type", null)); //$NON-NLS-1$
+ return;
+ }
+
+ // The measurement interval should be of a minimum length to be meaningful
+ assert (LOAD_SAMPLE_DELAY >= 100);
+ // so the cache is useful
+ assert (LOAD_CACHE_LIFETIME >= LOAD_SAMPLE_DELAY);
+
+ // This way of computing the CPU load is only applicable to Linux
+ if (!Platform.getOS().equals(Platform.OS_LINUX)) {
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Operation not supported", null)); //$NON-NLS-1$
+ return;
+ }
+
+ // Is a request is already ongoing?
+ if(fLoadRequestOngoing) {
+ // queue current new request
+ fLoadInfoRequestCache.put(context, rm);
+ return;
+ }
+ // no request ongoing, so proceed
+ fLoadRequestOngoing = true;
+
+ // caching mechanism to keep things sane, even if the views(s)
+ // request load information very often.
+ long currentTime = System.currentTimeMillis();
+
+ // time to fetch fresh load information?
+ if (fLastCpuLoadRefresh + LOAD_CACHE_LIFETIME < currentTime) {
+ fLastCpuLoadRefresh = currentTime;
+ }
+ else {
+ // not time yet... re-use cached load data
+ processLoads(context, rm, fCachedLoads);
+ fLoadRequestOngoing = false;
+ return;
+ }
+
+ final ProcStatParser procStatParser = new ProcStatParser();
+ final ICommandControlDMContext dmc = DMContexts.getAncestorOfType(context, ICommandControlDMContext.class);
+ final String statFile = "/proc/stat"; //$NON-NLS-1$
+ final String localFile = "/tmp/" + GdbPlugin.PLUGIN_ID + ".proc.stat." + getSession().getId(); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // Remote debugging? We will ask GDB to get us the /proc/stat file from target, twice, with a delay between.
+ if (fBackend.getSessionType() == SessionType.REMOTE) {
+ fCommandControl.queueCommand(
+ fCommandFactory.createCLIRemoteGet(dmc, statFile, localFile),
+ new ImmediateDataRequestMonitor<MIInfo>(rm) {
+ @Override
+ protected void handleCompleted() {
+ if (! isSuccess()) {
+ fLoadRequestOngoing = false;
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Can't get load info for CPU", null)); //$NON-NLS-1$
+ return;
+ }
+
+ // Success - parse first set of stat counters
+ try {
+ procStatParser.parseStatFile(localFile);
+ } catch (Exception e) {
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Can't get load info for CPU", null)); //$NON-NLS-1$
+ fLoadRequestOngoing = false;
+ return;
+ }
+ // delete temp file
+ new File(localFile).delete();
+
+ getExecutor().schedule(new Runnable() {
+ @Override
+ public void run() {
+ fCommandControl.queueCommand(
+ fCommandFactory.createCLIRemoteGet(dmc, statFile, localFile),
+ new ImmediateDataRequestMonitor<MIInfo>(rm) {
+ @Override
+ protected void handleCompleted() {
+ if (! isSuccess()) {
+ fLoadRequestOngoing = false;
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Can't get load info for CPU", null)); //$NON-NLS-1$
+ return;
+ }
+
+ // Success - parse the second set of stat counters and compute loads
+ try {
+ procStatParser.parseStatFile(localFile);
+ } catch (Exception e) {
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Can't get load info for CPU", null)); //$NON-NLS-1$
+ fLoadRequestOngoing = false;
+ return;
+ }
+ // delete temp file
+ new File(localFile).delete();
+
+ // Compute load
+ fCachedLoads = procStatParser.getCpuLoad();
+ processLoads(context, rm, fCachedLoads);
+
+ // done with request
+ fLoadRequestOngoing = false;
+ // process any queued request
+ for(Entry<IDMContext, DataRequestMonitor<ILoadInfo>> e : fLoadInfoRequestCache.entrySet()) {
+ processLoads(e.getKey(), e.getValue(), fCachedLoads);
+ }
+ fLoadInfoRequestCache.clear();
+ }
+ });
+ }
+ }, LOAD_SAMPLE_DELAY, TimeUnit.MILLISECONDS);
+ }
+ });
+ // Local debugging? Then we can read /proc/stat directly
+ } else {
+ // Read /proc/stat file for the first time
+ try {
+ procStatParser.parseStatFile(statFile);
+ } catch (Exception e) {
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Can't get load info for CPU", null)); //$NON-NLS-1$
+ fLoadRequestOngoing = false;
+ return;
+ }
+
+ // Read /proc/stat file again after a delay
+ getExecutor().schedule(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ procStatParser.parseStatFile(statFile);
+ } catch (Exception e) {
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Can't get load info for CPU", null)); //$NON-NLS-1$
+ fLoadRequestOngoing = false;
+ return;
+ }
+ // compute load
+ fCachedLoads = procStatParser.getCpuLoad();
+ processLoads(context, rm, fCachedLoads);
+
+ // done with request
+ fLoadRequestOngoing = false;
+ // process any queued request
+ for(Entry<IDMContext, DataRequestMonitor<ILoadInfo>> e : fLoadInfoRequestCache.entrySet()) {
+ processLoads(e.getKey(), e.getValue(), fCachedLoads);
+ }
+ fLoadInfoRequestCache.clear();
+ }
+ }, LOAD_SAMPLE_DELAY, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ /**
+ * For a given "load info" request, this method processes the load obtained from the
+ * proc stat parser and creates/sends the response.
+ * @param context
+ * @param rm
+ * @param loads
+ */
+ private void processLoads(final IDMContext context, final DataRequestMonitor<ILoadInfo> rm, final ProcStatCoreLoads loads) {
+
+ // problem with fetching load info
+ if (loads == null) {
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Can't get load info", null)); //$NON-NLS-1$
+ return;
+ }
+ // core context?
+ if (context instanceof ICoreDMContext) {
+ String coreId = ((ICoreDMContext) context).getId();
+ // Integer precision sufficient for our purpose
+ float load = loads.getLoad(coreId);
+ rm.done(new GDBLoadInfo(Integer.toString((int)load)));
+ }
+ else if (context instanceof ICPUDMContext) {
+ // get the list of cores in that CPU
+ getCores(context,
+ new ImmediateDataRequestMonitor<ICoreDMContext[]>() {
+ @Override
+ protected void handleCompleted() {
+ ICoreDMContext[] coreContexts = getData();
+
+ if (!isSuccess() || coreContexts == null || coreContexts.length < 1) {
+ // Unable to get any core data
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Can't get load info for CPU", null)); //$NON-NLS-1$
+ return;
+ }
+
+ int i = 0;
+ float load = 0.0f;
+ // compute the average load of cores in that CPU
+ for (ICoreDMContext coreCtx : coreContexts) {
+ String coreId = coreCtx.getId();
+ load += loads.getLoad(coreId);
+ i++;
+ }
+ load /= i;
+ rm.done(new GDBLoadInfo(Integer.toString((int)load)));
+ }
+ }
+ );
+ }
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBHardwareAndOS2.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBHardwareAndOS2.java
index 256c67d..7c0c3bd 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBHardwareAndOS2.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBHardwareAndOS2.java
@@ -7,10 +7,13 @@
*
* Contributors:
* Vladimir Prus (Mentor Graphics) - initial API and implementation
+ * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
+import java.util.Map;
+
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
@@ -64,4 +67,28 @@ public interface IGDBHardwareAndOS2 extends IGDBHardwareAndOS {
* Return table describing resources of specified class.
*/
void getResourcesInformation(IDMContext dmc, String resourceClassId, DataRequestMonitor<IResourcesInformation> rm);
+
+
+ /**
+ * Information about the CPU/core load for one given CPU or core
+ */
+ public interface ILoadInfo
+ {
+ /**
+ * A string representing the current load (between "0" and "100")
+ */
+ public String getLoad();
+ /**
+ * Used to give more details about a CPU's/core's load. For instance
+ * the breakdown of the different load types and their proportion: system,
+ * user, I/O, interrupts, etc.
+ */
+ public Map<String,String> getDetailedLoad();
+ }
+
+ /**
+ * Computes CPU/core load information according to context and
+ * asynchronously returns the result in a ILoadInfo object
+ */
+ void getLoadInfo(IDMContext dmc, DataRequestMonitor<ILoadInfo> rm);
}
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/Suite_Sessionless_Tests.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/Suite_Sessionless_Tests.java
index de08ef1..3039dee 100644
--- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/Suite_Sessionless_Tests.java
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/Suite_Sessionless_Tests.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - Initial Implementation
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.commands;
@@ -14,6 +15,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIStringHandlerTests;
import org.eclipse.cdt.dsf.mi.service.command.output.MIThreadTests;
import org.eclipse.cdt.tests.dsf.gdb.framework.OnceOnlySuite;
import org.eclipse.cdt.tests.dsf.gdb.tests.LaunchUtilsTest;
+import org.eclipse.cdt.tests.dsf.gdb.tests.ProcStatParserTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -29,7 +31,8 @@ import org.junit.runners.Suite;
TestMICommandConstructCommand.class,
MIThreadTests.class,
LaunchUtilsTest.class,
- MIStringHandlerTests.class
+ MIStringHandlerTests.class,
+ ProcStatParserTest.class
/* Add your test class here */
})
public class Suite_Sessionless_Tests {
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/ProcStatParserTest.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/ProcStatParserTest.java
new file mode 100644
index 0000000..23f2ede
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/ProcStatParserTest.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ * 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:
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
+ *******************************************************************************/
+package org.eclipse.cdt.tests.dsf.gdb.tests;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.eclipse.cdt.dsf.gdb.internal.ProcStatCoreLoads;
+import org.eclipse.cdt.dsf.gdb.internal.ProcStatParser;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ProcStatParserTest {
+
+ final static String stat_t0 = "cpu 27599070 16857 1627173 178832624 958471 10 21253 0 0 0\n" +
+ "cpu0 7076626 3073 420740 44122942 620655 7 19123 0 0 0\n" +
+ "cpu1 6839475 2644 480003 44885633 53738 2 1200 0 0 0\n" +
+ "cpu2 6861775 9347 337505 44860715 195008 0 573 0 0 0\n" +
+ "cpu3 6821192 1792 388924 44963332 89067 0 355 0 0 0\n" +
+ "intr 255054962 1785 9 0 0 0 0 0 0 1 393 0 0 125 0 0 0 1861780 5056689 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3138534 3946219 2295808 199 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
+ "ctxt 406954066\n" +
+ "btime 1357642511\n" +
+ "processes 187587\n" +
+ "procs_running 2\n" +
+ "procs_blocked 0\n" +
+ "softirq 187777133 0 82842161 104536 3977894 3827626 0 3881246 12353598 94844 80695228";
+ final static String stat_t0_file = "/tmp/stat_t0";
+
+ final static String stat_t1 = "cpu 27599216 16857 1627190 178835528 958483 10 21255 0 0 0\n" +
+ "cpu0 7076664 3073 420751 44123650 620668 7 19125 0 0 0\n" +
+ "cpu1 6839509 2644 480004 44886368 53738 2 1200 0 0 0\n" +
+ "cpu2 6861813 9347 337507 44861445 195008 0 573 0 0 0\n" +
+ "cpu3 6821229 1792 388926 44964063 89067 0 355 0 0 0\n" +
+ "intr 255057230 1785 9 0 0 0 0 0 0 1 393 0 0 125 0 0 0 1861874 5056997 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3138618 3946264 2295808 199 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
+ "ctxt 406958462\n" +
+ "btime 1357642511\n" +
+ "processes 187593\n" +
+ "procs_running 5\n" +
+ "procs_blocked 0\n" +
+ "softirq 187779126 0 82842674 104538 3977978 3827690 0 3881346 12353760 94845 80696295";
+ final static String stat_t1_file = "/tmp/stat_t1";
+
+ final static String stat_t2 = "cpu 27602962 16857 1627282 178835528 958483 10 21256 0 0 0\n" +
+ "cpu0 7077593 3073 420781 44123650 620668 7 19126 0 0 0\n" +
+ "cpu1 6840413 2644 480060 44886368 53738 2 1200 0 0 0\n" +
+ "cpu2 6862773 9347 337507 44861445 195008 0 573 0 0 0\n" +
+ "cpu3 6822181 1792 388933 44964063 89067 0 355 0 0 0\n" +
+ "intr 255070028 1785 9 0 0 0 0 0 0 1 393 0 0 125 0 0 0 1861998 5057533 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3138674 3946472 2295808 199 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
+ "ctxt 407001757\n" +
+ "btime 1357642511\n" +
+ "processes 187607\n" +
+ "procs_running 5\n" +
+ "procs_blocked 0\n" +
+ "softirq 187794229 0 82852274 104540 3978034 3827918 0 3881474 12354181 94845 80700963";
+ final static String stat_t2_file = "/tmp/stat_t2";
+
+ // to trigger exception upon parsing
+ final static String stat_wrong_content = "cpu 27602962 16857 1627282 178835528 958483 10 21256 0 0 0\n" +
+ "cpu0 AAAAAAA 3073 420781 44123650 620668 7 19126 0 0 0\n" +
+ "cpu1 AAAAAAA 2644 480060 44886368 53738 2 1200 0 0 0\n" +
+ "cpu2 AAAAAAA 9347 337507 44861445 195008 0 573 0 0 0\n" +
+ "cpu3 AAAAAAA 1792 388933 44964063 89067 0 355 0 0 0\n" +
+ "intr 255070028 1785 9 0 0 0 0 0 0 1 393 0 0 125 0 0 0 1861998 5057533 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3138674 3946472 2295808 199 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
+ "ctxt 407001757\n" +
+ "btime 1357642511\n" +
+ "processes 187607\n" +
+ "procs_running 5\n" +
+ "procs_blocked 0\n" +
+ "softirq 187794229 0 82852274 104540 3978034 3827918 0 3881474 12354181 94845 80700963";
+ final static String stat_wrong_content_file = "/tmp/stat_wrong_content";
+
+
+ @BeforeClass
+ public static void init_once() {
+ // generate test input files once at beginning of tests
+ writeStr2File(stat_t0, stat_t0_file);
+ writeStr2File(stat_t1, stat_t1_file);
+ writeStr2File(stat_t2, stat_t2_file);
+ writeStr2File(stat_wrong_content, stat_wrong_content_file);
+ }
+
+ @AfterClass
+ public static void cleanup() {
+ // cleanup at end of tests
+ new File(stat_t0_file).delete();
+ new File(stat_t1_file).delete();
+ new File(stat_t2_file).delete();
+ new File(stat_wrong_content_file).delete();
+ }
+
+
+
+ // testcases
+
+
+ @Test
+ public void testProcStatParse1() throws Exception {
+ ProcStatParser procStatParser = new ProcStatParser();
+ procStatParser.parseStatFile(stat_t0_file);
+ procStatParser.parseStatFile(stat_t1_file);
+ ProcStatCoreLoads load = procStatParser.getCpuLoad();
+
+ int l0 = (int)load.getLoad("0").floatValue();
+ assertEquals(8,l0);
+ int l1 = (int)load.getLoad("1").floatValue();
+ assertEquals(4,l1);
+ int l2 = (int)load.getLoad("2").floatValue();
+ assertEquals(5,l2);
+ int l3 = (int)load.getLoad("3").floatValue();
+ assertEquals(5,l3);
+ }
+
+ @Test
+ public void testProcStatParse2() throws Exception {
+ ProcStatParser procStatParser = new ProcStatParser();
+ procStatParser.parseStatFile(stat_t1_file);
+ procStatParser.parseStatFile(stat_t2_file);
+ ProcStatCoreLoads load = procStatParser.getCpuLoad();
+
+ int l0 = (int)load.getLoad("0").floatValue();
+ assertEquals(100,l0);
+ int l1 = (int)load.getLoad("1").floatValue();
+ assertEquals(100,l1);
+ int l2 = (int)load.getLoad("2").floatValue();
+ assertEquals(100,l2);
+ int l3 = (int)load.getLoad("3").floatValue();
+ assertEquals(100,l3);
+ }
+
+ @Test
+ public void testProcStatParse3() throws Exception {
+ ProcStatParser procStatParser = new ProcStatParser();
+ procStatParser.parseStatFile(stat_t0_file);
+ procStatParser.parseStatFile(stat_t2_file);
+ ProcStatCoreLoads load = procStatParser.getCpuLoad();
+
+ int l0 = (int)load.getLoad("0").floatValue();
+ assertEquals(59,l0);
+ int l1 = (int)load.getLoad("1").floatValue();
+ assertEquals(57,l1);
+ int l2 = (int)load.getLoad("2").floatValue();
+ assertEquals(57,l2);
+ int l3 = (int)load.getLoad("3").floatValue();
+ assertEquals(57,l3);
+ }
+
+ /**
+ * Reverse the order of the /proc/stat files to cause parsing problem
+ * @throws Exception
+ */
+ @Test
+ public void testProcStatParseWrongOrder() throws Exception {
+ ProcStatParser procStatParser = new ProcStatParser();
+ procStatParser.parseStatFile(stat_t2_file);
+ procStatParser.parseStatFile(stat_t0_file);
+ ProcStatCoreLoads load = procStatParser.getCpuLoad();
+ assertEquals(load, null);
+ }
+
+
+ @Test
+ public void testProcStatParseOneSetOfCounters() throws Exception {
+ ProcStatParser procStatParser = new ProcStatParser();
+ procStatParser.parseStatFile(stat_t0_file);
+ ProcStatCoreLoads load = procStatParser.getCpuLoad();
+
+ int l0 = (int)load.getLoad("0").floatValue();
+ assertEquals(15,l0);
+ int l1 = (int)load.getLoad("1").floatValue();
+ assertEquals(14,l1);
+ int l2 = (int)load.getLoad("2").floatValue();
+ assertEquals(14,l2);
+ int l3 = (int)load.getLoad("3").floatValue();
+ assertEquals(13,l3);
+ }
+
+ @Test(expected=FileNotFoundException.class)
+ public void testStatFileDoesNotExist() throws Exception {
+ ProcStatParser procStatParser = new ProcStatParser();
+ // read non-existing stat file
+ procStatParser.parseStatFile("/file/does/not/exist");
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testStatFileDoesntParse() throws Exception {
+ ProcStatParser procStatParser = new ProcStatParser();
+ // read non-existing stat file
+ procStatParser.parseStatFile(stat_wrong_content_file);
+ }
+
+
+ // util functions
+
+ private static void writeStr2File(String str, String fileName) {
+ FileWriter fileWriter = null;
+ File f = new File(fileName);
+ try {
+ fileWriter = new FileWriter(f);
+ fileWriter.write(str);
+ fileWriter.close();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/visualizer/org.eclipse.cdt.visualizer.ui/src/org/eclipse/cdt/visualizer/ui/VisualizerAction.java b/visualizer/org.eclipse.cdt.visualizer.ui/src/org/eclipse/cdt/visualizer/ui/VisualizerAction.java
index 0098d84..d941822 100755
--- a/visualizer/org.eclipse.cdt.visualizer.ui/src/org/eclipse/cdt/visualizer/ui/VisualizerAction.java
+++ b/visualizer/org.eclipse.cdt.visualizer.ui/src/org/eclipse/cdt/visualizer/ui/VisualizerAction.java
@@ -7,6 +7,7 @@
*
* Contributors:
* William R. Swanson (Tilera Corporation)
+ * Marc Dumais (Ericsson) - Initial API and implementation (Bug 396268)
*******************************************************************************/
package org.eclipse.cdt.visualizer.ui;
@@ -38,6 +39,11 @@ public class VisualizerAction extends Action
}
/** Constructor. */
+ public VisualizerAction(String text, int style) {
+ super(text, style);
+ }
+
+ /** Constructor. */
public VisualizerAction(String text, String description) {
super(text);
setDescription(description);