library <stat>: standardized new category calculations

This commit arose out of the discussion (and research)
surrounding the issue cited below. It is an attempt to
consolidate and standardize the calculation of jiffies
categories (e.g. 'idle', 'busy', etc.) once & for all.

Also included is the enum STAT_TIC_NUM_CONTRIBUTORS in
case anyone, in the future, decides to calculate usage
based upon elapsed time * Hz (like top does in process
level %CPU stats). In such an event, a total number of
CPUs or NUMA Nodes would be needed for proper scaling.

Reference(s):
https://gitlab.com/procps-ng/procps/issues/48

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2016-12-27 08:08:08 -06:00 committed by Craig Small
parent 12e070dd5f
commit 2c86c4984a
2 changed files with 79 additions and 1 deletions

View File

@ -57,6 +57,7 @@
struct stat_jifs {
unsigned long long user, nice, system, idle, iowait, irq, sirq, stolen, guest, gnice;
unsigned long long xtot, xbsy, xidl, xusr, xsys;
};
struct stat_data {
@ -76,6 +77,7 @@ struct hist_sys {
struct hist_tic {
int id;
int numa_node;
int count;
struct stat_jifs new;
struct stat_jifs old;
};
@ -159,6 +161,7 @@ setDECL(extra) { (void)R; (void)S; (void)T; }
setDECL(TIC_ID) { (void)S; R->result.s_int = T->id; }
setDECL(TIC_NUMA_NODE) { (void)S; R->result.s_int = T->numa_node; }
setDECL(TIC_NUM_CONTRIBUTORS) { (void)S; R->result.s_int = T->count; }
TIC_set(TIC_USER, ull_int, user)
TIC_set(TIC_NICE, ull_int, nice)
@ -171,6 +174,12 @@ TIC_set(TIC_STOLEN, ull_int, stolen)
TIC_set(TIC_GUEST, ull_int, guest)
TIC_set(TIC_GUEST_NICE, ull_int, gnice)
TIC_set(TIC_SUM_TOTAL, ull_int, xtot)
TIC_set(TIC_SUM_BUSY, ull_int, xbsy)
TIC_set(TIC_SUM_IDLE, ull_int, xidl)
TIC_set(TIC_SUM_USER, ull_int, xusr)
TIC_set(TIC_SUM_SYSTEM, ull_int, xsys)
TICsetH(TIC_DELTA_USER, sl_int, user)
TICsetH(TIC_DELTA_NICE, sl_int, nice)
TICsetH(TIC_DELTA_SYSTEM, sl_int, system)
@ -182,6 +191,12 @@ TICsetH(TIC_DELTA_STOLEN, sl_int, stolen)
TICsetH(TIC_DELTA_GUEST, sl_int, guest)
TICsetH(TIC_DELTA_GUEST_NICE, sl_int, gnice)
TICsetH(TIC_DELTA_SUM_TOTAL, sl_int, xtot)
TICsetH(TIC_DELTA_SUM_BUSY, sl_int, xbsy)
TICsetH(TIC_DELTA_SUM_IDLE, sl_int, xidl)
TICsetH(TIC_DELTA_SUM_USER, sl_int, xusr)
TICsetH(TIC_DELTA_SUM_SYSTEM, sl_int, xsys)
SYS_set(SYS_CTX_SWITCHES, ul_int, ctxt)
SYS_set(SYS_INTERRUPTS, ul_int, intr)
SYS_set(SYS_PROC_BLOCKED, ul_int, procs_blocked)
@ -276,6 +291,7 @@ static struct {
{ RS(TIC_ID), QS(s_int), TS(s_int) },
{ RS(TIC_NUMA_NODE), QS(s_int), TS(s_int) },
{ RS(TIC_NUM_CONTRIBUTORS), QS(s_int), TS(s_int) },
{ RS(TIC_USER), QS(ull_int), TS(ull_int) },
{ RS(TIC_NICE), QS(ull_int), TS(ull_int) },
{ RS(TIC_SYSTEM), QS(ull_int), TS(ull_int) },
@ -287,6 +303,12 @@ static struct {
{ RS(TIC_GUEST), QS(ull_int), TS(ull_int) },
{ RS(TIC_GUEST_NICE), QS(ull_int), TS(ull_int) },
{ RS(TIC_SUM_TOTAL), QS(ull_int), TS(ull_int) },
{ RS(TIC_SUM_BUSY), QS(ull_int), TS(ull_int) },
{ RS(TIC_SUM_IDLE), QS(ull_int), TS(ull_int) },
{ RS(TIC_SUM_USER), QS(ull_int), TS(ull_int) },
{ RS(TIC_SUM_SYSTEM), QS(ull_int), TS(ull_int) },
{ RS(TIC_DELTA_USER), QS(sl_int), TS(sl_int) },
{ RS(TIC_DELTA_NICE), QS(sl_int), TS(sl_int) },
{ RS(TIC_DELTA_SYSTEM), QS(sl_int), TS(sl_int) },
@ -298,6 +320,12 @@ static struct {
{ RS(TIC_DELTA_GUEST), QS(sl_int), TS(sl_int) },
{ RS(TIC_DELTA_GUEST_NICE), QS(sl_int), TS(sl_int) },
{ RS(TIC_DELTA_SUM_TOTAL), QS(sl_int), TS(sl_int) },
{ RS(TIC_DELTA_SUM_BUSY), QS(sl_int), TS(sl_int) },
{ RS(TIC_DELTA_SUM_IDLE), QS(sl_int), TS(sl_int) },
{ RS(TIC_DELTA_SUM_USER), QS(sl_int), TS(sl_int) },
{ RS(TIC_DELTA_SUM_SYSTEM), QS(sl_int), TS(sl_int) },
{ RS(SYS_CTX_SWITCHES), QS(ul_int), TS(ul_int) },
{ RS(SYS_INTERRUPTS), QS(ul_int), TS(ul_int) },
{ RS(SYS_PROC_BLOCKED), QS(ul_int), TS(ul_int) },
@ -385,6 +413,33 @@ static inline void stat_cleanup_stacks_all (
} // end: stat_cleanup_stacks_all
static inline int stat_derive_unique (
struct hist_tic *this)
{
/* note: we exclude guest tics from xtot since ...
'user' already includes 'guest'
'nice' already includes 'gnice'
( see: ./kernel/sched/cputime.c, account_guest_time ) */
this->new.xtot
= this->new.user
+ this->new.nice
+ this->new.system
+ this->new.idle
+ this->new.iowait
+ this->new.irq
+ this->new.sirq
+ this->new.stolen;
this->new.xusr = this->new.user + this->new.nice;
/* this stolen guy is one i'm not sure of yet, but it's documented as:
"the time spent in other operating systems
when running in a virtualized environment"
so it would seem to apply to an 'involuntary wait' for a guest OS */
this->new.xidl = this->new.idle + this->new.iowait + this->new.stolen;
this->new.xbsy = this->new.xtot - this->new.xidl;
this->new.xsys = this->new.xbsy - this->new.xusr;
} // end: stat_derive_unique
static void stat_extents_free_all (
struct ext_support *this)
{
@ -490,8 +545,15 @@ static int stat_make_numa_hist (
nod_ptr->new.guest += cpu_ptr->new.guest; nod_ptr->old.guest += cpu_ptr->old.guest;
nod_ptr->new.gnice += cpu_ptr->new.gnice; nod_ptr->old.gnice += cpu_ptr->old.gnice;
nod_ptr->new.xtot += cpu_ptr->new.xtot; nod_ptr->old.xtot += cpu_ptr->old.xtot;
nod_ptr->new.xbsy += cpu_ptr->new.xbsy; nod_ptr->old.xbsy += cpu_ptr->old.xbsy;
nod_ptr->new.xidl += cpu_ptr->new.xidl; nod_ptr->old.xidl += cpu_ptr->old.xidl;
nod_ptr->new.xusr += cpu_ptr->new.xusr; nod_ptr->old.xusr += cpu_ptr->old.xusr;
nod_ptr->new.xsys += cpu_ptr->new.xsys; nod_ptr->old.xsys += cpu_ptr->old.xsys;
cpu_ptr->numa_node = node;
nod_ptr->id = node;
nod_ptr->count++; ;
}
}
info->nodes.hist.n_inuse = info->nodes.total;
@ -554,6 +616,7 @@ static int stat_read_failed (
, &sum_ptr->new.sirq, &sum_ptr->new.stolen
, &sum_ptr->new.guest, &sum_ptr->new.gnice))
return -1;
stat_derive_unique(sum_ptr);
// let's not distort the deltas the first time thru ...
if (!info->stat_was_read)
memcpy(&sum_ptr->old, &sum_ptr->new, sizeof(struct stat_jifs));
@ -568,6 +631,7 @@ reap_em_again:
memcpy(&cpu_ptr->old, &cpu_ptr->new, sizeof(struct stat_jifs));
// next can be overridden under 'stat_make_numa_hist'
cpu_ptr->numa_node = STAT_NODE_INVALID;
cpu_ptr->count = 1;
if (8 > (rc = sscanf(bp, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu"
, &cpu_ptr->id
@ -580,6 +644,7 @@ reap_em_again:
cpu_ptr->id = id_sav;
break; // we must tolerate cpus taken offline
}
stat_derive_unique(cpu_ptr);
// let's not distort the deltas the first time thru ...
if (!info->stat_was_read)
memcpy(&cpu_ptr->old, &cpu_ptr->new, sizeof(struct stat_jifs));
@ -595,7 +660,7 @@ reap_em_again:
goto reap_em_again;
}
info->cpus.total = info->cpus.hist.n_inuse = i;
info->cpus.total = info->cpus.hist.n_inuse = sum_ptr->count = i;
// remember sys_hist stuff from last time around
memcpy(&info->sys_hist.old, &info->sys_hist.new, sizeof(struct stat_data));

View File

@ -29,6 +29,7 @@ enum stat_item {
STAT_TIC_ID, // s_int
STAT_TIC_NUMA_NODE, // s_int
STAT_TIC_NUM_CONTRIBUTORS, // s_int
STAT_TIC_USER, // ull_int
STAT_TIC_NICE, // ull_int
STAT_TIC_SYSTEM, // ull_int
@ -40,6 +41,12 @@ enum stat_item {
STAT_TIC_GUEST, // ull_int
STAT_TIC_GUEST_NICE, // ull_int
STAT_TIC_SUM_TOTAL, // ull_int
STAT_TIC_SUM_BUSY, // ull_int
STAT_TIC_SUM_IDLE, // ull_int
STAT_TIC_SUM_USER, // ull_int
STAT_TIC_SUM_SYSTEM, // ull_int
STAT_TIC_DELTA_USER, // sl_int
STAT_TIC_DELTA_NICE, // sl_int
STAT_TIC_DELTA_SYSTEM, // sl_int
@ -51,6 +58,12 @@ enum stat_item {
STAT_TIC_DELTA_GUEST, // sl_int
STAT_TIC_DELTA_GUEST_NICE, // sl_int
STAT_TIC_DELTA_SUM_TOTAL, // sl_int
STAT_TIC_DELTA_SUM_BUSY, // sl_int
STAT_TIC_DELTA_SUM_IDLE, // sl_int
STAT_TIC_DELTA_SUM_USER, // sl_int
STAT_TIC_DELTA_SUM_SYSTEM, // sl_int
STAT_SYS_CTX_SWITCHES, // ul_int
STAT_SYS_INTERRUPTS, // ul_int
STAT_SYS_PROC_BLOCKED, // ul_int