aboutsummaryrefslogtreecommitdiff
path: root/utils/vmstat.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/vmstat.c')
-rw-r--r--utils/vmstat.c332
1 files changed, 218 insertions, 114 deletions
diff --git a/utils/vmstat.c b/utils/vmstat.c
index c7f7a7af..7d852992 100644
--- a/utils/vmstat.c
+++ b/utils/vmstat.c
@@ -1,8 +1,7 @@
/* Print vm statistics
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1996,97,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -25,30 +24,30 @@
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
+#include <fcntl.h>
+#include <version.h>
#include <mach.h>
#include <mach/vm_statistics.h>
#include <mach/default_pager.h>
#include <hurd.h>
+#include <hurd/paths.h>
-char *argp_program_version = "vmstat 1.1 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (vmstat);
static const struct argp_option options[] = {
- {"terse", 't', 0, 0, "Use short one-line output format", 1 },
+ {"terse", 't', 0, 0, "Use short one-line output format"},
{"no-header", 'H', 0, 0, "Don't print a descriptive header line"},
{"prefix", 'p', 0, 0, "Always display a description before stats"},
{"no-prefix", 'P', 0, 0, "Never display a description before stats"},
{"pages", 'v', 0, 0, "Display sizes in pages"},
{"kilobytes", 'k', 0, 0, "Display sizes in 1024 byte blocks"},
{"bytes", 'b', 0, 0, "Display sizes in bytes"},
-
- /* A header for all the individual field options. */
- { 0,0,0,0, "Selecting which statistics to show:", 2},
-
{0}
};
static const char *args_doc = "[PERIOD [COUNT [HEADER_INTERVAL]]]";
-static const char *doc = "If PERIOD is supplied, then terse mode is"
+static const char *doc = "Show system virtual memory statistics"
+"\vIf PERIOD is supplied, then terse mode is"
" selected, and the output repeated every PERIOD seconds, with cumulative"
" fields given the difference from the last output. If COUNT is given"
" and non-zero, only that many lines are output. HEADER_INTERVAL"
@@ -61,6 +60,7 @@ static const char *doc = "If PERIOD is supplied, then terse mode is"
than what the system returns values in, as we represent some quantities as
bytes instead of pages)! */
typedef long long val_t;
+#define BADVAL ((val_t) -1LL) /* a good generic value for "couldn't get" */
/* What a given number describes. */
enum val_type
@@ -71,6 +71,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
@@ -80,13 +105,13 @@ print_val (val_t val, enum val_type type,
size_t size_units, int fwidth, int sign)
{
if (type == PCENT)
- printf (sign ? "%+*d%%" : "%*d%%", fwidth - 1, val);
+ printf (sign ? "%+*lld%%" : "%*lld%%", fwidth - 1, val);
else if ((type == SIZE || type == PAGESZ) && size_units == 0)
{
float fval = val;
char *units = " KMGT", *u = units;
- while (fval > 1024)
+ while (fval >= 10000)
{
fval /= 1024;
u++;
@@ -101,10 +126,14 @@ print_val (val_t val, enum val_type type,
{
if ((type == SIZE || type == PAGESZ) && size_units > 0)
val /= size_units;
- printf (sign ? "%+*d" : "%*d", fwidth, val);
+ printf (sign ? "%+*lld" : "%*lld", fwidth, val);
}
}
+/* 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
{
@@ -117,15 +146,15 @@ struct vm_state; /* fwd */
struct field
{
- /* Name of the field; used for the option name. */
+ /* Name of the field. */
char *name;
- /* A descriptive title used for long output format. */
- char *desc;
-
/* Terse header used for the columnar style output. */
char *hdr;
+ /* A description of this field (for user help). */
+ char *doc;
+
/* Type of this field. */
enum field_change_type change_type;
@@ -134,6 +163,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;
@@ -148,7 +180,7 @@ struct field
};
/* State about system vm from which we compute the above defined fields. */
-struct vm_state
+struct vm_state
{
/* General vm statistics. */
struct vm_statistics vmstats;
@@ -167,7 +199,7 @@ vm_state_refresh (struct vm_state *state)
return err;
/* Mark the info as invalid, but leave DEF_PAGER alone. */
- bzero (&state->def_pager_info, sizeof state->def_pager_info);
+ memset (&state->def_pager_info, 0, sizeof state->def_pager_info);
return 0;
}
@@ -198,7 +230,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;
}
@@ -215,89 +247,125 @@ ensure_def_pager_info (struct vm_state *state)
mach_port_t host;
err = get_privileged_ports (&host, 0);
- if (err)
+ if (err == EPERM)
{
- error (0, err, "get_privileged_ports");
- return 0;
+ /* We are not root, so try opening the /servers file. */
+ state->def_pager = file_name_lookup (_SERVERS_DEFPAGER, O_READ, 0);
+ if (state->def_pager == MACH_PORT_NULL)
+ {
+ error (0, errno, _SERVERS_DEFPAGER);
+ return 0;
+ }
}
+ if (state->def_pager == MACH_PORT_NULL)
+ {
+ if (err)
+ {
+ error (0, err, "get_privileged_ports");
+ return 0;
+ }
- err = vm_set_default_memory_manager (host, &state->def_pager);
- mach_port_deallocate (mach_task_self (), host);
+ err = vm_set_default_memory_manager (host, &state->def_pager);
+ mach_port_deallocate (mach_task_self (), host);
+
+ if (err)
+ {
+ error (0, err, "vm_set_default_memory_manager");
+ return 0;
+ }
+ }
+ }
- if (err)
+ if (!MACH_PORT_VALID (state->def_pager))
+ {
+ if (state->def_pager == MACH_PORT_NULL)
{
- error (0, err, "vm_set_default_memory_manager");
- return 0;
+ error (0, 0,
+ "No default pager running, so no swap information available");
+ state->def_pager = MACH_PORT_DEAD; /* so we don't try again */
}
+ return 0;
}
err = default_pager_info (state->def_pager, &state->def_pager_info);
if (err)
error (0, err, "default_pager_info");
-
return (err == 0);
}
-static val_t
-get_swap_size (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state) ? state->def_pager_info.dpi_total_space : -1;
-}
+#define SWAP_FIELD(getter, expr) \
+ static val_t getter (struct vm_state *state, const struct field *field) \
+ { return ensure_def_pager_info (state) ? (val_t) (expr) : BADVAL; }
-static val_t
-get_swap_free (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state) ? state->def_pager_info.dpi_free_space : -1;
-}
-
-static val_t
-get_swap_page_size (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state) ? state->def_pager_info.dpi_page_size : -1;
-}
-
-static val_t
-get_swap_active (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state)
- ? (state->def_pager_info.dpi_total_space
- - state->def_pager_info.dpi_free_space)
- : -1;
-}
+SWAP_FIELD (get_swap_size, state->def_pager_info.dpi_total_space)
+SWAP_FIELD (get_swap_free, state->def_pager_info.dpi_free_space)
+SWAP_FIELD (get_swap_page_size, state->def_pager_info.dpi_page_size)
+SWAP_FIELD (get_swap_active, (state->def_pager_info.dpi_total_space
+ - state->def_pager_info.dpi_free_space))
/* 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", "Pagesize", " pgsz", CONST,PAGESZ, 1,_F(pagesize)},
- {"size", "Size", " size", CONST,SIZE, 1,0,get_size},
- {"free", "Free", " free", VARY, SIZE, 1,_F(free_count)},
- {"active", "Active", " actv", VARY, SIZE, 1,_F(active_count)},
- {"inactive", "Inactive", "inact", VARY, SIZE, 1,_F(inactive_count)},
- {"wired", "Wired", "wired", VARY, SIZE, 1,_F(wire_count)},
- {"zero-filled", "Zeroed", "zeroed", CUMUL,SIZE, 1,_F(zero_fill_count)},
- {"reactivated", "Reactivated", "react", CUMUL,SIZE, 1,_F(reactivations)},
- {"pageins", "Pageins", "pgins", CUMUL,SIZE, 1,_F(pageins)},
- {"pageouts", "Pageouts", "pgouts", CUMUL,SIZE, 1,_F(pageouts)},
- {"faults", "Faults", "pfaults",CUMUL,COUNT,1,_F(faults)},
- {"cow-faults", "Cow faults", "cowpfs", CUMUL,COUNT,1,_F(cow_faults)},
- {"cache-lookups","Cache lookups","clkups", CUMUL,COUNT,0,_F(lookups)},
- {"cache-hits", "Cache hits", "chits", CUMUL,COUNT,0,_F(hits)},
- {"cache-hit-ratio","Cache hit ratio","chrat",VARY,PCENT,1,-1,get_cache_hit_ratio},
- {"swap-size", "Swap size", "swsize", CONST,SIZE, 1,0,get_swap_size},
- {"swap-active", "Swap active", "swactv", VARY, SIZE, 0,0,get_swap_active},
- {"swap-free", "Swap free", "swfree", VARY, SIZE, 1,0,get_swap_free},
- {"swap-pagesize","Swap pagesize","swpgsz", CONST,PAGESZ, 0,0,get_swap_page_size},
+ {"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, VAL_MAX_MEM, 1, _F (inactive_count) },
+ {"wired", "wired", "Unpageable physical memory",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (wire_count) },
+ {"zero filled", "zeroed","Cumulative zero-filled pages",
+ CUMUL, SIZE, 90*G, 1, _F (zero_fill_count) },
+ {"reactivated", "react", "Cumulative reactivated inactive pages",
+ CUMUL, SIZE, 900*M, 1, _F (reactivations) },
+ {"pageins", "pgins", "Cumulative pages paged in",
+ CUMUL, SIZE, 90*G, 1, _F (pageins) },
+ {"pageouts", "pgouts","Cumulative pages paged out",
+ CUMUL, SIZE, 90*G, 1, _F (pageouts) },
+ {"page faults", "pfaults","Cumulative page faults",
+ CUMUL, COUNT, 99999999, 1, _F (faults) },
+ {"cow faults", "cowpfs", "Cumulative copy-on-write page faults",
+ 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, VAL_MAX_SWAP, 1, 0 ,get_swap_size },
+ {"swap active", "swactv", "Default-pager swap area in use",
+ VARY, SIZE, VAL_MAX_SWAP, 0, 0 ,get_swap_active },
+ {"swap free", "swfree", "Default-pager swap area available for swapping",
+ VARY, SIZE, VAL_MAX_SWAP, 1, 0 ,get_swap_free },
+ {"swap pagesize","swpgsz", "Units used for swapping to the default pager",
+ CONST, PAGESZ, 16*K, 0, 0 ,get_swap_page_size },
{0}
};
#undef _F
+/* Convert a field name to the corresponding user-option. */
+static char *name_to_option (const char *name)
+{
+ char *opt = strdup (name), *p;
+ if (opt)
+ for (p = opt; *p; p++)
+ if (*p == ' ')
+ *p = '-';
+ return opt;
+}
+
int
main (int argc, char **argv)
{
@@ -327,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;
@@ -352,8 +420,9 @@ main (int argc, char **argv)
struct argp_option *field_opts;
int field_opts_size;
struct argp field_argp = { 0, parse_opt };
- const struct argp *parents[] = { &field_argp, 0 };
- const struct argp argp = { options, parse_opt, args_doc, doc, parents };
+ const struct argp_child children[] =
+ {{&field_argp, 0, "Selecting which statistics to show:"}, {0}};
+ const struct argp argp = { options, parse_opt, args_doc, doc, children };
/* See how many fields we know about. */
for (field = fields; field->name; field++)
@@ -362,19 +431,19 @@ main (int argc, char **argv)
/* Construct an options vector for them. */
field_opts_size = ((num_fields + 1) * sizeof (struct argp_option));
field_opts = alloca (field_opts_size);
- bzero (field_opts, field_opts_size);
+ memset (field_opts, 0, field_opts_size);
for (field = fields; field->name; field++)
{
int which = field - fields;
struct argp_option *opt = &field_opts[which];
- opt->name = field->name;
+ opt->name = name_to_option (field->name);
opt->key = -1 - which; /* options are numbered -1 ... -(N - 1). */
- opt->doc = field->desc;
+ opt->doc = field->doc;
opt->group = 2;
}
- /* No need to terminate FIELD_OPTS because the bzero above's done so. */
+ /* No need to terminate FIELD_OPTS because the memset above has done so. */
field_argp.options = field_opts;
@@ -387,10 +456,10 @@ main (int argc, char **argv)
if (field->standard)
output_fields |= (1 << (field - fields));
- /* Returns an appropiate SIZE_UNITS for printing FIELD. */
-#define SIZE_UNITS(field) \
- (size_units >= 0 \
- ? size_units \
+ /* Returns an appropriate SIZE_UNITS for printing FIELD. */
+#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
@@ -399,9 +468,15 @@ 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. */
+ memset (&state, 0, sizeof (state)); /* Initialize STATE. */
err = vm_state_refresh (&state);
if (err)
error (2, err, "vm_state_refresh");
@@ -429,6 +504,9 @@ main (int argc, char **argv)
do
{
+ int num;
+ int fwidths[num_fields];
+
if (first_hdr)
first_hdr = 0;
else
@@ -447,7 +525,7 @@ main (int argc, char **argv)
else
{
PSEP (", ", "(");
- printf ("%s: ", field->desc);
+ printf ("%s: ", field->name);
PVAL (val, field, 0, 0);
}
}
@@ -455,39 +533,62 @@ 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');
}
-
+
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)
+ if (val < 0)
+ /* Couldn't fetch this field, don't try again. */
+ const_fields &= ~(1 << (field - fields));
+ else
{
- sign = 1;
- val -= vm_state_get_field (&prev_state, field);
- }
+ int sign = 0;
- PSEP (" ", 0);
- PVAL (val, field, width, sign);
+ if (repeats && field->change_type == CUMUL)
+ {
+ sign = 1;
+ val -= vm_state_get_field (&prev_state, field);
+ }
+
+ PSEP (" ", 0);
+ PVAL (val, field, fwidths[num], sign);
+ }
}
putchar ('\n');
@@ -507,7 +608,7 @@ main (int argc, char **argv)
else
/* Verbose output. */
{
- int max_desc_width = 0;
+ int max_width = 0;
if (print_prefix < 0)
/* By default, only print a prefix if there are multiple fields. */
@@ -518,23 +619,26 @@ main (int argc, char **argv)
for (field = fields; field->name; field++)
if (output_fields & (1 << (field - fields)))
{
- int desc_len = strlen (field->desc);
- if (desc_len > max_desc_width)
- max_desc_width = desc_len;
+ int width = strlen (field->name) + FWIDTH (field);
+ if (width > max_width)
+ max_width = width;
}
for (field = fields; field->name; field++)
if (output_fields & (1 << (field - fields)))
{
val_t val = vm_state_get_field (&state, field);
- int fwidth = 0;
- if (print_prefix)
+ if (val >= 0)
{
- printf ("%s:", field->desc);
- fwidth = max_desc_width + 5 - strlen (field->desc);
+ int fwidth = 0;
+ if (print_prefix)
+ {
+ printf ("%s: ", field->name);
+ fwidth = max_width - strlen (field->name);
+ }
+ PVAL (val, field, fwidth, 0);
+ putchar ('\n');
}
- PVAL (val, field, fwidth, 0);
- putchar ('\n');
}
}