summaryrefslogtreecommitdiff
path: root/utils/vmstat.c
diff options
context:
space:
mode:
authorMiles Bader <miles@gnu.org>1996-07-26 02:49:26 +0000
committerMiles Bader <miles@gnu.org>1996-07-26 02:49:26 +0000
commitc63de13c80cd9f003b1861c2f0d360fc5c9acad1 (patch)
tree797821e0da777bc42efc9ccb964c78eab19bb062 /utils/vmstat.c
parentfd2f59752aa7ff131109d063ab1639088ee50bd7 (diff)
(options, main): -k/--kilobytes, -v/--pages, and -b/--bytes options added.
(fields): New struct members initialized. `size', `cache-hit-ratio', `swap-size', `swap-active', `swap-free', and `swap-pagesize' added. (val_t, enum val_display_type, enum field_change_type): New types. (val_display_type_is_size, print_val, vm_state_refresh, vm_state_get_field, get_vmstats_field, get_size, ensure_def_pager_info, get_swap_size, get_swap_free, get_swap_page_size, get_swap_active): New functions. (struct field): CHANGE_TYPE, DISP_TYPE, STANDARD, and COMPUTE fields added. CUM field removed. (struct vm_state): New type. (main): Changed greatly to use vm_state type & functions, use print_val, and support CONST display types nicely. (argp_program_version): Version changed to 1.1.
Diffstat (limited to 'utils/vmstat.c')
-rw-r--r--utils/vmstat.c437
1 files changed, 354 insertions, 83 deletions
diff --git a/utils/vmstat.c b/utils/vmstat.c
index d99efcc7..6bb90ad3 100644
--- a/utils/vmstat.c
+++ b/utils/vmstat.c
@@ -28,11 +28,107 @@
#include <mach.h>
#include <mach/vm_statistics.h>
+#include <mach/default_pager.h>
#include <hurd.h>
-char *argp_program_version = "vmstat 1.0 (GNU " HURD_RELEASE ")";
+char *argp_program_version = "vmstat 1.1 (GNU " HURD_RELEASE ")";
-struct field {
+static const struct argp_option options[] = {
+ {"terse", 't', 0, 0, "Use short one-line output format", 1 },
+ {"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"
+" 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"
+" defaults to 23, and if not zero, is the number of repeats after which a"
+" blank line and the header will be reprinted (as well as the totals for"
+" cumulative fields).";
+
+/* We use this one type to represent all values printed by this program. It
+ should be signed, and hopefully large enough! */
+typedef ssize_t val_t;
+
+/* How to print a given number. */
+enum val_display_type
+{
+ ASIS, /* Always printed as-is. */
+ COUNT, /* As-is. */
+ PAGES, /* Divided by the page size. */
+ KBYTES, /* Divided by 1024. */
+ BYTES, /* As-is. */
+ SIZES, /* Use the most convenient unit, with suffix. */
+ PCENT, /* Append `%'. */
+};
+
+/* Returns true if TYPE is a `size' type. */
+static int
+val_display_type_is_size (enum val_display_type type)
+{
+ return type == PAGES || type == KBYTES || type == BYTES || type == SIZES;
+}
+
+/* Print a number in a way described by HOW. PSIZE is the page size. FWIDTH
+ is the width of the field to print it in, right-justified. If SIGN is
+ true, the value is always printed with a sign, even if it's positive. */
+static void
+print_val (val_t val, int fwidth, enum val_display_type how, int sign,
+ size_t psize)
+{
+ if (how == SIZES)
+ {
+ float fval = val;
+ char *units = " KMGT", *u = units;
+
+ while (fval > 1024)
+ {
+ fval /= 1024;
+ u++;
+ }
+
+ printf ((fval >= 1000
+ ? (sign ? "%+*.0f%c" : "%*.0f%c")
+ : (sign ? "%+*.3g%c" : "%*.3g%c")),
+ fwidth - 1, fval, *u);
+ }
+ else
+ {
+ if (how == PAGES)
+ val /= psize;
+ else if (how == KBYTES)
+ val /= 1024;
+ else if (how == PCENT)
+ fwidth--;
+
+ printf (sign ? "%+*d" : "%*d", fwidth, val);
+ if (how == PCENT)
+ putchar ('%');
+ }
+}
+
+/* How this field changes with time. */
+enum field_change_type
+{
+ VARY, /* Can go up or down. */
+ CONST, /* Always the same. */
+ CUMUL, /* Monotonic increasing. */
+};
+
+struct vm_state; /* fwd */
+
+struct field
+{
/* Name of the field; used for the option name. */
char *name;
@@ -42,69 +138,190 @@ struct field {
/* Terse header used for the columnar style output. */
char *hdr;
- /* True if this field is `cumulative', that is, monotonic increasing. */
- int cum;
+ /* Type of this field. */
+ enum field_change_type change_type;
+
+ /* How to display the number associated with this field.
+ If this is anything but `DIMLESS', then it can be overriden by the
+ user. */
+ enum val_display_type disp_type;
- /* Offset of the integer_t field in a vm_statistics structure */
+ /* True if we display this field by default (user can always override). */
+ int standard :1;
+
+ /* Offset of the integer_t field in a vm_statistics structure. -1 if a
+ computed field (in which case the COMPUTE field should be filled in). */
int offs;
+
+ /* How to compute this field. If 0, get_vmstats_value is used. This
+ function should return a negative number if there's some problem getting
+ the field. */
+ val_t (*compute)(struct vm_state *state, const struct field *field);
};
+
+/* State about system vm from which we compute the above defined fields. */
+struct vm_state
+{
+ /* General vm statistics. */
+ struct vm_statistics vmstats;
-/* Returns the byte offset of the field FIELD in a vm_statistics structure. */
-#define FOFFS(field_name) offsetof (struct vm_statistics, field_name)
+ /* default pager port (must be privileged to fetch this). */
+ mach_port_t def_pager;
+ struct default_pager_info def_pager_info;
+};
-/* Yields an lvalue refering to FIELD in STATS. */
-#define FVAL(stats, field) (*(integer_t *)((char *)&(stats) + (field)->offs))
+static error_t
+vm_state_refresh (struct vm_state *state)
+{
+ error_t err = vm_statistics (mach_task_self (), &state->vmstats);
-/* vm_statistics fields we know about. */
-static const struct field fields[] = {
- { "pagesize", "Pagesize", "pgsz", 0, FOFFS (pagesize) },
- { "free", "Free pages", "free", 0, FOFFS (free_count) },
- { "active", "Active pages", "actv", 0, FOFFS (active_count) },
- { "inactive", "Inactive pages", "inac", 0, FOFFS (inactive_count) },
- { "wired", "Wired pages", "wire", 0, FOFFS (wire_count) },
- { "zero-filled", "Zeroed pages", "zeroed", 1, FOFFS (zero_fill_count) },
- { "reactivations","Reactivations", "react", 1, FOFFS (reactivations) },
- { "pageins", "Pageins", "pgins", 1, FOFFS (pageins) },
- { "pageouts", "Pageouts", "pgouts", 1, FOFFS (pageouts) },
- { "faults", "Faults", "pfaults", 1, FOFFS (faults) },
- { "cow-faults", "Cow faults", "cowpfs", 1, FOFFS (cow_faults) },
- { "cache-lookups","Cache lookups", "clkups", 1, FOFFS (lookups) },
- { "cache-hits", "Cache hits", "chits", 1, FOFFS (hits) },
- {0}
-};
+ if (err)
+ return err;
-static const struct argp_option options[] = {
- {"terse", 't', 0, 0, "Use short one-line output format", 1 },
- {"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"},
+ /* Mark the info as invalid, but leave DEF_PAGER alone. */
+ bzero (&state->def_pager_info, sizeof state->def_pager_info);
- /* A header for all the individual field options. */
- { 0,0,0,0, "Selecting which statistics to show:", 2},
+ return 0;
+}
+
+static val_t
+get_vmstats_field (struct vm_state *state, const struct field *field)
+{
+ val_t val =
+ (val_t)(*(integer_t *)((char *)&state->vmstats + field->offs));
+ if (val_display_type_is_size (field->disp_type))
+ val *= state->vmstats.pagesize;
+ return val;
+}
+
+static val_t
+get_size (struct vm_state *state, const struct field *field)
+{
+ return
+ (state->vmstats.free_count + state->vmstats.active_count
+ + state->vmstats.inactive_count + state->vmstats.wire_count)
+ * state->vmstats.pagesize;
+}
+
+static val_t
+vm_state_get_field (struct vm_state *state, const struct field *field)
+{
+ return (field->compute ?: get_vmstats_field) (state, field);
+}
+
+static val_t
+get_cache_hit_ratio (struct vm_state *state, const struct field *field)
+{
+ return state->vmstats.hits * 100 / state->vmstats.lookups;
+}
+
+/* Makes sure STATE contains a default pager port and associated info, and
+ returns 0 if not (after printing an error). */
+static int
+ensure_def_pager_info (struct vm_state *state)
+{
+ error_t err;
+
+ if (state->def_pager == MACH_PORT_NULL)
+ {
+ mach_port_t host;
+
+ err = get_privileged_ports (&host, 0);
+ 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);
+
+ if (err)
+ {
+ error (0, err, "vm_set_default_memory_manager");
+ 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;
+}
+
+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;
+}
+
+/* Returns the byte offset of the field FIELD in a vm_statistics structure. */
+#define _F(field_name) offsetof (struct vm_statistics, field_name)
+
+/* vm_statistics fields we know about. */
+static const struct field fields[] =
+{
+ {"pagesize", "Pagesize", " pgsz", CONST,ASIS, 1,_F(pagesize)},
+ {"size", "Size", " size", CONST,SIZES,1,0,get_size},
+ {"free", "Free", " free", VARY, SIZES,1,_F(free_count)},
+ {"active", "Active", " actv", VARY, SIZES,1,_F(active_count)},
+ {"inactive", "Inactive", "inact", VARY, SIZES,1,_F(inactive_count)},
+ {"wired", "Wired", "wired", VARY, SIZES,1,_F(wire_count)},
+ {"zero-filled", "Zeroed", "zeroed", CUMUL,SIZES,1,_F(zero_fill_count)},
+ {"reactivated", "Reactivated", "react", CUMUL,SIZES,1,_F(reactivations)},
+ {"pageins", "Pageins", "pgins", CUMUL,SIZES,1,_F(pageins)},
+ {"pageouts", "Pageouts", "pgouts", CUMUL,SIZES,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,SIZES,1,0,get_swap_size},
+ {"swap-active", "Swap active", "swactv", VARY, SIZES,0,0,get_swap_active},
+ {"swap-free", "Swap free", "swfree", VARY, SIZES,1,0,get_swap_free},
+ {"swap-pagesize","Swap pagesize","swpgsz", CONST,ASIS, 0,0,get_swap_page_size},
{0}
};
-static const char *args_doc = "[PERIOD [COUNT [HEADER_INTERVAL]]]";
-static const char *doc = "If 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"
-" defaults to 23, and if not zero, is the number of repeats after which a"
-" blank line and the header will be reprinted (as well as the totals for"
-" cumulative fields).";
-
+#undef _F
+
int
main (int argc, char **argv)
{
error_t err;
const struct field *field;
- struct vm_statistics stats;
+ struct vm_state state;
int num_fields = 0; /* Number of vm_fields known. */
unsigned long output_fields = 0; /* A bit per field, from 0. */
int count = 1; /* Number of repeats. */
unsigned period = 0; /* Seconds between terse mode repeats. */
- unsigned hdr_interval = 23; /* */
-
+ unsigned hdr_interval = 22; /* */
+ enum val_display_type user_disp_type = ASIS;
int terse = 0, print_heading = 1, print_prefix = -1;
/* Parse our options... */
@@ -120,6 +337,9 @@ main (int argc, char **argv)
case 'p': print_prefix = 1; break;
case 'P': print_prefix = 0; break;
case 'H': print_heading = 0; break;
+ case 'b': user_disp_type = BYTES; break;
+ case 'v': user_disp_type = PAGES; break;
+ case 'k': user_disp_type = KBYTES; break;
case ARGP_KEY_ARG:
terse = 1;
@@ -174,17 +394,49 @@ main (int argc, char **argv)
argp_parse (&argp, argc, argv, 0, 0, 0);
if (output_fields == 0)
- output_fields = ~0; /* By default, show all fields. */
+ /* Show default fields. */
+ for (field = fields; field->name; field++)
+ if (field->standard)
+ output_fields |= (1 << (field - fields));
+
+ /* Returns a value describing how to display FIELD. */
+#define FDISPTYPE(field) \
+ (user_disp_type == ASIS || !val_display_type_is_size ((field)->disp_type) \
+ ? (field)->disp_type \
+ : user_disp_type)
+
+ /* Prints SEP if the variable FIRST is 0, otherwise, prints START (if
+ it's non-zero), and sets first to 0. */
+#define PSEP(sep, start) \
+ (first ? (first = 0, (start && fputs (start, stdout))) : fputs (sep, stdout))
+
+ /* Actually fetch the statistics. */
+ bzero (&state, sizeof (state)); /* Initialize STATE. */
+ err = vm_state_refresh (&state);
+ if (err)
+ error (2, err, "vm_state_refresh");
if (terse)
/* Terse (one-line) output mode. */
{
int first_hdr = 1, first, repeats;
- struct vm_statistics prev_stats;
+ struct vm_state prev_state;
+ int const_fields = 0;
if (count == 0)
count = -1;
+ /* We only show const fields once per page, so find out which ones
+ those are. */
+ for (field = fields; field->name; field++)
+ if ((output_fields & (1 << (field - fields)))
+ && field->change_type == CONST)
+ const_fields |= (1 << (field - fields));
+ output_fields &= ~const_fields;
+
+ if (const_fields)
+ hdr_interval--; /* Allow room for the constant fields. */
+
do
{
if (first_hdr)
@@ -192,56 +444,74 @@ main (int argc, char **argv)
else
putchar ('\n');
- if (print_heading)
+ if (const_fields)
+ /* Output constant fields on a line preceding the header. */
{
- int which;
- for (which = 0, first = 1; which < num_fields; which++)
- if (output_fields & (1 << which))
+ for (field = fields, first = 1; field->name; field++)
+ if (const_fields & (1 << (field - fields)))
{
- if (first)
- first = 0;
+ val_t val = vm_state_get_field (&state, field);
+ if (val < 0)
+ /* Couldn't fetch this field, don't try again. */
+ const_fields &= ~(1 << (field - fields));
else
- putchar (' ');
- fputs (fields[which].hdr, stdout);
+ {
+ PSEP (", ", "(");
+ printf ("%s: ", field->desc);
+ print_val (val, 0, FDISPTYPE (field), 0,
+ state.vmstats.pagesize);
+ }
+ }
+ if (! first)
+ puts (")");
+ }
+
+ if (print_heading)
+ {
+ for (field = fields, first = 1; field->name; field++)
+ if (output_fields & (1 << (field - fields)))
+ {
+ PSEP (" ", 0);
+ fputs (field->hdr, stdout);
}
putchar ('\n');
}
- bzero (&prev_stats, sizeof (prev_stats));
+ prev_state = state;
for (repeats = 0
; count && repeats < hdr_interval && count
; repeats++, count--)
{
- /* Actually fetch the statistics. */
- err = vm_statistics (mach_task_self (), &stats);
- if (err)
- error (2, err, "vm_statistics");
-
/* Output the fields. */
for (field = fields, first = 1; field->name; field++)
if (output_fields & (1 << (field - fields)))
{
- integer_t val = FVAL (stats, field);
+ int sign = 0;
int width = strlen (field->hdr);
+ val_t val = vm_state_get_field (&state, field);
- if (field->cum)
+ if (repeats && field->change_type == CUMUL)
{
- integer_t cum = val;
- val -= FVAL (prev_stats, field);
- FVAL (prev_stats, field) = cum;
+ sign = 1;
+ val -= vm_state_get_field (&prev_state, field);
}
- if (first)
- first = 0;
- else
- putchar (' ');
- printf ("%*d", width, val);
+ PSEP (" ", 0);
+ print_val (val, width, FDISPTYPE (field), sign,
+ state.vmstats.pagesize);
}
putchar ('\n');
+ prev_state = state;
+
if (period)
- sleep (period);
+ {
+ sleep (period);
+ err = vm_state_refresh (&state);
+ if (err)
+ error (2, err, "vm_state_refresh");
+ }
}
}
while (count);
@@ -265,19 +535,20 @@ main (int argc, char **argv)
max_desc_width = desc_len;
}
- /* Actually fetch the statistics. */
- err = vm_statistics (mach_task_self (), &stats);
- if (err)
- error (2, err, "vm_statistics");
-
for (field = fields; field->name; field++)
if (output_fields & (1 << (field - fields)))
- if (print_prefix)
- printf ("%s:%*d\n", field->desc,
- max_desc_width + 5 - strlen (field->desc),
- FVAL (stats, field));
- else
- printf ("%d\n", FVAL (stats, field));
+ {
+ val_t val = vm_state_get_field (&state, field);
+ int fwidth = 0;
+ if (print_prefix)
+ {
+ printf ("%s:", field->desc);
+ fwidth = max_desc_width + 5 - strlen (field->desc);
+ }
+ print_val (val, fwidth, FDISPTYPE (field), 0,
+ state.vmstats.pagesize);
+ putchar ('\n');
+ }
}
exit (0);