1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-15 13:05:22 +02:00

Bug 396268 - [Visualizer] Add CPU/core load information to the multicore

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>
This commit is contained in:
Marc Dumais 2013-02-28 08:17:19 -05:00 committed by Marc Khouzam
parent 52c0edd492
commit 91de353168
23 changed files with 1891 additions and 22 deletions

View file

@ -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

View file

@ -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());
}
}
}

View file

@ -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);
}
}
}

View file

@ -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 ---

View file

@ -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 ---

View file

@ -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;
}
}

View file

@ -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. */

View file

@ -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);
}

View file

@ -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();
}
}
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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$
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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)));
}
}
);
}
}
}

View file

@ -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);
}

View file

@ -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 {

View file

@ -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();
}
}
}

View file

@ -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;
@ -37,6 +38,11 @@ public class VisualizerAction extends Action
// programmatically.
}
/** Constructor. */
public VisualizerAction(String text, int style) {
super(text, style);
}
/** Constructor. */
public VisualizerAction(String text, String description) {
super(text);