Skip to content

Commit a60fbbc

Browse files
committed
sadc/sar: New /proc/meminfo fields to memory statistics
Five new fields have been added to memory statistics displayed by sar. These new fields are part of A_MEMORY activity and will be displayed using option "-r ALL" with sar. No layout format incompatible change with this patch: The datafile created by this version of sar can still be read by a previous version of sar (though the new fields won't be displayed of course as they are unknown by this old version). Various outputs from sadf (JSON, XML, etc.) have been updated to take into account these new metrics. Originally suggested by Peter Portante (@portante). Signed-off-by: Sebastien GODARD <[email protected]>
1 parent 24918f9 commit a60fbbc

File tree

11 files changed

+178
-21
lines changed

11 files changed

+178
-21
lines changed

activity.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ struct activity memory_act = {
274274
.f_xml_print = xml_print_memory_stats,
275275
.f_json_print = json_print_memory_stats,
276276
.hdr_line = "frmpg/s;bufpg/s;campg/s|"
277-
"kbmemfree;kbmemused;%memused;kbbuffers;kbcached;kbcommit;%commit;kbactive;kbinact;kbdirty|"
277+
"kbmemfree;kbmemused;%memused;kbbuffers;kbcached;kbcommit;%commit;kbactive;kbinact;kbdirty&kbanonpg;kbslab;kbkstack;kbpgtbl;kbvmused|"
278278
"kbswpfree;kbswpused;%swpused;kbswpcad;%swpcad",
279279
.name = "A_MEMORY",
280280
#endif

json_stats.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,20 @@ __print_funct_t json_print_memory_stats(struct activity *a, int curr, int tab,
495495
smc->activekb,
496496
smc->inactkb,
497497
smc->dirtykb);
498+
499+
if (DISPLAY_MEM_ALL(a->opt_flags)) {
500+
/* Display extended memory stats */
501+
printf(", \"anonpg\": %lu, "
502+
"\"slab\": %lu, "
503+
"\"kstack\": %lu, "
504+
"\"pgtbl\": %lu, "
505+
"\"vmused\": %lu",
506+
smc->anonpgkb,
507+
smc->slabkb,
508+
smc->kstackkb,
509+
smc->pgtblkb,
510+
smc->vmusedkb);
511+
}
498512
}
499513

500514
if (DISPLAY_SWAP(a->opt_flags)) {

pr_stats.c

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,12 @@ void stub_print_memory_stats(struct activity *a, int prev, int curr,
411411
avg_comkb = 0,
412412
avg_activekb = 0,
413413
avg_inactkb = 0,
414-
avg_dirtykb = 0;
414+
avg_dirtykb = 0,
415+
avg_anonpgkb = 0,
416+
avg_slabkb = 0,
417+
avg_kstackkb = 0,
418+
avg_pgtblkb = 0,
419+
avg_vmusedkb = 0;
415420
static unsigned long long
416421
avg_frskb = 0,
417422
avg_tlskb = 0,
@@ -432,12 +437,16 @@ void stub_print_memory_stats(struct activity *a, int prev, int curr,
432437
if (DISPLAY_MEM_AMT(a->opt_flags)) {
433438
if (dis) {
434439
printf("\n%-11s kbmemfree kbmemused %%memused kbbuffers kbcached"
435-
" kbcommit %%commit kbactive kbinact kbdirty\n", timestamp[!curr]);
440+
" kbcommit %%commit kbactive kbinact kbdirty", timestamp[!curr]);
441+
if (DISPLAY_MEM_ALL(a->opt_flags)) {
442+
printf(" kbanonpg kbslab kbkstack kbpgtbl kbvmused");
443+
}
444+
printf("\n");
436445
}
437446

438447
if (!dispavg) {
439448
/* Display instantaneous values */
440-
printf("%-11s %9lu %9lu %6.2f %9lu %9lu %9lu %7.2f %9lu %9lu %9lu\n",
449+
printf("%-11s %9lu %9lu %6.2f %9lu %9lu %9lu %7.2f %9lu %9lu %9lu",
441450
timestamp[curr],
442451
smc->frmkb,
443452
smc->tlmkb - smc->frmkb,
@@ -452,6 +461,18 @@ void stub_print_memory_stats(struct activity *a, int prev, int curr,
452461
smc->inactkb,
453462
smc->dirtykb);
454463

464+
if (DISPLAY_MEM_ALL(a->opt_flags)) {
465+
/* Display extended memory statistics */
466+
printf(" %9lu %9lu %9lu %9lu %9lu",
467+
smc->anonpgkb,
468+
smc->slabkb,
469+
smc->kstackkb,
470+
smc->pgtblkb,
471+
smc->vmusedkb);
472+
}
473+
474+
printf("\n");
475+
455476
/*
456477
* Will be used to compute the average.
457478
* We assume that the total amount of memory installed can not vary
@@ -464,10 +485,15 @@ void stub_print_memory_stats(struct activity *a, int prev, int curr,
464485
avg_activekb += smc->activekb;
465486
avg_inactkb += smc->inactkb;
466487
avg_dirtykb += smc->dirtykb;
488+
avg_anonpgkb += smc->anonpgkb;
489+
avg_slabkb += smc->slabkb;
490+
avg_kstackkb += smc->kstackkb;
491+
avg_pgtblkb += smc->pgtblkb;
492+
avg_vmusedkb += smc->vmusedkb;
467493
}
468494
else {
469495
/* Display average values */
470-
printf("%-11s %9.0f %9.0f %6.2f %9.0f %9.0f %9.0f %7.2f %9.0f %9.0f %9.0f\n",
496+
printf("%-11s %9.0f %9.0f %6.2f %9.0f %9.0f %9.0f %7.2f %9.0f %9.0f %9.0f",
471497
timestamp[curr],
472498
(double) avg_frmkb / avg_count,
473499
(double) smc->tlmkb - ((double) avg_frmkb / avg_count),
@@ -485,9 +511,22 @@ void stub_print_memory_stats(struct activity *a, int prev, int curr,
485511
(double) avg_inactkb / avg_count,
486512
(double) avg_dirtykb / avg_count);
487513

514+
if (DISPLAY_MEM_ALL(a->opt_flags)) {
515+
printf(" %9.0f %9.0f %9.0f %9.0f %9.0f",
516+
(double) avg_anonpgkb / avg_count,
517+
(double) avg_slabkb / avg_count,
518+
(double) avg_kstackkb / avg_count,
519+
(double) avg_pgtblkb / avg_count,
520+
(double) avg_vmusedkb / avg_count);
521+
}
522+
523+
printf("\n");
524+
488525
/* Reset average counters */
489526
avg_frmkb = avg_bufkb = avg_camkb = avg_comkb = 0;
490527
avg_activekb = avg_inactkb = avg_dirtykb = 0;
528+
avg_anonpgkb = avg_slabkb = avg_kstackkb = 0;
529+
avg_pgtblkb = avg_vmusedkb = 0;
491530
}
492531
}
493532

rd_stats.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,26 @@ void read_meminfo(struct stats_memory *st_memory)
268268
/* Read the amount of commited memory in kB */
269269
sscanf(line + 13, "%lu", &st_memory->comkb);
270270
}
271+
else if (!strncmp(line, "AnonPages:", 10)) {
272+
/* Read the amount of pages mapped into userspace page tables in kB */
273+
sscanf(line + 10, "%lu", &st_memory->anonpgkb);
274+
}
275+
else if (!strncmp(line, "Slab:", 5)) {
276+
/* Read the amount of in-kernel data structures cache in kB */
277+
sscanf(line + 5, "%lu", &st_memory->slabkb);
278+
}
279+
else if (!strncmp(line, "KernelStack:", 12)) {
280+
/* Read the kernel stack utilization in kB */
281+
sscanf(line + 12, "%lu", &st_memory->kstackkb);
282+
}
283+
else if (!strncmp(line, "PageTables:", 11)) {
284+
/* Read the amount of memory dedicated to the lowest level of page tables in kB */
285+
sscanf(line + 11, "%lu", &st_memory->pgtblkb);
286+
}
287+
else if (!strncmp(line, "VmallocUsed:", 12)) {
288+
/* Read the amount of vmalloc area which is used in kB */
289+
sscanf(line + 12, "%lu", &st_memory->vmusedkb);
290+
}
271291
}
272292

273293
fclose(fp);

rd_stats.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ struct stats_memory {
166166
unsigned long activekb __attribute__ ((aligned (8)));
167167
unsigned long inactkb __attribute__ ((aligned (8)));
168168
unsigned long dirtykb __attribute__ ((aligned (8)));
169+
unsigned long anonpgkb __attribute__ ((aligned (8)));
170+
unsigned long slabkb __attribute__ ((aligned (8)));
171+
unsigned long kstackkb __attribute__ ((aligned (8)));
172+
unsigned long pgtblkb __attribute__ ((aligned (8)));
173+
unsigned long vmusedkb __attribute__ ((aligned (8)));
169174
};
170175

171176
#define STATS_MEMORY_SIZE (sizeof(struct stats_memory))

rndr_stats.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,7 @@ __print_funct_t render_memory_stats(struct activity *a, int isdb, char *pre,
733733
*smp = (struct stats_memory *) a->buf[!curr];
734734
int pt_newlin
735735
= (DISPLAY_HORIZONTALLY(flags) ? PT_NOFLAG : PT_NEWLIN);
736+
int ptn;
736737

737738
if (DISPLAY_MEMORY(a->opt_flags)) {
738739

@@ -800,9 +801,32 @@ __print_funct_t render_memory_stats(struct activity *a, int isdb, char *pre,
800801
"-\tkbinact", NULL, NULL,
801802
smc->inactkb, DNOVAL, NULL);
802803

803-
render(isdb, pre, PT_USEINT | pt_newlin,
804+
ptn = DISPLAY_MEM_ALL(a->opt_flags) ? 0 : pt_newlin;
805+
render(isdb, pre, PT_USEINT | ptn,
804806
"-\tkbdirty", NULL, NULL,
805807
smc->dirtykb, DNOVAL, NULL);
808+
809+
if (DISPLAY_MEM_ALL(a->opt_flags)) {
810+
render(isdb, pre, PT_USEINT,
811+
"-\tkbanonpg", NULL, NULL,
812+
smc->anonpgkb, DNOVAL, NULL);
813+
814+
render(isdb, pre, PT_USEINT,
815+
"-\tkbslab", NULL, NULL,
816+
smc->slabkb, DNOVAL, NULL);
817+
818+
render(isdb, pre, PT_USEINT,
819+
"-\tkbkstack", NULL, NULL,
820+
smc->kstackkb, DNOVAL, NULL);
821+
822+
render(isdb, pre, PT_USEINT,
823+
"-\tkbpgtbl", NULL, NULL,
824+
smc->pgtblkb, DNOVAL, NULL);
825+
826+
render(isdb, pre, PT_USEINT | pt_newlin,
827+
"-\tkbvmused", NULL, NULL,
828+
smc->vmusedkb, DNOVAL, NULL);
829+
}
806830
}
807831

808832
if (DISPLAY_SWAP(a->opt_flags)) {

sa.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,13 @@
116116
#define AO_F_MEM_DIA 0x00000001
117117
#define AO_F_MEM_AMT 0x00000002
118118
#define AO_F_MEM_SWAP 0x00000004
119+
/* AO_F_MEM_ALL: See opt_flags in struct activity below */
120+
#define AO_F_MEM_ALL (AO_F_MEM_AMT << 8)
119121

120122
#define DISPLAY_MEMORY(m) (((m) & AO_F_MEM_DIA) == AO_F_MEM_DIA)
121123
#define DISPLAY_MEM_AMT(m) (((m) & AO_F_MEM_AMT) == AO_F_MEM_AMT)
122124
#define DISPLAY_SWAP(m) (((m) & AO_F_MEM_SWAP) == AO_F_MEM_SWAP)
125+
#define DISPLAY_MEM_ALL(m) (((m) & AO_F_MEM_ALL) == AO_F_MEM_ALL)
123126

124127
/* Output flags for option -u [ ALL ] */
125128
#define AO_F_CPU_DEF 0x00000001
@@ -380,6 +383,10 @@ struct activity {
380383
__print_funct_t (*f_json_print) (struct activity *, int, int, unsigned long long);
381384
/*
382385
* Header string displayed by sadf -d/-D.
386+
* Header lines for each output (for activities with multiple outputs) are
387+
* separated with a '|' character.
388+
* For a given output, the first field corresponding to extended statistics
389+
* (eg. -r ALL) begins with a '&' character.
383390
*/
384391
char *hdr_line;
385392
/*
@@ -427,6 +434,10 @@ struct activity {
427434
/*
428435
* Optional flags for activity. This is eg. used when AO_MULTIPLE_OUTPUTS
429436
* option is set.
437+
* 0x0001 - 0x0080 : Multiple outputs (eg. AO_F_MEM_AMT, AO_F_MEM_SWAP...)
438+
* 0x0100 - 0x8000 : If bit set then display complete header (hdr_line) for
439+
* corresponding output
440+
* 0x010000+ : Optional flags
430441
*/
431442
unsigned int opt_flags;
432443
/*

sa_common.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -957,8 +957,8 @@ int get_activity_nr(struct activity *act[], unsigned int option, int count_outpu
957957
if ((act[i]->options & option) == option) {
958958

959959
if (HAS_MULTIPLE_OUTPUTS(act[i]->options) && count_outputs) {
960-
for (msk = 1; msk < 0x10; msk <<= 1) {
961-
if (act[i]->opt_flags & msk) {
960+
for (msk = 1; msk < 0x100; msk <<= 1) {
961+
if ((act[i]->opt_flags & 0xff) & msk) {
962962
n++;
963963
}
964964
}
@@ -1520,17 +1520,21 @@ int parse_sar_opt(char *argv[], int *opt, struct activity *act[],
15201520
int i, p;
15211521

15221522
for (i = 1; *(argv[*opt] + i); i++) {
1523+
/*
1524+
* Note: argv[*opt] contains something like "-BruW"
1525+
* *(argv[*opt] + i) will contain 'B', 'r', etc.
1526+
*/
15231527

15241528
switch (*(argv[*opt] + i)) {
15251529

15261530
case 'A':
15271531
select_all_activities(act);
15281532

1529-
/* Force '-P ALL -I XALL' */
1533+
/* Force '-P ALL -I XALL -r ALL -u ALL' */
15301534

15311535
p = get_activity_position(act, A_MEMORY);
15321536
act[p]->opt_flags |= AO_F_MEM_AMT + AO_F_MEM_DIA +
1533-
AO_F_MEM_SWAP;
1537+
AO_F_MEM_SWAP + AO_F_MEM_ALL;
15341538

15351539
p = get_activity_position(act, A_IRQ);
15361540
set_bitmap(act[p]->bitmap->b_array, ~0,
@@ -1604,6 +1608,11 @@ int parse_sar_opt(char *argv[], int *opt, struct activity *act[],
16041608
p = get_activity_position(act, A_MEMORY);
16051609
act[p]->options |= AO_SELECTED;
16061610
act[p]->opt_flags |= AO_F_MEM_AMT;
1611+
if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
1612+
(*opt)++;
1613+
act[p]->opt_flags |= AO_F_MEM_ALL;
1614+
return 0;
1615+
}
16071616
break;
16081617

16091618
case 'R':

sadf.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ void write_textual_comments(int curr, int use_tm_start, int use_tm_end, int tab,
434434
*/
435435
void list_fields(unsigned int act_id)
436436
{
437-
int i;
437+
int i, j;
438438
unsigned int msk;
439439
char *hl;
440440
char hline[HEADER_LINE_LEN];
@@ -457,8 +457,24 @@ void list_fields(unsigned int act_id)
457457
msk = 1;
458458
strcpy(hline, act[i]->hdr_line);
459459
for (hl = strtok(hline, "|"); hl; hl = strtok(NULL, "|"), msk <<= 1) {
460-
if ((hl != NULL) && (act[i]->opt_flags & msk)) {
461-
printf(";%s", hl);
460+
if ((hl != NULL) && ((act[i]->opt_flags & 0xff) & msk)) {
461+
if (strchr(hl, '&')) {
462+
j = strcspn(hl, "&");
463+
if ((act[i]->opt_flags & 0xff00) & (msk << 8)) {
464+
/* Display whole header line */
465+
*(hl + j) = ';';
466+
printf(";%s", hl);
467+
}
468+
else {
469+
/* Display only the first part of the header line */
470+
*(hl + j) = '\0';
471+
printf(";%s", hl);
472+
}
473+
*(hl + j) = '&';
474+
}
475+
else {
476+
printf(";%s", hl);
477+
}
462478
if ((act[i]->nr > 1) && DISPLAY_HORIZONTALLY(flags)) {
463479
printf("[...]");
464480
}
@@ -1379,9 +1395,9 @@ void main_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_nr
13791395

13801396
optf = act[p]->opt_flags;
13811397

1382-
for (msk = 1; msk < 0x10; msk <<= 1) {
1383-
if (act[p]->opt_flags & msk) {
1384-
act[p]->opt_flags &= msk;
1398+
for (msk = 1; msk < 0x100; msk <<= 1) {
1399+
if ((act[p]->opt_flags & 0xff) & msk) {
1400+
act[p]->opt_flags &= (0xffffff00 + msk);
13851401

13861402
rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
13871403
act[p]->id, &reset, file_actlst,

sar.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ void usage(char *progname)
108108
print_usage_title(stderr, progname);
109109
fprintf(stderr, _("Options are:\n"
110110
"[ -A ] [ -B ] [ -b ] [ -C ] [ -D ] [ -d ] [ -F ] [ -H ] [ -h ] [ -p ] [ -q ]\n"
111-
"[ -R ] [ -r ] [ -S ] [ -t ] [ -u [ ALL ] ] [ -V ] [ -v ] [ -W ] [ -w ] [ -y ]\n"
111+
"[ -R ] [ -r [ ALL ] ] [ -S ] [ -t ] [ -u [ ALL ] ] [ -V ] [ -v ] [ -W ]\n"
112+
"[ -w ] [ -y ]\n"
112113
"[ -I { <int> [,...] | SUM | ALL | XALL } ] [ -P { <cpu> [,...] | ALL } ]\n"
113114
"[ -m { <keyword> [,...] | ALL } ] [ -n { <keyword> [,...] | ALL } ]\n"
114115
"[ -j { ID | LABEL | PATH | UUID | ... } ]\n"
@@ -168,7 +169,8 @@ void display_help(char *progname)
168169
"\t\tUDP6\tUDP traffic\t(v6)\n"));
169170
printf(_("\t-q\tQueue length and load average statistics\n"));
170171
printf(_("\t-R\tMemory statistics\n"));
171-
printf(_("\t-r\tMemory utilization statistics\n"));
172+
printf(_("\t-r [ ALL ]\n"
173+
"\tMemory utilization statistics\n"));
172174
printf(_("\t-S\tSwap space utilization statistics\n"));
173175
printf(_("\t-u [ ALL ]\n"
174176
"\t\tCPU utilization statistics\n"));
@@ -1007,9 +1009,9 @@ void read_stats_from_file(char from_file[])
10071009

10081010
optf = act[p]->opt_flags;
10091011

1010-
for (msk = 1; msk < 0x10; msk <<= 1) {
1011-
if (act[p]->opt_flags & msk) {
1012-
act[p]->opt_flags &= msk;
1012+
for (msk = 1; msk < 0x100; msk <<= 1) {
1013+
if ((act[p]->opt_flags & 0xff) & msk) {
1014+
act[p]->opt_flags &= (0xffffff00 + msk);
10131015

10141016
handle_curr_act_stats(ifd, fpos, &curr, &cnt,
10151017
&eosaf, rows, act[p]->id,

0 commit comments

Comments
 (0)