top: snapshot /proc/stat reads to minimize distortions

Almost forever, top has been accessing the /proc/stat/
directory one line at a time until either smp_num_cpus
was reached or (more recently) Screen_rows is reached.

When NUMA/Nodes support is enabled screen rows will no
longer serve as a limit because all cpus must be read.

With this commit, the entire /proc/stat/ directory can
be read at once so all statistics will be frozen. Thus
individual cpus will no longer keep "ticing" until top
gets around to accessing them via some separate fgets.

The distortion this commit eliminates was quite easily
seen when comparing old/new tops using: individual cpu
stats vs. cpu summary; a healthy delay interval of 3-5
seconds; manually synchronized update cycles (the hard
part); some system loading (maybe another top at -d0).

Additionally, this patch eliminates some long standing
unnecessary initialization made possible because of an
allocation via calloc. If some parts are never touched
by sscanf due to a kernel version, it's unnecessary to
repeatedly re-initialize those portions to zero again.

Reference(s):
. numa extensions added
commit 8d989c68c068541a814bf0d2340ac9b0373f24b5
. useless initialization evolution (old to new)
commit e54c8239b1c46cf7b99dd6120c9090303fa969c8
commit 9278134e49b6bf4d6e05c40f63cc6d6d6936e01b
commit fd62123562c2b71f292d3d3ee1a085709048b11a
commit f348575edc915db9df89acfb3f292920726ffe9a

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2013-04-14 00:00:00 -05:00 committed by Craig Small
parent 3ac09447e5
commit d16fd8e462

View File

@ -2289,8 +2289,8 @@ static void zap_fieldstab (void) {
* [ and beyond sumSLOT == tics for each cpu NUMA node ] */
static CPU_t *cpus_refresh (CPU_t *cpus) {
static FILE *fp = NULL;
static int sav_slot = -1;
char buf[MEDBUFSIZ]; // enough for /proc/stat CPU line (not the intr line)
static int siz, sav_slot = -1;
static char *buf;
#ifdef NUMA_ENABLED
#define sumSLOT ( smp_num_cpus )
#define totSLOT ( 1 + smp_num_cpus + Numa_node_tot)
@ -2300,6 +2300,8 @@ static CPU_t *cpus_refresh (CPU_t *cpus) {
#define totSLOT ( 1 + Cpu_faux_tot )
int i;
#endif
int num, tot_read;
char *bp;
/*** hotplug_acclimated ***/
if (sav_slot != sumSLOT) {
@ -2321,12 +2323,27 @@ static CPU_t *cpus_refresh (CPU_t *cpus) {
rewind(fp);
fflush(fp);
#define buffGRW 1024
/* we slurp in the entire directory thus avoiding repeated calls to fgets,
especially in a massively parallel environment. additionally, each cpu
line is then frozen in time rather than changing until we get around to
accessing it. this helps to minimize (not eliminate) most distortions. */
tot_read = 0;
if (buf) buf[0] = '\0';
else buf = alloc_c((siz = buffGRW));
while (0 < (num = fread(buf + tot_read, 1, (siz - tot_read), fp))) {
tot_read += num;
if (tot_read < siz) break;
buf = alloc_r(buf, (siz += buffGRW));
};
buf[tot_read] = '\0';
bp = buf;
#undef buffGRW
// remember from last time around
memcpy(&cpus[sumSLOT].sav, &cpus[sumSLOT].cur, sizeof(CT_t));
// then value the last slot with the cpu summary line
if (!fgets(buf, sizeof(buf), fp)) error_exit(N_txt(FAIL_statget_txt));
memset(&cpus[sumSLOT].cur, 0, sizeof(CT_t));
if (4 > sscanf(buf, "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu"
if (4 > sscanf(bp, "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu"
, &cpus[sumSLOT].cur.u, &cpus[sumSLOT].cur.n, &cpus[sumSLOT].cur.s
, &cpus[sumSLOT].cur.i, &cpus[sumSLOT].cur.w, &cpus[sumSLOT].cur.x
, &cpus[sumSLOT].cur.y, &cpus[sumSLOT].cur.z))
@ -2364,14 +2381,12 @@ static CPU_t *cpus_refresh (CPU_t *cpus) {
for (i = 0; i < sumSLOT && i < Screen_rows; i++) {
#endif
#ifdef PRETEND8CPUS
rewind(fp);
fgets(buf, sizeof(buf), fp);
bp = buf;
#endif
bp = 1 + strchr(bp, '\n');
// remember from last time around
memcpy(&cpus[i].sav, &cpus[i].cur, sizeof(CT_t));
if (!fgets(buf, sizeof(buf), fp)) error_exit(N_txt(FAIL_statget_txt));
memset(&cpus[i].cur, 0, sizeof(CT_t));
if (4 > sscanf(buf, "cpu%d %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu", &cpus[i].id
if (4 > sscanf(bp, "cpu%d %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu", &cpus[i].id
, &cpus[i].cur.u, &cpus[i].cur.n, &cpus[i].cur.s
, &cpus[i].cur.i, &cpus[i].cur.w, &cpus[i].cur.x
, &cpus[i].cur.y, &cpus[i].cur.z)) {