1*7aa76ffcSBryan Cantrill /* 2*7aa76ffcSBryan Cantrill * CDDL HEADER START 3*7aa76ffcSBryan Cantrill * 4*7aa76ffcSBryan Cantrill * The contents of this file are subject to the terms of the 5*7aa76ffcSBryan Cantrill * Common Development and Distribution License (the "License"). 6*7aa76ffcSBryan Cantrill * You may not use this file except in compliance with the License. 7*7aa76ffcSBryan Cantrill * 8*7aa76ffcSBryan Cantrill * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7aa76ffcSBryan Cantrill * or http://www.opensolaris.org/os/licensing. 10*7aa76ffcSBryan Cantrill * See the License for the specific language governing permissions 11*7aa76ffcSBryan Cantrill * and limitations under the License. 12*7aa76ffcSBryan Cantrill * 13*7aa76ffcSBryan Cantrill * When distributing Covered Code, include this CDDL HEADER in each 14*7aa76ffcSBryan Cantrill * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7aa76ffcSBryan Cantrill * If applicable, add the following below this CDDL HEADER, with the 16*7aa76ffcSBryan Cantrill * fields enclosed by brackets "[]" replaced with your own identifying 17*7aa76ffcSBryan Cantrill * information: Portions Copyright [yyyy] [name of copyright owner] 18*7aa76ffcSBryan Cantrill * 19*7aa76ffcSBryan Cantrill * CDDL HEADER END 20*7aa76ffcSBryan Cantrill */ 21*7aa76ffcSBryan Cantrill 22*7aa76ffcSBryan Cantrill /* 23*7aa76ffcSBryan Cantrill * Copyright (c) 2011, Joyent, Inc. All rights reserved. 24*7aa76ffcSBryan Cantrill */ 25*7aa76ffcSBryan Cantrill 26*7aa76ffcSBryan Cantrill #include <sys/kstat.h> 27*7aa76ffcSBryan Cantrill #include <kstat.h> 28*7aa76ffcSBryan Cantrill #include <stdlib.h> 29*7aa76ffcSBryan Cantrill #include <unistd.h> 30*7aa76ffcSBryan Cantrill #include <assert.h> 31*7aa76ffcSBryan Cantrill #include <errno.h> 32*7aa76ffcSBryan Cantrill #include <stdio.h> 33*7aa76ffcSBryan Cantrill #include <string.h> 34*7aa76ffcSBryan Cantrill #include <strings.h> 35*7aa76ffcSBryan Cantrill #include <alloca.h> 36*7aa76ffcSBryan Cantrill #include <signal.h> 37*7aa76ffcSBryan Cantrill #include <sys/varargs.h> 38*7aa76ffcSBryan Cantrill #include <sys/int_limits.h> 39*7aa76ffcSBryan Cantrill 40*7aa76ffcSBryan Cantrill #define KSTAT_FIELD_USEINSTANCE 0x01 41*7aa76ffcSBryan Cantrill #define KSTAT_FIELD_NODELTA 0x02 42*7aa76ffcSBryan Cantrill #define KSTAT_FIELD_FILLER 0x04 43*7aa76ffcSBryan Cantrill 44*7aa76ffcSBryan Cantrill typedef struct kstat_field { 45*7aa76ffcSBryan Cantrill char *ksf_header; /* header for field */ 46*7aa76ffcSBryan Cantrill char *ksf_name; /* name of stat, if any */ 47*7aa76ffcSBryan Cantrill int ksf_width; /* width for field in output line */ 48*7aa76ffcSBryan Cantrill uint32_t ksf_flags; /* flags for this field, if any */ 49*7aa76ffcSBryan Cantrill int ksf_hint; /* index hint for field in kstat */ 50*7aa76ffcSBryan Cantrill } kstat_field_t; 51*7aa76ffcSBryan Cantrill 52*7aa76ffcSBryan Cantrill typedef struct kstat_instance { 53*7aa76ffcSBryan Cantrill char ksi_name[KSTAT_STRLEN]; /* name of the underlying kstat */ 54*7aa76ffcSBryan Cantrill int ksi_instance; /* instance identifer of this kstat */ 55*7aa76ffcSBryan Cantrill kstat_t *ksi_ksp; /* pointer to the kstat */ 56*7aa76ffcSBryan Cantrill uint64_t *ksi_data[2]; /* pointer to two generations of data */ 57*7aa76ffcSBryan Cantrill hrtime_t ksi_snaptime[2]; /* hrtime for data generations */ 58*7aa76ffcSBryan Cantrill int ksi_gen; /* current generation */ 59*7aa76ffcSBryan Cantrill struct kstat_instance *ksi_next; /* next in instance list */ 60*7aa76ffcSBryan Cantrill } kstat_instance_t; 61*7aa76ffcSBryan Cantrill 62*7aa76ffcSBryan Cantrill const char *g_cmd = "kvmstat"; 63*7aa76ffcSBryan Cantrill 64*7aa76ffcSBryan Cantrill static void 65*7aa76ffcSBryan Cantrill fatal(char *fmt, ...) 66*7aa76ffcSBryan Cantrill { 67*7aa76ffcSBryan Cantrill va_list ap; 68*7aa76ffcSBryan Cantrill int error = errno; 69*7aa76ffcSBryan Cantrill 70*7aa76ffcSBryan Cantrill va_start(ap, fmt); 71*7aa76ffcSBryan Cantrill 72*7aa76ffcSBryan Cantrill (void) fprintf(stderr, "%s: ", g_cmd); 73*7aa76ffcSBryan Cantrill /*LINTED*/ 74*7aa76ffcSBryan Cantrill (void) vfprintf(stderr, fmt, ap); 75*7aa76ffcSBryan Cantrill 76*7aa76ffcSBryan Cantrill if (fmt[strlen(fmt) - 1] != '\n') 77*7aa76ffcSBryan Cantrill (void) fprintf(stderr, ": %s\n", strerror(error)); 78*7aa76ffcSBryan Cantrill 79*7aa76ffcSBryan Cantrill exit(EXIT_FAILURE); 80*7aa76ffcSBryan Cantrill } 81*7aa76ffcSBryan Cantrill 82*7aa76ffcSBryan Cantrill int 83*7aa76ffcSBryan Cantrill kstat_field_hint(kstat_t *ksp, kstat_field_t *field) 84*7aa76ffcSBryan Cantrill { 85*7aa76ffcSBryan Cantrill kstat_named_t *nm = KSTAT_NAMED_PTR(ksp); 86*7aa76ffcSBryan Cantrill int i; 87*7aa76ffcSBryan Cantrill 88*7aa76ffcSBryan Cantrill assert(ksp->ks_type == KSTAT_TYPE_NAMED); 89*7aa76ffcSBryan Cantrill 90*7aa76ffcSBryan Cantrill for (i = 0; i < ksp->ks_ndata; i++) { 91*7aa76ffcSBryan Cantrill if (strcmp(field->ksf_name, nm[i].name) == 0) 92*7aa76ffcSBryan Cantrill return (field->ksf_hint = i); 93*7aa76ffcSBryan Cantrill } 94*7aa76ffcSBryan Cantrill 95*7aa76ffcSBryan Cantrill fatal("could not find field '%s' in %s:%d\n", 96*7aa76ffcSBryan Cantrill field->ksf_name, ksp->ks_name, ksp->ks_instance); 97*7aa76ffcSBryan Cantrill 98*7aa76ffcSBryan Cantrill return (0); 99*7aa76ffcSBryan Cantrill } 100*7aa76ffcSBryan Cantrill 101*7aa76ffcSBryan Cantrill int 102*7aa76ffcSBryan Cantrill kstat_instances_compare(const void *lhs, const void *rhs) 103*7aa76ffcSBryan Cantrill { 104*7aa76ffcSBryan Cantrill kstat_instance_t *l = *((kstat_instance_t **)lhs); 105*7aa76ffcSBryan Cantrill kstat_instance_t *r = *((kstat_instance_t **)rhs); 106*7aa76ffcSBryan Cantrill int rval; 107*7aa76ffcSBryan Cantrill 108*7aa76ffcSBryan Cantrill if ((rval = strcmp(l->ksi_name, r->ksi_name)) != 0) 109*7aa76ffcSBryan Cantrill return (rval); 110*7aa76ffcSBryan Cantrill 111*7aa76ffcSBryan Cantrill if (l->ksi_instance < r->ksi_instance) 112*7aa76ffcSBryan Cantrill return (-1); 113*7aa76ffcSBryan Cantrill 114*7aa76ffcSBryan Cantrill if (l->ksi_instance > r->ksi_instance) 115*7aa76ffcSBryan Cantrill return (1); 116*7aa76ffcSBryan Cantrill 117*7aa76ffcSBryan Cantrill return (0); 118*7aa76ffcSBryan Cantrill } 119*7aa76ffcSBryan Cantrill 120*7aa76ffcSBryan Cantrill void 121*7aa76ffcSBryan Cantrill kstat_instances_update(kstat_ctl_t *kcp, kstat_instance_t **head, 122*7aa76ffcSBryan Cantrill boolean_t (*interested)(kstat_t *)) 123*7aa76ffcSBryan Cantrill { 124*7aa76ffcSBryan Cantrill int ninstances = 0, i; 125*7aa76ffcSBryan Cantrill kstat_instance_t **sorted, *ksi, *next; 126*7aa76ffcSBryan Cantrill kstat_t *ksp; 127*7aa76ffcSBryan Cantrill kid_t kid; 128*7aa76ffcSBryan Cantrill 129*7aa76ffcSBryan Cantrill if ((kid = kstat_chain_update(kcp)) == 0 && *head != NULL) 130*7aa76ffcSBryan Cantrill return; 131*7aa76ffcSBryan Cantrill 132*7aa76ffcSBryan Cantrill if (kid == -1) 133*7aa76ffcSBryan Cantrill fatal("failed to update kstat chain"); 134*7aa76ffcSBryan Cantrill 135*7aa76ffcSBryan Cantrill for (ksi = *head; ksi != NULL; ksi = ksi->ksi_next) 136*7aa76ffcSBryan Cantrill ksi->ksi_ksp = NULL; 137*7aa76ffcSBryan Cantrill 138*7aa76ffcSBryan Cantrill for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 139*7aa76ffcSBryan Cantrill kstat_instance_t *last = NULL; 140*7aa76ffcSBryan Cantrill 141*7aa76ffcSBryan Cantrill if (!interested(ksp)) 142*7aa76ffcSBryan Cantrill continue; 143*7aa76ffcSBryan Cantrill 144*7aa76ffcSBryan Cantrill /* 145*7aa76ffcSBryan Cantrill * Now look to see if we have this instance and name. (Yes, 146*7aa76ffcSBryan Cantrill * this is a linear search; we're assuming that this list is 147*7aa76ffcSBryan Cantrill * modest in size.) 148*7aa76ffcSBryan Cantrill */ 149*7aa76ffcSBryan Cantrill for (ksi = *head; ksi != NULL; ksi = ksi->ksi_next) { 150*7aa76ffcSBryan Cantrill last = ksi; 151*7aa76ffcSBryan Cantrill 152*7aa76ffcSBryan Cantrill if (ksi->ksi_instance != ksp->ks_instance) 153*7aa76ffcSBryan Cantrill continue; 154*7aa76ffcSBryan Cantrill 155*7aa76ffcSBryan Cantrill if (strcmp(ksi->ksi_name, ksp->ks_name) != 0) 156*7aa76ffcSBryan Cantrill continue; 157*7aa76ffcSBryan Cantrill 158*7aa76ffcSBryan Cantrill ksi->ksi_ksp = ksp; 159*7aa76ffcSBryan Cantrill ninstances++; 160*7aa76ffcSBryan Cantrill break; 161*7aa76ffcSBryan Cantrill } 162*7aa76ffcSBryan Cantrill 163*7aa76ffcSBryan Cantrill if (ksi != NULL) 164*7aa76ffcSBryan Cantrill continue; 165*7aa76ffcSBryan Cantrill 166*7aa76ffcSBryan Cantrill if ((ksi = malloc(sizeof (kstat_instance_t))) == NULL) 167*7aa76ffcSBryan Cantrill fatal("could not allocate memory for stat instance"); 168*7aa76ffcSBryan Cantrill 169*7aa76ffcSBryan Cantrill bzero(ksi, sizeof (kstat_instance_t)); 170*7aa76ffcSBryan Cantrill (void) strlcpy(ksi->ksi_name, ksp->ks_name, KSTAT_STRLEN); 171*7aa76ffcSBryan Cantrill ksi->ksi_instance = ksp->ks_instance; 172*7aa76ffcSBryan Cantrill ksi->ksi_ksp = ksp; 173*7aa76ffcSBryan Cantrill ksi->ksi_next = NULL; 174*7aa76ffcSBryan Cantrill 175*7aa76ffcSBryan Cantrill if (last == NULL) { 176*7aa76ffcSBryan Cantrill assert(*head == NULL); 177*7aa76ffcSBryan Cantrill *head = ksi; 178*7aa76ffcSBryan Cantrill } else { 179*7aa76ffcSBryan Cantrill last->ksi_next = ksi; 180*7aa76ffcSBryan Cantrill } 181*7aa76ffcSBryan Cantrill 182*7aa76ffcSBryan Cantrill ninstances++; 183*7aa76ffcSBryan Cantrill } 184*7aa76ffcSBryan Cantrill 185*7aa76ffcSBryan Cantrill /* 186*7aa76ffcSBryan Cantrill * Now we know how many instances we have; iterate back over them, 187*7aa76ffcSBryan Cantrill * pruning the stale ones and adding the active ones to a holding 188*7aa76ffcSBryan Cantrill * array in which to sort them. 189*7aa76ffcSBryan Cantrill */ 190*7aa76ffcSBryan Cantrill sorted = (void *)alloca(ninstances * sizeof (kstat_instance_t *)); 191*7aa76ffcSBryan Cantrill ninstances = 0; 192*7aa76ffcSBryan Cantrill 193*7aa76ffcSBryan Cantrill for (ksi = *head; ksi != NULL; ksi = next) { 194*7aa76ffcSBryan Cantrill next = ksi->ksi_next; 195*7aa76ffcSBryan Cantrill 196*7aa76ffcSBryan Cantrill if (ksi->ksi_ksp == NULL) { 197*7aa76ffcSBryan Cantrill free(ksi); 198*7aa76ffcSBryan Cantrill } else { 199*7aa76ffcSBryan Cantrill sorted[ninstances++] = ksi; 200*7aa76ffcSBryan Cantrill } 201*7aa76ffcSBryan Cantrill } 202*7aa76ffcSBryan Cantrill 203*7aa76ffcSBryan Cantrill if (ninstances == 0) { 204*7aa76ffcSBryan Cantrill *head = NULL; 205*7aa76ffcSBryan Cantrill return; 206*7aa76ffcSBryan Cantrill } 207*7aa76ffcSBryan Cantrill 208*7aa76ffcSBryan Cantrill qsort(sorted, ninstances, sizeof (kstat_instance_t *), 209*7aa76ffcSBryan Cantrill kstat_instances_compare); 210*7aa76ffcSBryan Cantrill 211*7aa76ffcSBryan Cantrill *head = sorted[0]; 212*7aa76ffcSBryan Cantrill 213*7aa76ffcSBryan Cantrill for (i = 0; i < ninstances; i++) { 214*7aa76ffcSBryan Cantrill ksi = sorted[i]; 215*7aa76ffcSBryan Cantrill ksi->ksi_next = i < ninstances - 1 ? sorted[i + 1] : NULL; 216*7aa76ffcSBryan Cantrill } 217*7aa76ffcSBryan Cantrill } 218*7aa76ffcSBryan Cantrill 219*7aa76ffcSBryan Cantrill void 220*7aa76ffcSBryan Cantrill kstat_instances_read(kstat_ctl_t *kcp, kstat_instance_t *instances, 221*7aa76ffcSBryan Cantrill kstat_field_t *fields) 222*7aa76ffcSBryan Cantrill { 223*7aa76ffcSBryan Cantrill kstat_instance_t *ksi; 224*7aa76ffcSBryan Cantrill int i, nfields; 225*7aa76ffcSBryan Cantrill 226*7aa76ffcSBryan Cantrill for (nfields = 0; fields[nfields].ksf_header != NULL; nfields++) 227*7aa76ffcSBryan Cantrill continue; 228*7aa76ffcSBryan Cantrill 229*7aa76ffcSBryan Cantrill for (ksi = instances; ksi != NULL; ksi = ksi->ksi_next) { 230*7aa76ffcSBryan Cantrill kstat_t *ksp = ksi->ksi_ksp; 231*7aa76ffcSBryan Cantrill 232*7aa76ffcSBryan Cantrill if (ksp == NULL) 233*7aa76ffcSBryan Cantrill continue; 234*7aa76ffcSBryan Cantrill 235*7aa76ffcSBryan Cantrill if (kstat_read(kcp, ksp, NULL) == -1) { 236*7aa76ffcSBryan Cantrill if (errno == ENXIO) { 237*7aa76ffcSBryan Cantrill /* 238*7aa76ffcSBryan Cantrill * Our kstat has been removed since the update; 239*7aa76ffcSBryan Cantrill * NULL it out to prevent us from trying to read 240*7aa76ffcSBryan Cantrill * it again (and to indicate that it should not 241*7aa76ffcSBryan Cantrill * be displayed) and drive on. 242*7aa76ffcSBryan Cantrill */ 243*7aa76ffcSBryan Cantrill ksi->ksi_ksp = NULL; 244*7aa76ffcSBryan Cantrill continue; 245*7aa76ffcSBryan Cantrill } 246*7aa76ffcSBryan Cantrill 247*7aa76ffcSBryan Cantrill fatal("failed to read kstat %s:%d", 248*7aa76ffcSBryan Cantrill ksi->ksi_name, ksi->ksi_instance); 249*7aa76ffcSBryan Cantrill } 250*7aa76ffcSBryan Cantrill 251*7aa76ffcSBryan Cantrill if (ksp->ks_type != KSTAT_TYPE_NAMED) { 252*7aa76ffcSBryan Cantrill fatal("%s:%d is not a named kstat", ksi->ksi_name, 253*7aa76ffcSBryan Cantrill ksi->ksi_instance); 254*7aa76ffcSBryan Cantrill } 255*7aa76ffcSBryan Cantrill 256*7aa76ffcSBryan Cantrill if (ksi->ksi_data[0] == NULL) { 257*7aa76ffcSBryan Cantrill size_t size = nfields * sizeof (uint64_t) * 2; 258*7aa76ffcSBryan Cantrill uint64_t *data; 259*7aa76ffcSBryan Cantrill 260*7aa76ffcSBryan Cantrill if ((data = malloc(size)) == NULL) 261*7aa76ffcSBryan Cantrill fatal("could not allocate memory"); 262*7aa76ffcSBryan Cantrill 263*7aa76ffcSBryan Cantrill bzero(data, size); 264*7aa76ffcSBryan Cantrill ksi->ksi_data[0] = data; 265*7aa76ffcSBryan Cantrill ksi->ksi_data[1] = &data[nfields]; 266*7aa76ffcSBryan Cantrill } 267*7aa76ffcSBryan Cantrill 268*7aa76ffcSBryan Cantrill for (i = 0; i < nfields; i++) { 269*7aa76ffcSBryan Cantrill kstat_named_t *nm = KSTAT_NAMED_PTR(ksp); 270*7aa76ffcSBryan Cantrill kstat_field_t *field = &fields[i]; 271*7aa76ffcSBryan Cantrill int hint = field->ksf_hint; 272*7aa76ffcSBryan Cantrill 273*7aa76ffcSBryan Cantrill if (field->ksf_name == NULL) 274*7aa76ffcSBryan Cantrill continue; 275*7aa76ffcSBryan Cantrill 276*7aa76ffcSBryan Cantrill if (hint < 0 || hint >= ksp->ks_ndata || 277*7aa76ffcSBryan Cantrill strcmp(field->ksf_name, nm[hint].name) != 0) { 278*7aa76ffcSBryan Cantrill hint = kstat_field_hint(ksp, field); 279*7aa76ffcSBryan Cantrill } 280*7aa76ffcSBryan Cantrill 281*7aa76ffcSBryan Cantrill ksi->ksi_data[ksi->ksi_gen][i] = nm[hint].value.ui64; 282*7aa76ffcSBryan Cantrill } 283*7aa76ffcSBryan Cantrill 284*7aa76ffcSBryan Cantrill ksi->ksi_snaptime[ksi->ksi_gen] = ksp->ks_snaptime; 285*7aa76ffcSBryan Cantrill ksi->ksi_gen ^= 1; 286*7aa76ffcSBryan Cantrill } 287*7aa76ffcSBryan Cantrill } 288*7aa76ffcSBryan Cantrill 289*7aa76ffcSBryan Cantrill uint64_t 290*7aa76ffcSBryan Cantrill kstat_instances_delta(kstat_instance_t *ksi, int i) 291*7aa76ffcSBryan Cantrill { 292*7aa76ffcSBryan Cantrill int gen = ksi->ksi_gen; 293*7aa76ffcSBryan Cantrill uint64_t delta = ksi->ksi_data[gen ^ 1][i] - ksi->ksi_data[gen][i]; 294*7aa76ffcSBryan Cantrill uint64_t tdelta = ksi->ksi_snaptime[gen ^ 1] - ksi->ksi_snaptime[gen]; 295*7aa76ffcSBryan Cantrill 296*7aa76ffcSBryan Cantrill return (((delta * (uint64_t)NANOSEC) + (tdelta / 2)) / tdelta); 297*7aa76ffcSBryan Cantrill } 298*7aa76ffcSBryan Cantrill 299*7aa76ffcSBryan Cantrill void 300*7aa76ffcSBryan Cantrill kstat_instances_print(kstat_instance_t *instances, kstat_field_t *fields, 301*7aa76ffcSBryan Cantrill boolean_t header) 302*7aa76ffcSBryan Cantrill { 303*7aa76ffcSBryan Cantrill kstat_instance_t *ksi = instances; 304*7aa76ffcSBryan Cantrill int i, nfields; 305*7aa76ffcSBryan Cantrill 306*7aa76ffcSBryan Cantrill for (nfields = 0; fields[nfields].ksf_header != NULL; nfields++) 307*7aa76ffcSBryan Cantrill continue; 308*7aa76ffcSBryan Cantrill 309*7aa76ffcSBryan Cantrill if (header) { 310*7aa76ffcSBryan Cantrill for (i = 0; i < nfields; i++) { 311*7aa76ffcSBryan Cantrill (void) printf("%*s%c", fields[i].ksf_width, 312*7aa76ffcSBryan Cantrill fields[i].ksf_header, i < nfields - 1 ? ' ' : '\n'); 313*7aa76ffcSBryan Cantrill } 314*7aa76ffcSBryan Cantrill } 315*7aa76ffcSBryan Cantrill 316*7aa76ffcSBryan Cantrill for (ksi = instances; ksi != NULL; ksi = ksi->ksi_next) { 317*7aa76ffcSBryan Cantrill if (ksi->ksi_snaptime[1] == 0 || ksi->ksi_ksp == NULL) 318*7aa76ffcSBryan Cantrill continue; 319*7aa76ffcSBryan Cantrill 320*7aa76ffcSBryan Cantrill for (i = 0; i < nfields; i++) { 321*7aa76ffcSBryan Cantrill char trailer = i < nfields - 1 ? ' ' : '\n'; 322*7aa76ffcSBryan Cantrill 323*7aa76ffcSBryan Cantrill if (fields[i].ksf_flags & KSTAT_FIELD_FILLER) { 324*7aa76ffcSBryan Cantrill (void) printf("%*s%c", fields[i].ksf_width, 325*7aa76ffcSBryan Cantrill fields[i].ksf_header, trailer); 326*7aa76ffcSBryan Cantrill continue; 327*7aa76ffcSBryan Cantrill } 328*7aa76ffcSBryan Cantrill 329*7aa76ffcSBryan Cantrill (void) printf("%*lld%c", fields[i].ksf_width, 330*7aa76ffcSBryan Cantrill fields[i].ksf_flags & KSTAT_FIELD_USEINSTANCE ? 331*7aa76ffcSBryan Cantrill ksi->ksi_instance : 332*7aa76ffcSBryan Cantrill fields[i].ksf_flags & KSTAT_FIELD_NODELTA ? 333*7aa76ffcSBryan Cantrill ksi->ksi_data[ksi->ksi_gen ^ 1][i] : 334*7aa76ffcSBryan Cantrill kstat_instances_delta(ksi, i), trailer); 335*7aa76ffcSBryan Cantrill } 336*7aa76ffcSBryan Cantrill } 337*7aa76ffcSBryan Cantrill } 338*7aa76ffcSBryan Cantrill 339*7aa76ffcSBryan Cantrill boolean_t 340*7aa76ffcSBryan Cantrill interested(kstat_t *ksp) 341*7aa76ffcSBryan Cantrill { 342*7aa76ffcSBryan Cantrill const char *module = "kvm"; 343*7aa76ffcSBryan Cantrill const char *class = "misc"; 344*7aa76ffcSBryan Cantrill const char *name = "vcpu-"; 345*7aa76ffcSBryan Cantrill 346*7aa76ffcSBryan Cantrill if (strcmp(ksp->ks_module, module) != 0) 347*7aa76ffcSBryan Cantrill return (B_FALSE); 348*7aa76ffcSBryan Cantrill 349*7aa76ffcSBryan Cantrill if (strcmp(ksp->ks_class, class) != 0) 350*7aa76ffcSBryan Cantrill return (B_FALSE); 351*7aa76ffcSBryan Cantrill 352*7aa76ffcSBryan Cantrill if (strstr(ksp->ks_name, name) != ksp->ks_name) 353*7aa76ffcSBryan Cantrill return (B_FALSE); 354*7aa76ffcSBryan Cantrill 355*7aa76ffcSBryan Cantrill return (B_TRUE); 356*7aa76ffcSBryan Cantrill } 357*7aa76ffcSBryan Cantrill 358*7aa76ffcSBryan Cantrill /* BEGIN CSTYLED */ 359*7aa76ffcSBryan Cantrill char *g_usage = "Usage: kvmstat [interval [count]]\n" 360*7aa76ffcSBryan Cantrill "\n" 361*7aa76ffcSBryan Cantrill " Displays statistics for running kernel virtual machines, with one line\n" 362*7aa76ffcSBryan Cantrill " per virtual CPU. All statistics are reported as per-second rates.\n" 363*7aa76ffcSBryan Cantrill "\n" 364*7aa76ffcSBryan Cantrill " The columns are as follows:\n" 365*7aa76ffcSBryan Cantrill "\n" 366*7aa76ffcSBryan Cantrill " pid => identifier of process controlling the virtual CPU\n" 367*7aa76ffcSBryan Cantrill " vcpu => virtual CPU identifier relative to its virtual machine\n" 368*7aa76ffcSBryan Cantrill " exits => virtual machine exits for the virtual CPU\n" 369*7aa76ffcSBryan Cantrill " haltx => virtual machine exits due to the HLT instruction\n" 370*7aa76ffcSBryan Cantrill " irqx => virtual machine exits due to a pending external interrupt\n" 371*7aa76ffcSBryan Cantrill " irqwx => virtual machine exits due to an open interrupt window\n" 372*7aa76ffcSBryan Cantrill " iox => virtual machine exits due to an I/O instruction\n" 373*7aa76ffcSBryan Cantrill " mmiox => virtual machine exits due to memory mapped I/O \n" 374*7aa76ffcSBryan Cantrill " irqs => interrupts injected into the virtual CPU\n" 375*7aa76ffcSBryan Cantrill " emul => instructions emulated in the kernel\n" 376*7aa76ffcSBryan Cantrill " eptv => extended page table violations\n" 377*7aa76ffcSBryan Cantrill "\n"; 378*7aa76ffcSBryan Cantrill /* END CSTYLED */ 379*7aa76ffcSBryan Cantrill 380*7aa76ffcSBryan Cantrill void 381*7aa76ffcSBryan Cantrill usage() 382*7aa76ffcSBryan Cantrill { 383*7aa76ffcSBryan Cantrill (void) fprintf(stderr, "%s", g_usage); 384*7aa76ffcSBryan Cantrill exit(EXIT_FAILURE); 385*7aa76ffcSBryan Cantrill } 386*7aa76ffcSBryan Cantrill 387*7aa76ffcSBryan Cantrill /*ARGSUSED*/ 388*7aa76ffcSBryan Cantrill void 389*7aa76ffcSBryan Cantrill intr(int sig) 390*7aa76ffcSBryan Cantrill {} 391*7aa76ffcSBryan Cantrill 392*7aa76ffcSBryan Cantrill /*ARGSUSED*/ 393*7aa76ffcSBryan Cantrill int 394*7aa76ffcSBryan Cantrill main(int argc, char **argv) 395*7aa76ffcSBryan Cantrill { 396*7aa76ffcSBryan Cantrill kstat_ctl_t *kcp; 397*7aa76ffcSBryan Cantrill kstat_instance_t *instances = NULL; 398*7aa76ffcSBryan Cantrill int i = 0; 399*7aa76ffcSBryan Cantrill int interval = 1; 400*7aa76ffcSBryan Cantrill int count = INT32_MAX; 401*7aa76ffcSBryan Cantrill struct itimerval itimer; 402*7aa76ffcSBryan Cantrill struct sigaction act; 403*7aa76ffcSBryan Cantrill sigset_t set; 404*7aa76ffcSBryan Cantrill char *endp; 405*7aa76ffcSBryan Cantrill 406*7aa76ffcSBryan Cantrill kstat_field_t fields[] = { 407*7aa76ffcSBryan Cantrill { "pid", "pid", 6, KSTAT_FIELD_NODELTA }, 408*7aa76ffcSBryan Cantrill { "vcpu", NULL, 4, KSTAT_FIELD_USEINSTANCE }, 409*7aa76ffcSBryan Cantrill { "|", NULL, 1, KSTAT_FIELD_FILLER }, 410*7aa76ffcSBryan Cantrill { "exits", "exits", 6 }, 411*7aa76ffcSBryan Cantrill { ":", NULL, 1, KSTAT_FIELD_FILLER }, 412*7aa76ffcSBryan Cantrill { "haltx", "halt-exits", 6 }, 413*7aa76ffcSBryan Cantrill { "irqx", "irq-exits", 6 }, 414*7aa76ffcSBryan Cantrill { "irqwx", "irq-window-exits", 6 }, 415*7aa76ffcSBryan Cantrill { "iox", "io-exits", 6 }, 416*7aa76ffcSBryan Cantrill { "mmiox", "mmio-exits", 6 }, 417*7aa76ffcSBryan Cantrill { "|", NULL, 1, KSTAT_FIELD_FILLER }, 418*7aa76ffcSBryan Cantrill { "irqs", "irq-injections", 6 }, 419*7aa76ffcSBryan Cantrill { "emul", "insn-emulation", 6 }, 420*7aa76ffcSBryan Cantrill { "eptv", "pf-fixed", 6 }, 421*7aa76ffcSBryan Cantrill { NULL } 422*7aa76ffcSBryan Cantrill }; 423*7aa76ffcSBryan Cantrill 424*7aa76ffcSBryan Cantrill if (argc > 1) { 425*7aa76ffcSBryan Cantrill interval = strtol(argv[1], &endp, 10); 426*7aa76ffcSBryan Cantrill 427*7aa76ffcSBryan Cantrill if (*endp != '\0' || interval <= 0) 428*7aa76ffcSBryan Cantrill usage(); 429*7aa76ffcSBryan Cantrill } 430*7aa76ffcSBryan Cantrill 431*7aa76ffcSBryan Cantrill if (argc > 2) { 432*7aa76ffcSBryan Cantrill count = strtol(argv[2], &endp, 10); 433*7aa76ffcSBryan Cantrill 434*7aa76ffcSBryan Cantrill if (*endp != '\0' || count <= 0) 435*7aa76ffcSBryan Cantrill usage(); 436*7aa76ffcSBryan Cantrill } 437*7aa76ffcSBryan Cantrill 438*7aa76ffcSBryan Cantrill if ((kcp = kstat_open()) == NULL) 439*7aa76ffcSBryan Cantrill fatal("could not open /dev/kstat"); 440*7aa76ffcSBryan Cantrill 441*7aa76ffcSBryan Cantrill (void) sigemptyset(&act.sa_mask); 442*7aa76ffcSBryan Cantrill act.sa_flags = 0; 443*7aa76ffcSBryan Cantrill act.sa_handler = intr; 444*7aa76ffcSBryan Cantrill (void) sigaction(SIGALRM, &act, NULL); 445*7aa76ffcSBryan Cantrill 446*7aa76ffcSBryan Cantrill (void) sigemptyset(&set); 447*7aa76ffcSBryan Cantrill (void) sigaddset(&set, SIGALRM); 448*7aa76ffcSBryan Cantrill (void) sigprocmask(SIG_BLOCK, &set, NULL); 449*7aa76ffcSBryan Cantrill 450*7aa76ffcSBryan Cantrill bzero(&itimer, sizeof (itimer)); 451*7aa76ffcSBryan Cantrill itimer.it_value.tv_sec = interval; 452*7aa76ffcSBryan Cantrill itimer.it_interval.tv_sec = interval; 453*7aa76ffcSBryan Cantrill 454*7aa76ffcSBryan Cantrill if (setitimer(ITIMER_REAL, &itimer, NULL) != 0) { 455*7aa76ffcSBryan Cantrill fatal("could not set timer to %d second%s", interval, 456*7aa76ffcSBryan Cantrill interval == 1 ? "" : "s"); 457*7aa76ffcSBryan Cantrill } 458*7aa76ffcSBryan Cantrill 459*7aa76ffcSBryan Cantrill (void) sigemptyset(&set); 460*7aa76ffcSBryan Cantrill 461*7aa76ffcSBryan Cantrill for (;;) { 462*7aa76ffcSBryan Cantrill kstat_instances_update(kcp, &instances, interested); 463*7aa76ffcSBryan Cantrill kstat_instances_read(kcp, instances, fields); 464*7aa76ffcSBryan Cantrill 465*7aa76ffcSBryan Cantrill if (i++ > 0) { 466*7aa76ffcSBryan Cantrill kstat_instances_print(instances, fields, 467*7aa76ffcSBryan Cantrill instances != NULL && instances->ksi_next == NULL ? 468*7aa76ffcSBryan Cantrill (((i - 2) % 20) == 0) : B_TRUE); 469*7aa76ffcSBryan Cantrill } 470*7aa76ffcSBryan Cantrill 471*7aa76ffcSBryan Cantrill if (i > count) 472*7aa76ffcSBryan Cantrill break; 473*7aa76ffcSBryan Cantrill 474*7aa76ffcSBryan Cantrill (void) sigsuspend(&set); 475*7aa76ffcSBryan Cantrill } 476*7aa76ffcSBryan Cantrill 477*7aa76ffcSBryan Cantrill /*NOTREACHED*/ 478*7aa76ffcSBryan Cantrill return (0); 479*7aa76ffcSBryan Cantrill } 480