mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-15 21:15:23 +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:
parent
52c0edd492
commit
91de353168
23 changed files with 1891 additions and 22 deletions
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ---
|
||||
|
||||
|
|
|
@ -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 ---
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
|
@ -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$
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue