xref: /freebsd/usr.bin/ctlstat/ctlstat.c (revision 5be4479bfd0e0d494a58902c5fd47d1b54a8e50f)
1130f4520SKenneth D. Merry /*-
2130f4520SKenneth D. Merry  * Copyright (c) 2004, 2008, 2009 Silicon Graphics International Corp.
3bb8f9017SAlexander Motin  * Copyright (c) 2017 Alexander Motin <mav@FreeBSD.org>
4130f4520SKenneth D. Merry  * All rights reserved.
5130f4520SKenneth D. Merry  *
6130f4520SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
7130f4520SKenneth D. Merry  * modification, are permitted provided that the following conditions
8130f4520SKenneth D. Merry  * are met:
9130f4520SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
10130f4520SKenneth D. Merry  *    notice, this list of conditions, and the following disclaimer,
11130f4520SKenneth D. Merry  *    without modification.
12130f4520SKenneth D. Merry  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
13130f4520SKenneth D. Merry  *    substantially similar to the "NO WARRANTY" disclaimer below
14130f4520SKenneth D. Merry  *    ("Disclaimer") and any redistribution must be conditioned upon
15130f4520SKenneth D. Merry  *    including a substantially similar Disclaimer requirement for further
16130f4520SKenneth D. Merry  *    binary redistribution.
17130f4520SKenneth D. Merry  *
18130f4520SKenneth D. Merry  * NO WARRANTY
19130f4520SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20130f4520SKenneth D. Merry  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21130f4520SKenneth D. Merry  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
22130f4520SKenneth D. Merry  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23130f4520SKenneth D. Merry  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24130f4520SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25130f4520SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26130f4520SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27130f4520SKenneth D. Merry  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28130f4520SKenneth D. Merry  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29130f4520SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGES.
30130f4520SKenneth D. Merry  *
31130f4520SKenneth D. Merry  * $Id: //depot/users/kenm/FreeBSD-test2/usr.bin/ctlstat/ctlstat.c#4 $
32130f4520SKenneth D. Merry  */
33130f4520SKenneth D. Merry /*
34130f4520SKenneth D. Merry  * CAM Target Layer statistics program
35130f4520SKenneth D. Merry  *
36130f4520SKenneth D. Merry  * Authors: Ken Merry <ken@FreeBSD.org>, Will Andrews <will@FreeBSD.org>
37130f4520SKenneth D. Merry  */
38130f4520SKenneth D. Merry 
39130f4520SKenneth D. Merry #include <sys/cdefs.h>
40130f4520SKenneth D. Merry __FBSDID("$FreeBSD$");
41130f4520SKenneth D. Merry 
42130f4520SKenneth D. Merry #include <sys/ioctl.h>
43130f4520SKenneth D. Merry #include <sys/types.h>
44130f4520SKenneth D. Merry #include <sys/param.h>
45130f4520SKenneth D. Merry #include <sys/time.h>
46130f4520SKenneth D. Merry #include <sys/sysctl.h>
47130f4520SKenneth D. Merry #include <sys/resource.h>
48130f4520SKenneth D. Merry #include <sys/queue.h>
49130f4520SKenneth D. Merry #include <sys/callout.h>
50130f4520SKenneth D. Merry #include <stdint.h>
51130f4520SKenneth D. Merry #include <stdio.h>
52130f4520SKenneth D. Merry #include <stdlib.h>
53130f4520SKenneth D. Merry #include <unistd.h>
54130f4520SKenneth D. Merry #include <fcntl.h>
55130f4520SKenneth D. Merry #include <getopt.h>
56130f4520SKenneth D. Merry #include <string.h>
57130f4520SKenneth D. Merry #include <errno.h>
58130f4520SKenneth D. Merry #include <err.h>
59130f4520SKenneth D. Merry #include <ctype.h>
60130f4520SKenneth D. Merry #include <bitstring.h>
61130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h>
62130f4520SKenneth D. Merry #include <cam/ctl/ctl.h>
63130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h>
64130f4520SKenneth D. Merry #include <cam/ctl/ctl_scsi_all.h>
65130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.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 /*
70bb8f9017SAlexander Motin  * The default amount of space we allocate for stats storage space.
71bb8f9017SAlexander Motin  * We dynamically allocate more if needed.
72130f4520SKenneth D. Merry  */
73bb8f9017SAlexander Motin #define	CTL_STAT_NUM_ITEMS	256
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  */
80bb8f9017SAlexander Motin #define	CTL_STAT_BITS		1024L
81130f4520SKenneth D. Merry 
8261639a0aSAlexander Motin static const char *ctlstat_opts = "Cc:Ddhjl:n:p: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)
105bb8f9017SAlexander Motin #define	CTLSTAT_FLAG_TIME_VALID		(1 << 5)
106bb8f9017SAlexander Motin #define	CTLSTAT_FLAG_MASK		(1 << 6)
107bb8f9017SAlexander Motin #define	CTLSTAT_FLAG_LUNS		(1 << 7)
108bb8f9017SAlexander Motin #define	CTLSTAT_FLAG_PORTS		(1 << 8)
109130f4520SKenneth D. Merry #define	F_CPU(ctx) ((ctx)->flags & CTLSTAT_FLAG_CPU)
110130f4520SKenneth D. Merry #define	F_HDR(ctx) ((ctx)->flags & CTLSTAT_FLAG_HEADER)
111130f4520SKenneth D. Merry #define	F_FIRST(ctx) ((ctx)->flags & CTLSTAT_FLAG_FIRST_RUN)
112130f4520SKenneth D. Merry #define	F_TOTALS(ctx) ((ctx)->flags & CTLSTAT_FLAG_TOTALS)
113130f4520SKenneth D. Merry #define	F_DMA(ctx) ((ctx)->flags & CTLSTAT_FLAG_DMA_TIME)
114bb8f9017SAlexander Motin #define	F_TIMEVAL(ctx) ((ctx)->flags & CTLSTAT_FLAG_TIME_VALID)
115bb8f9017SAlexander Motin #define	F_MASK(ctx) ((ctx)->flags & CTLSTAT_FLAG_MASK)
116bb8f9017SAlexander Motin #define	F_LUNS(ctx) ((ctx)->flags & CTLSTAT_FLAG_LUNS)
117bb8f9017SAlexander Motin #define	F_PORTS(ctx) ((ctx)->flags & CTLSTAT_FLAG_PORTS)
118130f4520SKenneth D. Merry 
119130f4520SKenneth D. Merry struct ctlstat_context {
120130f4520SKenneth D. Merry 	ctlstat_mode_types mode;
121130f4520SKenneth D. Merry 	int flags;
122bb8f9017SAlexander Motin 	struct ctl_io_stats *cur_stats, *prev_stats;
123bb8f9017SAlexander Motin 	struct ctl_io_stats cur_total_stats[3], prev_total_stats[3];
124130f4520SKenneth D. Merry 	struct timespec cur_time, prev_time;
125130f4520SKenneth D. Merry 	struct ctl_cpu_stats cur_cpu, prev_cpu;
126130f4520SKenneth D. Merry 	uint64_t cur_total_jiffies, prev_total_jiffies;
127130f4520SKenneth D. Merry 	uint64_t cur_idle, prev_idle;
128bb8f9017SAlexander Motin 	bitstr_t bit_decl(item_mask, CTL_STAT_BITS);
129bb8f9017SAlexander Motin 	int cur_items, prev_items;
130bb8f9017SAlexander Motin 	int cur_alloc, prev_alloc;
131130f4520SKenneth D. Merry 	int numdevs;
132130f4520SKenneth D. Merry 	int header_interval;
133130f4520SKenneth D. Merry };
134130f4520SKenneth D. Merry 
135130f4520SKenneth D. Merry #ifndef min
136130f4520SKenneth D. Merry #define	min(x,y)	(((x) < (y)) ? (x) : (y))
137130f4520SKenneth D. Merry #endif
138130f4520SKenneth D. Merry 
139130f4520SKenneth D. Merry static void usage(int error);
140bb8f9017SAlexander Motin static int getstats(int fd, int *alloc_items, int *num_items,
141bb8f9017SAlexander Motin     struct ctl_io_stats **xstats, struct timespec *cur_time, int *time_valid);
142130f4520SKenneth D. Merry static int getcpu(struct ctl_cpu_stats *cpu_stats);
143bb8f9017SAlexander Motin static void compute_stats(struct ctl_io_stats *cur_stats,
144bb8f9017SAlexander Motin 			  struct ctl_io_stats *prev_stats,
145130f4520SKenneth D. Merry 			  long double etime, long double *mbsec,
146130f4520SKenneth D. Merry 			  long double *kb_per_transfer,
147130f4520SKenneth D. Merry 			  long double *transfers_per_second,
148130f4520SKenneth D. Merry 			  long double *ms_per_transfer,
149130f4520SKenneth D. Merry 			  long double *ms_per_dma,
150130f4520SKenneth D. Merry 			  long double *dmas_per_second);
151130f4520SKenneth D. Merry 
152130f4520SKenneth D. Merry static void
153130f4520SKenneth D. Merry usage(int error)
154130f4520SKenneth D. Merry {
15533d35bebSKenneth D. Merry 	fputs(ctlstat_usage, error ? stderr : stdout);
156130f4520SKenneth D. Merry }
157130f4520SKenneth D. Merry 
158130f4520SKenneth D. Merry static int
159bb8f9017SAlexander Motin getstats(int fd, int *alloc_items, int *num_items, struct ctl_io_stats **stats,
160130f4520SKenneth D. Merry 	 struct timespec *cur_time, int *flags)
161130f4520SKenneth D. Merry {
162bb8f9017SAlexander Motin 	struct ctl_get_io_stats get_stats;
163bb8f9017SAlexander Motin 	int more_space_count = 0;
164130f4520SKenneth D. Merry 
165bb8f9017SAlexander Motin 	if (*alloc_items == 0)
166bb8f9017SAlexander Motin 		*alloc_items = CTL_STAT_NUM_ITEMS;
167130f4520SKenneth D. Merry retry:
168bb8f9017SAlexander Motin 	if (*stats == NULL)
169bb8f9017SAlexander Motin 		*stats = malloc(sizeof(**stats) * *alloc_items);
170130f4520SKenneth D. Merry 
171bb8f9017SAlexander Motin 	memset(&get_stats, 0, sizeof(get_stats));
172bb8f9017SAlexander Motin 	get_stats.alloc_len = *alloc_items * sizeof(**stats);
173bb8f9017SAlexander Motin 	memset(*stats, 0, get_stats.alloc_len);
174bb8f9017SAlexander Motin 	get_stats.stats = *stats;
175130f4520SKenneth D. Merry 
176bb8f9017SAlexander Motin 	if (ioctl(fd, (*flags & CTLSTAT_FLAG_PORTS) ? CTL_GET_PORT_STATS :
177bb8f9017SAlexander Motin 	    CTL_GET_LUN_STATS, &get_stats) == -1)
178bb8f9017SAlexander Motin 		err(1, "CTL_GET_*_STATS ioctl returned error");
179130f4520SKenneth D. Merry 
180bb8f9017SAlexander Motin 	switch (get_stats.status) {
181130f4520SKenneth D. Merry 	case CTL_SS_OK:
182130f4520SKenneth D. Merry 		break;
183130f4520SKenneth D. Merry 	case CTL_SS_ERROR:
184bb8f9017SAlexander Motin 		err(1, "CTL_GET_*_STATS ioctl returned CTL_SS_ERROR");
185130f4520SKenneth D. Merry 		break;
186130f4520SKenneth D. Merry 	case CTL_SS_NEED_MORE_SPACE:
187bb8f9017SAlexander Motin 		if (more_space_count >= 2)
188bb8f9017SAlexander Motin 			errx(1, "CTL_GET_*_STATS returned NEED_MORE_SPACE again");
189bb8f9017SAlexander Motin 		*alloc_items = get_stats.num_items * 5 / 4;
190bb8f9017SAlexander Motin 		free(*stats);
191bb8f9017SAlexander Motin 		*stats = NULL;
192130f4520SKenneth D. Merry 		more_space_count++;
193130f4520SKenneth D. Merry 		goto retry;
194130f4520SKenneth D. Merry 		break; /* NOTREACHED */
195130f4520SKenneth D. Merry 	default:
196bb8f9017SAlexander Motin 		errx(1, "CTL_GET_*_STATS ioctl returned unknown status %d",
197bb8f9017SAlexander Motin 		     get_stats.status);
198130f4520SKenneth D. Merry 		break;
199130f4520SKenneth D. Merry 	}
200130f4520SKenneth D. Merry 
201bb8f9017SAlexander Motin 	*num_items = get_stats.fill_len / sizeof(**stats);
202bb8f9017SAlexander Motin 	cur_time->tv_sec = get_stats.timestamp.tv_sec;
203bb8f9017SAlexander Motin 	cur_time->tv_nsec = get_stats.timestamp.tv_nsec;
204bb8f9017SAlexander Motin 	if (get_stats.flags & CTL_STATS_FLAG_TIME_VALID)
205bb8f9017SAlexander Motin 		*flags |= CTLSTAT_FLAG_TIME_VALID;
206130f4520SKenneth D. Merry 	else
207bb8f9017SAlexander Motin 		*flags &= ~CTLSTAT_FLAG_TIME_VALID;
208130f4520SKenneth D. Merry 
209130f4520SKenneth D. Merry 	return (0);
210130f4520SKenneth D. Merry }
211130f4520SKenneth D. Merry 
212130f4520SKenneth D. Merry static int
213130f4520SKenneth D. Merry getcpu(struct ctl_cpu_stats *cpu_stats)
214130f4520SKenneth D. Merry {
215130f4520SKenneth D. Merry 	long cp_time[CPUSTATES];
216130f4520SKenneth D. Merry 	size_t cplen;
217130f4520SKenneth D. Merry 
218130f4520SKenneth D. Merry 	cplen = sizeof(cp_time);
219130f4520SKenneth D. Merry 
220130f4520SKenneth D. Merry 	if (sysctlbyname("kern.cp_time", &cp_time, &cplen, NULL, 0) == -1) {
221130f4520SKenneth D. Merry 		warn("sysctlbyname(kern.cp_time...) failed");
222130f4520SKenneth D. Merry 		return (1);
223130f4520SKenneth D. Merry 	}
224130f4520SKenneth D. Merry 
225130f4520SKenneth D. Merry 	cpu_stats->user = cp_time[CP_USER];
226130f4520SKenneth D. Merry 	cpu_stats->nice = cp_time[CP_NICE];
227130f4520SKenneth D. Merry 	cpu_stats->system = cp_time[CP_SYS];
228130f4520SKenneth D. Merry 	cpu_stats->intr = cp_time[CP_INTR];
229130f4520SKenneth D. Merry 	cpu_stats->idle = cp_time[CP_IDLE];
230130f4520SKenneth D. Merry 
231130f4520SKenneth D. Merry 	return (0);
232130f4520SKenneth D. Merry }
233130f4520SKenneth D. Merry 
234130f4520SKenneth D. Merry static void
235bb8f9017SAlexander Motin compute_stats(struct ctl_io_stats *cur_stats,
236bb8f9017SAlexander Motin 	      struct ctl_io_stats *prev_stats, long double etime,
237130f4520SKenneth D. Merry 	      long double *mbsec, long double *kb_per_transfer,
238130f4520SKenneth D. Merry 	      long double *transfers_per_second, long double *ms_per_transfer,
239130f4520SKenneth D. Merry 	      long double *ms_per_dma, long double *dmas_per_second)
240130f4520SKenneth D. Merry {
241130f4520SKenneth D. Merry 	uint64_t total_bytes = 0, total_operations = 0, total_dmas = 0;
242130f4520SKenneth D. Merry 	struct bintime total_time_bt, total_dma_bt;
243130f4520SKenneth D. Merry 	struct timespec total_time_ts, total_dma_ts;
244130f4520SKenneth D. Merry 	int i;
245130f4520SKenneth D. Merry 
246130f4520SKenneth D. Merry 	bzero(&total_time_bt, sizeof(total_time_bt));
247130f4520SKenneth D. Merry 	bzero(&total_dma_bt, sizeof(total_dma_bt));
248130f4520SKenneth D. Merry 	bzero(&total_time_ts, sizeof(total_time_ts));
249130f4520SKenneth D. Merry 	bzero(&total_dma_ts, sizeof(total_dma_ts));
250130f4520SKenneth D. Merry 	for (i = 0; i < CTL_STATS_NUM_TYPES; i++) {
251bb8f9017SAlexander Motin 		total_bytes += cur_stats->bytes[i];
252bb8f9017SAlexander Motin 		total_operations += cur_stats->operations[i];
253bb8f9017SAlexander Motin 		total_dmas += cur_stats->dmas[i];
254bb8f9017SAlexander Motin 		bintime_add(&total_time_bt, &cur_stats->time[i]);
255bb8f9017SAlexander Motin 		bintime_add(&total_dma_bt, &cur_stats->dma_time[i]);
256130f4520SKenneth D. Merry 		if (prev_stats != NULL) {
257bb8f9017SAlexander Motin 			total_bytes -= prev_stats->bytes[i];
258bb8f9017SAlexander Motin 			total_operations -= prev_stats->operations[i];
259bb8f9017SAlexander Motin 			total_dmas -= prev_stats->dmas[i];
260bb8f9017SAlexander Motin 			bintime_sub(&total_time_bt, &prev_stats->time[i]);
261bb8f9017SAlexander Motin 			bintime_sub(&total_dma_bt, &prev_stats->dma_time[i]);
262130f4520SKenneth D. Merry 		}
263130f4520SKenneth D. Merry 	}
264130f4520SKenneth D. Merry 
265130f4520SKenneth D. Merry 	*mbsec = total_bytes;
266130f4520SKenneth D. Merry 	*mbsec /= 1024 * 1024;
267130f4520SKenneth D. Merry 	if (etime > 0.0)
268130f4520SKenneth D. Merry 		*mbsec /= etime;
269130f4520SKenneth D. Merry 	else
270130f4520SKenneth D. Merry 		*mbsec = 0;
271130f4520SKenneth D. Merry 	*kb_per_transfer = total_bytes;
272130f4520SKenneth D. Merry 	*kb_per_transfer /= 1024;
273130f4520SKenneth D. Merry 	if (total_operations > 0)
274130f4520SKenneth D. Merry 		*kb_per_transfer /= total_operations;
275130f4520SKenneth D. Merry 	else
276130f4520SKenneth D. Merry 		*kb_per_transfer = 0;
277130f4520SKenneth D. Merry 	*transfers_per_second = total_operations;
278130f4520SKenneth D. Merry 	*dmas_per_second = total_dmas;
279130f4520SKenneth D. Merry 	if (etime > 0.0) {
280130f4520SKenneth D. Merry 		*transfers_per_second /= etime;
281130f4520SKenneth D. Merry 		*dmas_per_second /= etime;
282130f4520SKenneth D. Merry 	} else {
283130f4520SKenneth D. Merry 		*transfers_per_second = 0;
284130f4520SKenneth D. Merry 		*dmas_per_second = 0;
285130f4520SKenneth D. Merry 	}
286130f4520SKenneth D. Merry 
287130f4520SKenneth D. Merry 	bintime2timespec(&total_time_bt, &total_time_ts);
288130f4520SKenneth D. Merry 	bintime2timespec(&total_dma_bt, &total_dma_ts);
289130f4520SKenneth D. Merry 	if (total_operations > 0) {
290130f4520SKenneth D. Merry 		/*
291130f4520SKenneth D. Merry 		 * Convert the timespec to milliseconds.
292130f4520SKenneth D. Merry 		 */
293130f4520SKenneth D. Merry 		*ms_per_transfer = total_time_ts.tv_sec * 1000;
294130f4520SKenneth D. Merry 		*ms_per_transfer += total_time_ts.tv_nsec / 1000000;
295130f4520SKenneth D. Merry 		*ms_per_transfer /= total_operations;
296130f4520SKenneth D. Merry 	} else
297130f4520SKenneth D. Merry 		*ms_per_transfer = 0;
298130f4520SKenneth D. Merry 
299130f4520SKenneth D. Merry 	if (total_dmas > 0) {
300130f4520SKenneth D. Merry 		/*
301130f4520SKenneth D. Merry 		 * Convert the timespec to milliseconds.
302130f4520SKenneth D. Merry 		 */
303130f4520SKenneth D. Merry 		*ms_per_dma = total_dma_ts.tv_sec * 1000;
304130f4520SKenneth D. Merry 		*ms_per_dma += total_dma_ts.tv_nsec / 1000000;
305130f4520SKenneth D. Merry 		*ms_per_dma /= total_dmas;
306130f4520SKenneth D. Merry 	} else
307130f4520SKenneth D. Merry 		*ms_per_dma = 0;
308130f4520SKenneth D. Merry }
309130f4520SKenneth D. Merry 
310130f4520SKenneth D. Merry /* The dump_stats() and json_stats() functions perform essentially the same
311130f4520SKenneth D. Merry  * purpose, but dump the statistics in different formats.  JSON is more
312130f4520SKenneth D. Merry  * conducive to programming, however.
313130f4520SKenneth D. Merry  */
314130f4520SKenneth D. Merry 
315924233ebSAlexander Motin #define	PRINT_BINTIME(bt) \
316924233ebSAlexander Motin 	printf("%jd.%06ju", (intmax_t)(bt).sec, \
3172eb293b9SAlexander Motin 	       (uintmax_t)(((bt).frac >> 32) * 1000000 >> 32))
318bf70beceSEd Schouten static const char *iotypes[] = {"NO IO", "READ", "WRITE"};
319130f4520SKenneth D. Merry 
320130f4520SKenneth D. Merry static void
321bb8f9017SAlexander Motin ctlstat_dump(struct ctlstat_context *ctx)
322bb8f9017SAlexander Motin {
323*5be4479bSAlexander Motin 	int iotype, i, n;
324bb8f9017SAlexander Motin 	struct ctl_io_stats *stats = ctx->cur_stats;
325130f4520SKenneth D. Merry 
326*5be4479bSAlexander Motin 	for (i = n = 0; i < ctx->cur_items;i++) {
327*5be4479bSAlexander Motin 		if (F_MASK(ctx) && bit_test(ctx->item_mask,
328*5be4479bSAlexander Motin 		    (int)stats[i].item) == 0)
32961639a0aSAlexander Motin 			continue;
330bb8f9017SAlexander Motin 		printf("%s %d\n", F_PORTS(ctx) ? "port" : "lun", stats[i].item);
331bb8f9017SAlexander Motin 		for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; iotype++) {
332bb8f9017SAlexander Motin 			printf("  io type %d (%s)\n", iotype, iotypes[iotype]);
333130f4520SKenneth D. Merry 			printf("   bytes %ju\n", (uintmax_t)
334bb8f9017SAlexander Motin 			    stats[i].bytes[iotype]);
335130f4520SKenneth D. Merry 			printf("   operations %ju\n", (uintmax_t)
336bb8f9017SAlexander Motin 			    stats[i].operations[iotype]);
337bb8f9017SAlexander Motin 			printf("   dmas %ju\n", (uintmax_t)
338bb8f9017SAlexander Motin 			    stats[i].dmas[iotype]);
339924233ebSAlexander Motin 			printf("   io time ");
340924233ebSAlexander Motin 			PRINT_BINTIME(stats[i].time[iotype]);
341924233ebSAlexander Motin 			printf("\n   dma time ");
342924233ebSAlexander Motin 			PRINT_BINTIME(stats[i].dma_time[iotype]);
343924233ebSAlexander Motin 			printf("\n");
344130f4520SKenneth D. Merry 		}
345*5be4479bSAlexander Motin 		if (++n >= ctx->numdevs)
346*5be4479bSAlexander Motin 			break;
347130f4520SKenneth D. Merry 	}
348130f4520SKenneth D. Merry }
349130f4520SKenneth D. Merry 
350130f4520SKenneth D. Merry static void
351130f4520SKenneth D. Merry ctlstat_json(struct ctlstat_context *ctx) {
352*5be4479bSAlexander Motin 	int iotype, i, n;
353bb8f9017SAlexander Motin 	struct ctl_io_stats *stats = ctx->cur_stats;
354130f4520SKenneth D. Merry 
355bb8f9017SAlexander Motin 	printf("{\"%s\":[", F_PORTS(ctx) ? "ports" : "luns");
356*5be4479bSAlexander Motin 	for (i = n = 0; i < ctx->cur_items; i++) {
357*5be4479bSAlexander Motin 		if (F_MASK(ctx) && bit_test(ctx->item_mask,
358*5be4479bSAlexander Motin 		    (int)stats[i].item) == 0)
35961639a0aSAlexander Motin 			continue;
360130f4520SKenneth D. Merry 		printf("{\"num\":%d,\"io\":[",
361bb8f9017SAlexander Motin 		    stats[i].item);
362bb8f9017SAlexander Motin 		for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; iotype++) {
363130f4520SKenneth D. Merry 			printf("{\"type\":\"%s\",", iotypes[iotype]);
364924233ebSAlexander Motin 			printf("\"bytes\":%ju,", (uintmax_t)
365924233ebSAlexander Motin 			    stats[i].bytes[iotype]);
366924233ebSAlexander Motin 			printf("\"operations\":%ju,", (uintmax_t)
367924233ebSAlexander Motin 			    stats[i].operations[iotype]);
368924233ebSAlexander Motin 			printf("\"dmas\":%ju,", (uintmax_t)
369bb8f9017SAlexander Motin 			    stats[i].dmas[iotype]);
370924233ebSAlexander Motin 			printf("\"io time\":");
371924233ebSAlexander Motin 			PRINT_BINTIME(stats[i].time[iotype]);
372924233ebSAlexander Motin 			printf(",\"dma time\":");
373924233ebSAlexander Motin 			PRINT_BINTIME(stats[i].dma_time[iotype]);
374924233ebSAlexander Motin 			printf("}");
375130f4520SKenneth D. Merry 			if (iotype < (CTL_STATS_NUM_TYPES - 1))
376130f4520SKenneth D. Merry 				printf(","); /* continue io array */
377130f4520SKenneth D. Merry 		}
378bb8f9017SAlexander Motin 		printf("]}");
379*5be4479bSAlexander Motin 		if (++n >= ctx->numdevs)
380*5be4479bSAlexander Motin 			break;
381bb8f9017SAlexander Motin 		if (i < (ctx->cur_items - 1))
382130f4520SKenneth D. Merry 			printf(","); /* continue lun array */
383130f4520SKenneth D. Merry 	}
384bb8f9017SAlexander Motin 	printf("]}");
385130f4520SKenneth D. Merry }
386130f4520SKenneth D. Merry 
387130f4520SKenneth D. Merry static void
388130f4520SKenneth D. Merry ctlstat_standard(struct ctlstat_context *ctx) {
3895e796316SKenneth D. Merry 	long double etime;
390130f4520SKenneth D. Merry 	uint64_t delta_jiffies, delta_idle;
391130f4520SKenneth D. Merry 	long double cpu_percentage;
392*5be4479bSAlexander Motin 	int i, j, n;
393130f4520SKenneth D. Merry 
394130f4520SKenneth D. Merry 	cpu_percentage = 0;
395130f4520SKenneth D. Merry 
396130f4520SKenneth D. Merry 	if (F_CPU(ctx) && (getcpu(&ctx->cur_cpu) != 0))
397130f4520SKenneth D. Merry 		errx(1, "error returned from getcpu()");
398130f4520SKenneth D. Merry 
3995e796316SKenneth D. Merry 	etime = ctx->cur_time.tv_sec - ctx->prev_time.tv_sec +
4005e796316SKenneth D. Merry 	    (ctx->prev_time.tv_nsec - ctx->cur_time.tv_nsec) * 1e-9;
401130f4520SKenneth D. Merry 
402130f4520SKenneth D. Merry 	if (F_CPU(ctx)) {
403130f4520SKenneth D. Merry 		ctx->prev_total_jiffies = ctx->cur_total_jiffies;
404130f4520SKenneth D. Merry 		ctx->cur_total_jiffies = ctx->cur_cpu.user +
405130f4520SKenneth D. Merry 		    ctx->cur_cpu.nice + ctx->cur_cpu.system +
406130f4520SKenneth D. Merry 		    ctx->cur_cpu.intr + ctx->cur_cpu.idle;
407130f4520SKenneth D. Merry 		delta_jiffies = ctx->cur_total_jiffies;
408130f4520SKenneth D. Merry 		if (F_FIRST(ctx) == 0)
409130f4520SKenneth D. Merry 			delta_jiffies -= ctx->prev_total_jiffies;
410130f4520SKenneth D. Merry 		ctx->prev_idle = ctx->cur_idle;
411130f4520SKenneth D. Merry 		ctx->cur_idle = ctx->cur_cpu.idle;
412130f4520SKenneth D. Merry 		delta_idle = ctx->cur_idle - ctx->prev_idle;
413130f4520SKenneth D. Merry 
414130f4520SKenneth D. Merry 		cpu_percentage = delta_jiffies - delta_idle;
415130f4520SKenneth D. Merry 		cpu_percentage /= delta_jiffies;
416130f4520SKenneth D. Merry 		cpu_percentage *= 100;
417130f4520SKenneth D. Merry 	}
418130f4520SKenneth D. Merry 
419130f4520SKenneth D. Merry 	if (F_HDR(ctx)) {
420130f4520SKenneth D. Merry 		ctx->header_interval--;
421130f4520SKenneth D. Merry 		if (ctx->header_interval <= 0) {
422130f4520SKenneth D. Merry 			if (F_CPU(ctx))
423130f4520SKenneth D. Merry 				fprintf(stdout, " CPU");
42461639a0aSAlexander Motin 			if (F_TOTALS(ctx)) {
42561639a0aSAlexander Motin 				fprintf(stdout, "%s     Read       %s"
42661639a0aSAlexander Motin 					"    Write       %s    Total\n",
427bb8f9017SAlexander Motin 					(F_TIMEVAL(ctx) != 0) ? "      " : "",
428bb8f9017SAlexander Motin 					(F_TIMEVAL(ctx) != 0) ? "      " : "",
429bb8f9017SAlexander Motin 					(F_TIMEVAL(ctx) != 0) ? "      " : "");
430*5be4479bSAlexander Motin 				n = 3;
43161639a0aSAlexander Motin 			} else {
432*5be4479bSAlexander Motin 				for (i = n = 0; i < min(CTL_STAT_BITS,
433bb8f9017SAlexander Motin 				     ctx->cur_items); i++) {
434bb8f9017SAlexander Motin 					int item;
435130f4520SKenneth D. Merry 
436130f4520SKenneth D. Merry 					/*
437130f4520SKenneth D. Merry 					 * Obviously this won't work with
438130f4520SKenneth D. Merry 					 * LUN numbers greater than a signed
439130f4520SKenneth D. Merry 					 * integer.
440130f4520SKenneth D. Merry 					 */
441bb8f9017SAlexander Motin 					item = (int)ctx->cur_stats[i].item;
442130f4520SKenneth D. Merry 
443bb8f9017SAlexander Motin 					if (F_MASK(ctx) &&
444bb8f9017SAlexander Motin 					    bit_test(ctx->item_mask, item) == 0)
445130f4520SKenneth D. Merry 						continue;
446d5a6319aSAlexander Motin 					fprintf(stdout, "%15.6s%d %s",
447bb8f9017SAlexander Motin 					    F_PORTS(ctx) ? "port" : "lun", item,
448bb8f9017SAlexander Motin 					    (F_TIMEVAL(ctx) != 0) ? "     " : "");
449*5be4479bSAlexander Motin 					if (++n >= ctx->numdevs)
450*5be4479bSAlexander Motin 						break;
451130f4520SKenneth D. Merry 				}
452130f4520SKenneth D. Merry 				fprintf(stdout, "\n");
453130f4520SKenneth D. Merry 			}
45461639a0aSAlexander Motin 			if (F_CPU(ctx))
45561639a0aSAlexander Motin 				fprintf(stdout, "    ");
456*5be4479bSAlexander Motin 			for (i = 0; i < n; i++)
45761639a0aSAlexander Motin 				fprintf(stdout, "%s KB/t   %s MB/s",
458bb8f9017SAlexander Motin 					(F_TIMEVAL(ctx) != 0) ? "    ms" : "",
459130f4520SKenneth D. Merry 					(F_DMA(ctx) == 0) ? "tps" : "dps");
460130f4520SKenneth D. Merry 			fprintf(stdout, "\n");
461130f4520SKenneth D. Merry 			ctx->header_interval = 20;
462130f4520SKenneth D. Merry 		}
463130f4520SKenneth D. Merry 	}
464130f4520SKenneth D. Merry 
46561639a0aSAlexander Motin 	if (F_CPU(ctx))
46661639a0aSAlexander Motin 		fprintf(stdout, "%3.0Lf%%", cpu_percentage);
467130f4520SKenneth D. Merry 	if (F_TOTALS(ctx) != 0) {
468130f4520SKenneth D. Merry 		long double mbsec[3];
469130f4520SKenneth D. Merry 		long double kb_per_transfer[3];
470130f4520SKenneth D. Merry 		long double transfers_per_sec[3];
471130f4520SKenneth D. Merry 		long double ms_per_transfer[3];
472130f4520SKenneth D. Merry 		long double ms_per_dma[3];
473130f4520SKenneth D. Merry 		long double dmas_per_sec[3];
474130f4520SKenneth D. Merry 
475130f4520SKenneth D. Merry 		for (i = 0; i < 3; i++)
476130f4520SKenneth D. Merry 			ctx->prev_total_stats[i] = ctx->cur_total_stats[i];
477130f4520SKenneth D. Merry 
478130f4520SKenneth D. Merry 		memset(&ctx->cur_total_stats, 0, sizeof(ctx->cur_total_stats));
479130f4520SKenneth D. Merry 
480130f4520SKenneth D. Merry 		/* Use macros to make the next loop more readable. */
481bb8f9017SAlexander Motin #define	ADD_STATS_BYTES(st, i, j) \
482bb8f9017SAlexander Motin 	ctx->cur_total_stats[st].bytes[j] += \
483bb8f9017SAlexander Motin 	    ctx->cur_stats[i].bytes[j]
484bb8f9017SAlexander Motin #define	ADD_STATS_OPERATIONS(st, i, j) \
485bb8f9017SAlexander Motin 	ctx->cur_total_stats[st].operations[j] += \
486bb8f9017SAlexander Motin 	    ctx->cur_stats[i].operations[j]
487bb8f9017SAlexander Motin #define	ADD_STATS_DMAS(st, i, j) \
488bb8f9017SAlexander Motin 	ctx->cur_total_stats[st].dmas[j] += \
489bb8f9017SAlexander Motin 	    ctx->cur_stats[i].dmas[j]
490bb8f9017SAlexander Motin #define	ADD_STATS_TIME(st, i, j) \
491bb8f9017SAlexander Motin 	bintime_add(&ctx->cur_total_stats[st].time[j], \
492bb8f9017SAlexander Motin 	    &ctx->cur_stats[i].time[j])
493bb8f9017SAlexander Motin #define	ADD_STATS_DMA_TIME(st, i, j) \
494bb8f9017SAlexander Motin 	bintime_add(&ctx->cur_total_stats[st].dma_time[j], \
495bb8f9017SAlexander Motin 	    &ctx->cur_stats[i].dma_time[j])
496130f4520SKenneth D. Merry 
497bb8f9017SAlexander Motin 		for (i = 0; i < ctx->cur_items; i++) {
498bb8f9017SAlexander Motin 			if (F_MASK(ctx) && bit_test(ctx->item_mask,
499bb8f9017SAlexander Motin 			    (int)ctx->cur_stats[i].item) == 0)
50061639a0aSAlexander Motin 				continue;
501130f4520SKenneth D. Merry 			for (j = 0; j < CTL_STATS_NUM_TYPES; j++) {
502bb8f9017SAlexander Motin 				ADD_STATS_BYTES(2, i, j);
503bb8f9017SAlexander Motin 				ADD_STATS_OPERATIONS(2, i, j);
504bb8f9017SAlexander Motin 				ADD_STATS_DMAS(2, i, j);
505bb8f9017SAlexander Motin 				ADD_STATS_TIME(2, i, j);
506bb8f9017SAlexander Motin 				ADD_STATS_DMA_TIME(2, i, j);
507130f4520SKenneth D. Merry 			}
508bb8f9017SAlexander Motin 			ADD_STATS_BYTES(0, i, CTL_STATS_READ);
509bb8f9017SAlexander Motin 			ADD_STATS_OPERATIONS(0, i, CTL_STATS_READ);
510bb8f9017SAlexander Motin 			ADD_STATS_DMAS(0, i, CTL_STATS_READ);
511bb8f9017SAlexander Motin 			ADD_STATS_TIME(0, i, CTL_STATS_READ);
512bb8f9017SAlexander Motin 			ADD_STATS_DMA_TIME(0, i, CTL_STATS_READ);
513130f4520SKenneth D. Merry 
514bb8f9017SAlexander Motin 			ADD_STATS_BYTES(1, i, CTL_STATS_WRITE);
515bb8f9017SAlexander Motin 			ADD_STATS_OPERATIONS(1, i, CTL_STATS_WRITE);
516bb8f9017SAlexander Motin 			ADD_STATS_DMAS(1, i, CTL_STATS_WRITE);
517bb8f9017SAlexander Motin 			ADD_STATS_TIME(1, i, CTL_STATS_WRITE);
518bb8f9017SAlexander Motin 			ADD_STATS_DMA_TIME(1, i, CTL_STATS_WRITE);
519130f4520SKenneth D. Merry 		}
520130f4520SKenneth D. Merry 
521130f4520SKenneth D. Merry 		for (i = 0; i < 3; i++) {
522bb8f9017SAlexander Motin 			compute_stats(&ctx->cur_total_stats[i],
523130f4520SKenneth D. Merry 				F_FIRST(ctx) ? NULL : &ctx->prev_total_stats[i],
524130f4520SKenneth D. Merry 				etime, &mbsec[i], &kb_per_transfer[i],
525130f4520SKenneth D. Merry 				&transfers_per_sec[i],
526130f4520SKenneth D. Merry 				&ms_per_transfer[i], &ms_per_dma[i],
527130f4520SKenneth D. Merry 				&dmas_per_sec[i]);
528130f4520SKenneth D. Merry 			if (F_DMA(ctx) != 0)
52961639a0aSAlexander Motin 				fprintf(stdout, " %5.1Lf",
530130f4520SKenneth D. Merry 					ms_per_dma[i]);
531bb8f9017SAlexander Motin 			else if (F_TIMEVAL(ctx) != 0)
53261639a0aSAlexander Motin 				fprintf(stdout, " %5.1Lf",
533130f4520SKenneth D. Merry 					ms_per_transfer[i]);
53461639a0aSAlexander Motin 			fprintf(stdout, " %4.0Lf %5.0Lf %4.0Lf",
535130f4520SKenneth D. Merry 				kb_per_transfer[i],
536130f4520SKenneth D. Merry 				(F_DMA(ctx) == 0) ? transfers_per_sec[i] :
537130f4520SKenneth D. Merry 				dmas_per_sec[i], mbsec[i]);
538130f4520SKenneth D. Merry 		}
539130f4520SKenneth D. Merry 	} else {
540*5be4479bSAlexander Motin 		for (i = n = 0; i < min(CTL_STAT_BITS, ctx->cur_items); i++) {
541130f4520SKenneth D. Merry 			long double mbsec, kb_per_transfer;
542130f4520SKenneth D. Merry 			long double transfers_per_sec;
543130f4520SKenneth D. Merry 			long double ms_per_transfer;
544130f4520SKenneth D. Merry 			long double ms_per_dma;
545130f4520SKenneth D. Merry 			long double dmas_per_sec;
546130f4520SKenneth D. Merry 
547bb8f9017SAlexander Motin 			if (F_MASK(ctx) && bit_test(ctx->item_mask,
548bb8f9017SAlexander Motin 			    (int)ctx->cur_stats[i].item) == 0)
549130f4520SKenneth D. Merry 				continue;
550bb8f9017SAlexander Motin 			for (j = 0; j < ctx->prev_items; j++) {
551bb8f9017SAlexander Motin 				if (ctx->prev_stats[j].item ==
552bb8f9017SAlexander Motin 				    ctx->cur_stats[i].item)
553bb8f9017SAlexander Motin 					break;
554bb8f9017SAlexander Motin 			}
555bb8f9017SAlexander Motin 			if (j >= ctx->prev_items)
556bb8f9017SAlexander Motin 				j = -1;
557bb8f9017SAlexander Motin 			compute_stats(&ctx->cur_stats[i],
558bb8f9017SAlexander Motin 			    j >= 0 ? &ctx->prev_stats[j] : NULL,
55961639a0aSAlexander Motin 			    etime, &mbsec, &kb_per_transfer,
560130f4520SKenneth D. Merry 			    &transfers_per_sec, &ms_per_transfer,
561130f4520SKenneth D. Merry 			    &ms_per_dma, &dmas_per_sec);
562130f4520SKenneth D. Merry 			if (F_DMA(ctx))
56361639a0aSAlexander Motin 				fprintf(stdout, " %5.1Lf",
564130f4520SKenneth D. Merry 					ms_per_dma);
565bb8f9017SAlexander Motin 			else if (F_TIMEVAL(ctx) != 0)
56661639a0aSAlexander Motin 				fprintf(stdout, " %5.1Lf",
567130f4520SKenneth D. Merry 					ms_per_transfer);
56861639a0aSAlexander Motin 			fprintf(stdout, " %4.0Lf %5.0Lf %4.0Lf",
569130f4520SKenneth D. Merry 				kb_per_transfer, (F_DMA(ctx) == 0) ?
570130f4520SKenneth D. Merry 				transfers_per_sec : dmas_per_sec, mbsec);
571*5be4479bSAlexander Motin 			if (++n >= ctx->numdevs)
572*5be4479bSAlexander Motin 				break;
573130f4520SKenneth D. Merry 		}
574130f4520SKenneth D. Merry 	}
575130f4520SKenneth D. Merry }
576130f4520SKenneth D. Merry 
577130f4520SKenneth D. Merry int
578130f4520SKenneth D. Merry main(int argc, char **argv)
579130f4520SKenneth D. Merry {
580130f4520SKenneth D. Merry 	int c;
581130f4520SKenneth D. Merry 	int count, waittime;
582130f4520SKenneth D. Merry 	int fd, retval;
583130f4520SKenneth D. Merry 	struct ctlstat_context ctx;
584bb8f9017SAlexander Motin 	struct ctl_io_stats *tmp_stats;
585130f4520SKenneth D. Merry 
586130f4520SKenneth D. Merry 	/* default values */
587130f4520SKenneth D. Merry 	retval = 0;
588130f4520SKenneth D. Merry 	waittime = 1;
589130f4520SKenneth D. Merry 	count = -1;
590130f4520SKenneth D. Merry 	memset(&ctx, 0, sizeof(ctx));
591130f4520SKenneth D. Merry 	ctx.numdevs = 3;
592130f4520SKenneth D. Merry 	ctx.mode = CTLSTAT_MODE_STANDARD;
593130f4520SKenneth D. Merry 	ctx.flags |= CTLSTAT_FLAG_CPU;
594130f4520SKenneth D. Merry 	ctx.flags |= CTLSTAT_FLAG_FIRST_RUN;
595130f4520SKenneth D. Merry 	ctx.flags |= CTLSTAT_FLAG_HEADER;
596130f4520SKenneth D. Merry 
597130f4520SKenneth D. Merry 	while ((c = getopt(argc, argv, ctlstat_opts)) != -1) {
598130f4520SKenneth D. Merry 		switch (c) {
599130f4520SKenneth D. Merry 		case 'C':
600130f4520SKenneth D. Merry 			ctx.flags &= ~CTLSTAT_FLAG_CPU;
601130f4520SKenneth D. Merry 			break;
602130f4520SKenneth D. Merry 		case 'c':
603130f4520SKenneth D. Merry 			count = atoi(optarg);
604130f4520SKenneth D. Merry 			break;
605130f4520SKenneth D. Merry 		case 'd':
606130f4520SKenneth D. Merry 			ctx.flags |= CTLSTAT_FLAG_DMA_TIME;
607130f4520SKenneth D. Merry 			break;
608130f4520SKenneth D. Merry 		case 'D':
609130f4520SKenneth D. Merry 			ctx.mode = CTLSTAT_MODE_DUMP;
610130f4520SKenneth D. Merry 			waittime = 30;
611130f4520SKenneth D. Merry 			break;
612130f4520SKenneth D. Merry 		case 'h':
613130f4520SKenneth D. Merry 			ctx.flags &= ~CTLSTAT_FLAG_HEADER;
614130f4520SKenneth D. Merry 			break;
615130f4520SKenneth D. Merry 		case 'j':
616130f4520SKenneth D. Merry 			ctx.mode = CTLSTAT_MODE_JSON;
617130f4520SKenneth D. Merry 			waittime = 30;
618130f4520SKenneth D. Merry 			break;
619130f4520SKenneth D. Merry 		case 'l': {
620130f4520SKenneth D. Merry 			int cur_lun;
621130f4520SKenneth D. Merry 
622130f4520SKenneth D. Merry 			cur_lun = atoi(optarg);
623bb8f9017SAlexander Motin 			if (cur_lun > CTL_STAT_BITS)
624130f4520SKenneth D. Merry 				errx(1, "Invalid LUN number %d", cur_lun);
625130f4520SKenneth D. Merry 
626bb8f9017SAlexander Motin 			if (!F_MASK(&ctx))
627130f4520SKenneth D. Merry 				ctx.numdevs = 1;
628130f4520SKenneth D. Merry 			else
629130f4520SKenneth D. Merry 				ctx.numdevs++;
630bb8f9017SAlexander Motin 			bit_set(ctx.item_mask, cur_lun);
631bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_MASK;
632bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_LUNS;
633130f4520SKenneth D. Merry 			break;
634130f4520SKenneth D. Merry 		}
635130f4520SKenneth D. Merry 		case 'n':
636130f4520SKenneth D. Merry 			ctx.numdevs = atoi(optarg);
637130f4520SKenneth D. Merry 			break;
63861639a0aSAlexander Motin 		case 'p': {
63961639a0aSAlexander Motin 			int cur_port;
64061639a0aSAlexander Motin 
64161639a0aSAlexander Motin 			cur_port = atoi(optarg);
642bb8f9017SAlexander Motin 			if (cur_port > CTL_STAT_BITS)
643bb8f9017SAlexander Motin 				errx(1, "Invalid port number %d", cur_port);
64461639a0aSAlexander Motin 
645bb8f9017SAlexander Motin 			if (!F_MASK(&ctx))
646bb8f9017SAlexander Motin 				ctx.numdevs = 1;
647bb8f9017SAlexander Motin 			else
648bb8f9017SAlexander Motin 				ctx.numdevs++;
649bb8f9017SAlexander Motin 			bit_set(ctx.item_mask, cur_port);
650bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_MASK;
651bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_PORTS;
65261639a0aSAlexander Motin 			break;
65361639a0aSAlexander Motin 		}
654130f4520SKenneth D. Merry 		case 't':
655130f4520SKenneth D. Merry 			ctx.flags |= CTLSTAT_FLAG_TOTALS;
656130f4520SKenneth D. Merry 			break;
657130f4520SKenneth D. Merry 		case 'w':
658130f4520SKenneth D. Merry 			waittime = atoi(optarg);
659130f4520SKenneth D. Merry 			break;
660130f4520SKenneth D. Merry 		default:
661130f4520SKenneth D. Merry 			retval = 1;
662130f4520SKenneth D. Merry 			usage(retval);
663130f4520SKenneth D. Merry 			exit(retval);
664130f4520SKenneth D. Merry 			break;
665130f4520SKenneth D. Merry 		}
666130f4520SKenneth D. Merry 	}
667130f4520SKenneth D. Merry 
668bb8f9017SAlexander Motin 	if (F_LUNS(&ctx) && F_PORTS(&ctx))
669bb8f9017SAlexander Motin 		errx(1, "Options -p and -l are exclusive.");
670bb8f9017SAlexander Motin 
671bb8f9017SAlexander Motin 	if (!F_LUNS(&ctx) && !F_PORTS(&ctx)) {
672bb8f9017SAlexander Motin 		if (F_TOTALS(&ctx))
673bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_PORTS;
674bb8f9017SAlexander Motin 		else
675bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_LUNS;
676bb8f9017SAlexander Motin 	}
677bb8f9017SAlexander Motin 
678130f4520SKenneth D. Merry 	if ((fd = open(CTL_DEFAULT_DEV, O_RDWR)) == -1)
679130f4520SKenneth D. Merry 		err(1, "cannot open %s", CTL_DEFAULT_DEV);
680130f4520SKenneth D. Merry 
681130f4520SKenneth D. Merry 	for (;count != 0;) {
682bb8f9017SAlexander Motin 		tmp_stats = ctx.prev_stats;
683bb8f9017SAlexander Motin 		ctx.prev_stats = ctx.cur_stats;
684bb8f9017SAlexander Motin 		ctx.cur_stats = tmp_stats;
685bb8f9017SAlexander Motin 		c = ctx.prev_alloc;
686bb8f9017SAlexander Motin 		ctx.prev_alloc = ctx.cur_alloc;
687bb8f9017SAlexander Motin 		ctx.cur_alloc = c;
688bb8f9017SAlexander Motin 		c = ctx.prev_items;
689bb8f9017SAlexander Motin 		ctx.prev_items = ctx.cur_items;
690bb8f9017SAlexander Motin 		ctx.cur_items = c;
691130f4520SKenneth D. Merry 		ctx.prev_time = ctx.cur_time;
692130f4520SKenneth D. Merry 		ctx.prev_cpu = ctx.cur_cpu;
693bb8f9017SAlexander Motin 		if (getstats(fd, &ctx.cur_alloc, &ctx.cur_items,
694bb8f9017SAlexander Motin 		    &ctx.cur_stats, &ctx.cur_time, &ctx.flags) != 0)
695130f4520SKenneth D. Merry 			errx(1, "error returned from getstats()");
696130f4520SKenneth D. Merry 
697130f4520SKenneth D. Merry 		switch(ctx.mode) {
698130f4520SKenneth D. Merry 		case CTLSTAT_MODE_STANDARD:
699130f4520SKenneth D. Merry 			ctlstat_standard(&ctx);
700130f4520SKenneth D. Merry 			break;
701130f4520SKenneth D. Merry 		case CTLSTAT_MODE_DUMP:
702130f4520SKenneth D. Merry 			ctlstat_dump(&ctx);
703130f4520SKenneth D. Merry 			break;
704130f4520SKenneth D. Merry 		case CTLSTAT_MODE_JSON:
705130f4520SKenneth D. Merry 			ctlstat_json(&ctx);
706130f4520SKenneth D. Merry 			break;
707130f4520SKenneth D. Merry 		default:
708130f4520SKenneth D. Merry 			break;
709130f4520SKenneth D. Merry 		}
710130f4520SKenneth D. Merry 
711130f4520SKenneth D. Merry 		fprintf(stdout, "\n");
712130f4520SKenneth D. Merry 		ctx.flags &= ~CTLSTAT_FLAG_FIRST_RUN;
713130f4520SKenneth D. Merry 		if (count != 1)
714130f4520SKenneth D. Merry 			sleep(waittime);
715130f4520SKenneth D. Merry 		if (count > 0)
716130f4520SKenneth D. Merry 			count--;
717130f4520SKenneth D. Merry 	}
718130f4520SKenneth D. Merry 
719130f4520SKenneth D. Merry 	exit (retval);
720130f4520SKenneth D. Merry }
721130f4520SKenneth D. Merry 
722130f4520SKenneth D. Merry /*
723130f4520SKenneth D. Merry  * vim: ts=8
724130f4520SKenneth D. Merry  */
725