diff options
Diffstat (limited to 'usr/src/cmd/stat')
-rw-r--r-- | usr/src/cmd/stat/Makefile | 5 | ||||
-rw-r--r-- | usr/src/cmd/stat/zschedstat/Makefile | 50 | ||||
-rw-r--r-- | usr/src/cmd/stat/zschedstat/zschedstat.c | 335 |
3 files changed, 388 insertions, 2 deletions
diff --git a/usr/src/cmd/stat/Makefile b/usr/src/cmd/stat/Makefile index faaa19f42c..01b96d14d2 100644 --- a/usr/src/cmd/stat/Makefile +++ b/usr/src/cmd/stat/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2011 Joyent, Inc. All rights reserved. +# Copyright 2011, 2012, Joyent, Inc. All rights reserved. # Use is subject to license terms. # # cmd/stat/Makefile @@ -33,7 +33,8 @@ SUBDIRS= arcstat \ mpstat \ vfsstat \ vmstat \ - ziostat + ziostat \ + zschedstat all := TARGET = all install := TARGET = install diff --git a/usr/src/cmd/stat/zschedstat/Makefile b/usr/src/cmd/stat/zschedstat/Makefile new file mode 100644 index 0000000000..b8654d0ba4 --- /dev/null +++ b/usr/src/cmd/stat/zschedstat/Makefile @@ -0,0 +1,50 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright (c) 2012, Joyent, Inc. All rights reserved. +# + +include $(SRC)/cmd/Makefile.cmd + +PROG= zschedstat +OBJS = zschedstat.o +SRCS =$(OBJS:%.o=%.c) $(COMMON_SRCS) + +LDLIBS += -lkstat + +lint := LINTFLAGS = -muxs + +.KEEP_STATE: + +all: $(PROG) + +install: all .WAIT $(ROOTPROG) + +clean: + +$(ROOTBINPROG): $(PROG) + $(INS.file) + +lint: lint_SRCS + +check: + $(CSTYLE) -pP $(SRCS:%=%) + +include $(SRC)/cmd/Makefile.targ diff --git a/usr/src/cmd/stat/zschedstat/zschedstat.c b/usr/src/cmd/stat/zschedstat/zschedstat.c new file mode 100644 index 0000000000..ba89e2403f --- /dev/null +++ b/usr/src/cmd/stat/zschedstat/zschedstat.c @@ -0,0 +1,335 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2012 Joyent, Inc. All rights reserved. + */ + + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <kstat.h> +#include <errno.h> +#include <sys/zone.h> + +typedef struct { + boolean_t valid; + uint64_t rqueue; + uint64_t rticks; + uint32_t fss_share_pct; + uint64_t fss_pri_hi; + uint64_t fss_pri_avg; + double avrun1; + uint64_t ns_usr; + uint64_t ns_sys; + uint64_t ns_wt; + uint64_t cpu_cap; + uint64_t cpu_baseline; + uint64_t cpu_cap_usage; + uint64_t above_base_sec; + uint64_t delay_cnt; + uint64_t delay_time; + /* Values from the previous cycle so we can diff */ + uint64_t prv_rticks; + uint64_t prv_ns_usr; + uint64_t prv_ns_sys; + uint64_t prv_ns_wt; + uint64_t prv_above_base_sec; + uint64_t prv_delay_cnt; + uint64_t prv_delay_time; +} zinfo_t; + +/* + * MAX_ZONEID is only 10000, so it is a lot faster to go direct to the entry + * we want, even though valid entries in this array will be sparse. + */ + +static zinfo_t zinfo[MAX_ZONEID]; +static uint32_t nsec_per_tick = 0; + +static void +usage() +{ + (void) fprintf(stderr, "zschedstat [-r] [interval [count]]\n"); + exit(1); +} + +static void +get_zone_misc(int zid, kstat_t *ksp) +{ + kstat_named_t *kp; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "run_queue"); + zinfo[zid].rqueue = kp->value.ui64; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "run_ticks"); + zinfo[zid].rticks = kp->value.ui64; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "fss_share_percent"); + zinfo[zid].fss_share_pct = kp->value.ui32; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "fss_pri_hi"); + zinfo[zid].fss_pri_hi = kp->value.ui64; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "fss_pri_avg"); + zinfo[zid].fss_pri_avg = kp->value.ui64; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "avenrun_1min"); + zinfo[zid].avrun1 = (double)kp->value.ui32 / FSCALE; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "nsec_user"); + zinfo[zid].ns_usr = kp->value.ui64; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "nsec_sys"); + zinfo[zid].ns_sys = kp->value.ui64; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "nsec_waitrq"); + zinfo[zid].ns_wt = kp->value.ui64; +} + +static void +get_zone_caps(int zid, kstat_t *ksp) +{ + kstat_named_t *kp; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "value"); + zinfo[zid].cpu_cap = kp->value.ui64; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "baseline"); + zinfo[zid].cpu_baseline = kp->value.ui64; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "usage"); + zinfo[zid].cpu_cap_usage = kp->value.ui64; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "above_base_sec"); + zinfo[zid].above_base_sec = kp->value.ui64; +} + +static void +get_zone_vfs(int zid, kstat_t *ksp) +{ + kstat_named_t *kp; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "delay_cnt"); + zinfo[zid].delay_cnt = kp->value.ui64; + + kp = (kstat_named_t *)kstat_data_lookup(ksp, "delay_time"); + zinfo[zid].delay_time = kp->value.ui64; +} + +static void +read_kstats() +{ + kstat_ctl_t *kc; + kstat_t *ksp; + + if ((kc = kstat_open()) == NULL) { + (void) fprintf(stderr, "open failed\n"); + exit(1); + } + + for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { + if (strcmp("zones", ksp->ks_module) == 0 && + strcmp("zone_misc", ksp->ks_class) == 0) { + if (kstat_read(kc, ksp, NULL) == -1) { + (void) fprintf(stderr, "read failed\n"); + exit(1); + } + zinfo[ksp->ks_instance].valid = B_TRUE; + + get_zone_misc(ksp->ks_instance, ksp); + + } else if (strcmp("caps", ksp->ks_module) == 0 && + strcmp("zone_caps", ksp->ks_class) == 0 && + strncmp("cpucaps_zone", ksp->ks_name, 12) == 0) { + if (kstat_read(kc, ksp, NULL) == -1) { + (void) fprintf(stderr, "read failed\n"); + exit(1); + } + zinfo[ksp->ks_instance].valid = B_TRUE; + + get_zone_caps(ksp->ks_instance, ksp); + + } else if (strcmp("zone_vfs", ksp->ks_module) == 0) { + if (kstat_read(kc, ksp, NULL) == -1) { + (void) fprintf(stderr, "read failed\n"); + exit(1); + } + zinfo[ksp->ks_instance].valid = B_TRUE; + + get_zone_vfs(ksp->ks_instance, ksp); + + } else if (nsec_per_tick == 0 && + strcmp("unix", ksp->ks_module) == 0 && + strcmp("system_misc", ksp->ks_name) == 0) { + kstat_named_t *kp; + + if (kstat_read(kc, ksp, NULL) == -1) { + (void) fprintf(stderr, "read failed\n"); + exit(1); + } + + kp = (kstat_named_t *)kstat_data_lookup(ksp, + "nsec_per_tick"); + nsec_per_tick = kp->value.ui32; + } + } + + (void) kstat_close(kc); +} + +static float +fmt_nsec(uint64_t curr, uint64_t prv) +{ + float s; + uint64_t nsec; + + nsec = curr - prv; + s = (float)nsec / (long)NANOSEC; + + return (s); +} + +/* convert usecs to msecs */ +static float +fmt_usec(uint64_t curr, uint64_t prv) +{ + float s; + uint64_t usec; + + usec = curr - prv; + s = (float)usec / (long)MILLISEC; + + return (s); +} + +static float +fmt_ticks(uint64_t curr, uint64_t prv) +{ + float s; + uint64_t ticks, nsec; + + ticks = curr - prv; + nsec = ticks * nsec_per_tick; + + s = (float)nsec / (long)NANOSEC; + + return (s); +} + +static void +print_data(boolean_t parse) +{ + int i; + char *fmt; + + if (parse) { + fmt = "%d,%lld,%.2f,%.1f,%lld,%lld,%lld,%lld,%lld," + "%.2f,%lld,%.2f,%.2f,%.2f,%.2f\n"; + } else { + fmt = "%4d %2lld %6.2f %5.1f %2lld %2lld %5lld %5lld %2lld " + "%5.2f %4lld %6.2f %6.2f %6.2f %6.2f\n"; + + (void) printf("%4s %2s %6s %5s %2s %2s %5s %5s %2s " + "%5s %4s %6s %6s %6s %6s\n", + "zid", "rq", "rsec", "sh%", "ph", "pa", "cap", "usage", + "bs", "1mla", "dcnt", "dms", "user", "sys", "wtrq"); + } + + for (i = 0; i < MAX_ZONEID; i++) { + if (zinfo[i].valid == B_FALSE) + continue; + + /*LINTED E_SEC_PRINTF_VAR_FMT*/ + (void) printf(fmt, + i, + zinfo[i].rqueue, + fmt_ticks(zinfo[i].rticks, zinfo[i].prv_rticks), + (float)zinfo[i].fss_share_pct / (float)10, + zinfo[i].fss_pri_hi, + zinfo[i].fss_pri_avg, + zinfo[i].cpu_cap, + zinfo[i].cpu_cap_usage, + zinfo[i].above_base_sec - zinfo[i].prv_above_base_sec, + zinfo[i].avrun1, + zinfo[i].delay_cnt - zinfo[i].prv_delay_cnt, + fmt_usec(zinfo[i].delay_time, zinfo[i].prv_delay_time), + fmt_nsec(zinfo[i].ns_usr, zinfo[i].prv_ns_usr), + fmt_nsec(zinfo[i].ns_sys, zinfo[i].prv_ns_sys), + fmt_nsec(zinfo[i].ns_wt, zinfo[i].prv_ns_wt)); + + zinfo[i].valid = B_FALSE; + zinfo[i].prv_rticks = zinfo[i].rticks; + zinfo[i].prv_ns_usr = zinfo[i].ns_usr; + zinfo[i].prv_ns_sys = zinfo[i].ns_sys; + zinfo[i].prv_ns_wt = zinfo[i].ns_wt; + zinfo[i].prv_above_base_sec = zinfo[i].above_base_sec; + zinfo[i].prv_delay_cnt = zinfo[i].delay_cnt; + zinfo[i].prv_delay_time = zinfo[i].delay_time; + } +} + +int +main(int argc, char **argv) +{ + int interval = 5; + int count; + int forever = 1; + int arg; + extern int optind; + boolean_t do_parse = B_FALSE; + + while ((arg = getopt(argc, argv, "r")) != EOF) { + switch (arg) { + case 'r': + do_parse = B_TRUE; + break; + default: + usage(); + } + } + + if (argc > optind) { + interval = atoi(argv[optind]); + optind++; + + if (argc > optind) { + count = atoi(argv[optind]); + forever = 0; + optind++; + } + } + if (argc > optind) + usage(); + + for (;;) { + read_kstats(); + print_data(do_parse); + if (forever == 0 && --count == 0) + break; + (void) sleep(interval); + } + + return (0); +} |