blob: 4a47d1acfe7404834630801443f1f3a972d6130b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Ericsson
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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<>();
/**
* 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<>();
}
/**
* 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;
}
}