summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--utils/vmstat.c151
1 files changed, 106 insertions, 45 deletions
diff --git a/utils/vmstat.c b/utils/vmstat.c
index a0c38234..e6e0bf63 100644
--- a/utils/vmstat.c
+++ b/utils/vmstat.c
@@ -73,6 +73,31 @@ enum val_type
PCENT, /* Append `%'. */
};
+/* Return the `nominal' width of a field of type TYPE, in units of SIZE_UNITS. */
+static size_t
+val_width (val_t val, enum val_type type, size_t size_units)
+{
+ size_t vwidth (val_t val)
+ {
+ size_t w = 1;
+ if (val < 0)
+ w++, val = -val;
+ while (val > 9)
+ w++, val /= 10;
+ return w;
+ }
+ if (type == PCENT)
+ return vwidth (val) + 1;
+ else if ((type == SIZE || type == PAGESZ) && size_units == 0)
+ return val > 1000 ? 5 : vwidth (val) + 1;
+ else
+ {
+ if ((type == SIZE || type == PAGESZ) && size_units > 0)
+ val /= size_units;
+ return vwidth (val);
+ }
+}
+
/* Print a number of type TYPE. If SIZE_UNITS is non-zero, then values of
type SIZE are divided by that amount and printed without a suffix. FWIDTH
is the width of the field to print it in, right-justified. If SIGN is
@@ -107,6 +132,10 @@ print_val (val_t val, enum val_type type,
}
}
+/* Special values for val_t ranges. */
+#define VAL_MAX_MEM -1 /* up to the system memory size */
+#define VAL_MAX_SWAP -2 /* up to the system swap size */
+
/* How this field changes with time. */
enum field_change_type
{
@@ -136,6 +165,9 @@ struct field
user. */
enum val_type type;
+ /* The `maximum value' this field can have -- used for field widths. */
+ val_t max;
+
/* True if we display this field by default (user can always override). */
int standard :1;
@@ -200,7 +232,7 @@ vm_state_get_field (struct vm_state *state, const struct field *field)
}
static val_t
-get_cache_hit_ratio (struct vm_state *state, const struct field *field)
+get_memobj_hit_ratio (struct vm_state *state, const struct field *field)
{
return state->vmstats.hits * 100 / state->vmstats.lookups;
}
@@ -274,47 +306,51 @@ get_swap_active (struct vm_state *state, const struct field *field)
/* Returns the byte offset of the field FIELD in a vm_statistics structure. */
#define _F(field_name) offsetof (struct vm_statistics, field_name)
+#define K 1024
+#define M (1024*K)
+#define G (1024LL*M)
+
/* vm_statistics fields we know about. */
static const struct field fields[] =
{
- {"pagesize", " pgsz", "System pagesize",
- CONST,PAGESZ, 1,_F(pagesize)},
- {"size", " size", "Usable physical memory",
- CONST,SIZE, 1,0,get_size},
- {"free", " free", "Unused physical memory",
- VARY, SIZE, 1,_F(free_count)},
- {"active", " actv", "Physical memory in active use",
- VARY, SIZE, 1,_F(active_count)},
+ {"pagesize", "pgsz", "System pagesize",
+ CONST, PAGESZ, 16*K, 1, _F (pagesize) },
+ {"size", "size", "Usable physical memory",
+ CONST, SIZE, VAL_MAX_MEM, 1, 0, get_size },
+ {"free", "free", "Unused physical memory",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (free_count) },
+ {"active", "actv", "Physical memory in active use",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (active_count) },
{"inactive", "inact", "Physical memory in the inactive queue",
- VARY, SIZE, 1,_F(inactive_count)},
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (inactive_count) },
{"wired", "wired", "Unpageable physical memory",
- VARY, SIZE, 1,_F(wire_count)},
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (wire_count) },
{"zero filled", "zeroed","Cumulative zero-filled pages",
- CUMUL,SIZE, 1,_F(zero_fill_count)},
+ CUMUL, SIZE, 90*G, 1, _F (zero_fill_count) },
{"reactivated", "react", "Cumulative reactivated inactive pages",
- CUMUL,SIZE, 1,_F(reactivations)},
+ CUMUL, SIZE, 900*M, 1, _F (reactivations) },
{"pageins", "pgins", "Cumulative pages paged in",
- CUMUL,SIZE, 1,_F(pageins)},
+ CUMUL, SIZE, 90*G, 1, _F (pageins) },
{"pageouts", "pgouts","Cumulative pages paged out",
- CUMUL,SIZE, 1,_F(pageouts)},
+ CUMUL, SIZE, 90*G, 1, _F (pageouts) },
{"page faults", "pfaults","Cumulative page faults",
- CUMUL,COUNT,1,_F(faults)},
+ CUMUL, COUNT, 99999999, 1, _F (faults) },
{"cow faults", "cowpfs", "Cumulative copy-on-write page faults",
- CUMUL,COUNT,1,_F(cow_faults)},
- {"cache lookups","clkups", "...",
- CUMUL,COUNT,0,_F(lookups)},
- {"cache hits", "chits", "...",
- CUMUL,COUNT,0,_F(hits)},
- {"cache hit ratio","chrat","...",
- VARY,PCENT,1,-1,get_cache_hit_ratio},
+ CUMUL, COUNT, 9999999, 1, _F (cow_faults) },
+ {"memobj lookups","lkups","Memory-object lookups",
+ CUMUL, COUNT, 999999, 0, _F (lookups) },
+ {"memobj hits", "hits", "Memory-object lookups with active pagers",
+ CUMUL, COUNT, 999999, 0, _F (hits) },
+ {"memobj hit ratio","hrat","Percentage of memory-object lookups with active pagers",
+ VARY, PCENT, 99, 1, -1, get_memobj_hit_ratio },
{"swap size", "swsize", "Size of the default-pager swap area",
- CONST,SIZE, 1,0,get_swap_size},
+ CONST, SIZE, VAL_MAX_SWAP, 1, 0 ,get_swap_size },
{"swap active", "swactv", "Default-pager swap area in use",
- VARY, SIZE, 0,0,get_swap_active},
+ VARY, SIZE, VAL_MAX_SWAP, 0, 0 ,get_swap_active },
{"swap free", "swfree", "Default-pager swap area available for swapping",
- VARY, SIZE, 1,0,get_swap_free},
+ VARY, SIZE, VAL_MAX_SWAP, 1, 0 ,get_swap_free },
{"swap pagesize","swpgsz", "Units used for swapping to the default pager",
- CONST,PAGESZ, 0,0,get_swap_page_size},
+ CONST, PAGESZ, 16*K, 0, 0 ,get_swap_page_size },
{0}
};
#undef _F
@@ -323,7 +359,7 @@ static const struct field fields[] =
static char *name_to_option (const char *name)
{
char *opt = strdup (name), *p;
- if (! opt)
+ if (opt)
for (p = opt; *p; p++)
if (*p == ' ')
*p = '-';
@@ -359,7 +395,7 @@ main (int argc, char **argv)
case 'H': print_heading = 0; break;
case 'b': size_units = 1; break;
case 'v': size_units = -1; break;
- case 'k': size_units = 1024; break;
+ case 'k': size_units = K; break;
case ARGP_KEY_ARG:
terse = 1;
@@ -420,9 +456,9 @@ main (int argc, char **argv)
output_fields |= (1 << (field - fields));
/* Returns an appropiate SIZE_UNITS for printing FIELD. */
-#define SIZE_UNITS(field) \
- (size_units >= 0 \
- ? size_units \
+#define SIZE_UNITS(field) \
+ (size_units >= 0 \
+ ? size_units \
: ((field)->type == PAGESZ ? 0 : state.vmstats.pagesize))
/* Prints SEP if the variable FIRST is 0, otherwise, prints START (if
@@ -431,7 +467,13 @@ main (int argc, char **argv)
(first ? (first = 0, (start && fputs (start, stdout))) : fputs (sep, stdout))
#define PVAL(val, field, width, sign) \
print_val (val, (field)->type, SIZE_UNITS (field), width, sign)
-
+ /* Intuit the likely maximum field width of FIELD. */
+#define FWIDTH(field) \
+ val_width ((field)->max == VAL_MAX_MEM ? get_size (&state, field) \
+ : (field)->max == VAL_MAX_SWAP ? get_swap_size (&state, field) \
+ : (field)->max, \
+ (field)->type, SIZE_UNITS (field))
+
/* Actually fetch the statistics. */
bzero (&state, sizeof (state)); /* Initialize STATE. */
err = vm_state_refresh (&state);
@@ -461,6 +503,9 @@ main (int argc, char **argv)
do
{
+ int num;
+ size_t fwidths[num_fields];
+
if (first_hdr)
first_hdr = 0;
else
@@ -487,13 +532,30 @@ main (int argc, char **argv)
puts (")");
}
+ /* Calculate field widths. */
+ for (field = fields, num = 0; field->name; field++, num++)
+ if (output_fields & (1 << (field - fields)))
+ {
+ fwidths[num] = FWIDTH (field);
+ if (count != 1 && size_units == 0
+ && field->change_type == CUMUL && field->type == SIZE)
+ /* We may be printing a `+' prefix for field changes, and
+ since this is using the mostly constant-width SIZE
+ notation, individual changes may be the same width as
+ appropriated for absolute values -- so reserver another
+ column for the `+' character. */
+ fwidths[num]++;
+ if (fwidths[num] < strlen (field->hdr))
+ fwidths[num] = strlen (field->hdr);
+ }
+
if (print_heading)
{
- for (field = fields, first = 1; field->name; field++)
+ for (field = fields, num = 0, first = 1; field->name; field++, num++)
if (output_fields & (1 << (field - fields)))
{
PSEP (" ", 0);
- fputs (field->hdr, stdout);
+ fprintf (stdout, "%*s", fwidths[num], field->hdr);
}
putchar ('\n');
}
@@ -501,15 +563,14 @@ main (int argc, char **argv)
prev_state = state;
for (repeats = 0
- ; count && repeats < hdr_interval && count
+ ; count && repeats < hdr_interval
; repeats++, count--)
{
/* Output the fields. */
- for (field = fields, first = 1; field->name; field++)
+ for (field = fields, num = 0, first = 1; field->name; field++, num++)
if (output_fields & (1 << (field - fields)))
{
int sign = 0;
- int width = strlen (field->hdr);
val_t val = vm_state_get_field (&state, field);
if (repeats && field->change_type == CUMUL)
@@ -519,7 +580,7 @@ main (int argc, char **argv)
}
PSEP (" ", 0);
- PVAL (val, field, width, sign);
+ PVAL (val, field, fwidths[num], sign);
}
putchar ('\n');
@@ -539,7 +600,7 @@ main (int argc, char **argv)
else
/* Verbose output. */
{
- int max_name_width = 0;
+ int max_width = 0;
if (print_prefix < 0)
/* By default, only print a prefix if there are multiple fields. */
@@ -550,9 +611,9 @@ main (int argc, char **argv)
for (field = fields; field->name; field++)
if (output_fields & (1 << (field - fields)))
{
- int name_len = strlen (field->name);
- if (name_len > max_name_width)
- max_name_width = name_len;
+ int width = strlen (field->name) + FWIDTH (field);
+ if (width > max_width)
+ max_width = width;
}
for (field = fields; field->name; field++)
@@ -562,8 +623,8 @@ main (int argc, char **argv)
int fwidth = 0;
if (print_prefix)
{
- printf ("%s:", field->name);
- fwidth = max_name_width + 5 - strlen (field->name);
+ printf ("%s: ", field->name);
+ fwidth = max_width - strlen (field->name);
}
PVAL (val, field, fwidth, 0);
putchar ('\n');