1130f4520SKenneth D. Merry /*- 2130f4520SKenneth D. Merry * Copyright (c) 2004, 2008, 2009 Silicon Graphics International Corp. 3130f4520SKenneth D. Merry * All rights reserved. 4130f4520SKenneth D. Merry * 5130f4520SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 6130f4520SKenneth D. Merry * modification, are permitted provided that the following conditions 7130f4520SKenneth D. Merry * are met: 8130f4520SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 9130f4520SKenneth D. Merry * notice, this list of conditions, and the following disclaimer, 10130f4520SKenneth D. Merry * without modification. 11130f4520SKenneth D. Merry * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12130f4520SKenneth D. Merry * substantially similar to the "NO WARRANTY" disclaimer below 13130f4520SKenneth D. Merry * ("Disclaimer") and any redistribution must be conditioned upon 14130f4520SKenneth D. Merry * including a substantially similar Disclaimer requirement for further 15130f4520SKenneth D. Merry * binary redistribution. 16130f4520SKenneth D. Merry * 17130f4520SKenneth D. Merry * NO WARRANTY 18130f4520SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19130f4520SKenneth D. Merry * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20130f4520SKenneth D. Merry * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21130f4520SKenneth D. Merry * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22130f4520SKenneth D. Merry * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23130f4520SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24130f4520SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25130f4520SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26130f4520SKenneth D. Merry * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27130f4520SKenneth D. Merry * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28130f4520SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGES. 29130f4520SKenneth D. Merry * 30130f4520SKenneth D. Merry * $Id: //depot/users/kenm/FreeBSD-test2/usr.bin/ctlstat/ctlstat.c#4 $ 31130f4520SKenneth D. Merry */ 32130f4520SKenneth D. Merry /* 33130f4520SKenneth D. Merry * CAM Target Layer statistics program 34130f4520SKenneth D. Merry * 35130f4520SKenneth D. Merry * Authors: Ken Merry <ken@FreeBSD.org>, Will Andrews <will@FreeBSD.org> 36130f4520SKenneth D. Merry */ 37130f4520SKenneth D. Merry 38130f4520SKenneth D. Merry #include <sys/cdefs.h> 39130f4520SKenneth D. Merry __FBSDID("$FreeBSD$"); 40130f4520SKenneth D. Merry 41130f4520SKenneth D. Merry #include <sys/ioctl.h> 42130f4520SKenneth D. Merry #include <sys/types.h> 43130f4520SKenneth D. Merry #include <sys/param.h> 44130f4520SKenneth D. Merry #include <sys/time.h> 45130f4520SKenneth D. Merry #include <sys/sysctl.h> 46130f4520SKenneth D. Merry #include <sys/resource.h> 47130f4520SKenneth D. Merry #include <sys/queue.h> 48130f4520SKenneth D. Merry #include <sys/callout.h> 49130f4520SKenneth D. Merry #include <stdint.h> 50130f4520SKenneth D. Merry #include <stdio.h> 51130f4520SKenneth D. Merry #include <stdlib.h> 52130f4520SKenneth D. Merry #include <unistd.h> 53130f4520SKenneth D. Merry #include <fcntl.h> 54130f4520SKenneth D. Merry #include <getopt.h> 55130f4520SKenneth D. Merry #include <string.h> 56130f4520SKenneth D. Merry #include <errno.h> 57130f4520SKenneth D. Merry #include <err.h> 58130f4520SKenneth D. Merry #include <ctype.h> 59130f4520SKenneth D. Merry #include <bitstring.h> 60130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h> 61130f4520SKenneth D. Merry #include <cam/ctl/ctl.h> 62130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h> 63130f4520SKenneth D. Merry #include <cam/ctl/ctl_scsi_all.h> 64130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.h> 65130f4520SKenneth D. Merry #include <cam/ctl/ctl_frontend_internal.h> 66130f4520SKenneth D. Merry #include <cam/ctl/ctl_backend.h> 67130f4520SKenneth D. Merry #include <cam/ctl/ctl_ioctl.h> 68130f4520SKenneth D. Merry 69130f4520SKenneth D. Merry /* 70130f4520SKenneth D. Merry * The default amount of space we allocate for LUN storage space. We 71130f4520SKenneth D. Merry * dynamically allocate more if needed. 72130f4520SKenneth D. Merry */ 73130f4520SKenneth D. Merry #define CTL_STAT_NUM_LUNS 30 74130f4520SKenneth D. Merry 75130f4520SKenneth D. Merry /* 76130f4520SKenneth D. Merry * The default number of LUN selection bits we allocate. This is large 77130f4520SKenneth D. Merry * because we don't currently increase it if the user specifies a LUN 78130f4520SKenneth D. Merry * number of 1024 or larger. 79130f4520SKenneth D. Merry */ 80130f4520SKenneth D. Merry #define CTL_STAT_LUN_BITS 1024L 81130f4520SKenneth D. Merry 82130f4520SKenneth D. Merry static const char *ctlstat_opts = "Cc:Ddhjl:n:tw:"; 83130f4520SKenneth D. Merry static const char *ctlstat_usage = "Usage: ctlstat [-CDdjht] [-l lunnum]" 84130f4520SKenneth D. Merry "[-c count] [-n numdevs] [-w wait]\n"; 85130f4520SKenneth D. Merry 86130f4520SKenneth D. Merry struct ctl_cpu_stats { 87130f4520SKenneth D. Merry uint64_t user; 88130f4520SKenneth D. Merry uint64_t nice; 89130f4520SKenneth D. Merry uint64_t system; 90130f4520SKenneth D. Merry uint64_t intr; 91130f4520SKenneth D. Merry uint64_t idle; 92130f4520SKenneth D. Merry }; 93130f4520SKenneth D. Merry 94130f4520SKenneth D. Merry typedef enum { 95130f4520SKenneth D. Merry CTLSTAT_MODE_STANDARD, 96130f4520SKenneth D. Merry CTLSTAT_MODE_DUMP, 97130f4520SKenneth D. Merry CTLSTAT_MODE_JSON, 98130f4520SKenneth D. Merry } ctlstat_mode_types; 99130f4520SKenneth D. Merry 100130f4520SKenneth D. Merry #define CTLSTAT_FLAG_CPU (1 << 0) 101130f4520SKenneth D. Merry #define CTLSTAT_FLAG_HEADER (1 << 1) 102130f4520SKenneth D. Merry #define CTLSTAT_FLAG_FIRST_RUN (1 << 2) 103130f4520SKenneth D. Merry #define CTLSTAT_FLAG_TOTALS (1 << 3) 104130f4520SKenneth D. Merry #define CTLSTAT_FLAG_DMA_TIME (1 << 4) 105130f4520SKenneth D. Merry #define CTLSTAT_FLAG_LUN_TIME_VALID (1 << 5) 106130f4520SKenneth D. Merry #define F_CPU(ctx) ((ctx)->flags & CTLSTAT_FLAG_CPU) 107130f4520SKenneth D. Merry #define F_HDR(ctx) ((ctx)->flags & CTLSTAT_FLAG_HEADER) 108130f4520SKenneth D. Merry #define F_FIRST(ctx) ((ctx)->flags & CTLSTAT_FLAG_FIRST_RUN) 109130f4520SKenneth D. Merry #define F_TOTALS(ctx) ((ctx)->flags & CTLSTAT_FLAG_TOTALS) 110130f4520SKenneth D. Merry #define F_DMA(ctx) ((ctx)->flags & CTLSTAT_FLAG_DMA_TIME) 111130f4520SKenneth D. Merry #define F_LUNVAL(ctx) ((ctx)->flags & CTLSTAT_FLAG_LUN_TIME_VALID) 112130f4520SKenneth D. Merry 113130f4520SKenneth D. Merry struct ctlstat_context { 114130f4520SKenneth D. Merry ctlstat_mode_types mode; 115130f4520SKenneth D. Merry int flags; 116130f4520SKenneth D. Merry struct ctl_lun_io_stats *cur_lun_stats, *prev_lun_stats, 117130f4520SKenneth D. Merry *tmp_lun_stats; 118130f4520SKenneth D. Merry struct ctl_lun_io_stats cur_total_stats[3], prev_total_stats[3]; 119130f4520SKenneth D. Merry struct timespec cur_time, prev_time; 120130f4520SKenneth D. Merry struct ctl_cpu_stats cur_cpu, prev_cpu; 121130f4520SKenneth D. Merry uint64_t cur_total_jiffies, prev_total_jiffies; 122130f4520SKenneth D. Merry uint64_t cur_idle, prev_idle; 123130f4520SKenneth D. Merry bitstr_t bit_decl(lun_mask, CTL_STAT_LUN_BITS); 124130f4520SKenneth D. Merry int num_luns; 125130f4520SKenneth D. Merry int numdevs; 126130f4520SKenneth D. Merry int header_interval; 127130f4520SKenneth D. Merry }; 128130f4520SKenneth D. Merry 129130f4520SKenneth D. Merry #ifndef min 130130f4520SKenneth D. Merry #define min(x,y) (((x) < (y)) ? (x) : (y)) 131130f4520SKenneth D. Merry #endif 132130f4520SKenneth D. Merry 133130f4520SKenneth D. Merry static void usage(int error); 134130f4520SKenneth D. Merry static int getstats(int fd, int *num_luns, struct ctl_lun_io_stats **xlun_stats, 135130f4520SKenneth D. Merry struct timespec *cur_time, int *lun_time_valid); 136130f4520SKenneth D. Merry static int getcpu(struct ctl_cpu_stats *cpu_stats); 137130f4520SKenneth D. Merry static void compute_stats(struct ctl_lun_io_stats *cur_stats, 138130f4520SKenneth D. Merry struct ctl_lun_io_stats *prev_stats, 139130f4520SKenneth D. Merry long double etime, long double *mbsec, 140130f4520SKenneth D. Merry long double *kb_per_transfer, 141130f4520SKenneth D. Merry long double *transfers_per_second, 142130f4520SKenneth D. Merry long double *ms_per_transfer, 143130f4520SKenneth D. Merry long double *ms_per_dma, 144130f4520SKenneth D. Merry long double *dmas_per_second); 145130f4520SKenneth D. Merry 146130f4520SKenneth D. Merry static void 147130f4520SKenneth D. Merry usage(int error) 148130f4520SKenneth D. Merry { 149*33d35bebSKenneth D. Merry fputs(ctlstat_usage, error ? stderr : stdout); 150130f4520SKenneth D. Merry } 151130f4520SKenneth D. Merry 152130f4520SKenneth D. Merry static int 153130f4520SKenneth D. Merry getstats(int fd, int *num_luns, struct ctl_lun_io_stats **xlun_stats, 154130f4520SKenneth D. Merry struct timespec *cur_time, int *flags) 155130f4520SKenneth D. Merry { 156130f4520SKenneth D. Merry struct ctl_lun_io_stats *lun_stats; 157130f4520SKenneth D. Merry struct ctl_stats stats; 158130f4520SKenneth D. Merry int more_space_count; 159130f4520SKenneth D. Merry 160130f4520SKenneth D. Merry more_space_count = 0; 161130f4520SKenneth D. Merry 162130f4520SKenneth D. Merry if (*num_luns == 0) 163130f4520SKenneth D. Merry *num_luns = CTL_STAT_NUM_LUNS; 164130f4520SKenneth D. Merry 165130f4520SKenneth D. Merry lun_stats = *xlun_stats; 166130f4520SKenneth D. Merry retry: 167130f4520SKenneth D. Merry 168130f4520SKenneth D. Merry if (lun_stats == NULL) { 169130f4520SKenneth D. Merry lun_stats = (struct ctl_lun_io_stats *)malloc( 170130f4520SKenneth D. Merry sizeof(*lun_stats) * *num_luns); 171130f4520SKenneth D. Merry } 172130f4520SKenneth D. Merry 173130f4520SKenneth D. Merry memset(&stats, 0, sizeof(stats)); 174130f4520SKenneth D. Merry stats.alloc_len = *num_luns * sizeof(*lun_stats); 175130f4520SKenneth D. Merry memset(lun_stats, 0, stats.alloc_len); 176130f4520SKenneth D. Merry stats.lun_stats = lun_stats; 177130f4520SKenneth D. Merry 178130f4520SKenneth D. Merry if (ioctl(fd, CTL_GETSTATS, &stats) == -1) 179130f4520SKenneth D. Merry err(1, "error returned from CTL_GETSTATS ioctl"); 180130f4520SKenneth D. Merry 181130f4520SKenneth D. Merry switch (stats.status) { 182130f4520SKenneth D. Merry case CTL_SS_OK: 183130f4520SKenneth D. Merry break; 184130f4520SKenneth D. Merry case CTL_SS_ERROR: 185130f4520SKenneth D. Merry err(1, "CTL_SS_ERROR returned from CTL_GETSTATS ioctl"); 186130f4520SKenneth D. Merry break; 187130f4520SKenneth D. Merry case CTL_SS_NEED_MORE_SPACE: 188130f4520SKenneth D. Merry if (more_space_count > 0) { 189130f4520SKenneth D. Merry errx(1, "CTL_GETSTATS returned NEED_MORE_SPACE again"); 190130f4520SKenneth D. Merry } 191130f4520SKenneth D. Merry *num_luns = stats.num_luns; 192130f4520SKenneth D. Merry free(lun_stats); 193130f4520SKenneth D. Merry lun_stats = NULL; 194130f4520SKenneth D. Merry more_space_count++; 195130f4520SKenneth D. Merry goto retry; 196130f4520SKenneth D. Merry break; /* NOTREACHED */ 197130f4520SKenneth D. Merry default: 198130f4520SKenneth D. Merry errx(1, "unknown status %d returned from CTL_GETSTATS ioctl", 199130f4520SKenneth D. Merry stats.status); 200130f4520SKenneth D. Merry break; 201130f4520SKenneth D. Merry } 202130f4520SKenneth D. Merry 203130f4520SKenneth D. Merry *xlun_stats = lun_stats; 204130f4520SKenneth D. Merry *num_luns = stats.num_luns; 205130f4520SKenneth D. Merry cur_time->tv_sec = stats.timestamp.tv_sec; 206130f4520SKenneth D. Merry cur_time->tv_nsec = stats.timestamp.tv_nsec; 207130f4520SKenneth D. Merry if (stats.flags & CTL_STATS_FLAG_TIME_VALID) 208130f4520SKenneth D. Merry *flags |= CTLSTAT_FLAG_LUN_TIME_VALID; 209130f4520SKenneth D. Merry else 210130f4520SKenneth D. Merry *flags &= ~CTLSTAT_FLAG_LUN_TIME_VALID; 211130f4520SKenneth D. Merry 212130f4520SKenneth D. Merry return (0); 213130f4520SKenneth D. Merry } 214130f4520SKenneth D. Merry 215130f4520SKenneth D. Merry static int 216130f4520SKenneth D. Merry getcpu(struct ctl_cpu_stats *cpu_stats) 217130f4520SKenneth D. Merry { 218130f4520SKenneth D. Merry long cp_time[CPUSTATES]; 219130f4520SKenneth D. Merry size_t cplen; 220130f4520SKenneth D. Merry 221130f4520SKenneth D. Merry cplen = sizeof(cp_time); 222130f4520SKenneth D. Merry 223130f4520SKenneth D. Merry if (sysctlbyname("kern.cp_time", &cp_time, &cplen, NULL, 0) == -1) { 224130f4520SKenneth D. Merry warn("sysctlbyname(kern.cp_time...) failed"); 225130f4520SKenneth D. Merry return (1); 226130f4520SKenneth D. Merry } 227130f4520SKenneth D. Merry 228130f4520SKenneth D. Merry cpu_stats->user = cp_time[CP_USER]; 229130f4520SKenneth D. Merry cpu_stats->nice = cp_time[CP_NICE]; 230130f4520SKenneth D. Merry cpu_stats->system = cp_time[CP_SYS]; 231130f4520SKenneth D. Merry cpu_stats->intr = cp_time[CP_INTR]; 232130f4520SKenneth D. Merry cpu_stats->idle = cp_time[CP_IDLE]; 233130f4520SKenneth D. Merry 234130f4520SKenneth D. Merry return (0); 235130f4520SKenneth D. Merry } 236130f4520SKenneth D. Merry 237130f4520SKenneth D. Merry static void 238130f4520SKenneth D. Merry compute_stats(struct ctl_lun_io_stats *cur_stats, 239130f4520SKenneth D. Merry struct ctl_lun_io_stats *prev_stats, long double etime, 240130f4520SKenneth D. Merry long double *mbsec, long double *kb_per_transfer, 241130f4520SKenneth D. Merry long double *transfers_per_second, long double *ms_per_transfer, 242130f4520SKenneth D. Merry long double *ms_per_dma, long double *dmas_per_second) 243130f4520SKenneth D. Merry { 244130f4520SKenneth D. Merry uint64_t total_bytes = 0, total_operations = 0, total_dmas = 0; 245130f4520SKenneth D. Merry uint32_t port; 246130f4520SKenneth D. Merry struct bintime total_time_bt, total_dma_bt; 247130f4520SKenneth D. Merry struct timespec total_time_ts, total_dma_ts; 248130f4520SKenneth D. Merry int i; 249130f4520SKenneth D. Merry 250130f4520SKenneth D. Merry bzero(&total_time_bt, sizeof(total_time_bt)); 251130f4520SKenneth D. Merry bzero(&total_dma_bt, sizeof(total_dma_bt)); 252130f4520SKenneth D. Merry bzero(&total_time_ts, sizeof(total_time_ts)); 253130f4520SKenneth D. Merry bzero(&total_dma_ts, sizeof(total_dma_ts)); 254130f4520SKenneth D. Merry for (port = 0; port < CTL_MAX_PORTS; port++) { 255130f4520SKenneth D. Merry for (i = 0; i < CTL_STATS_NUM_TYPES; i++) { 256130f4520SKenneth D. Merry total_bytes += cur_stats->ports[port].bytes[i]; 257130f4520SKenneth D. Merry total_operations += 258130f4520SKenneth D. Merry cur_stats->ports[port].operations[i]; 259130f4520SKenneth D. Merry total_dmas += cur_stats->ports[port].num_dmas[i]; 260130f4520SKenneth D. Merry bintime_add(&total_time_bt, 261130f4520SKenneth D. Merry &cur_stats->ports[port].time[i]); 262130f4520SKenneth D. Merry bintime_add(&total_dma_bt, 263130f4520SKenneth D. Merry &cur_stats->ports[port].dma_time[i]); 264130f4520SKenneth D. Merry if (prev_stats != NULL) { 265130f4520SKenneth D. Merry total_bytes -= 266130f4520SKenneth D. Merry prev_stats->ports[port].bytes[i]; 267130f4520SKenneth D. Merry total_operations -= 268130f4520SKenneth D. Merry prev_stats->ports[port].operations[i]; 269130f4520SKenneth D. Merry total_dmas -= 270130f4520SKenneth D. Merry prev_stats->ports[port].num_dmas[i]; 271130f4520SKenneth D. Merry bintime_sub(&total_time_bt, 272130f4520SKenneth D. Merry &prev_stats->ports[port].time[i]); 273130f4520SKenneth D. Merry bintime_sub(&total_dma_bt, 274130f4520SKenneth D. Merry &prev_stats->ports[port].dma_time[i]); 275130f4520SKenneth D. Merry } 276130f4520SKenneth D. Merry } 277130f4520SKenneth D. Merry } 278130f4520SKenneth D. Merry 279130f4520SKenneth D. Merry *mbsec = total_bytes; 280130f4520SKenneth D. Merry *mbsec /= 1024 * 1024; 281130f4520SKenneth D. Merry if (etime > 0.0) 282130f4520SKenneth D. Merry *mbsec /= etime; 283130f4520SKenneth D. Merry else 284130f4520SKenneth D. Merry *mbsec = 0; 285130f4520SKenneth D. Merry *kb_per_transfer = total_bytes; 286130f4520SKenneth D. Merry *kb_per_transfer /= 1024; 287130f4520SKenneth D. Merry if (total_operations > 0) 288130f4520SKenneth D. Merry *kb_per_transfer /= total_operations; 289130f4520SKenneth D. Merry else 290130f4520SKenneth D. Merry *kb_per_transfer = 0; 291130f4520SKenneth D. Merry *transfers_per_second = total_operations; 292130f4520SKenneth D. Merry *dmas_per_second = total_dmas; 293130f4520SKenneth D. Merry if (etime > 0.0) { 294130f4520SKenneth D. Merry *transfers_per_second /= etime; 295130f4520SKenneth D. Merry *dmas_per_second /= etime; 296130f4520SKenneth D. Merry } else { 297130f4520SKenneth D. Merry *transfers_per_second = 0; 298130f4520SKenneth D. Merry *dmas_per_second = 0; 299130f4520SKenneth D. Merry } 300130f4520SKenneth D. Merry 301130f4520SKenneth D. Merry bintime2timespec(&total_time_bt, &total_time_ts); 302130f4520SKenneth D. Merry bintime2timespec(&total_dma_bt, &total_dma_ts); 303130f4520SKenneth D. Merry if (total_operations > 0) { 304130f4520SKenneth D. Merry /* 305130f4520SKenneth D. Merry * Convert the timespec to milliseconds. 306130f4520SKenneth D. Merry */ 307130f4520SKenneth D. Merry *ms_per_transfer = total_time_ts.tv_sec * 1000; 308130f4520SKenneth D. Merry *ms_per_transfer += total_time_ts.tv_nsec / 1000000; 309130f4520SKenneth D. Merry *ms_per_transfer /= total_operations; 310130f4520SKenneth D. Merry } else 311130f4520SKenneth D. Merry *ms_per_transfer = 0; 312130f4520SKenneth D. Merry 313130f4520SKenneth D. Merry if (total_dmas > 0) { 314130f4520SKenneth D. Merry /* 315130f4520SKenneth D. Merry * Convert the timespec to milliseconds. 316130f4520SKenneth D. Merry */ 317130f4520SKenneth D. Merry *ms_per_dma = total_dma_ts.tv_sec * 1000; 318130f4520SKenneth D. Merry *ms_per_dma += total_dma_ts.tv_nsec / 1000000; 319130f4520SKenneth D. Merry *ms_per_dma /= total_dmas; 320130f4520SKenneth D. Merry } else 321130f4520SKenneth D. Merry *ms_per_dma = 0; 322130f4520SKenneth D. Merry } 323130f4520SKenneth D. Merry 324130f4520SKenneth D. Merry /* The dump_stats() and json_stats() functions perform essentially the same 325130f4520SKenneth D. Merry * purpose, but dump the statistics in different formats. JSON is more 326130f4520SKenneth D. Merry * conducive to programming, however. 327130f4520SKenneth D. Merry */ 328130f4520SKenneth D. Merry 329130f4520SKenneth D. Merry #define PRINT_BINTIME(prefix, bt) \ 330130f4520SKenneth D. Merry printf("%s %jd s %ju frac\n", prefix, (intmax_t)(bt).sec, \ 331130f4520SKenneth D. Merry (uintmax_t)(bt).frac) 332130f4520SKenneth D. Merry const char *iotypes[] = {"NO IO", "READ", "WRITE"}; 333130f4520SKenneth D. Merry 334130f4520SKenneth D. Merry static void 335130f4520SKenneth D. Merry ctlstat_dump(struct ctlstat_context *ctx) { 336130f4520SKenneth D. Merry int iotype, lun, port; 337130f4520SKenneth D. Merry struct ctl_lun_io_stats *stats = ctx->cur_lun_stats; 338130f4520SKenneth D. Merry 339130f4520SKenneth D. Merry for (lun = 0; lun < ctx->num_luns;lun++) { 340130f4520SKenneth D. Merry printf("lun %d\n", lun); 341130f4520SKenneth D. Merry for (port = 0; port < CTL_MAX_PORTS; port++) { 342130f4520SKenneth D. Merry printf(" port %d\n", 343130f4520SKenneth D. Merry stats[lun].ports[port].targ_port); 344130f4520SKenneth D. Merry for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; 345130f4520SKenneth D. Merry iotype++) { 346130f4520SKenneth D. Merry printf(" io type %d (%s)\n", iotype, 347130f4520SKenneth D. Merry iotypes[iotype]); 348130f4520SKenneth D. Merry printf(" bytes %ju\n", (uintmax_t) 349130f4520SKenneth D. Merry stats[lun].ports[port].bytes[iotype]); 350130f4520SKenneth D. Merry printf(" operations %ju\n", (uintmax_t) 351130f4520SKenneth D. Merry stats[lun].ports[port].operations[iotype]); 352130f4520SKenneth D. Merry PRINT_BINTIME(" io time", 353130f4520SKenneth D. Merry stats[lun].ports[port].time[iotype]); 354130f4520SKenneth D. Merry printf(" num dmas %ju\n", (uintmax_t) 355130f4520SKenneth D. Merry stats[lun].ports[port].num_dmas[iotype]); 356130f4520SKenneth D. Merry PRINT_BINTIME(" dma time", 357130f4520SKenneth D. Merry stats[lun].ports[port].dma_time[iotype]); 358130f4520SKenneth D. Merry } 359130f4520SKenneth D. Merry } 360130f4520SKenneth D. Merry } 361130f4520SKenneth D. Merry } 362130f4520SKenneth D. Merry 363130f4520SKenneth D. Merry #define JSON_BINTIME(prefix, bt) \ 364130f4520SKenneth D. Merry printf("\"%s\":{\"sec\":%jd,\"frac\":%ju},", \ 365130f4520SKenneth D. Merry prefix, (intmax_t)(bt).sec, (uintmax_t)(bt).frac) 366130f4520SKenneth D. Merry 367130f4520SKenneth D. Merry static void 368130f4520SKenneth D. Merry ctlstat_json(struct ctlstat_context *ctx) { 369130f4520SKenneth D. Merry int iotype, lun, port; 370130f4520SKenneth D. Merry struct ctl_lun_io_stats *stats = ctx->cur_lun_stats; 371130f4520SKenneth D. Merry 372130f4520SKenneth D. Merry printf("{\"luns\":["); 373130f4520SKenneth D. Merry for (lun = 0; lun < ctx->num_luns; lun++) { 374130f4520SKenneth D. Merry printf("{\"ports\":["); 375130f4520SKenneth D. Merry for (port = 0; port < CTL_MAX_PORTS;port++) { 376130f4520SKenneth D. Merry printf("{\"num\":%d,\"io\":[", 377130f4520SKenneth D. Merry stats[lun].ports[port].targ_port); 378130f4520SKenneth D. Merry for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; 379130f4520SKenneth D. Merry iotype++) { 380130f4520SKenneth D. Merry printf("{\"type\":\"%s\",", iotypes[iotype]); 381130f4520SKenneth D. Merry printf("\"bytes\":%ju,", (uintmax_t)stats[ 382130f4520SKenneth D. Merry lun].ports[port].bytes[iotype]); 383130f4520SKenneth D. Merry printf("\"operations\":%ju,", (uintmax_t)stats[ 384130f4520SKenneth D. Merry lun].ports[port].operations[iotype]); 385130f4520SKenneth D. Merry JSON_BINTIME("io time", 386130f4520SKenneth D. Merry stats[lun].ports[port].time[iotype]); 387130f4520SKenneth D. Merry JSON_BINTIME("dma time", 388130f4520SKenneth D. Merry stats[lun].ports[port].dma_time[iotype]); 389130f4520SKenneth D. Merry printf("\"num dmas\":%ju}", (uintmax_t) 390130f4520SKenneth D. Merry stats[lun].ports[port].num_dmas[iotype]); 391130f4520SKenneth D. Merry if (iotype < (CTL_STATS_NUM_TYPES - 1)) 392130f4520SKenneth D. Merry printf(","); /* continue io array */ 393130f4520SKenneth D. Merry } 394130f4520SKenneth D. Merry printf("]}"); /* close port */ 395130f4520SKenneth D. Merry if (port < (CTL_MAX_PORTS - 1)) 396130f4520SKenneth D. Merry printf(","); /* continue port array */ 397130f4520SKenneth D. Merry } 398130f4520SKenneth D. Merry printf("]}"); /* close lun */ 399130f4520SKenneth D. Merry if (lun < (ctx->num_luns - 1)) 400130f4520SKenneth D. Merry printf(","); /* continue lun array */ 401130f4520SKenneth D. Merry } 402130f4520SKenneth D. Merry printf("]}"); /* close luns and toplevel */ 403130f4520SKenneth D. Merry } 404130f4520SKenneth D. Merry 405130f4520SKenneth D. Merry static void 406130f4520SKenneth D. Merry ctlstat_standard(struct ctlstat_context *ctx) { 407130f4520SKenneth D. Merry long double cur_secs, prev_secs, etime; 408130f4520SKenneth D. Merry uint64_t delta_jiffies, delta_idle; 409130f4520SKenneth D. Merry uint32_t port; 410130f4520SKenneth D. Merry long double cpu_percentage; 411130f4520SKenneth D. Merry int i; 412130f4520SKenneth D. Merry int j; 413130f4520SKenneth D. Merry 414130f4520SKenneth D. Merry cpu_percentage = 0; 415130f4520SKenneth D. Merry 416130f4520SKenneth D. Merry if (F_CPU(ctx) && (getcpu(&ctx->cur_cpu) != 0)) 417130f4520SKenneth D. Merry errx(1, "error returned from getcpu()"); 418130f4520SKenneth D. Merry 419130f4520SKenneth D. Merry cur_secs = ctx->cur_time.tv_sec + (ctx->cur_time.tv_nsec / 1000000000); 420130f4520SKenneth D. Merry prev_secs = ctx->prev_time.tv_sec + 421130f4520SKenneth D. Merry (ctx->prev_time.tv_nsec / 1000000000); 422130f4520SKenneth D. Merry 423130f4520SKenneth D. Merry etime = cur_secs - prev_secs; 424130f4520SKenneth D. Merry 425130f4520SKenneth D. Merry if (F_CPU(ctx)) { 426130f4520SKenneth D. Merry ctx->prev_total_jiffies = ctx->cur_total_jiffies; 427130f4520SKenneth D. Merry ctx->cur_total_jiffies = ctx->cur_cpu.user + 428130f4520SKenneth D. Merry ctx->cur_cpu.nice + ctx->cur_cpu.system + 429130f4520SKenneth D. Merry ctx->cur_cpu.intr + ctx->cur_cpu.idle; 430130f4520SKenneth D. Merry delta_jiffies = ctx->cur_total_jiffies; 431130f4520SKenneth D. Merry if (F_FIRST(ctx) == 0) 432130f4520SKenneth D. Merry delta_jiffies -= ctx->prev_total_jiffies; 433130f4520SKenneth D. Merry ctx->prev_idle = ctx->cur_idle; 434130f4520SKenneth D. Merry ctx->cur_idle = ctx->cur_cpu.idle; 435130f4520SKenneth D. Merry delta_idle = ctx->cur_idle - ctx->prev_idle; 436130f4520SKenneth D. Merry 437130f4520SKenneth D. Merry cpu_percentage = delta_jiffies - delta_idle; 438130f4520SKenneth D. Merry cpu_percentage /= delta_jiffies; 439130f4520SKenneth D. Merry cpu_percentage *= 100; 440130f4520SKenneth D. Merry } 441130f4520SKenneth D. Merry 442130f4520SKenneth D. Merry if (F_HDR(ctx)) { 443130f4520SKenneth D. Merry ctx->header_interval--; 444130f4520SKenneth D. Merry if (ctx->header_interval <= 0) { 445130f4520SKenneth D. Merry int hdr_devs; 446130f4520SKenneth D. Merry 447130f4520SKenneth D. Merry hdr_devs = 0; 448130f4520SKenneth D. Merry 449130f4520SKenneth D. Merry if (F_TOTALS(ctx)) { 450130f4520SKenneth D. Merry fprintf(stdout, "%s System Read %s" 451130f4520SKenneth D. Merry "System Write %sSystem Total%s\n", 452130f4520SKenneth D. Merry (F_LUNVAL(ctx) != 0) ? " " : "", 453130f4520SKenneth D. Merry (F_LUNVAL(ctx) != 0) ? " " : "", 454130f4520SKenneth D. Merry (F_LUNVAL(ctx) != 0) ? " " : "", 455130f4520SKenneth D. Merry (F_CPU(ctx) == 0) ? " CPU" : ""); 456130f4520SKenneth D. Merry hdr_devs = 3; 457130f4520SKenneth D. Merry } else { 458130f4520SKenneth D. Merry if (F_CPU(ctx)) 459130f4520SKenneth D. Merry fprintf(stdout, " CPU "); 460130f4520SKenneth D. Merry for (i = 0; i < min(CTL_STAT_LUN_BITS, 461130f4520SKenneth D. Merry ctx->num_luns); i++) { 462130f4520SKenneth D. Merry int lun; 463130f4520SKenneth D. Merry 464130f4520SKenneth D. Merry /* 465130f4520SKenneth D. Merry * Obviously this won't work with 466130f4520SKenneth D. Merry * LUN numbers greater than a signed 467130f4520SKenneth D. Merry * integer. 468130f4520SKenneth D. Merry */ 469130f4520SKenneth D. Merry lun = (int)ctx->cur_lun_stats[i 470130f4520SKenneth D. Merry ].lun_number; 471130f4520SKenneth D. Merry 472130f4520SKenneth D. Merry if (bit_test(ctx->lun_mask, lun) == 0) 473130f4520SKenneth D. Merry continue; 474130f4520SKenneth D. Merry fprintf(stdout, "%15.6s%d ", 475130f4520SKenneth D. Merry "lun", lun); 476130f4520SKenneth D. Merry hdr_devs++; 477130f4520SKenneth D. Merry } 478130f4520SKenneth D. Merry fprintf(stdout, "\n"); 479130f4520SKenneth D. Merry } 480130f4520SKenneth D. Merry for (i = 0; i < hdr_devs; i++) 481130f4520SKenneth D. Merry fprintf(stdout, "%s %sKB/t %s MB/s ", 482130f4520SKenneth D. Merry ((F_CPU(ctx) != 0) && (i == 0) && 483130f4520SKenneth D. Merry (F_TOTALS(ctx) == 0)) ? " " : "", 484130f4520SKenneth D. Merry (F_LUNVAL(ctx) != 0) ? " ms " : "", 485130f4520SKenneth D. Merry (F_DMA(ctx) == 0) ? "tps" : "dps"); 486130f4520SKenneth D. Merry fprintf(stdout, "\n"); 487130f4520SKenneth D. Merry ctx->header_interval = 20; 488130f4520SKenneth D. Merry } 489130f4520SKenneth D. Merry } 490130f4520SKenneth D. Merry 491130f4520SKenneth D. Merry if (F_TOTALS(ctx) != 0) { 492130f4520SKenneth D. Merry long double mbsec[3]; 493130f4520SKenneth D. Merry long double kb_per_transfer[3]; 494130f4520SKenneth D. Merry long double transfers_per_sec[3]; 495130f4520SKenneth D. Merry long double ms_per_transfer[3]; 496130f4520SKenneth D. Merry long double ms_per_dma[3]; 497130f4520SKenneth D. Merry long double dmas_per_sec[3]; 498130f4520SKenneth D. Merry 499130f4520SKenneth D. Merry for (i = 0; i < 3; i++) 500130f4520SKenneth D. Merry ctx->prev_total_stats[i] = ctx->cur_total_stats[i]; 501130f4520SKenneth D. Merry 502130f4520SKenneth D. Merry memset(&ctx->cur_total_stats, 0, sizeof(ctx->cur_total_stats)); 503130f4520SKenneth D. Merry 504130f4520SKenneth D. Merry /* Use macros to make the next loop more readable. */ 505130f4520SKenneth D. Merry #define ADD_STATS_BYTES(st, p, i, j) \ 506130f4520SKenneth D. Merry ctx->cur_total_stats[st].ports[p].bytes[j] += \ 507130f4520SKenneth D. Merry ctx->cur_lun_stats[i].ports[p].bytes[j] 508130f4520SKenneth D. Merry #define ADD_STATS_OPERATIONS(st, p, i, j) \ 509130f4520SKenneth D. Merry ctx->cur_total_stats[st].ports[p].operations[j] += \ 510130f4520SKenneth D. Merry ctx->cur_lun_stats[i].ports[p].operations[j] 511130f4520SKenneth D. Merry #define ADD_STATS_NUM_DMAS(st, p, i, j) \ 512130f4520SKenneth D. Merry ctx->cur_total_stats[st].ports[p].num_dmas[j] += \ 513130f4520SKenneth D. Merry ctx->cur_lun_stats[i].ports[p].num_dmas[j] 514130f4520SKenneth D. Merry #define ADD_STATS_TIME(st, p, i, j) \ 515130f4520SKenneth D. Merry bintime_add(&ctx->cur_total_stats[st].ports[p].time[j], \ 516130f4520SKenneth D. Merry &ctx->cur_lun_stats[i].ports[p].time[j]) 517130f4520SKenneth D. Merry #define ADD_STATS_DMA_TIME(st, p, i, j) \ 518130f4520SKenneth D. Merry bintime_add(&ctx->cur_total_stats[st].ports[p].dma_time[j], \ 519130f4520SKenneth D. Merry &ctx->cur_lun_stats[i].ports[p].dma_time[j]) 520130f4520SKenneth D. Merry 521130f4520SKenneth D. Merry for (i = 0; i < ctx->num_luns; i++) { 522130f4520SKenneth D. Merry for (port = 0; port < CTL_MAX_PORTS; port++) { 523130f4520SKenneth D. Merry for (j = 0; j < CTL_STATS_NUM_TYPES; j++) { 524130f4520SKenneth D. Merry ADD_STATS_BYTES(2, port, i, j); 525130f4520SKenneth D. Merry ADD_STATS_OPERATIONS(2, port, i, j); 526130f4520SKenneth D. Merry ADD_STATS_NUM_DMAS(2, port, i, j); 527130f4520SKenneth D. Merry ADD_STATS_TIME(2, port, i, j); 528130f4520SKenneth D. Merry ADD_STATS_DMA_TIME(2, port, i, j); 529130f4520SKenneth D. Merry } 530130f4520SKenneth D. Merry ADD_STATS_BYTES(0, port, i, CTL_STATS_READ); 531130f4520SKenneth D. Merry ADD_STATS_OPERATIONS(0, port, i, 532130f4520SKenneth D. Merry CTL_STATS_READ); 533130f4520SKenneth D. Merry ADD_STATS_NUM_DMAS(0, port, i, CTL_STATS_READ); 534130f4520SKenneth D. Merry ADD_STATS_TIME(0, port, i, CTL_STATS_READ); 535130f4520SKenneth D. Merry ADD_STATS_DMA_TIME(0, port, i, CTL_STATS_READ); 536130f4520SKenneth D. Merry 537130f4520SKenneth D. Merry ADD_STATS_BYTES(1, port, i, CTL_STATS_WRITE); 538130f4520SKenneth D. Merry ADD_STATS_OPERATIONS(1, port, i, 539130f4520SKenneth D. Merry CTL_STATS_WRITE); 540130f4520SKenneth D. Merry ADD_STATS_NUM_DMAS(1, port, i, CTL_STATS_WRITE); 541130f4520SKenneth D. Merry ADD_STATS_TIME(1, port, i, CTL_STATS_WRITE); 542130f4520SKenneth D. Merry ADD_STATS_DMA_TIME(1, port, i, CTL_STATS_WRITE); 543130f4520SKenneth D. Merry } 544130f4520SKenneth D. Merry } 545130f4520SKenneth D. Merry 546130f4520SKenneth D. Merry for (i = 0; i < 3; i++) { 547130f4520SKenneth D. Merry compute_stats(&ctx->cur_total_stats[i], 548130f4520SKenneth D. Merry F_FIRST(ctx) ? NULL : &ctx->prev_total_stats[i], 549130f4520SKenneth D. Merry etime, &mbsec[i], &kb_per_transfer[i], 550130f4520SKenneth D. Merry &transfers_per_sec[i], 551130f4520SKenneth D. Merry &ms_per_transfer[i], &ms_per_dma[i], 552130f4520SKenneth D. Merry &dmas_per_sec[i]); 553130f4520SKenneth D. Merry if (F_DMA(ctx) != 0) 554130f4520SKenneth D. Merry fprintf(stdout, " %2.2Lf", 555130f4520SKenneth D. Merry ms_per_dma[i]); 556130f4520SKenneth D. Merry else if (F_LUNVAL(ctx) != 0) 557130f4520SKenneth D. Merry fprintf(stdout, " %2.2Lf", 558130f4520SKenneth D. Merry ms_per_transfer[i]); 559130f4520SKenneth D. Merry fprintf(stdout, " %5.2Lf %3.0Lf %5.2Lf ", 560130f4520SKenneth D. Merry kb_per_transfer[i], 561130f4520SKenneth D. Merry (F_DMA(ctx) == 0) ? transfers_per_sec[i] : 562130f4520SKenneth D. Merry dmas_per_sec[i], mbsec[i]); 563130f4520SKenneth D. Merry } 564130f4520SKenneth D. Merry if (F_CPU(ctx)) 565130f4520SKenneth D. Merry fprintf(stdout, " %5.1Lf%%", cpu_percentage); 566130f4520SKenneth D. Merry } else { 567130f4520SKenneth D. Merry if (F_CPU(ctx)) 568130f4520SKenneth D. Merry fprintf(stdout, "%5.1Lf%% ", cpu_percentage); 569130f4520SKenneth D. Merry 570130f4520SKenneth D. Merry for (i = 0; i < min(CTL_STAT_LUN_BITS, ctx->num_luns); i++) { 571130f4520SKenneth D. Merry long double mbsec, kb_per_transfer; 572130f4520SKenneth D. Merry long double transfers_per_sec; 573130f4520SKenneth D. Merry long double ms_per_transfer; 574130f4520SKenneth D. Merry long double ms_per_dma; 575130f4520SKenneth D. Merry long double dmas_per_sec; 576130f4520SKenneth D. Merry 577130f4520SKenneth D. Merry if (bit_test(ctx->lun_mask, 578130f4520SKenneth D. Merry (int)ctx->cur_lun_stats[i].lun_number) == 0) 579130f4520SKenneth D. Merry continue; 580130f4520SKenneth D. Merry compute_stats(&ctx->cur_lun_stats[i], F_FIRST(ctx) ? 581130f4520SKenneth D. Merry NULL : &ctx->prev_lun_stats[i], etime, 582130f4520SKenneth D. Merry &mbsec, &kb_per_transfer, 583130f4520SKenneth D. Merry &transfers_per_sec, &ms_per_transfer, 584130f4520SKenneth D. Merry &ms_per_dma, &dmas_per_sec); 585130f4520SKenneth D. Merry if (F_DMA(ctx)) 586130f4520SKenneth D. Merry fprintf(stdout, " %2.2Lf", 587130f4520SKenneth D. Merry ms_per_dma); 588130f4520SKenneth D. Merry else if (F_LUNVAL(ctx) != 0) 589130f4520SKenneth D. Merry fprintf(stdout, " %2.2Lf", 590130f4520SKenneth D. Merry ms_per_transfer); 591130f4520SKenneth D. Merry fprintf(stdout, " %5.2Lf %3.0Lf %5.2Lf ", 592130f4520SKenneth D. Merry kb_per_transfer, (F_DMA(ctx) == 0) ? 593130f4520SKenneth D. Merry transfers_per_sec : dmas_per_sec, mbsec); 594130f4520SKenneth D. Merry } 595130f4520SKenneth D. Merry } 596130f4520SKenneth D. Merry } 597130f4520SKenneth D. Merry 598130f4520SKenneth D. Merry int 599130f4520SKenneth D. Merry main(int argc, char **argv) 600130f4520SKenneth D. Merry { 601130f4520SKenneth D. Merry int c; 602130f4520SKenneth D. Merry int count, waittime; 603130f4520SKenneth D. Merry int set_lun; 604130f4520SKenneth D. Merry int fd, retval; 605130f4520SKenneth D. Merry struct ctlstat_context ctx; 606130f4520SKenneth D. Merry 607130f4520SKenneth D. Merry /* default values */ 608130f4520SKenneth D. Merry retval = 0; 609130f4520SKenneth D. Merry waittime = 1; 610130f4520SKenneth D. Merry count = -1; 611130f4520SKenneth D. Merry memset(&ctx, 0, sizeof(ctx)); 612130f4520SKenneth D. Merry ctx.numdevs = 3; 613130f4520SKenneth D. Merry ctx.mode = CTLSTAT_MODE_STANDARD; 614130f4520SKenneth D. Merry ctx.flags |= CTLSTAT_FLAG_CPU; 615130f4520SKenneth D. Merry ctx.flags |= CTLSTAT_FLAG_FIRST_RUN; 616130f4520SKenneth D. Merry ctx.flags |= CTLSTAT_FLAG_HEADER; 617130f4520SKenneth D. Merry 618130f4520SKenneth D. Merry while ((c = getopt(argc, argv, ctlstat_opts)) != -1) { 619130f4520SKenneth D. Merry switch (c) { 620130f4520SKenneth D. Merry case 'C': 621130f4520SKenneth D. Merry ctx.flags &= ~CTLSTAT_FLAG_CPU; 622130f4520SKenneth D. Merry break; 623130f4520SKenneth D. Merry case 'c': 624130f4520SKenneth D. Merry count = atoi(optarg); 625130f4520SKenneth D. Merry break; 626130f4520SKenneth D. Merry case 'd': 627130f4520SKenneth D. Merry ctx.flags |= CTLSTAT_FLAG_DMA_TIME; 628130f4520SKenneth D. Merry break; 629130f4520SKenneth D. Merry case 'D': 630130f4520SKenneth D. Merry ctx.mode = CTLSTAT_MODE_DUMP; 631130f4520SKenneth D. Merry waittime = 30; 632130f4520SKenneth D. Merry break; 633130f4520SKenneth D. Merry case 'h': 634130f4520SKenneth D. Merry ctx.flags &= ~CTLSTAT_FLAG_HEADER; 635130f4520SKenneth D. Merry break; 636130f4520SKenneth D. Merry case 'j': 637130f4520SKenneth D. Merry ctx.mode = CTLSTAT_MODE_JSON; 638130f4520SKenneth D. Merry waittime = 30; 639130f4520SKenneth D. Merry break; 640130f4520SKenneth D. Merry case 'l': { 641130f4520SKenneth D. Merry int cur_lun; 642130f4520SKenneth D. Merry 643130f4520SKenneth D. Merry cur_lun = atoi(optarg); 644130f4520SKenneth D. Merry if (cur_lun > CTL_STAT_LUN_BITS) 645130f4520SKenneth D. Merry errx(1, "Invalid LUN number %d", cur_lun); 646130f4520SKenneth D. Merry 647130f4520SKenneth D. Merry bit_ffs(ctx.lun_mask, CTL_STAT_LUN_BITS, &set_lun); 648130f4520SKenneth D. Merry if (set_lun == -1) 649130f4520SKenneth D. Merry ctx.numdevs = 1; 650130f4520SKenneth D. Merry else 651130f4520SKenneth D. Merry ctx.numdevs++; 652130f4520SKenneth D. Merry bit_set(ctx.lun_mask, cur_lun); 653130f4520SKenneth D. Merry break; 654130f4520SKenneth D. Merry } 655130f4520SKenneth D. Merry case 'n': 656130f4520SKenneth D. Merry ctx.numdevs = atoi(optarg); 657130f4520SKenneth D. Merry break; 658130f4520SKenneth D. Merry case 't': 659130f4520SKenneth D. Merry ctx.flags |= CTLSTAT_FLAG_TOTALS; 660130f4520SKenneth D. Merry ctx.numdevs = 3; 661130f4520SKenneth D. Merry break; 662130f4520SKenneth D. Merry case 'w': 663130f4520SKenneth D. Merry waittime = atoi(optarg); 664130f4520SKenneth D. Merry break; 665130f4520SKenneth D. Merry default: 666130f4520SKenneth D. Merry retval = 1; 667130f4520SKenneth D. Merry usage(retval); 668130f4520SKenneth D. Merry exit(retval); 669130f4520SKenneth D. Merry break; 670130f4520SKenneth D. Merry } 671130f4520SKenneth D. Merry } 672130f4520SKenneth D. Merry 673130f4520SKenneth D. Merry bit_ffs(ctx.lun_mask, CTL_STAT_LUN_BITS, &set_lun); 674130f4520SKenneth D. Merry 675130f4520SKenneth D. Merry if ((F_TOTALS(&ctx)) 676130f4520SKenneth D. Merry && (set_lun != -1)) { 677130f4520SKenneth D. Merry errx(1, "Total Mode (-t) is incompatible with individual " 678130f4520SKenneth D. Merry "LUN mode (-l)"); 679130f4520SKenneth D. Merry } else if (set_lun == -1) { 680130f4520SKenneth D. Merry /* 681130f4520SKenneth D. Merry * Note that this just selects the first N LUNs to display, 682130f4520SKenneth D. Merry * but at this point we have no knoweledge of which LUN 683130f4520SKenneth D. Merry * numbers actually exist. So we may select LUNs that 684130f4520SKenneth D. Merry * aren't there. 685130f4520SKenneth D. Merry */ 686130f4520SKenneth D. Merry bit_nset(ctx.lun_mask, 0, min(ctx.numdevs - 1, 687130f4520SKenneth D. Merry CTL_STAT_LUN_BITS - 1)); 688130f4520SKenneth D. Merry } 689130f4520SKenneth D. Merry 690130f4520SKenneth D. Merry if ((fd = open(CTL_DEFAULT_DEV, O_RDWR)) == -1) 691130f4520SKenneth D. Merry err(1, "cannot open %s", CTL_DEFAULT_DEV); 692130f4520SKenneth D. Merry 693130f4520SKenneth D. Merry for (;count != 0;) { 694130f4520SKenneth D. Merry ctx.tmp_lun_stats = ctx.prev_lun_stats; 695130f4520SKenneth D. Merry ctx.prev_lun_stats = ctx.cur_lun_stats; 696130f4520SKenneth D. Merry ctx.cur_lun_stats = ctx.tmp_lun_stats; 697130f4520SKenneth D. Merry ctx.prev_time = ctx.cur_time; 698130f4520SKenneth D. Merry ctx.prev_cpu = ctx.cur_cpu; 699130f4520SKenneth D. Merry if (getstats(fd, &ctx.num_luns, &ctx.cur_lun_stats, 700130f4520SKenneth D. Merry &ctx.cur_time, &ctx.flags) != 0) 701130f4520SKenneth D. Merry errx(1, "error returned from getstats()"); 702130f4520SKenneth D. Merry 703130f4520SKenneth D. Merry switch(ctx.mode) { 704130f4520SKenneth D. Merry case CTLSTAT_MODE_STANDARD: 705130f4520SKenneth D. Merry ctlstat_standard(&ctx); 706130f4520SKenneth D. Merry break; 707130f4520SKenneth D. Merry case CTLSTAT_MODE_DUMP: 708130f4520SKenneth D. Merry ctlstat_dump(&ctx); 709130f4520SKenneth D. Merry break; 710130f4520SKenneth D. Merry case CTLSTAT_MODE_JSON: 711130f4520SKenneth D. Merry ctlstat_json(&ctx); 712130f4520SKenneth D. Merry break; 713130f4520SKenneth D. Merry default: 714130f4520SKenneth D. Merry break; 715130f4520SKenneth D. Merry } 716130f4520SKenneth D. Merry 717130f4520SKenneth D. Merry fprintf(stdout, "\n"); 718130f4520SKenneth D. Merry ctx.flags &= ~CTLSTAT_FLAG_FIRST_RUN; 719130f4520SKenneth D. Merry if (count != 1) 720130f4520SKenneth D. Merry sleep(waittime); 721130f4520SKenneth D. Merry if (count > 0) 722130f4520SKenneth D. Merry count--; 723130f4520SKenneth D. Merry } 724130f4520SKenneth D. Merry 725130f4520SKenneth D. Merry exit (retval); 726130f4520SKenneth D. Merry } 727130f4520SKenneth D. Merry 728130f4520SKenneth D. Merry /* 729130f4520SKenneth D. Merry * vim: ts=8 730130f4520SKenneth D. Merry */ 731