1*130f4520SKenneth D. Merry /*- 2*130f4520SKenneth D. Merry * Copyright (c) 2004, 2008, 2009 Silicon Graphics International Corp. 3*130f4520SKenneth D. Merry * All rights reserved. 4*130f4520SKenneth D. Merry * 5*130f4520SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 6*130f4520SKenneth D. Merry * modification, are permitted provided that the following conditions 7*130f4520SKenneth D. Merry * are met: 8*130f4520SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 9*130f4520SKenneth D. Merry * notice, this list of conditions, and the following disclaimer, 10*130f4520SKenneth D. Merry * without modification. 11*130f4520SKenneth D. Merry * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12*130f4520SKenneth D. Merry * substantially similar to the "NO WARRANTY" disclaimer below 13*130f4520SKenneth D. Merry * ("Disclaimer") and any redistribution must be conditioned upon 14*130f4520SKenneth D. Merry * including a substantially similar Disclaimer requirement for further 15*130f4520SKenneth D. Merry * binary redistribution. 16*130f4520SKenneth D. Merry * 17*130f4520SKenneth D. Merry * NO WARRANTY 18*130f4520SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19*130f4520SKenneth D. Merry * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20*130f4520SKenneth D. Merry * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21*130f4520SKenneth D. Merry * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22*130f4520SKenneth D. Merry * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*130f4520SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*130f4520SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*130f4520SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26*130f4520SKenneth D. Merry * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27*130f4520SKenneth D. Merry * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*130f4520SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGES. 29*130f4520SKenneth D. Merry * 30*130f4520SKenneth D. Merry * $Id: //depot/users/kenm/FreeBSD-test2/usr.bin/ctlstat/ctlstat.c#4 $ 31*130f4520SKenneth D. Merry */ 32*130f4520SKenneth D. Merry /* 33*130f4520SKenneth D. Merry * CAM Target Layer statistics program 34*130f4520SKenneth D. Merry * 35*130f4520SKenneth D. Merry * Authors: Ken Merry <ken@FreeBSD.org>, Will Andrews <will@FreeBSD.org> 36*130f4520SKenneth D. Merry */ 37*130f4520SKenneth D. Merry 38*130f4520SKenneth D. Merry #include <sys/cdefs.h> 39*130f4520SKenneth D. Merry __FBSDID("$FreeBSD$"); 40*130f4520SKenneth D. Merry 41*130f4520SKenneth D. Merry #include <sys/ioctl.h> 42*130f4520SKenneth D. Merry #include <sys/types.h> 43*130f4520SKenneth D. Merry #include <sys/param.h> 44*130f4520SKenneth D. Merry #include <sys/time.h> 45*130f4520SKenneth D. Merry #include <sys/sysctl.h> 46*130f4520SKenneth D. Merry #include <sys/resource.h> 47*130f4520SKenneth D. Merry #include <sys/queue.h> 48*130f4520SKenneth D. Merry #include <sys/callout.h> 49*130f4520SKenneth D. Merry #include <stdint.h> 50*130f4520SKenneth D. Merry #include <stdio.h> 51*130f4520SKenneth D. Merry #include <stdlib.h> 52*130f4520SKenneth D. Merry #include <unistd.h> 53*130f4520SKenneth D. Merry #include <fcntl.h> 54*130f4520SKenneth D. Merry #include <getopt.h> 55*130f4520SKenneth D. Merry #include <string.h> 56*130f4520SKenneth D. Merry #include <errno.h> 57*130f4520SKenneth D. Merry #include <err.h> 58*130f4520SKenneth D. Merry #include <ctype.h> 59*130f4520SKenneth D. Merry #include <bitstring.h> 60*130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h> 61*130f4520SKenneth D. Merry #include <cam/ctl/ctl.h> 62*130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h> 63*130f4520SKenneth D. Merry #include <cam/ctl/ctl_scsi_all.h> 64*130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.h> 65*130f4520SKenneth D. Merry #include <cam/ctl/ctl_frontend_internal.h> 66*130f4520SKenneth D. Merry #include <cam/ctl/ctl_backend.h> 67*130f4520SKenneth D. Merry #include <cam/ctl/ctl_ioctl.h> 68*130f4520SKenneth D. Merry 69*130f4520SKenneth D. Merry /* 70*130f4520SKenneth D. Merry * The default amount of space we allocate for LUN storage space. We 71*130f4520SKenneth D. Merry * dynamically allocate more if needed. 72*130f4520SKenneth D. Merry */ 73*130f4520SKenneth D. Merry #define CTL_STAT_NUM_LUNS 30 74*130f4520SKenneth D. Merry 75*130f4520SKenneth D. Merry /* 76*130f4520SKenneth D. Merry * The default number of LUN selection bits we allocate. This is large 77*130f4520SKenneth D. Merry * because we don't currently increase it if the user specifies a LUN 78*130f4520SKenneth D. Merry * number of 1024 or larger. 79*130f4520SKenneth D. Merry */ 80*130f4520SKenneth D. Merry #define CTL_STAT_LUN_BITS 1024L 81*130f4520SKenneth D. Merry 82*130f4520SKenneth D. Merry static const char *ctlstat_opts = "Cc:Ddhjl:n:tw:"; 83*130f4520SKenneth D. Merry static const char *ctlstat_usage = "Usage: ctlstat [-CDdjht] [-l lunnum]" 84*130f4520SKenneth D. Merry "[-c count] [-n numdevs] [-w wait]\n"; 85*130f4520SKenneth D. Merry 86*130f4520SKenneth D. Merry struct ctl_cpu_stats { 87*130f4520SKenneth D. Merry uint64_t user; 88*130f4520SKenneth D. Merry uint64_t nice; 89*130f4520SKenneth D. Merry uint64_t system; 90*130f4520SKenneth D. Merry uint64_t intr; 91*130f4520SKenneth D. Merry uint64_t idle; 92*130f4520SKenneth D. Merry }; 93*130f4520SKenneth D. Merry 94*130f4520SKenneth D. Merry typedef enum { 95*130f4520SKenneth D. Merry CTLSTAT_MODE_STANDARD, 96*130f4520SKenneth D. Merry CTLSTAT_MODE_DUMP, 97*130f4520SKenneth D. Merry CTLSTAT_MODE_JSON, 98*130f4520SKenneth D. Merry } ctlstat_mode_types; 99*130f4520SKenneth D. Merry 100*130f4520SKenneth D. Merry #define CTLSTAT_FLAG_CPU (1 << 0) 101*130f4520SKenneth D. Merry #define CTLSTAT_FLAG_HEADER (1 << 1) 102*130f4520SKenneth D. Merry #define CTLSTAT_FLAG_FIRST_RUN (1 << 2) 103*130f4520SKenneth D. Merry #define CTLSTAT_FLAG_TOTALS (1 << 3) 104*130f4520SKenneth D. Merry #define CTLSTAT_FLAG_DMA_TIME (1 << 4) 105*130f4520SKenneth D. Merry #define CTLSTAT_FLAG_LUN_TIME_VALID (1 << 5) 106*130f4520SKenneth D. Merry #define F_CPU(ctx) ((ctx)->flags & CTLSTAT_FLAG_CPU) 107*130f4520SKenneth D. Merry #define F_HDR(ctx) ((ctx)->flags & CTLSTAT_FLAG_HEADER) 108*130f4520SKenneth D. Merry #define F_FIRST(ctx) ((ctx)->flags & CTLSTAT_FLAG_FIRST_RUN) 109*130f4520SKenneth D. Merry #define F_TOTALS(ctx) ((ctx)->flags & CTLSTAT_FLAG_TOTALS) 110*130f4520SKenneth D. Merry #define F_DMA(ctx) ((ctx)->flags & CTLSTAT_FLAG_DMA_TIME) 111*130f4520SKenneth D. Merry #define F_LUNVAL(ctx) ((ctx)->flags & CTLSTAT_FLAG_LUN_TIME_VALID) 112*130f4520SKenneth D. Merry 113*130f4520SKenneth D. Merry struct ctlstat_context { 114*130f4520SKenneth D. Merry ctlstat_mode_types mode; 115*130f4520SKenneth D. Merry int flags; 116*130f4520SKenneth D. Merry struct ctl_lun_io_stats *cur_lun_stats, *prev_lun_stats, 117*130f4520SKenneth D. Merry *tmp_lun_stats; 118*130f4520SKenneth D. Merry struct ctl_lun_io_stats cur_total_stats[3], prev_total_stats[3]; 119*130f4520SKenneth D. Merry struct timespec cur_time, prev_time; 120*130f4520SKenneth D. Merry struct ctl_cpu_stats cur_cpu, prev_cpu; 121*130f4520SKenneth D. Merry uint64_t cur_total_jiffies, prev_total_jiffies; 122*130f4520SKenneth D. Merry uint64_t cur_idle, prev_idle; 123*130f4520SKenneth D. Merry bitstr_t bit_decl(lun_mask, CTL_STAT_LUN_BITS); 124*130f4520SKenneth D. Merry int num_luns; 125*130f4520SKenneth D. Merry int numdevs; 126*130f4520SKenneth D. Merry int header_interval; 127*130f4520SKenneth D. Merry }; 128*130f4520SKenneth D. Merry 129*130f4520SKenneth D. Merry #ifndef min 130*130f4520SKenneth D. Merry #define min(x,y) (((x) < (y)) ? (x) : (y)) 131*130f4520SKenneth D. Merry #endif 132*130f4520SKenneth D. Merry 133*130f4520SKenneth D. Merry static void usage(int error); 134*130f4520SKenneth D. Merry static int getstats(int fd, int *num_luns, struct ctl_lun_io_stats **xlun_stats, 135*130f4520SKenneth D. Merry struct timespec *cur_time, int *lun_time_valid); 136*130f4520SKenneth D. Merry static int getcpu(struct ctl_cpu_stats *cpu_stats); 137*130f4520SKenneth D. Merry static void compute_stats(struct ctl_lun_io_stats *cur_stats, 138*130f4520SKenneth D. Merry struct ctl_lun_io_stats *prev_stats, 139*130f4520SKenneth D. Merry long double etime, long double *mbsec, 140*130f4520SKenneth D. Merry long double *kb_per_transfer, 141*130f4520SKenneth D. Merry long double *transfers_per_second, 142*130f4520SKenneth D. Merry long double *ms_per_transfer, 143*130f4520SKenneth D. Merry long double *ms_per_dma, 144*130f4520SKenneth D. Merry long double *dmas_per_second); 145*130f4520SKenneth D. Merry 146*130f4520SKenneth D. Merry static void 147*130f4520SKenneth D. Merry usage(int error) 148*130f4520SKenneth D. Merry { 149*130f4520SKenneth D. Merry fprintf(error ? stderr : stdout, ctlstat_usage); 150*130f4520SKenneth D. Merry } 151*130f4520SKenneth D. Merry 152*130f4520SKenneth D. Merry static int 153*130f4520SKenneth D. Merry getstats(int fd, int *num_luns, struct ctl_lun_io_stats **xlun_stats, 154*130f4520SKenneth D. Merry struct timespec *cur_time, int *flags) 155*130f4520SKenneth D. Merry { 156*130f4520SKenneth D. Merry struct ctl_lun_io_stats *lun_stats; 157*130f4520SKenneth D. Merry struct ctl_stats stats; 158*130f4520SKenneth D. Merry int more_space_count; 159*130f4520SKenneth D. Merry 160*130f4520SKenneth D. Merry more_space_count = 0; 161*130f4520SKenneth D. Merry 162*130f4520SKenneth D. Merry if (*num_luns == 0) 163*130f4520SKenneth D. Merry *num_luns = CTL_STAT_NUM_LUNS; 164*130f4520SKenneth D. Merry 165*130f4520SKenneth D. Merry lun_stats = *xlun_stats; 166*130f4520SKenneth D. Merry retry: 167*130f4520SKenneth D. Merry 168*130f4520SKenneth D. Merry if (lun_stats == NULL) { 169*130f4520SKenneth D. Merry lun_stats = (struct ctl_lun_io_stats *)malloc( 170*130f4520SKenneth D. Merry sizeof(*lun_stats) * *num_luns); 171*130f4520SKenneth D. Merry } 172*130f4520SKenneth D. Merry 173*130f4520SKenneth D. Merry memset(&stats, 0, sizeof(stats)); 174*130f4520SKenneth D. Merry stats.alloc_len = *num_luns * sizeof(*lun_stats); 175*130f4520SKenneth D. Merry memset(lun_stats, 0, stats.alloc_len); 176*130f4520SKenneth D. Merry stats.lun_stats = lun_stats; 177*130f4520SKenneth D. Merry 178*130f4520SKenneth D. Merry if (ioctl(fd, CTL_GETSTATS, &stats) == -1) 179*130f4520SKenneth D. Merry err(1, "error returned from CTL_GETSTATS ioctl"); 180*130f4520SKenneth D. Merry 181*130f4520SKenneth D. Merry switch (stats.status) { 182*130f4520SKenneth D. Merry case CTL_SS_OK: 183*130f4520SKenneth D. Merry break; 184*130f4520SKenneth D. Merry case CTL_SS_ERROR: 185*130f4520SKenneth D. Merry err(1, "CTL_SS_ERROR returned from CTL_GETSTATS ioctl"); 186*130f4520SKenneth D. Merry break; 187*130f4520SKenneth D. Merry case CTL_SS_NEED_MORE_SPACE: 188*130f4520SKenneth D. Merry if (more_space_count > 0) { 189*130f4520SKenneth D. Merry errx(1, "CTL_GETSTATS returned NEED_MORE_SPACE again"); 190*130f4520SKenneth D. Merry } 191*130f4520SKenneth D. Merry *num_luns = stats.num_luns; 192*130f4520SKenneth D. Merry free(lun_stats); 193*130f4520SKenneth D. Merry lun_stats = NULL; 194*130f4520SKenneth D. Merry more_space_count++; 195*130f4520SKenneth D. Merry goto retry; 196*130f4520SKenneth D. Merry break; /* NOTREACHED */ 197*130f4520SKenneth D. Merry default: 198*130f4520SKenneth D. Merry errx(1, "unknown status %d returned from CTL_GETSTATS ioctl", 199*130f4520SKenneth D. Merry stats.status); 200*130f4520SKenneth D. Merry break; 201*130f4520SKenneth D. Merry } 202*130f4520SKenneth D. Merry 203*130f4520SKenneth D. Merry *xlun_stats = lun_stats; 204*130f4520SKenneth D. Merry *num_luns = stats.num_luns; 205*130f4520SKenneth D. Merry cur_time->tv_sec = stats.timestamp.tv_sec; 206*130f4520SKenneth D. Merry cur_time->tv_nsec = stats.timestamp.tv_nsec; 207*130f4520SKenneth D. Merry if (stats.flags & CTL_STATS_FLAG_TIME_VALID) 208*130f4520SKenneth D. Merry *flags |= CTLSTAT_FLAG_LUN_TIME_VALID; 209*130f4520SKenneth D. Merry else 210*130f4520SKenneth D. Merry *flags &= ~CTLSTAT_FLAG_LUN_TIME_VALID; 211*130f4520SKenneth D. Merry 212*130f4520SKenneth D. Merry return (0); 213*130f4520SKenneth D. Merry } 214*130f4520SKenneth D. Merry 215*130f4520SKenneth D. Merry static int 216*130f4520SKenneth D. Merry getcpu(struct ctl_cpu_stats *cpu_stats) 217*130f4520SKenneth D. Merry { 218*130f4520SKenneth D. Merry long cp_time[CPUSTATES]; 219*130f4520SKenneth D. Merry size_t cplen; 220*130f4520SKenneth D. Merry 221*130f4520SKenneth D. Merry cplen = sizeof(cp_time); 222*130f4520SKenneth D. Merry 223*130f4520SKenneth D. Merry if (sysctlbyname("kern.cp_time", &cp_time, &cplen, NULL, 0) == -1) { 224*130f4520SKenneth D. Merry warn("sysctlbyname(kern.cp_time...) failed"); 225*130f4520SKenneth D. Merry return (1); 226*130f4520SKenneth D. Merry } 227*130f4520SKenneth D. Merry 228*130f4520SKenneth D. Merry cpu_stats->user = cp_time[CP_USER]; 229*130f4520SKenneth D. Merry cpu_stats->nice = cp_time[CP_NICE]; 230*130f4520SKenneth D. Merry cpu_stats->system = cp_time[CP_SYS]; 231*130f4520SKenneth D. Merry cpu_stats->intr = cp_time[CP_INTR]; 232*130f4520SKenneth D. Merry cpu_stats->idle = cp_time[CP_IDLE]; 233*130f4520SKenneth D. Merry 234*130f4520SKenneth D. Merry return (0); 235*130f4520SKenneth D. Merry } 236*130f4520SKenneth D. Merry 237*130f4520SKenneth D. Merry static void 238*130f4520SKenneth D. Merry compute_stats(struct ctl_lun_io_stats *cur_stats, 239*130f4520SKenneth D. Merry struct ctl_lun_io_stats *prev_stats, long double etime, 240*130f4520SKenneth D. Merry long double *mbsec, long double *kb_per_transfer, 241*130f4520SKenneth D. Merry long double *transfers_per_second, long double *ms_per_transfer, 242*130f4520SKenneth D. Merry long double *ms_per_dma, long double *dmas_per_second) 243*130f4520SKenneth D. Merry { 244*130f4520SKenneth D. Merry uint64_t total_bytes = 0, total_operations = 0, total_dmas = 0; 245*130f4520SKenneth D. Merry uint32_t port; 246*130f4520SKenneth D. Merry struct bintime total_time_bt, total_dma_bt; 247*130f4520SKenneth D. Merry struct timespec total_time_ts, total_dma_ts; 248*130f4520SKenneth D. Merry int i; 249*130f4520SKenneth D. Merry 250*130f4520SKenneth D. Merry bzero(&total_time_bt, sizeof(total_time_bt)); 251*130f4520SKenneth D. Merry bzero(&total_dma_bt, sizeof(total_dma_bt)); 252*130f4520SKenneth D. Merry bzero(&total_time_ts, sizeof(total_time_ts)); 253*130f4520SKenneth D. Merry bzero(&total_dma_ts, sizeof(total_dma_ts)); 254*130f4520SKenneth D. Merry for (port = 0; port < CTL_MAX_PORTS; port++) { 255*130f4520SKenneth D. Merry for (i = 0; i < CTL_STATS_NUM_TYPES; i++) { 256*130f4520SKenneth D. Merry total_bytes += cur_stats->ports[port].bytes[i]; 257*130f4520SKenneth D. Merry total_operations += 258*130f4520SKenneth D. Merry cur_stats->ports[port].operations[i]; 259*130f4520SKenneth D. Merry total_dmas += cur_stats->ports[port].num_dmas[i]; 260*130f4520SKenneth D. Merry bintime_add(&total_time_bt, 261*130f4520SKenneth D. Merry &cur_stats->ports[port].time[i]); 262*130f4520SKenneth D. Merry bintime_add(&total_dma_bt, 263*130f4520SKenneth D. Merry &cur_stats->ports[port].dma_time[i]); 264*130f4520SKenneth D. Merry if (prev_stats != NULL) { 265*130f4520SKenneth D. Merry total_bytes -= 266*130f4520SKenneth D. Merry prev_stats->ports[port].bytes[i]; 267*130f4520SKenneth D. Merry total_operations -= 268*130f4520SKenneth D. Merry prev_stats->ports[port].operations[i]; 269*130f4520SKenneth D. Merry total_dmas -= 270*130f4520SKenneth D. Merry prev_stats->ports[port].num_dmas[i]; 271*130f4520SKenneth D. Merry bintime_sub(&total_time_bt, 272*130f4520SKenneth D. Merry &prev_stats->ports[port].time[i]); 273*130f4520SKenneth D. Merry bintime_sub(&total_dma_bt, 274*130f4520SKenneth D. Merry &prev_stats->ports[port].dma_time[i]); 275*130f4520SKenneth D. Merry } 276*130f4520SKenneth D. Merry } 277*130f4520SKenneth D. Merry } 278*130f4520SKenneth D. Merry 279*130f4520SKenneth D. Merry *mbsec = total_bytes; 280*130f4520SKenneth D. Merry *mbsec /= 1024 * 1024; 281*130f4520SKenneth D. Merry if (etime > 0.0) 282*130f4520SKenneth D. Merry *mbsec /= etime; 283*130f4520SKenneth D. Merry else 284*130f4520SKenneth D. Merry *mbsec = 0; 285*130f4520SKenneth D. Merry *kb_per_transfer = total_bytes; 286*130f4520SKenneth D. Merry *kb_per_transfer /= 1024; 287*130f4520SKenneth D. Merry if (total_operations > 0) 288*130f4520SKenneth D. Merry *kb_per_transfer /= total_operations; 289*130f4520SKenneth D. Merry else 290*130f4520SKenneth D. Merry *kb_per_transfer = 0; 291*130f4520SKenneth D. Merry *transfers_per_second = total_operations; 292*130f4520SKenneth D. Merry *dmas_per_second = total_dmas; 293*130f4520SKenneth D. Merry if (etime > 0.0) { 294*130f4520SKenneth D. Merry *transfers_per_second /= etime; 295*130f4520SKenneth D. Merry *dmas_per_second /= etime; 296*130f4520SKenneth D. Merry } else { 297*130f4520SKenneth D. Merry *transfers_per_second = 0; 298*130f4520SKenneth D. Merry *dmas_per_second = 0; 299*130f4520SKenneth D. Merry } 300*130f4520SKenneth D. Merry 301*130f4520SKenneth D. Merry bintime2timespec(&total_time_bt, &total_time_ts); 302*130f4520SKenneth D. Merry bintime2timespec(&total_dma_bt, &total_dma_ts); 303*130f4520SKenneth D. Merry if (total_operations > 0) { 304*130f4520SKenneth D. Merry /* 305*130f4520SKenneth D. Merry * Convert the timespec to milliseconds. 306*130f4520SKenneth D. Merry */ 307*130f4520SKenneth D. Merry *ms_per_transfer = total_time_ts.tv_sec * 1000; 308*130f4520SKenneth D. Merry *ms_per_transfer += total_time_ts.tv_nsec / 1000000; 309*130f4520SKenneth D. Merry *ms_per_transfer /= total_operations; 310*130f4520SKenneth D. Merry } else 311*130f4520SKenneth D. Merry *ms_per_transfer = 0; 312*130f4520SKenneth D. Merry 313*130f4520SKenneth D. Merry if (total_dmas > 0) { 314*130f4520SKenneth D. Merry /* 315*130f4520SKenneth D. Merry * Convert the timespec to milliseconds. 316*130f4520SKenneth D. Merry */ 317*130f4520SKenneth D. Merry *ms_per_dma = total_dma_ts.tv_sec * 1000; 318*130f4520SKenneth D. Merry *ms_per_dma += total_dma_ts.tv_nsec / 1000000; 319*130f4520SKenneth D. Merry *ms_per_dma /= total_dmas; 320*130f4520SKenneth D. Merry } else 321*130f4520SKenneth D. Merry *ms_per_dma = 0; 322*130f4520SKenneth D. Merry } 323*130f4520SKenneth D. Merry 324*130f4520SKenneth D. Merry /* The dump_stats() and json_stats() functions perform essentially the same 325*130f4520SKenneth D. Merry * purpose, but dump the statistics in different formats. JSON is more 326*130f4520SKenneth D. Merry * conducive to programming, however. 327*130f4520SKenneth D. Merry */ 328*130f4520SKenneth D. Merry 329*130f4520SKenneth D. Merry #define PRINT_BINTIME(prefix, bt) \ 330*130f4520SKenneth D. Merry printf("%s %jd s %ju frac\n", prefix, (intmax_t)(bt).sec, \ 331*130f4520SKenneth D. Merry (uintmax_t)(bt).frac) 332*130f4520SKenneth D. Merry const char *iotypes[] = {"NO IO", "READ", "WRITE"}; 333*130f4520SKenneth D. Merry 334*130f4520SKenneth D. Merry static void 335*130f4520SKenneth D. Merry ctlstat_dump(struct ctlstat_context *ctx) { 336*130f4520SKenneth D. Merry int iotype, lun, port; 337*130f4520SKenneth D. Merry struct ctl_lun_io_stats *stats = ctx->cur_lun_stats; 338*130f4520SKenneth D. Merry 339*130f4520SKenneth D. Merry for (lun = 0; lun < ctx->num_luns;lun++) { 340*130f4520SKenneth D. Merry printf("lun %d\n", lun); 341*130f4520SKenneth D. Merry for (port = 0; port < CTL_MAX_PORTS; port++) { 342*130f4520SKenneth D. Merry printf(" port %d\n", 343*130f4520SKenneth D. Merry stats[lun].ports[port].targ_port); 344*130f4520SKenneth D. Merry for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; 345*130f4520SKenneth D. Merry iotype++) { 346*130f4520SKenneth D. Merry printf(" io type %d (%s)\n", iotype, 347*130f4520SKenneth D. Merry iotypes[iotype]); 348*130f4520SKenneth D. Merry printf(" bytes %ju\n", (uintmax_t) 349*130f4520SKenneth D. Merry stats[lun].ports[port].bytes[iotype]); 350*130f4520SKenneth D. Merry printf(" operations %ju\n", (uintmax_t) 351*130f4520SKenneth D. Merry stats[lun].ports[port].operations[iotype]); 352*130f4520SKenneth D. Merry PRINT_BINTIME(" io time", 353*130f4520SKenneth D. Merry stats[lun].ports[port].time[iotype]); 354*130f4520SKenneth D. Merry printf(" num dmas %ju\n", (uintmax_t) 355*130f4520SKenneth D. Merry stats[lun].ports[port].num_dmas[iotype]); 356*130f4520SKenneth D. Merry PRINT_BINTIME(" dma time", 357*130f4520SKenneth D. Merry stats[lun].ports[port].dma_time[iotype]); 358*130f4520SKenneth D. Merry } 359*130f4520SKenneth D. Merry } 360*130f4520SKenneth D. Merry } 361*130f4520SKenneth D. Merry } 362*130f4520SKenneth D. Merry 363*130f4520SKenneth D. Merry #define JSON_BINTIME(prefix, bt) \ 364*130f4520SKenneth D. Merry printf("\"%s\":{\"sec\":%jd,\"frac\":%ju},", \ 365*130f4520SKenneth D. Merry prefix, (intmax_t)(bt).sec, (uintmax_t)(bt).frac) 366*130f4520SKenneth D. Merry 367*130f4520SKenneth D. Merry static void 368*130f4520SKenneth D. Merry ctlstat_json(struct ctlstat_context *ctx) { 369*130f4520SKenneth D. Merry int iotype, lun, port; 370*130f4520SKenneth D. Merry struct ctl_lun_io_stats *stats = ctx->cur_lun_stats; 371*130f4520SKenneth D. Merry 372*130f4520SKenneth D. Merry printf("{\"luns\":["); 373*130f4520SKenneth D. Merry for (lun = 0; lun < ctx->num_luns; lun++) { 374*130f4520SKenneth D. Merry printf("{\"ports\":["); 375*130f4520SKenneth D. Merry for (port = 0; port < CTL_MAX_PORTS;port++) { 376*130f4520SKenneth D. Merry printf("{\"num\":%d,\"io\":[", 377*130f4520SKenneth D. Merry stats[lun].ports[port].targ_port); 378*130f4520SKenneth D. Merry for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; 379*130f4520SKenneth D. Merry iotype++) { 380*130f4520SKenneth D. Merry printf("{\"type\":\"%s\",", iotypes[iotype]); 381*130f4520SKenneth D. Merry printf("\"bytes\":%ju,", (uintmax_t)stats[ 382*130f4520SKenneth D. Merry lun].ports[port].bytes[iotype]); 383*130f4520SKenneth D. Merry printf("\"operations\":%ju,", (uintmax_t)stats[ 384*130f4520SKenneth D. Merry lun].ports[port].operations[iotype]); 385*130f4520SKenneth D. Merry JSON_BINTIME("io time", 386*130f4520SKenneth D. Merry stats[lun].ports[port].time[iotype]); 387*130f4520SKenneth D. Merry JSON_BINTIME("dma time", 388*130f4520SKenneth D. Merry stats[lun].ports[port].dma_time[iotype]); 389*130f4520SKenneth D. Merry printf("\"num dmas\":%ju}", (uintmax_t) 390*130f4520SKenneth D. Merry stats[lun].ports[port].num_dmas[iotype]); 391*130f4520SKenneth D. Merry if (iotype < (CTL_STATS_NUM_TYPES - 1)) 392*130f4520SKenneth D. Merry printf(","); /* continue io array */ 393*130f4520SKenneth D. Merry } 394*130f4520SKenneth D. Merry printf("]}"); /* close port */ 395*130f4520SKenneth D. Merry if (port < (CTL_MAX_PORTS - 1)) 396*130f4520SKenneth D. Merry printf(","); /* continue port array */ 397*130f4520SKenneth D. Merry } 398*130f4520SKenneth D. Merry printf("]}"); /* close lun */ 399*130f4520SKenneth D. Merry if (lun < (ctx->num_luns - 1)) 400*130f4520SKenneth D. Merry printf(","); /* continue lun array */ 401*130f4520SKenneth D. Merry } 402*130f4520SKenneth D. Merry printf("]}"); /* close luns and toplevel */ 403*130f4520SKenneth D. Merry } 404*130f4520SKenneth D. Merry 405*130f4520SKenneth D. Merry static void 406*130f4520SKenneth D. Merry ctlstat_standard(struct ctlstat_context *ctx) { 407*130f4520SKenneth D. Merry long double cur_secs, prev_secs, etime; 408*130f4520SKenneth D. Merry uint64_t delta_jiffies, delta_idle; 409*130f4520SKenneth D. Merry uint32_t port; 410*130f4520SKenneth D. Merry long double cpu_percentage; 411*130f4520SKenneth D. Merry int i; 412*130f4520SKenneth D. Merry int j; 413*130f4520SKenneth D. Merry 414*130f4520SKenneth D. Merry cpu_percentage = 0; 415*130f4520SKenneth D. Merry 416*130f4520SKenneth D. Merry if (F_CPU(ctx) && (getcpu(&ctx->cur_cpu) != 0)) 417*130f4520SKenneth D. Merry errx(1, "error returned from getcpu()"); 418*130f4520SKenneth D. Merry 419*130f4520SKenneth D. Merry cur_secs = ctx->cur_time.tv_sec + (ctx->cur_time.tv_nsec / 1000000000); 420*130f4520SKenneth D. Merry prev_secs = ctx->prev_time.tv_sec + 421*130f4520SKenneth D. Merry (ctx->prev_time.tv_nsec / 1000000000); 422*130f4520SKenneth D. Merry 423*130f4520SKenneth D. Merry etime = cur_secs - prev_secs; 424*130f4520SKenneth D. Merry 425*130f4520SKenneth D. Merry if (F_CPU(ctx)) { 426*130f4520SKenneth D. Merry ctx->prev_total_jiffies = ctx->cur_total_jiffies; 427*130f4520SKenneth D. Merry ctx->cur_total_jiffies = ctx->cur_cpu.user + 428*130f4520SKenneth D. Merry ctx->cur_cpu.nice + ctx->cur_cpu.system + 429*130f4520SKenneth D. Merry ctx->cur_cpu.intr + ctx->cur_cpu.idle; 430*130f4520SKenneth D. Merry delta_jiffies = ctx->cur_total_jiffies; 431*130f4520SKenneth D. Merry if (F_FIRST(ctx) == 0) 432*130f4520SKenneth D. Merry delta_jiffies -= ctx->prev_total_jiffies; 433*130f4520SKenneth D. Merry ctx->prev_idle = ctx->cur_idle; 434*130f4520SKenneth D. Merry ctx->cur_idle = ctx->cur_cpu.idle; 435*130f4520SKenneth D. Merry delta_idle = ctx->cur_idle - ctx->prev_idle; 436*130f4520SKenneth D. Merry 437*130f4520SKenneth D. Merry cpu_percentage = delta_jiffies - delta_idle; 438*130f4520SKenneth D. Merry cpu_percentage /= delta_jiffies; 439*130f4520SKenneth D. Merry cpu_percentage *= 100; 440*130f4520SKenneth D. Merry } 441*130f4520SKenneth D. Merry 442*130f4520SKenneth D. Merry if (F_HDR(ctx)) { 443*130f4520SKenneth D. Merry ctx->header_interval--; 444*130f4520SKenneth D. Merry if (ctx->header_interval <= 0) { 445*130f4520SKenneth D. Merry int hdr_devs; 446*130f4520SKenneth D. Merry 447*130f4520SKenneth D. Merry hdr_devs = 0; 448*130f4520SKenneth D. Merry 449*130f4520SKenneth D. Merry if (F_TOTALS(ctx)) { 450*130f4520SKenneth D. Merry fprintf(stdout, "%s System Read %s" 451*130f4520SKenneth D. Merry "System Write %sSystem Total%s\n", 452*130f4520SKenneth D. Merry (F_LUNVAL(ctx) != 0) ? " " : "", 453*130f4520SKenneth D. Merry (F_LUNVAL(ctx) != 0) ? " " : "", 454*130f4520SKenneth D. Merry (F_LUNVAL(ctx) != 0) ? " " : "", 455*130f4520SKenneth D. Merry (F_CPU(ctx) == 0) ? " CPU" : ""); 456*130f4520SKenneth D. Merry hdr_devs = 3; 457*130f4520SKenneth D. Merry } else { 458*130f4520SKenneth D. Merry if (F_CPU(ctx)) 459*130f4520SKenneth D. Merry fprintf(stdout, " CPU "); 460*130f4520SKenneth D. Merry for (i = 0; i < min(CTL_STAT_LUN_BITS, 461*130f4520SKenneth D. Merry ctx->num_luns); i++) { 462*130f4520SKenneth D. Merry int lun; 463*130f4520SKenneth D. Merry 464*130f4520SKenneth D. Merry /* 465*130f4520SKenneth D. Merry * Obviously this won't work with 466*130f4520SKenneth D. Merry * LUN numbers greater than a signed 467*130f4520SKenneth D. Merry * integer. 468*130f4520SKenneth D. Merry */ 469*130f4520SKenneth D. Merry lun = (int)ctx->cur_lun_stats[i 470*130f4520SKenneth D. Merry ].lun_number; 471*130f4520SKenneth D. Merry 472*130f4520SKenneth D. Merry if (bit_test(ctx->lun_mask, lun) == 0) 473*130f4520SKenneth D. Merry continue; 474*130f4520SKenneth D. Merry fprintf(stdout, "%15.6s%d ", 475*130f4520SKenneth D. Merry "lun", lun); 476*130f4520SKenneth D. Merry hdr_devs++; 477*130f4520SKenneth D. Merry } 478*130f4520SKenneth D. Merry fprintf(stdout, "\n"); 479*130f4520SKenneth D. Merry } 480*130f4520SKenneth D. Merry for (i = 0; i < hdr_devs; i++) 481*130f4520SKenneth D. Merry fprintf(stdout, "%s %sKB/t %s MB/s ", 482*130f4520SKenneth D. Merry ((F_CPU(ctx) != 0) && (i == 0) && 483*130f4520SKenneth D. Merry (F_TOTALS(ctx) == 0)) ? " " : "", 484*130f4520SKenneth D. Merry (F_LUNVAL(ctx) != 0) ? " ms " : "", 485*130f4520SKenneth D. Merry (F_DMA(ctx) == 0) ? "tps" : "dps"); 486*130f4520SKenneth D. Merry fprintf(stdout, "\n"); 487*130f4520SKenneth D. Merry ctx->header_interval = 20; 488*130f4520SKenneth D. Merry } 489*130f4520SKenneth D. Merry } 490*130f4520SKenneth D. Merry 491*130f4520SKenneth D. Merry if (F_TOTALS(ctx) != 0) { 492*130f4520SKenneth D. Merry long double mbsec[3]; 493*130f4520SKenneth D. Merry long double kb_per_transfer[3]; 494*130f4520SKenneth D. Merry long double transfers_per_sec[3]; 495*130f4520SKenneth D. Merry long double ms_per_transfer[3]; 496*130f4520SKenneth D. Merry long double ms_per_dma[3]; 497*130f4520SKenneth D. Merry long double dmas_per_sec[3]; 498*130f4520SKenneth D. Merry 499*130f4520SKenneth D. Merry for (i = 0; i < 3; i++) 500*130f4520SKenneth D. Merry ctx->prev_total_stats[i] = ctx->cur_total_stats[i]; 501*130f4520SKenneth D. Merry 502*130f4520SKenneth D. Merry memset(&ctx->cur_total_stats, 0, sizeof(ctx->cur_total_stats)); 503*130f4520SKenneth D. Merry 504*130f4520SKenneth D. Merry /* Use macros to make the next loop more readable. */ 505*130f4520SKenneth D. Merry #define ADD_STATS_BYTES(st, p, i, j) \ 506*130f4520SKenneth D. Merry ctx->cur_total_stats[st].ports[p].bytes[j] += \ 507*130f4520SKenneth D. Merry ctx->cur_lun_stats[i].ports[p].bytes[j] 508*130f4520SKenneth D. Merry #define ADD_STATS_OPERATIONS(st, p, i, j) \ 509*130f4520SKenneth D. Merry ctx->cur_total_stats[st].ports[p].operations[j] += \ 510*130f4520SKenneth D. Merry ctx->cur_lun_stats[i].ports[p].operations[j] 511*130f4520SKenneth D. Merry #define ADD_STATS_NUM_DMAS(st, p, i, j) \ 512*130f4520SKenneth D. Merry ctx->cur_total_stats[st].ports[p].num_dmas[j] += \ 513*130f4520SKenneth D. Merry ctx->cur_lun_stats[i].ports[p].num_dmas[j] 514*130f4520SKenneth D. Merry #define ADD_STATS_TIME(st, p, i, j) \ 515*130f4520SKenneth D. Merry bintime_add(&ctx->cur_total_stats[st].ports[p].time[j], \ 516*130f4520SKenneth D. Merry &ctx->cur_lun_stats[i].ports[p].time[j]) 517*130f4520SKenneth D. Merry #define ADD_STATS_DMA_TIME(st, p, i, j) \ 518*130f4520SKenneth D. Merry bintime_add(&ctx->cur_total_stats[st].ports[p].dma_time[j], \ 519*130f4520SKenneth D. Merry &ctx->cur_lun_stats[i].ports[p].dma_time[j]) 520*130f4520SKenneth D. Merry 521*130f4520SKenneth D. Merry for (i = 0; i < ctx->num_luns; i++) { 522*130f4520SKenneth D. Merry for (port = 0; port < CTL_MAX_PORTS; port++) { 523*130f4520SKenneth D. Merry for (j = 0; j < CTL_STATS_NUM_TYPES; j++) { 524*130f4520SKenneth D. Merry ADD_STATS_BYTES(2, port, i, j); 525*130f4520SKenneth D. Merry ADD_STATS_OPERATIONS(2, port, i, j); 526*130f4520SKenneth D. Merry ADD_STATS_NUM_DMAS(2, port, i, j); 527*130f4520SKenneth D. Merry ADD_STATS_TIME(2, port, i, j); 528*130f4520SKenneth D. Merry ADD_STATS_DMA_TIME(2, port, i, j); 529*130f4520SKenneth D. Merry } 530*130f4520SKenneth D. Merry ADD_STATS_BYTES(0, port, i, CTL_STATS_READ); 531*130f4520SKenneth D. Merry ADD_STATS_OPERATIONS(0, port, i, 532*130f4520SKenneth D. Merry CTL_STATS_READ); 533*130f4520SKenneth D. Merry ADD_STATS_NUM_DMAS(0, port, i, CTL_STATS_READ); 534*130f4520SKenneth D. Merry ADD_STATS_TIME(0, port, i, CTL_STATS_READ); 535*130f4520SKenneth D. Merry ADD_STATS_DMA_TIME(0, port, i, CTL_STATS_READ); 536*130f4520SKenneth D. Merry 537*130f4520SKenneth D. Merry ADD_STATS_BYTES(1, port, i, CTL_STATS_WRITE); 538*130f4520SKenneth D. Merry ADD_STATS_OPERATIONS(1, port, i, 539*130f4520SKenneth D. Merry CTL_STATS_WRITE); 540*130f4520SKenneth D. Merry ADD_STATS_NUM_DMAS(1, port, i, CTL_STATS_WRITE); 541*130f4520SKenneth D. Merry ADD_STATS_TIME(1, port, i, CTL_STATS_WRITE); 542*130f4520SKenneth D. Merry ADD_STATS_DMA_TIME(1, port, i, CTL_STATS_WRITE); 543*130f4520SKenneth D. Merry } 544*130f4520SKenneth D. Merry } 545*130f4520SKenneth D. Merry 546*130f4520SKenneth D. Merry for (i = 0; i < 3; i++) { 547*130f4520SKenneth D. Merry compute_stats(&ctx->cur_total_stats[i], 548*130f4520SKenneth D. Merry F_FIRST(ctx) ? NULL : &ctx->prev_total_stats[i], 549*130f4520SKenneth D. Merry etime, &mbsec[i], &kb_per_transfer[i], 550*130f4520SKenneth D. Merry &transfers_per_sec[i], 551*130f4520SKenneth D. Merry &ms_per_transfer[i], &ms_per_dma[i], 552*130f4520SKenneth D. Merry &dmas_per_sec[i]); 553*130f4520SKenneth D. Merry if (F_DMA(ctx) != 0) 554*130f4520SKenneth D. Merry fprintf(stdout, " %2.2Lf", 555*130f4520SKenneth D. Merry ms_per_dma[i]); 556*130f4520SKenneth D. Merry else if (F_LUNVAL(ctx) != 0) 557*130f4520SKenneth D. Merry fprintf(stdout, " %2.2Lf", 558*130f4520SKenneth D. Merry ms_per_transfer[i]); 559*130f4520SKenneth D. Merry fprintf(stdout, " %5.2Lf %3.0Lf %5.2Lf ", 560*130f4520SKenneth D. Merry kb_per_transfer[i], 561*130f4520SKenneth D. Merry (F_DMA(ctx) == 0) ? transfers_per_sec[i] : 562*130f4520SKenneth D. Merry dmas_per_sec[i], mbsec[i]); 563*130f4520SKenneth D. Merry } 564*130f4520SKenneth D. Merry if (F_CPU(ctx)) 565*130f4520SKenneth D. Merry fprintf(stdout, " %5.1Lf%%", cpu_percentage); 566*130f4520SKenneth D. Merry } else { 567*130f4520SKenneth D. Merry if (F_CPU(ctx)) 568*130f4520SKenneth D. Merry fprintf(stdout, "%5.1Lf%% ", cpu_percentage); 569*130f4520SKenneth D. Merry 570*130f4520SKenneth D. Merry for (i = 0; i < min(CTL_STAT_LUN_BITS, ctx->num_luns); i++) { 571*130f4520SKenneth D. Merry long double mbsec, kb_per_transfer; 572*130f4520SKenneth D. Merry long double transfers_per_sec; 573*130f4520SKenneth D. Merry long double ms_per_transfer; 574*130f4520SKenneth D. Merry long double ms_per_dma; 575*130f4520SKenneth D. Merry long double dmas_per_sec; 576*130f4520SKenneth D. Merry 577*130f4520SKenneth D. Merry if (bit_test(ctx->lun_mask, 578*130f4520SKenneth D. Merry (int)ctx->cur_lun_stats[i].lun_number) == 0) 579*130f4520SKenneth D. Merry continue; 580*130f4520SKenneth D. Merry compute_stats(&ctx->cur_lun_stats[i], F_FIRST(ctx) ? 581*130f4520SKenneth D. Merry NULL : &ctx->prev_lun_stats[i], etime, 582*130f4520SKenneth D. Merry &mbsec, &kb_per_transfer, 583*130f4520SKenneth D. Merry &transfers_per_sec, &ms_per_transfer, 584*130f4520SKenneth D. Merry &ms_per_dma, &dmas_per_sec); 585*130f4520SKenneth D. Merry if (F_DMA(ctx)) 586*130f4520SKenneth D. Merry fprintf(stdout, " %2.2Lf", 587*130f4520SKenneth D. Merry ms_per_dma); 588*130f4520SKenneth D. Merry else if (F_LUNVAL(ctx) != 0) 589*130f4520SKenneth D. Merry fprintf(stdout, " %2.2Lf", 590*130f4520SKenneth D. Merry ms_per_transfer); 591*130f4520SKenneth D. Merry fprintf(stdout, " %5.2Lf %3.0Lf %5.2Lf ", 592*130f4520SKenneth D. Merry kb_per_transfer, (F_DMA(ctx) == 0) ? 593*130f4520SKenneth D. Merry transfers_per_sec : dmas_per_sec, mbsec); 594*130f4520SKenneth D. Merry } 595*130f4520SKenneth D. Merry } 596*130f4520SKenneth D. Merry } 597*130f4520SKenneth D. Merry 598*130f4520SKenneth D. Merry int 599*130f4520SKenneth D. Merry main(int argc, char **argv) 600*130f4520SKenneth D. Merry { 601*130f4520SKenneth D. Merry int c; 602*130f4520SKenneth D. Merry int count, waittime; 603*130f4520SKenneth D. Merry int set_lun; 604*130f4520SKenneth D. Merry int fd, retval; 605*130f4520SKenneth D. Merry struct ctlstat_context ctx; 606*130f4520SKenneth D. Merry 607*130f4520SKenneth D. Merry /* default values */ 608*130f4520SKenneth D. Merry retval = 0; 609*130f4520SKenneth D. Merry waittime = 1; 610*130f4520SKenneth D. Merry count = -1; 611*130f4520SKenneth D. Merry memset(&ctx, 0, sizeof(ctx)); 612*130f4520SKenneth D. Merry ctx.numdevs = 3; 613*130f4520SKenneth D. Merry ctx.mode = CTLSTAT_MODE_STANDARD; 614*130f4520SKenneth D. Merry ctx.flags |= CTLSTAT_FLAG_CPU; 615*130f4520SKenneth D. Merry ctx.flags |= CTLSTAT_FLAG_FIRST_RUN; 616*130f4520SKenneth D. Merry ctx.flags |= CTLSTAT_FLAG_HEADER; 617*130f4520SKenneth D. Merry 618*130f4520SKenneth D. Merry while ((c = getopt(argc, argv, ctlstat_opts)) != -1) { 619*130f4520SKenneth D. Merry switch (c) { 620*130f4520SKenneth D. Merry case 'C': 621*130f4520SKenneth D. Merry ctx.flags &= ~CTLSTAT_FLAG_CPU; 622*130f4520SKenneth D. Merry break; 623*130f4520SKenneth D. Merry case 'c': 624*130f4520SKenneth D. Merry count = atoi(optarg); 625*130f4520SKenneth D. Merry break; 626*130f4520SKenneth D. Merry case 'd': 627*130f4520SKenneth D. Merry ctx.flags |= CTLSTAT_FLAG_DMA_TIME; 628*130f4520SKenneth D. Merry break; 629*130f4520SKenneth D. Merry case 'D': 630*130f4520SKenneth D. Merry ctx.mode = CTLSTAT_MODE_DUMP; 631*130f4520SKenneth D. Merry waittime = 30; 632*130f4520SKenneth D. Merry break; 633*130f4520SKenneth D. Merry case 'h': 634*130f4520SKenneth D. Merry ctx.flags &= ~CTLSTAT_FLAG_HEADER; 635*130f4520SKenneth D. Merry break; 636*130f4520SKenneth D. Merry case 'j': 637*130f4520SKenneth D. Merry ctx.mode = CTLSTAT_MODE_JSON; 638*130f4520SKenneth D. Merry waittime = 30; 639*130f4520SKenneth D. Merry break; 640*130f4520SKenneth D. Merry case 'l': { 641*130f4520SKenneth D. Merry int cur_lun; 642*130f4520SKenneth D. Merry 643*130f4520SKenneth D. Merry cur_lun = atoi(optarg); 644*130f4520SKenneth D. Merry if (cur_lun > CTL_STAT_LUN_BITS) 645*130f4520SKenneth D. Merry errx(1, "Invalid LUN number %d", cur_lun); 646*130f4520SKenneth D. Merry 647*130f4520SKenneth D. Merry bit_ffs(ctx.lun_mask, CTL_STAT_LUN_BITS, &set_lun); 648*130f4520SKenneth D. Merry if (set_lun == -1) 649*130f4520SKenneth D. Merry ctx.numdevs = 1; 650*130f4520SKenneth D. Merry else 651*130f4520SKenneth D. Merry ctx.numdevs++; 652*130f4520SKenneth D. Merry bit_set(ctx.lun_mask, cur_lun); 653*130f4520SKenneth D. Merry break; 654*130f4520SKenneth D. Merry } 655*130f4520SKenneth D. Merry case 'n': 656*130f4520SKenneth D. Merry ctx.numdevs = atoi(optarg); 657*130f4520SKenneth D. Merry break; 658*130f4520SKenneth D. Merry case 't': 659*130f4520SKenneth D. Merry ctx.flags |= CTLSTAT_FLAG_TOTALS; 660*130f4520SKenneth D. Merry ctx.numdevs = 3; 661*130f4520SKenneth D. Merry break; 662*130f4520SKenneth D. Merry case 'w': 663*130f4520SKenneth D. Merry waittime = atoi(optarg); 664*130f4520SKenneth D. Merry break; 665*130f4520SKenneth D. Merry default: 666*130f4520SKenneth D. Merry retval = 1; 667*130f4520SKenneth D. Merry usage(retval); 668*130f4520SKenneth D. Merry exit(retval); 669*130f4520SKenneth D. Merry break; 670*130f4520SKenneth D. Merry } 671*130f4520SKenneth D. Merry } 672*130f4520SKenneth D. Merry 673*130f4520SKenneth D. Merry bit_ffs(ctx.lun_mask, CTL_STAT_LUN_BITS, &set_lun); 674*130f4520SKenneth D. Merry 675*130f4520SKenneth D. Merry if ((F_TOTALS(&ctx)) 676*130f4520SKenneth D. Merry && (set_lun != -1)) { 677*130f4520SKenneth D. Merry errx(1, "Total Mode (-t) is incompatible with individual " 678*130f4520SKenneth D. Merry "LUN mode (-l)"); 679*130f4520SKenneth D. Merry } else if (set_lun == -1) { 680*130f4520SKenneth D. Merry /* 681*130f4520SKenneth D. Merry * Note that this just selects the first N LUNs to display, 682*130f4520SKenneth D. Merry * but at this point we have no knoweledge of which LUN 683*130f4520SKenneth D. Merry * numbers actually exist. So we may select LUNs that 684*130f4520SKenneth D. Merry * aren't there. 685*130f4520SKenneth D. Merry */ 686*130f4520SKenneth D. Merry bit_nset(ctx.lun_mask, 0, min(ctx.numdevs - 1, 687*130f4520SKenneth D. Merry CTL_STAT_LUN_BITS - 1)); 688*130f4520SKenneth D. Merry } 689*130f4520SKenneth D. Merry 690*130f4520SKenneth D. Merry if ((fd = open(CTL_DEFAULT_DEV, O_RDWR)) == -1) 691*130f4520SKenneth D. Merry err(1, "cannot open %s", CTL_DEFAULT_DEV); 692*130f4520SKenneth D. Merry 693*130f4520SKenneth D. Merry for (;count != 0;) { 694*130f4520SKenneth D. Merry ctx.tmp_lun_stats = ctx.prev_lun_stats; 695*130f4520SKenneth D. Merry ctx.prev_lun_stats = ctx.cur_lun_stats; 696*130f4520SKenneth D. Merry ctx.cur_lun_stats = ctx.tmp_lun_stats; 697*130f4520SKenneth D. Merry ctx.prev_time = ctx.cur_time; 698*130f4520SKenneth D. Merry ctx.prev_cpu = ctx.cur_cpu; 699*130f4520SKenneth D. Merry if (getstats(fd, &ctx.num_luns, &ctx.cur_lun_stats, 700*130f4520SKenneth D. Merry &ctx.cur_time, &ctx.flags) != 0) 701*130f4520SKenneth D. Merry errx(1, "error returned from getstats()"); 702*130f4520SKenneth D. Merry 703*130f4520SKenneth D. Merry switch(ctx.mode) { 704*130f4520SKenneth D. Merry case CTLSTAT_MODE_STANDARD: 705*130f4520SKenneth D. Merry ctlstat_standard(&ctx); 706*130f4520SKenneth D. Merry break; 707*130f4520SKenneth D. Merry case CTLSTAT_MODE_DUMP: 708*130f4520SKenneth D. Merry ctlstat_dump(&ctx); 709*130f4520SKenneth D. Merry break; 710*130f4520SKenneth D. Merry case CTLSTAT_MODE_JSON: 711*130f4520SKenneth D. Merry ctlstat_json(&ctx); 712*130f4520SKenneth D. Merry break; 713*130f4520SKenneth D. Merry default: 714*130f4520SKenneth D. Merry break; 715*130f4520SKenneth D. Merry } 716*130f4520SKenneth D. Merry 717*130f4520SKenneth D. Merry fprintf(stdout, "\n"); 718*130f4520SKenneth D. Merry ctx.flags &= ~CTLSTAT_FLAG_FIRST_RUN; 719*130f4520SKenneth D. Merry if (count != 1) 720*130f4520SKenneth D. Merry sleep(waittime); 721*130f4520SKenneth D. Merry if (count > 0) 722*130f4520SKenneth D. Merry count--; 723*130f4520SKenneth D. Merry } 724*130f4520SKenneth D. Merry 725*130f4520SKenneth D. Merry exit (retval); 726*130f4520SKenneth D. Merry } 727*130f4520SKenneth D. Merry 728*130f4520SKenneth D. Merry /* 729*130f4520SKenneth D. Merry * vim: ts=8 730*130f4520SKenneth D. Merry */ 731