xref: /freebsd/usr.bin/ctlstat/ctlstat.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
1130f4520SKenneth D. Merry /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4130f4520SKenneth D. Merry  * Copyright (c) 2004, 2008, 2009 Silicon Graphics International Corp.
5bb8f9017SAlexander Motin  * Copyright (c) 2017 Alexander Motin <mav@FreeBSD.org>
6130f4520SKenneth D. Merry  * All rights reserved.
7130f4520SKenneth D. Merry  *
8130f4520SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
9130f4520SKenneth D. Merry  * modification, are permitted provided that the following conditions
10130f4520SKenneth D. Merry  * are met:
11130f4520SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
12130f4520SKenneth D. Merry  *    notice, this list of conditions, and the following disclaimer,
13130f4520SKenneth D. Merry  *    without modification.
14130f4520SKenneth D. Merry  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
15130f4520SKenneth D. Merry  *    substantially similar to the "NO WARRANTY" disclaimer below
16130f4520SKenneth D. Merry  *    ("Disclaimer") and any redistribution must be conditioned upon
17130f4520SKenneth D. Merry  *    including a substantially similar Disclaimer requirement for further
18130f4520SKenneth D. Merry  *    binary redistribution.
19130f4520SKenneth D. Merry  *
20130f4520SKenneth D. Merry  * NO WARRANTY
21130f4520SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22130f4520SKenneth D. Merry  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23130f4520SKenneth D. Merry  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
24130f4520SKenneth D. Merry  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25130f4520SKenneth D. Merry  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26130f4520SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27130f4520SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28130f4520SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29130f4520SKenneth D. Merry  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30130f4520SKenneth D. Merry  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31130f4520SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGES.
32130f4520SKenneth D. Merry  *
33130f4520SKenneth D. Merry  * $Id: //depot/users/kenm/FreeBSD-test2/usr.bin/ctlstat/ctlstat.c#4 $
34130f4520SKenneth D. Merry  */
35130f4520SKenneth D. Merry /*
36130f4520SKenneth D. Merry  * CAM Target Layer statistics program
37130f4520SKenneth D. Merry  *
38130f4520SKenneth D. Merry  * Authors: Ken Merry <ken@FreeBSD.org>, Will Andrews <will@FreeBSD.org>
39130f4520SKenneth D. Merry  */
40130f4520SKenneth D. Merry 
41130f4520SKenneth D. Merry #include <sys/cdefs.h>
42130f4520SKenneth D. Merry __FBSDID("$FreeBSD$");
43130f4520SKenneth D. Merry 
44130f4520SKenneth D. Merry #include <sys/param.h>
45130f4520SKenneth D. Merry #include <sys/callout.h>
461a7f22d9SAlan Somers #include <sys/ioctl.h>
471a7f22d9SAlan Somers #include <sys/queue.h>
481a7f22d9SAlan Somers #include <sys/resource.h>
491a7f22d9SAlan Somers #include <sys/sbuf.h>
501a7f22d9SAlan Somers #include <sys/socket.h>
511a7f22d9SAlan Somers #include <sys/sysctl.h>
521a7f22d9SAlan Somers #include <sys/time.h>
534c163a54SAlan Somers #include <assert.h>
541a7f22d9SAlan Somers #include <bsdxml.h>
551a7f22d9SAlan Somers #include <malloc_np.h>
56130f4520SKenneth D. Merry #include <stdint.h>
57130f4520SKenneth D. Merry #include <stdio.h>
58130f4520SKenneth D. Merry #include <stdlib.h>
59130f4520SKenneth D. Merry #include <unistd.h>
60130f4520SKenneth D. Merry #include <fcntl.h>
611a7f22d9SAlan Somers #include <inttypes.h>
62130f4520SKenneth D. Merry #include <getopt.h>
63130f4520SKenneth D. Merry #include <string.h>
64130f4520SKenneth D. Merry #include <errno.h>
65130f4520SKenneth D. Merry #include <err.h>
66130f4520SKenneth D. Merry #include <ctype.h>
67130f4520SKenneth D. Merry #include <bitstring.h>
68130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h>
69130f4520SKenneth D. Merry #include <cam/ctl/ctl.h>
70130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h>
71130f4520SKenneth D. Merry #include <cam/ctl/ctl_scsi_all.h>
72130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.h>
73130f4520SKenneth D. Merry #include <cam/ctl/ctl_backend.h>
74130f4520SKenneth D. Merry #include <cam/ctl/ctl_ioctl.h>
75130f4520SKenneth D. Merry 
76130f4520SKenneth D. Merry /*
77bb8f9017SAlexander Motin  * The default amount of space we allocate for stats storage space.
78bb8f9017SAlexander Motin  * We dynamically allocate more if needed.
79130f4520SKenneth D. Merry  */
80bb8f9017SAlexander Motin #define	CTL_STAT_NUM_ITEMS	256
81130f4520SKenneth D. Merry 
825e4b2529SBaptiste Daroussin static int ctl_stat_bits;
83130f4520SKenneth D. Merry 
841a7f22d9SAlan Somers static const char *ctlstat_opts = "Cc:DPdhjl:n:p:tw:";
851a7f22d9SAlan Somers static const char *ctlstat_usage = "Usage:  ctlstat [-CDPdjht] [-l lunnum]"
86130f4520SKenneth D. Merry 				   "[-c count] [-n numdevs] [-w wait]\n";
87130f4520SKenneth D. Merry 
88130f4520SKenneth D. Merry struct ctl_cpu_stats {
89130f4520SKenneth D. Merry 	uint64_t user;
90130f4520SKenneth D. Merry 	uint64_t nice;
91130f4520SKenneth D. Merry 	uint64_t system;
92130f4520SKenneth D. Merry 	uint64_t intr;
93130f4520SKenneth D. Merry 	uint64_t idle;
94130f4520SKenneth D. Merry };
95130f4520SKenneth D. Merry 
96130f4520SKenneth D. Merry typedef enum {
97130f4520SKenneth D. Merry 	CTLSTAT_MODE_STANDARD,
98130f4520SKenneth D. Merry 	CTLSTAT_MODE_DUMP,
99130f4520SKenneth D. Merry 	CTLSTAT_MODE_JSON,
1001a7f22d9SAlan Somers 	CTLSTAT_MODE_PROMETHEUS,
101130f4520SKenneth D. Merry } ctlstat_mode_types;
102130f4520SKenneth D. Merry 
103130f4520SKenneth D. Merry #define	CTLSTAT_FLAG_CPU		(1 << 0)
104130f4520SKenneth D. Merry #define	CTLSTAT_FLAG_HEADER		(1 << 1)
105130f4520SKenneth D. Merry #define	CTLSTAT_FLAG_FIRST_RUN		(1 << 2)
106130f4520SKenneth D. Merry #define	CTLSTAT_FLAG_TOTALS		(1 << 3)
107130f4520SKenneth D. Merry #define	CTLSTAT_FLAG_DMA_TIME		(1 << 4)
108bb8f9017SAlexander Motin #define	CTLSTAT_FLAG_TIME_VALID		(1 << 5)
109bb8f9017SAlexander Motin #define	CTLSTAT_FLAG_MASK		(1 << 6)
110bb8f9017SAlexander Motin #define	CTLSTAT_FLAG_LUNS		(1 << 7)
111bb8f9017SAlexander Motin #define	CTLSTAT_FLAG_PORTS		(1 << 8)
112130f4520SKenneth D. Merry #define	F_CPU(ctx) ((ctx)->flags & CTLSTAT_FLAG_CPU)
113130f4520SKenneth D. Merry #define	F_HDR(ctx) ((ctx)->flags & CTLSTAT_FLAG_HEADER)
114130f4520SKenneth D. Merry #define	F_FIRST(ctx) ((ctx)->flags & CTLSTAT_FLAG_FIRST_RUN)
115130f4520SKenneth D. Merry #define	F_TOTALS(ctx) ((ctx)->flags & CTLSTAT_FLAG_TOTALS)
116130f4520SKenneth D. Merry #define	F_DMA(ctx) ((ctx)->flags & CTLSTAT_FLAG_DMA_TIME)
117bb8f9017SAlexander Motin #define	F_TIMEVAL(ctx) ((ctx)->flags & CTLSTAT_FLAG_TIME_VALID)
118bb8f9017SAlexander Motin #define	F_MASK(ctx) ((ctx)->flags & CTLSTAT_FLAG_MASK)
119bb8f9017SAlexander Motin #define	F_LUNS(ctx) ((ctx)->flags & CTLSTAT_FLAG_LUNS)
120bb8f9017SAlexander Motin #define	F_PORTS(ctx) ((ctx)->flags & CTLSTAT_FLAG_PORTS)
121130f4520SKenneth D. Merry 
122130f4520SKenneth D. Merry struct ctlstat_context {
123130f4520SKenneth D. Merry 	ctlstat_mode_types mode;
124130f4520SKenneth D. Merry 	int flags;
125bb8f9017SAlexander Motin 	struct ctl_io_stats *cur_stats, *prev_stats;
126bb8f9017SAlexander Motin 	struct ctl_io_stats cur_total_stats[3], prev_total_stats[3];
127130f4520SKenneth D. Merry 	struct timespec cur_time, prev_time;
128130f4520SKenneth D. Merry 	struct ctl_cpu_stats cur_cpu, prev_cpu;
129130f4520SKenneth D. Merry 	uint64_t cur_total_jiffies, prev_total_jiffies;
130130f4520SKenneth D. Merry 	uint64_t cur_idle, prev_idle;
1315e4b2529SBaptiste Daroussin 	bitstr_t *item_mask;
132bb8f9017SAlexander Motin 	int cur_items, prev_items;
133bb8f9017SAlexander Motin 	int cur_alloc, prev_alloc;
134130f4520SKenneth D. Merry 	int numdevs;
135130f4520SKenneth D. Merry 	int header_interval;
136130f4520SKenneth D. Merry };
137130f4520SKenneth D. Merry 
1381a7f22d9SAlan Somers struct cctl_portlist_data {
1391a7f22d9SAlan Somers 	int level;
1401a7f22d9SAlan Somers 	struct sbuf *cur_sb[32];
1414c163a54SAlan Somers 	int id;
1421a7f22d9SAlan Somers 	int lun;
1431a7f22d9SAlan Somers 	int ntargets;
1441a7f22d9SAlan Somers 	char *target;
1451a7f22d9SAlan Somers 	char **targets;
1461a7f22d9SAlan Somers };
1471a7f22d9SAlan Somers 
148130f4520SKenneth D. Merry #ifndef min
149130f4520SKenneth D. Merry #define	min(x,y)	(((x) < (y)) ? (x) : (y))
150130f4520SKenneth D. Merry #endif
151130f4520SKenneth D. Merry 
152130f4520SKenneth D. Merry static void usage(int error);
153bb8f9017SAlexander Motin static int getstats(int fd, int *alloc_items, int *num_items,
1544c163a54SAlan Somers     struct ctl_io_stats **xstats, struct timespec *cur_time, int *time_valid,
1554c163a54SAlan Somers     bool ports);
156130f4520SKenneth D. Merry static int getcpu(struct ctl_cpu_stats *cpu_stats);
157bb8f9017SAlexander Motin static void compute_stats(struct ctl_io_stats *cur_stats,
158bb8f9017SAlexander Motin 			  struct ctl_io_stats *prev_stats,
159130f4520SKenneth D. Merry 			  long double etime, long double *mbsec,
160130f4520SKenneth D. Merry 			  long double *kb_per_transfer,
161130f4520SKenneth D. Merry 			  long double *transfers_per_second,
162130f4520SKenneth D. Merry 			  long double *ms_per_transfer,
163130f4520SKenneth D. Merry 			  long double *ms_per_dma,
164130f4520SKenneth D. Merry 			  long double *dmas_per_second);
165130f4520SKenneth D. Merry 
166130f4520SKenneth D. Merry static void
167130f4520SKenneth D. Merry usage(int error)
168130f4520SKenneth D. Merry {
16933d35bebSKenneth D. Merry 	fputs(ctlstat_usage, error ? stderr : stdout);
170130f4520SKenneth D. Merry }
171130f4520SKenneth D. Merry 
172130f4520SKenneth D. Merry static int
173bb8f9017SAlexander Motin getstats(int fd, int *alloc_items, int *num_items, struct ctl_io_stats **stats,
1744c163a54SAlan Somers 	 struct timespec *cur_time, int *flags, bool ports)
175130f4520SKenneth D. Merry {
176bb8f9017SAlexander Motin 	struct ctl_get_io_stats get_stats;
177bb8f9017SAlexander Motin 	int more_space_count = 0;
178130f4520SKenneth D. Merry 
179bb8f9017SAlexander Motin 	if (*alloc_items == 0)
180bb8f9017SAlexander Motin 		*alloc_items = CTL_STAT_NUM_ITEMS;
181130f4520SKenneth D. Merry retry:
182bb8f9017SAlexander Motin 	if (*stats == NULL)
183bb8f9017SAlexander Motin 		*stats = malloc(sizeof(**stats) * *alloc_items);
184130f4520SKenneth D. Merry 
185bb8f9017SAlexander Motin 	memset(&get_stats, 0, sizeof(get_stats));
186bb8f9017SAlexander Motin 	get_stats.alloc_len = *alloc_items * sizeof(**stats);
187bb8f9017SAlexander Motin 	memset(*stats, 0, get_stats.alloc_len);
188bb8f9017SAlexander Motin 	get_stats.stats = *stats;
189130f4520SKenneth D. Merry 
1904c163a54SAlan Somers 	if (ioctl(fd, ports ? CTL_GET_PORT_STATS : CTL_GET_LUN_STATS,
1914c163a54SAlan Somers 	    &get_stats) == -1)
192bb8f9017SAlexander Motin 		err(1, "CTL_GET_*_STATS ioctl returned error");
193130f4520SKenneth D. Merry 
194bb8f9017SAlexander Motin 	switch (get_stats.status) {
195130f4520SKenneth D. Merry 	case CTL_SS_OK:
196130f4520SKenneth D. Merry 		break;
197130f4520SKenneth D. Merry 	case CTL_SS_ERROR:
198bb8f9017SAlexander Motin 		err(1, "CTL_GET_*_STATS ioctl returned CTL_SS_ERROR");
199130f4520SKenneth D. Merry 		break;
200130f4520SKenneth D. Merry 	case CTL_SS_NEED_MORE_SPACE:
201bb8f9017SAlexander Motin 		if (more_space_count >= 2)
202bb8f9017SAlexander Motin 			errx(1, "CTL_GET_*_STATS returned NEED_MORE_SPACE again");
203bb8f9017SAlexander Motin 		*alloc_items = get_stats.num_items * 5 / 4;
204bb8f9017SAlexander Motin 		free(*stats);
205bb8f9017SAlexander Motin 		*stats = NULL;
206130f4520SKenneth D. Merry 		more_space_count++;
207130f4520SKenneth D. Merry 		goto retry;
208130f4520SKenneth D. Merry 		break; /* NOTREACHED */
209130f4520SKenneth D. Merry 	default:
210bb8f9017SAlexander Motin 		errx(1, "CTL_GET_*_STATS ioctl returned unknown status %d",
211bb8f9017SAlexander Motin 		     get_stats.status);
212130f4520SKenneth D. Merry 		break;
213130f4520SKenneth D. Merry 	}
214130f4520SKenneth D. Merry 
215bb8f9017SAlexander Motin 	*num_items = get_stats.fill_len / sizeof(**stats);
216bb8f9017SAlexander Motin 	cur_time->tv_sec = get_stats.timestamp.tv_sec;
217bb8f9017SAlexander Motin 	cur_time->tv_nsec = get_stats.timestamp.tv_nsec;
218bb8f9017SAlexander Motin 	if (get_stats.flags & CTL_STATS_FLAG_TIME_VALID)
219bb8f9017SAlexander Motin 		*flags |= CTLSTAT_FLAG_TIME_VALID;
220130f4520SKenneth D. Merry 	else
221bb8f9017SAlexander Motin 		*flags &= ~CTLSTAT_FLAG_TIME_VALID;
222130f4520SKenneth D. Merry 
223130f4520SKenneth D. Merry 	return (0);
224130f4520SKenneth D. Merry }
225130f4520SKenneth D. Merry 
226130f4520SKenneth D. Merry static int
227130f4520SKenneth D. Merry getcpu(struct ctl_cpu_stats *cpu_stats)
228130f4520SKenneth D. Merry {
229130f4520SKenneth D. Merry 	long cp_time[CPUSTATES];
230130f4520SKenneth D. Merry 	size_t cplen;
231130f4520SKenneth D. Merry 
232130f4520SKenneth D. Merry 	cplen = sizeof(cp_time);
233130f4520SKenneth D. Merry 
234130f4520SKenneth D. Merry 	if (sysctlbyname("kern.cp_time", &cp_time, &cplen, NULL, 0) == -1) {
235130f4520SKenneth D. Merry 		warn("sysctlbyname(kern.cp_time...) failed");
236130f4520SKenneth D. Merry 		return (1);
237130f4520SKenneth D. Merry 	}
238130f4520SKenneth D. Merry 
239130f4520SKenneth D. Merry 	cpu_stats->user = cp_time[CP_USER];
240130f4520SKenneth D. Merry 	cpu_stats->nice = cp_time[CP_NICE];
241130f4520SKenneth D. Merry 	cpu_stats->system = cp_time[CP_SYS];
242130f4520SKenneth D. Merry 	cpu_stats->intr = cp_time[CP_INTR];
243130f4520SKenneth D. Merry 	cpu_stats->idle = cp_time[CP_IDLE];
244130f4520SKenneth D. Merry 
245130f4520SKenneth D. Merry 	return (0);
246130f4520SKenneth D. Merry }
247130f4520SKenneth D. Merry 
248130f4520SKenneth D. Merry static void
249bb8f9017SAlexander Motin compute_stats(struct ctl_io_stats *cur_stats,
250bb8f9017SAlexander Motin 	      struct ctl_io_stats *prev_stats, long double etime,
251130f4520SKenneth D. Merry 	      long double *mbsec, long double *kb_per_transfer,
252130f4520SKenneth D. Merry 	      long double *transfers_per_second, long double *ms_per_transfer,
253130f4520SKenneth D. Merry 	      long double *ms_per_dma, long double *dmas_per_second)
254130f4520SKenneth D. Merry {
255130f4520SKenneth D. Merry 	uint64_t total_bytes = 0, total_operations = 0, total_dmas = 0;
256130f4520SKenneth D. Merry 	struct bintime total_time_bt, total_dma_bt;
257130f4520SKenneth D. Merry 	struct timespec total_time_ts, total_dma_ts;
258130f4520SKenneth D. Merry 	int i;
259130f4520SKenneth D. Merry 
260130f4520SKenneth D. Merry 	bzero(&total_time_bt, sizeof(total_time_bt));
261130f4520SKenneth D. Merry 	bzero(&total_dma_bt, sizeof(total_dma_bt));
262130f4520SKenneth D. Merry 	bzero(&total_time_ts, sizeof(total_time_ts));
263130f4520SKenneth D. Merry 	bzero(&total_dma_ts, sizeof(total_dma_ts));
264130f4520SKenneth D. Merry 	for (i = 0; i < CTL_STATS_NUM_TYPES; i++) {
265bb8f9017SAlexander Motin 		total_bytes += cur_stats->bytes[i];
266bb8f9017SAlexander Motin 		total_operations += cur_stats->operations[i];
267bb8f9017SAlexander Motin 		total_dmas += cur_stats->dmas[i];
268bb8f9017SAlexander Motin 		bintime_add(&total_time_bt, &cur_stats->time[i]);
269bb8f9017SAlexander Motin 		bintime_add(&total_dma_bt, &cur_stats->dma_time[i]);
270130f4520SKenneth D. Merry 		if (prev_stats != NULL) {
271bb8f9017SAlexander Motin 			total_bytes -= prev_stats->bytes[i];
272bb8f9017SAlexander Motin 			total_operations -= prev_stats->operations[i];
273bb8f9017SAlexander Motin 			total_dmas -= prev_stats->dmas[i];
274bb8f9017SAlexander Motin 			bintime_sub(&total_time_bt, &prev_stats->time[i]);
275bb8f9017SAlexander Motin 			bintime_sub(&total_dma_bt, &prev_stats->dma_time[i]);
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 
329924233ebSAlexander Motin #define	PRINT_BINTIME(bt) \
330924233ebSAlexander Motin 	printf("%jd.%06ju", (intmax_t)(bt).sec, \
3312eb293b9SAlexander Motin 	       (uintmax_t)(((bt).frac >> 32) * 1000000 >> 32))
332bf70beceSEd Schouten static const char *iotypes[] = {"NO IO", "READ", "WRITE"};
333130f4520SKenneth D. Merry 
334130f4520SKenneth D. Merry static void
335bb8f9017SAlexander Motin ctlstat_dump(struct ctlstat_context *ctx)
336bb8f9017SAlexander Motin {
3375be4479bSAlexander Motin 	int iotype, i, n;
338bb8f9017SAlexander Motin 	struct ctl_io_stats *stats = ctx->cur_stats;
339130f4520SKenneth D. Merry 
3405be4479bSAlexander Motin 	for (i = n = 0; i < ctx->cur_items;i++) {
3415be4479bSAlexander Motin 		if (F_MASK(ctx) && bit_test(ctx->item_mask,
3425be4479bSAlexander Motin 		    (int)stats[i].item) == 0)
34361639a0aSAlexander Motin 			continue;
344bb8f9017SAlexander Motin 		printf("%s %d\n", F_PORTS(ctx) ? "port" : "lun", stats[i].item);
345bb8f9017SAlexander Motin 		for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; iotype++) {
346bb8f9017SAlexander Motin 			printf("  io type %d (%s)\n", iotype, iotypes[iotype]);
347130f4520SKenneth D. Merry 			printf("   bytes %ju\n", (uintmax_t)
348bb8f9017SAlexander Motin 			    stats[i].bytes[iotype]);
349130f4520SKenneth D. Merry 			printf("   operations %ju\n", (uintmax_t)
350bb8f9017SAlexander Motin 			    stats[i].operations[iotype]);
351bb8f9017SAlexander Motin 			printf("   dmas %ju\n", (uintmax_t)
352bb8f9017SAlexander Motin 			    stats[i].dmas[iotype]);
353924233ebSAlexander Motin 			printf("   io time ");
354924233ebSAlexander Motin 			PRINT_BINTIME(stats[i].time[iotype]);
355924233ebSAlexander Motin 			printf("\n   dma time ");
356924233ebSAlexander Motin 			PRINT_BINTIME(stats[i].dma_time[iotype]);
357924233ebSAlexander Motin 			printf("\n");
358130f4520SKenneth D. Merry 		}
3595be4479bSAlexander Motin 		if (++n >= ctx->numdevs)
3605be4479bSAlexander Motin 			break;
361130f4520SKenneth D. Merry 	}
362130f4520SKenneth D. Merry }
363130f4520SKenneth D. Merry 
364130f4520SKenneth D. Merry static void
365130f4520SKenneth D. Merry ctlstat_json(struct ctlstat_context *ctx) {
3665be4479bSAlexander Motin 	int iotype, i, n;
367bb8f9017SAlexander Motin 	struct ctl_io_stats *stats = ctx->cur_stats;
368130f4520SKenneth D. Merry 
369bb8f9017SAlexander Motin 	printf("{\"%s\":[", F_PORTS(ctx) ? "ports" : "luns");
3705be4479bSAlexander Motin 	for (i = n = 0; i < ctx->cur_items; i++) {
3715be4479bSAlexander Motin 		if (F_MASK(ctx) && bit_test(ctx->item_mask,
3725be4479bSAlexander Motin 		    (int)stats[i].item) == 0)
37361639a0aSAlexander Motin 			continue;
374130f4520SKenneth D. Merry 		printf("{\"num\":%d,\"io\":[",
375bb8f9017SAlexander Motin 		    stats[i].item);
376bb8f9017SAlexander Motin 		for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; iotype++) {
377130f4520SKenneth D. Merry 			printf("{\"type\":\"%s\",", iotypes[iotype]);
378924233ebSAlexander Motin 			printf("\"bytes\":%ju,", (uintmax_t)
379924233ebSAlexander Motin 			    stats[i].bytes[iotype]);
380924233ebSAlexander Motin 			printf("\"operations\":%ju,", (uintmax_t)
381924233ebSAlexander Motin 			    stats[i].operations[iotype]);
382924233ebSAlexander Motin 			printf("\"dmas\":%ju,", (uintmax_t)
383bb8f9017SAlexander Motin 			    stats[i].dmas[iotype]);
384924233ebSAlexander Motin 			printf("\"io time\":");
385924233ebSAlexander Motin 			PRINT_BINTIME(stats[i].time[iotype]);
386924233ebSAlexander Motin 			printf(",\"dma time\":");
387924233ebSAlexander Motin 			PRINT_BINTIME(stats[i].dma_time[iotype]);
388924233ebSAlexander Motin 			printf("}");
389130f4520SKenneth D. Merry 			if (iotype < (CTL_STATS_NUM_TYPES - 1))
390130f4520SKenneth D. Merry 				printf(","); /* continue io array */
391130f4520SKenneth D. Merry 		}
392bb8f9017SAlexander Motin 		printf("]}");
3935be4479bSAlexander Motin 		if (++n >= ctx->numdevs)
3945be4479bSAlexander Motin 			break;
395bb8f9017SAlexander Motin 		if (i < (ctx->cur_items - 1))
396130f4520SKenneth D. Merry 			printf(","); /* continue lun array */
397130f4520SKenneth D. Merry 	}
398bb8f9017SAlexander Motin 	printf("]}");
399130f4520SKenneth D. Merry }
400130f4520SKenneth D. Merry 
4014c163a54SAlan Somers #define CTLSTAT_PROMETHEUS_LOOP(field, collector) \
4021a7f22d9SAlan Somers 	for (i = n = 0; i < ctx->cur_items; i++) { \
4031a7f22d9SAlan Somers 		if (F_MASK(ctx) && bit_test(ctx->item_mask, \
4041a7f22d9SAlan Somers 		    (int)stats[i].item) == 0) \
4051a7f22d9SAlan Somers 			continue; \
4061a7f22d9SAlan Somers 		for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; iotype++) { \
4074c163a54SAlan Somers 			int idx = stats[i].item; \
4084c163a54SAlan Somers 			/* \
4094c163a54SAlan Somers 			 * Note that Prometheus considers a label value of "" \
4104c163a54SAlan Somers 			 * to be the same as no label at all \
4114c163a54SAlan Somers 			 */ \
4124c163a54SAlan Somers 			const char *target = ""; \
4134c163a54SAlan Somers 			if (strcmp(collector, "port") == 0 && \
4144c163a54SAlan Somers 				targdata.targets[idx] != NULL) \
4154c163a54SAlan Somers 			{ \
4164c163a54SAlan Somers 				target = targdata.targets[idx]; \
4174c163a54SAlan Somers 			} \
4184c163a54SAlan Somers 			printf("iscsi_%s_" #field "{" \
4194c163a54SAlan Somers 			    "%s=\"%u\",target=\"%s\",type=\"%s\"} %" PRIu64 \
4201a7f22d9SAlan Somers 			    "\n", \
4214c163a54SAlan Somers 			    collector, collector, \
4224c163a54SAlan Somers 			    idx, target, iotypes[iotype], \
4231a7f22d9SAlan Somers 			    stats[i].field[iotype]); \
4241a7f22d9SAlan Somers 		} \
4251a7f22d9SAlan Somers 	} \
4261a7f22d9SAlan Somers 
4274c163a54SAlan Somers #define CTLSTAT_PROMETHEUS_TIMELOOP(field, collector) \
4281a7f22d9SAlan Somers 	for (i = n = 0; i < ctx->cur_items; i++) { \
4291a7f22d9SAlan Somers 		if (F_MASK(ctx) && bit_test(ctx->item_mask, \
4301a7f22d9SAlan Somers 		    (int)stats[i].item) == 0) \
4311a7f22d9SAlan Somers 			continue; \
4321a7f22d9SAlan Somers 		for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; iotype++) { \
4331a7f22d9SAlan Somers 			uint64_t us; \
4341a7f22d9SAlan Somers 			struct timespec ts; \
4354c163a54SAlan Somers 			int idx = stats[i].item; \
4364c163a54SAlan Somers 			/* \
4374c163a54SAlan Somers 			 * Note that Prometheus considers a label value of "" \
4384c163a54SAlan Somers 			 * to be the same as no label at all \
4394c163a54SAlan Somers 			 */ \
4404c163a54SAlan Somers 			const char *target = ""; \
4414c163a54SAlan Somers 			if (strcmp(collector, "port") == 0 && \
4424c163a54SAlan Somers 				targdata.targets[idx] != NULL) \
4434c163a54SAlan Somers 			{ \
4444c163a54SAlan Somers 				target = targdata.targets[idx]; \
4454c163a54SAlan Somers 			} \
4461a7f22d9SAlan Somers 			bintime2timespec(&stats[i].field[iotype], &ts); \
4471a7f22d9SAlan Somers 			us = ts.tv_sec * 1000000 + ts.tv_nsec / 1000; \
4484c163a54SAlan Somers 			printf("iscsi_%s_" #field "{" \
4494c163a54SAlan Somers 			    "%s=\"%u\",target=\"%s\",type=\"%s\"} %" PRIu64 \
4501a7f22d9SAlan Somers 			    "\n", \
4514c163a54SAlan Somers 			    collector, collector, \
4524c163a54SAlan Somers 			    idx, target, iotypes[iotype], us); \
4531a7f22d9SAlan Somers 		} \
4541a7f22d9SAlan Somers 	} \
4551a7f22d9SAlan Somers 
4561a7f22d9SAlan Somers static void
4574c163a54SAlan Somers cctl_start_pelement(void *user_data, const char *name, const char **attr)
4581a7f22d9SAlan Somers {
4591a7f22d9SAlan Somers 	struct cctl_portlist_data* targdata = user_data;
4601a7f22d9SAlan Somers 
4611a7f22d9SAlan Somers 	targdata->level++;
4621a7f22d9SAlan Somers 	if ((u_int)targdata->level >= (sizeof(targdata->cur_sb) /
4631a7f22d9SAlan Somers 	    sizeof(targdata->cur_sb[0])))
4641a7f22d9SAlan Somers 		errx(1, "%s: too many nesting levels, %zd max", __func__,
4651a7f22d9SAlan Somers 		     sizeof(targdata->cur_sb) / sizeof(targdata->cur_sb[0]));
4661a7f22d9SAlan Somers 
4671a7f22d9SAlan Somers 	targdata->cur_sb[targdata->level] = sbuf_new_auto();
4681a7f22d9SAlan Somers 	if (targdata->cur_sb[targdata->level] == NULL)
4691a7f22d9SAlan Somers 		err(1, "%s: Unable to allocate sbuf", __func__);
4701a7f22d9SAlan Somers 
4711a7f22d9SAlan Somers 	if (strcmp(name, "targ_port") == 0) {
4724c163a54SAlan Somers 		int i = 0;
4734c163a54SAlan Somers 
4741a7f22d9SAlan Somers 		targdata->lun = -1;
4754c163a54SAlan Somers 		targdata->id = -1;
4761a7f22d9SAlan Somers 		free(targdata->target);
4771a7f22d9SAlan Somers 		targdata->target = NULL;
4784c163a54SAlan Somers 		while (attr[i]) {
4794c163a54SAlan Somers 			if (strcmp(attr[i], "id") == 0) {
4804c163a54SAlan Somers 				/*
4814c163a54SAlan Somers 				 * Well-formed XML always pairs keys with
4824c163a54SAlan Somers 				 * values in attr
4834c163a54SAlan Somers 				 */
4844c163a54SAlan Somers 				assert(attr[i + 1]);
4854c163a54SAlan Somers 				targdata->id = atoi(attr[i + 1]);
4864c163a54SAlan Somers 			}
4874c163a54SAlan Somers 			i += 2;
4884c163a54SAlan Somers 		}
4894c163a54SAlan Somers 
4901a7f22d9SAlan Somers 	}
4911a7f22d9SAlan Somers }
4921a7f22d9SAlan Somers 
4931a7f22d9SAlan Somers static void
4941a7f22d9SAlan Somers cctl_char_phandler(void *user_data, const XML_Char *str, int len)
4951a7f22d9SAlan Somers {
4961a7f22d9SAlan Somers 	struct cctl_portlist_data *targdata = user_data;
4971a7f22d9SAlan Somers 
4981a7f22d9SAlan Somers 	sbuf_bcat(targdata->cur_sb[targdata->level], str, len);
4991a7f22d9SAlan Somers }
5001a7f22d9SAlan Somers 
5011a7f22d9SAlan Somers static void
5021a7f22d9SAlan Somers cctl_end_pelement(void *user_data, const char *name)
5031a7f22d9SAlan Somers {
5041a7f22d9SAlan Somers 	struct cctl_portlist_data* targdata = user_data;
5051a7f22d9SAlan Somers 	char *str;
5061a7f22d9SAlan Somers 
5071a7f22d9SAlan Somers 	if (targdata->cur_sb[targdata->level] == NULL)
5081a7f22d9SAlan Somers 		errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
5091a7f22d9SAlan Somers 		     targdata->level, name);
5101a7f22d9SAlan Somers 
5111a7f22d9SAlan Somers 	if (sbuf_finish(targdata->cur_sb[targdata->level]) != 0)
5121a7f22d9SAlan Somers 		err(1, "%s: sbuf_finish", __func__);
5131a7f22d9SAlan Somers 	str = strdup(sbuf_data(targdata->cur_sb[targdata->level]));
5141a7f22d9SAlan Somers 	if (str == NULL)
5151a7f22d9SAlan Somers 		err(1, "%s can't allocate %zd bytes for string", __func__,
5161a7f22d9SAlan Somers 		    sbuf_len(targdata->cur_sb[targdata->level]));
5171a7f22d9SAlan Somers 
5181a7f22d9SAlan Somers 	sbuf_delete(targdata->cur_sb[targdata->level]);
5191a7f22d9SAlan Somers 	targdata->cur_sb[targdata->level] = NULL;
5201a7f22d9SAlan Somers 	targdata->level--;
5211a7f22d9SAlan Somers 
5221a7f22d9SAlan Somers 	if (strcmp(name, "target") == 0) {
5231a7f22d9SAlan Somers 		free(targdata->target);
5241a7f22d9SAlan Somers 		targdata->target = str;
5251a7f22d9SAlan Somers 	} else if (strcmp(name, "targ_port") == 0) {
5264c163a54SAlan Somers 		if (targdata->id >= 0 && targdata->target != NULL) {
5274c163a54SAlan Somers 			if (targdata->id >= targdata->ntargets) {
5281a7f22d9SAlan Somers 				/*
5291a7f22d9SAlan Somers 				 * This can happen for example if there are
5304c163a54SAlan Somers 				 * targets with no LUNs.
5311a7f22d9SAlan Somers 				 */
5321a7f22d9SAlan Somers 				targdata->ntargets = MAX(targdata->ntargets * 2,
5334c163a54SAlan Somers 					targdata->id + 1);
5341a7f22d9SAlan Somers 				size_t newsize = targdata->ntargets *
5351a7f22d9SAlan Somers 					sizeof(char*);
5361a7f22d9SAlan Somers 				targdata->targets = rallocx(targdata->targets,
5371a7f22d9SAlan Somers 					newsize, MALLOCX_ZERO);
5381a7f22d9SAlan Somers 			}
5394c163a54SAlan Somers 			free(targdata->targets[targdata->id]);
5404c163a54SAlan Somers 			targdata->targets[targdata->id] = targdata->target;
5411a7f22d9SAlan Somers 			targdata->target = NULL;
5421a7f22d9SAlan Somers 		}
5431a7f22d9SAlan Somers 		free(str);
5441a7f22d9SAlan Somers 	} else {
5451a7f22d9SAlan Somers 		free(str);
5461a7f22d9SAlan Somers 	}
5471a7f22d9SAlan Somers }
5481a7f22d9SAlan Somers 
5491a7f22d9SAlan Somers static void
5504c163a54SAlan Somers ctlstat_prometheus(int fd, struct ctlstat_context *ctx, bool ports) {
5511a7f22d9SAlan Somers 	struct ctl_io_stats *stats = ctx->cur_stats;
5521a7f22d9SAlan Somers 	struct ctl_lun_list list;
5531a7f22d9SAlan Somers 	struct cctl_portlist_data targdata;
5541a7f22d9SAlan Somers 	XML_Parser parser;
5551a7f22d9SAlan Somers 	char *port_str = NULL;
5561a7f22d9SAlan Somers 	int iotype, i, n, retval;
5571a7f22d9SAlan Somers 	int port_len = 4096;
5584c163a54SAlan Somers 	const char *collector;
5591a7f22d9SAlan Somers 
5601a7f22d9SAlan Somers 	bzero(&targdata, sizeof(targdata));
5611a7f22d9SAlan Somers 	targdata.ntargets = ctx->cur_items;
5621a7f22d9SAlan Somers 	targdata.targets = calloc(targdata.ntargets, sizeof(char*));
5631a7f22d9SAlan Somers retry:
5641a7f22d9SAlan Somers 	port_str = (char *)realloc(port_str, port_len);
5651a7f22d9SAlan Somers 	bzero(&list, sizeof(list));
5661a7f22d9SAlan Somers 	list.alloc_len = port_len;
5671a7f22d9SAlan Somers 	list.status = CTL_LUN_LIST_NONE;
5681a7f22d9SAlan Somers 	list.lun_xml = port_str;
5691a7f22d9SAlan Somers 	if (ioctl(fd, CTL_PORT_LIST, &list) == -1)
5701a7f22d9SAlan Somers 		err(1, "%s: error issuing CTL_PORT_LIST ioctl", __func__);
5711a7f22d9SAlan Somers 	if (list.status == CTL_LUN_LIST_ERROR) {
5721a7f22d9SAlan Somers 		warnx("%s: error returned from CTL_PORT_LIST ioctl:\n%s",
5731a7f22d9SAlan Somers 		      __func__, list.error_str);
5741a7f22d9SAlan Somers 	} else if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
5751a7f22d9SAlan Somers 		port_len <<= 1;
5761a7f22d9SAlan Somers 		goto retry;
5771a7f22d9SAlan Somers 	}
5781a7f22d9SAlan Somers 
5791a7f22d9SAlan Somers 	parser = XML_ParserCreate(NULL);
5801a7f22d9SAlan Somers 	if (parser == NULL)
5811a7f22d9SAlan Somers 		err(1, "%s: Unable to create XML parser", __func__);
5821a7f22d9SAlan Somers 	XML_SetUserData(parser, &targdata);
5831a7f22d9SAlan Somers 	XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement);
5841a7f22d9SAlan Somers 	XML_SetCharacterDataHandler(parser, cctl_char_phandler);
5851a7f22d9SAlan Somers 
5861a7f22d9SAlan Somers 	retval = XML_Parse(parser, port_str, strlen(port_str), 1);
5871a7f22d9SAlan Somers 	if (retval != 1) {
5881a7f22d9SAlan Somers 		errx(1, "%s: Unable to parse XML: Error %d", __func__,
5891a7f22d9SAlan Somers 		    XML_GetErrorCode(parser));
5901a7f22d9SAlan Somers 	}
5911a7f22d9SAlan Somers 	XML_ParserFree(parser);
5921a7f22d9SAlan Somers 
5934c163a54SAlan Somers 	collector = ports ? "port" : "lun";
5941a7f22d9SAlan Somers 
5954c163a54SAlan Somers 	printf("# HELP iscsi_%s_bytes Number of bytes\n"
5964c163a54SAlan Somers 	       "# TYPE iscsi_%s_bytes counter\n", collector, collector);
5974c163a54SAlan Somers 	CTLSTAT_PROMETHEUS_LOOP(bytes, collector);
5984c163a54SAlan Somers 	printf("# HELP iscsi_%s_dmas Number of DMA\n"
5994c163a54SAlan Somers 	       "# TYPE iscsi_%s_dmas counter\n", collector, collector);
6004c163a54SAlan Somers 	CTLSTAT_PROMETHEUS_LOOP(dmas, collector);
6014c163a54SAlan Somers 	printf("# HELP iscsi_%s_operations Number of operations\n"
6024c163a54SAlan Somers 	       "# TYPE iscsi_%s_operations counter\n", collector, collector);
6034c163a54SAlan Somers 	CTLSTAT_PROMETHEUS_LOOP(operations, collector);
6044c163a54SAlan Somers 	printf("# HELP iscsi_%s_time Cumulative operation time in us\n"
6054c163a54SAlan Somers 	       "# TYPE iscsi_%s_time counter\n", collector, collector);
6064c163a54SAlan Somers 	CTLSTAT_PROMETHEUS_TIMELOOP(time, collector);
6074c163a54SAlan Somers 	printf("# HELP iscsi_%s_dma_time Cumulative DMA time in us\n"
6084c163a54SAlan Somers 	       "# TYPE iscsi_%s_dma_time counter\n", collector, collector);
6094c163a54SAlan Somers 	CTLSTAT_PROMETHEUS_TIMELOOP(dma_time, collector);
6101a7f22d9SAlan Somers 
6111a7f22d9SAlan Somers 	for (i = 0; i < targdata.ntargets; i++)
6121a7f22d9SAlan Somers 		free(targdata.targets[i]);
6131a7f22d9SAlan Somers 	free(targdata.target);
6141a7f22d9SAlan Somers 	free(targdata.targets);
6151a7f22d9SAlan Somers 
6161a7f22d9SAlan Somers 	fflush(stdout);
6171a7f22d9SAlan Somers }
6181a7f22d9SAlan Somers 
619130f4520SKenneth D. Merry static void
620130f4520SKenneth D. Merry ctlstat_standard(struct ctlstat_context *ctx) {
6215e796316SKenneth D. Merry 	long double etime;
622130f4520SKenneth D. Merry 	uint64_t delta_jiffies, delta_idle;
623130f4520SKenneth D. Merry 	long double cpu_percentage;
6245be4479bSAlexander Motin 	int i, j, n;
625130f4520SKenneth D. Merry 
626130f4520SKenneth D. Merry 	cpu_percentage = 0;
627130f4520SKenneth D. Merry 
628130f4520SKenneth D. Merry 	if (F_CPU(ctx) && (getcpu(&ctx->cur_cpu) != 0))
629130f4520SKenneth D. Merry 		errx(1, "error returned from getcpu()");
630130f4520SKenneth D. Merry 
6315e796316SKenneth D. Merry 	etime = ctx->cur_time.tv_sec - ctx->prev_time.tv_sec +
6325e796316SKenneth D. Merry 	    (ctx->prev_time.tv_nsec - ctx->cur_time.tv_nsec) * 1e-9;
633130f4520SKenneth D. Merry 
634130f4520SKenneth D. Merry 	if (F_CPU(ctx)) {
635130f4520SKenneth D. Merry 		ctx->prev_total_jiffies = ctx->cur_total_jiffies;
636130f4520SKenneth D. Merry 		ctx->cur_total_jiffies = ctx->cur_cpu.user +
637130f4520SKenneth D. Merry 		    ctx->cur_cpu.nice + ctx->cur_cpu.system +
638130f4520SKenneth D. Merry 		    ctx->cur_cpu.intr + ctx->cur_cpu.idle;
639130f4520SKenneth D. Merry 		delta_jiffies = ctx->cur_total_jiffies;
640130f4520SKenneth D. Merry 		if (F_FIRST(ctx) == 0)
641130f4520SKenneth D. Merry 			delta_jiffies -= ctx->prev_total_jiffies;
642130f4520SKenneth D. Merry 		ctx->prev_idle = ctx->cur_idle;
643130f4520SKenneth D. Merry 		ctx->cur_idle = ctx->cur_cpu.idle;
644130f4520SKenneth D. Merry 		delta_idle = ctx->cur_idle - ctx->prev_idle;
645130f4520SKenneth D. Merry 
646130f4520SKenneth D. Merry 		cpu_percentage = delta_jiffies - delta_idle;
647130f4520SKenneth D. Merry 		cpu_percentage /= delta_jiffies;
648130f4520SKenneth D. Merry 		cpu_percentage *= 100;
649130f4520SKenneth D. Merry 	}
650130f4520SKenneth D. Merry 
651130f4520SKenneth D. Merry 	if (F_HDR(ctx)) {
652130f4520SKenneth D. Merry 		ctx->header_interval--;
653130f4520SKenneth D. Merry 		if (ctx->header_interval <= 0) {
654130f4520SKenneth D. Merry 			if (F_CPU(ctx))
655130f4520SKenneth D. Merry 				fprintf(stdout, " CPU");
65661639a0aSAlexander Motin 			if (F_TOTALS(ctx)) {
65761639a0aSAlexander Motin 				fprintf(stdout, "%s     Read       %s"
65861639a0aSAlexander Motin 					"    Write       %s    Total\n",
659bb8f9017SAlexander Motin 					(F_TIMEVAL(ctx) != 0) ? "      " : "",
660bb8f9017SAlexander Motin 					(F_TIMEVAL(ctx) != 0) ? "      " : "",
661bb8f9017SAlexander Motin 					(F_TIMEVAL(ctx) != 0) ? "      " : "");
6625be4479bSAlexander Motin 				n = 3;
66361639a0aSAlexander Motin 			} else {
6645e4b2529SBaptiste Daroussin 				for (i = n = 0; i < min(ctl_stat_bits,
665bb8f9017SAlexander Motin 				     ctx->cur_items); i++) {
666bb8f9017SAlexander Motin 					int item;
667130f4520SKenneth D. Merry 
668130f4520SKenneth D. Merry 					/*
669130f4520SKenneth D. Merry 					 * Obviously this won't work with
670130f4520SKenneth D. Merry 					 * LUN numbers greater than a signed
671130f4520SKenneth D. Merry 					 * integer.
672130f4520SKenneth D. Merry 					 */
673bb8f9017SAlexander Motin 					item = (int)ctx->cur_stats[i].item;
674130f4520SKenneth D. Merry 
675bb8f9017SAlexander Motin 					if (F_MASK(ctx) &&
676bb8f9017SAlexander Motin 					    bit_test(ctx->item_mask, item) == 0)
677130f4520SKenneth D. Merry 						continue;
678d5a6319aSAlexander Motin 					fprintf(stdout, "%15.6s%d %s",
679bb8f9017SAlexander Motin 					    F_PORTS(ctx) ? "port" : "lun", item,
680bb8f9017SAlexander Motin 					    (F_TIMEVAL(ctx) != 0) ? "     " : "");
6815be4479bSAlexander Motin 					if (++n >= ctx->numdevs)
6825be4479bSAlexander Motin 						break;
683130f4520SKenneth D. Merry 				}
684130f4520SKenneth D. Merry 				fprintf(stdout, "\n");
685130f4520SKenneth D. Merry 			}
68661639a0aSAlexander Motin 			if (F_CPU(ctx))
68761639a0aSAlexander Motin 				fprintf(stdout, "    ");
6885be4479bSAlexander Motin 			for (i = 0; i < n; i++)
68961639a0aSAlexander Motin 				fprintf(stdout, "%s KB/t   %s MB/s",
690bb8f9017SAlexander Motin 					(F_TIMEVAL(ctx) != 0) ? "    ms" : "",
691130f4520SKenneth D. Merry 					(F_DMA(ctx) == 0) ? "tps" : "dps");
692130f4520SKenneth D. Merry 			fprintf(stdout, "\n");
693130f4520SKenneth D. Merry 			ctx->header_interval = 20;
694130f4520SKenneth D. Merry 		}
695130f4520SKenneth D. Merry 	}
696130f4520SKenneth D. Merry 
69761639a0aSAlexander Motin 	if (F_CPU(ctx))
69861639a0aSAlexander Motin 		fprintf(stdout, "%3.0Lf%%", cpu_percentage);
699130f4520SKenneth D. Merry 	if (F_TOTALS(ctx) != 0) {
700130f4520SKenneth D. Merry 		long double mbsec[3];
701130f4520SKenneth D. Merry 		long double kb_per_transfer[3];
702130f4520SKenneth D. Merry 		long double transfers_per_sec[3];
703130f4520SKenneth D. Merry 		long double ms_per_transfer[3];
704130f4520SKenneth D. Merry 		long double ms_per_dma[3];
705130f4520SKenneth D. Merry 		long double dmas_per_sec[3];
706130f4520SKenneth D. Merry 
707130f4520SKenneth D. Merry 		for (i = 0; i < 3; i++)
708130f4520SKenneth D. Merry 			ctx->prev_total_stats[i] = ctx->cur_total_stats[i];
709130f4520SKenneth D. Merry 
710130f4520SKenneth D. Merry 		memset(&ctx->cur_total_stats, 0, sizeof(ctx->cur_total_stats));
711130f4520SKenneth D. Merry 
712130f4520SKenneth D. Merry 		/* Use macros to make the next loop more readable. */
713bb8f9017SAlexander Motin #define	ADD_STATS_BYTES(st, i, j) \
714bb8f9017SAlexander Motin 	ctx->cur_total_stats[st].bytes[j] += \
715bb8f9017SAlexander Motin 	    ctx->cur_stats[i].bytes[j]
716bb8f9017SAlexander Motin #define	ADD_STATS_OPERATIONS(st, i, j) \
717bb8f9017SAlexander Motin 	ctx->cur_total_stats[st].operations[j] += \
718bb8f9017SAlexander Motin 	    ctx->cur_stats[i].operations[j]
719bb8f9017SAlexander Motin #define	ADD_STATS_DMAS(st, i, j) \
720bb8f9017SAlexander Motin 	ctx->cur_total_stats[st].dmas[j] += \
721bb8f9017SAlexander Motin 	    ctx->cur_stats[i].dmas[j]
722bb8f9017SAlexander Motin #define	ADD_STATS_TIME(st, i, j) \
723bb8f9017SAlexander Motin 	bintime_add(&ctx->cur_total_stats[st].time[j], \
724bb8f9017SAlexander Motin 	    &ctx->cur_stats[i].time[j])
725bb8f9017SAlexander Motin #define	ADD_STATS_DMA_TIME(st, i, j) \
726bb8f9017SAlexander Motin 	bintime_add(&ctx->cur_total_stats[st].dma_time[j], \
727bb8f9017SAlexander Motin 	    &ctx->cur_stats[i].dma_time[j])
728130f4520SKenneth D. Merry 
729bb8f9017SAlexander Motin 		for (i = 0; i < ctx->cur_items; i++) {
730bb8f9017SAlexander Motin 			if (F_MASK(ctx) && bit_test(ctx->item_mask,
731bb8f9017SAlexander Motin 			    (int)ctx->cur_stats[i].item) == 0)
73261639a0aSAlexander Motin 				continue;
733130f4520SKenneth D. Merry 			for (j = 0; j < CTL_STATS_NUM_TYPES; j++) {
734bb8f9017SAlexander Motin 				ADD_STATS_BYTES(2, i, j);
735bb8f9017SAlexander Motin 				ADD_STATS_OPERATIONS(2, i, j);
736bb8f9017SAlexander Motin 				ADD_STATS_DMAS(2, i, j);
737bb8f9017SAlexander Motin 				ADD_STATS_TIME(2, i, j);
738bb8f9017SAlexander Motin 				ADD_STATS_DMA_TIME(2, i, j);
739130f4520SKenneth D. Merry 			}
740bb8f9017SAlexander Motin 			ADD_STATS_BYTES(0, i, CTL_STATS_READ);
741bb8f9017SAlexander Motin 			ADD_STATS_OPERATIONS(0, i, CTL_STATS_READ);
742bb8f9017SAlexander Motin 			ADD_STATS_DMAS(0, i, CTL_STATS_READ);
743bb8f9017SAlexander Motin 			ADD_STATS_TIME(0, i, CTL_STATS_READ);
744bb8f9017SAlexander Motin 			ADD_STATS_DMA_TIME(0, i, CTL_STATS_READ);
745130f4520SKenneth D. Merry 
746bb8f9017SAlexander Motin 			ADD_STATS_BYTES(1, i, CTL_STATS_WRITE);
747bb8f9017SAlexander Motin 			ADD_STATS_OPERATIONS(1, i, CTL_STATS_WRITE);
748bb8f9017SAlexander Motin 			ADD_STATS_DMAS(1, i, CTL_STATS_WRITE);
749bb8f9017SAlexander Motin 			ADD_STATS_TIME(1, i, CTL_STATS_WRITE);
750bb8f9017SAlexander Motin 			ADD_STATS_DMA_TIME(1, i, CTL_STATS_WRITE);
751130f4520SKenneth D. Merry 		}
752130f4520SKenneth D. Merry 
753130f4520SKenneth D. Merry 		for (i = 0; i < 3; i++) {
754bb8f9017SAlexander Motin 			compute_stats(&ctx->cur_total_stats[i],
755130f4520SKenneth D. Merry 				F_FIRST(ctx) ? NULL : &ctx->prev_total_stats[i],
756130f4520SKenneth D. Merry 				etime, &mbsec[i], &kb_per_transfer[i],
757130f4520SKenneth D. Merry 				&transfers_per_sec[i],
758130f4520SKenneth D. Merry 				&ms_per_transfer[i], &ms_per_dma[i],
759130f4520SKenneth D. Merry 				&dmas_per_sec[i]);
760130f4520SKenneth D. Merry 			if (F_DMA(ctx) != 0)
76161639a0aSAlexander Motin 				fprintf(stdout, " %5.1Lf",
762130f4520SKenneth D. Merry 					ms_per_dma[i]);
763bb8f9017SAlexander Motin 			else if (F_TIMEVAL(ctx) != 0)
76461639a0aSAlexander Motin 				fprintf(stdout, " %5.1Lf",
765130f4520SKenneth D. Merry 					ms_per_transfer[i]);
76661639a0aSAlexander Motin 			fprintf(stdout, " %4.0Lf %5.0Lf %4.0Lf",
767130f4520SKenneth D. Merry 				kb_per_transfer[i],
768130f4520SKenneth D. Merry 				(F_DMA(ctx) == 0) ? transfers_per_sec[i] :
769130f4520SKenneth D. Merry 				dmas_per_sec[i], mbsec[i]);
770130f4520SKenneth D. Merry 		}
771130f4520SKenneth D. Merry 	} else {
7725e4b2529SBaptiste Daroussin 		for (i = n = 0; i < min(ctl_stat_bits, ctx->cur_items); i++) {
773130f4520SKenneth D. Merry 			long double mbsec, kb_per_transfer;
774130f4520SKenneth D. Merry 			long double transfers_per_sec;
775130f4520SKenneth D. Merry 			long double ms_per_transfer;
776130f4520SKenneth D. Merry 			long double ms_per_dma;
777130f4520SKenneth D. Merry 			long double dmas_per_sec;
778130f4520SKenneth D. Merry 
779bb8f9017SAlexander Motin 			if (F_MASK(ctx) && bit_test(ctx->item_mask,
780bb8f9017SAlexander Motin 			    (int)ctx->cur_stats[i].item) == 0)
781130f4520SKenneth D. Merry 				continue;
782bb8f9017SAlexander Motin 			for (j = 0; j < ctx->prev_items; j++) {
783bb8f9017SAlexander Motin 				if (ctx->prev_stats[j].item ==
784bb8f9017SAlexander Motin 				    ctx->cur_stats[i].item)
785bb8f9017SAlexander Motin 					break;
786bb8f9017SAlexander Motin 			}
787bb8f9017SAlexander Motin 			if (j >= ctx->prev_items)
788bb8f9017SAlexander Motin 				j = -1;
789bb8f9017SAlexander Motin 			compute_stats(&ctx->cur_stats[i],
790bb8f9017SAlexander Motin 			    j >= 0 ? &ctx->prev_stats[j] : NULL,
79161639a0aSAlexander Motin 			    etime, &mbsec, &kb_per_transfer,
792130f4520SKenneth D. Merry 			    &transfers_per_sec, &ms_per_transfer,
793130f4520SKenneth D. Merry 			    &ms_per_dma, &dmas_per_sec);
794130f4520SKenneth D. Merry 			if (F_DMA(ctx))
79561639a0aSAlexander Motin 				fprintf(stdout, " %5.1Lf",
796130f4520SKenneth D. Merry 					ms_per_dma);
797bb8f9017SAlexander Motin 			else if (F_TIMEVAL(ctx) != 0)
79861639a0aSAlexander Motin 				fprintf(stdout, " %5.1Lf",
799130f4520SKenneth D. Merry 					ms_per_transfer);
80061639a0aSAlexander Motin 			fprintf(stdout, " %4.0Lf %5.0Lf %4.0Lf",
801130f4520SKenneth D. Merry 				kb_per_transfer, (F_DMA(ctx) == 0) ?
802130f4520SKenneth D. Merry 				transfers_per_sec : dmas_per_sec, mbsec);
8035be4479bSAlexander Motin 			if (++n >= ctx->numdevs)
8045be4479bSAlexander Motin 				break;
805130f4520SKenneth D. Merry 		}
806130f4520SKenneth D. Merry 	}
807130f4520SKenneth D. Merry }
808130f4520SKenneth D. Merry 
8094c163a54SAlan Somers static void
8104c163a54SAlan Somers get_and_print_stats(int fd, struct ctlstat_context *ctx, bool ports)
8114c163a54SAlan Somers {
8124c163a54SAlan Somers 	struct ctl_io_stats *tmp_stats;
8134c163a54SAlan Somers 	int c;
8144c163a54SAlan Somers 
8154c163a54SAlan Somers 	tmp_stats = ctx->prev_stats;
8164c163a54SAlan Somers 	ctx->prev_stats = ctx->cur_stats;
8174c163a54SAlan Somers 	ctx->cur_stats = tmp_stats;
8184c163a54SAlan Somers 	c = ctx->prev_alloc;
8194c163a54SAlan Somers 	ctx->prev_alloc = ctx->cur_alloc;
8204c163a54SAlan Somers 	ctx->cur_alloc = c;
8214c163a54SAlan Somers 	c = ctx->prev_items;
8224c163a54SAlan Somers 	ctx->prev_items = ctx->cur_items;
8234c163a54SAlan Somers 	ctx->cur_items = c;
8244c163a54SAlan Somers 	ctx->prev_time = ctx->cur_time;
8254c163a54SAlan Somers 	ctx->prev_cpu = ctx->cur_cpu;
8264c163a54SAlan Somers 	if (getstats(fd, &ctx->cur_alloc, &ctx->cur_items,
8274c163a54SAlan Somers 	    &ctx->cur_stats, &ctx->cur_time, &ctx->flags, ports) != 0)
8284c163a54SAlan Somers 		errx(1, "error returned from getstats()");
8294c163a54SAlan Somers 
8304c163a54SAlan Somers 	switch(ctx->mode) {
8314c163a54SAlan Somers 	case CTLSTAT_MODE_STANDARD:
8324c163a54SAlan Somers 		ctlstat_standard(ctx);
8334c163a54SAlan Somers 		break;
8344c163a54SAlan Somers 	case CTLSTAT_MODE_DUMP:
8354c163a54SAlan Somers 		ctlstat_dump(ctx);
8364c163a54SAlan Somers 		break;
8374c163a54SAlan Somers 	case CTLSTAT_MODE_JSON:
8384c163a54SAlan Somers 		ctlstat_json(ctx);
8394c163a54SAlan Somers 		break;
8404c163a54SAlan Somers 	case CTLSTAT_MODE_PROMETHEUS:
8414c163a54SAlan Somers 		ctlstat_prometheus(fd, ctx, ports);
8424c163a54SAlan Somers 		break;
8434c163a54SAlan Somers 	default:
8444c163a54SAlan Somers 		break;
8454c163a54SAlan Somers 	}
8464c163a54SAlan Somers }
8474c163a54SAlan Somers 
848130f4520SKenneth D. Merry int
849130f4520SKenneth D. Merry main(int argc, char **argv)
850130f4520SKenneth D. Merry {
851130f4520SKenneth D. Merry 	int c;
852130f4520SKenneth D. Merry 	int count, waittime;
853130f4520SKenneth D. Merry 	int fd, retval;
8545e4b2529SBaptiste Daroussin 	size_t size;
855130f4520SKenneth D. Merry 	struct ctlstat_context ctx;
856130f4520SKenneth D. Merry 
857130f4520SKenneth D. Merry 	/* default values */
858130f4520SKenneth D. Merry 	retval = 0;
859130f4520SKenneth D. Merry 	waittime = 1;
860130f4520SKenneth D. Merry 	count = -1;
861130f4520SKenneth D. Merry 	memset(&ctx, 0, sizeof(ctx));
862130f4520SKenneth D. Merry 	ctx.numdevs = 3;
863130f4520SKenneth D. Merry 	ctx.mode = CTLSTAT_MODE_STANDARD;
864130f4520SKenneth D. Merry 	ctx.flags |= CTLSTAT_FLAG_CPU;
865130f4520SKenneth D. Merry 	ctx.flags |= CTLSTAT_FLAG_FIRST_RUN;
866130f4520SKenneth D. Merry 	ctx.flags |= CTLSTAT_FLAG_HEADER;
867130f4520SKenneth D. Merry 
8685e4b2529SBaptiste Daroussin 	size = sizeof(ctl_stat_bits);
8695e4b2529SBaptiste Daroussin 	if (sysctlbyname("kern.cam.ctl.max_luns", &ctl_stat_bits, &size, NULL,
8705e4b2529SBaptiste Daroussin 	    0) == -1) {
8715e4b2529SBaptiste Daroussin 		/* Backward compatibility for where the sysctl wasn't exposed */
8725e4b2529SBaptiste Daroussin 		ctl_stat_bits = 1024;
8735e4b2529SBaptiste Daroussin 	}
8745e4b2529SBaptiste Daroussin 	ctx.item_mask = bit_alloc(ctl_stat_bits);
8755e4b2529SBaptiste Daroussin 	if (ctx.item_mask == NULL)
8765e4b2529SBaptiste Daroussin 		err(1, "bit_alloc() failed");
8775e4b2529SBaptiste Daroussin 
878130f4520SKenneth D. Merry 	while ((c = getopt(argc, argv, ctlstat_opts)) != -1) {
879130f4520SKenneth D. Merry 		switch (c) {
880130f4520SKenneth D. Merry 		case 'C':
881130f4520SKenneth D. Merry 			ctx.flags &= ~CTLSTAT_FLAG_CPU;
882130f4520SKenneth D. Merry 			break;
883130f4520SKenneth D. Merry 		case 'c':
884130f4520SKenneth D. Merry 			count = atoi(optarg);
885130f4520SKenneth D. Merry 			break;
886130f4520SKenneth D. Merry 		case 'd':
887130f4520SKenneth D. Merry 			ctx.flags |= CTLSTAT_FLAG_DMA_TIME;
888130f4520SKenneth D. Merry 			break;
889130f4520SKenneth D. Merry 		case 'D':
890130f4520SKenneth D. Merry 			ctx.mode = CTLSTAT_MODE_DUMP;
891130f4520SKenneth D. Merry 			waittime = 30;
892130f4520SKenneth D. Merry 			break;
893130f4520SKenneth D. Merry 		case 'h':
894130f4520SKenneth D. Merry 			ctx.flags &= ~CTLSTAT_FLAG_HEADER;
895130f4520SKenneth D. Merry 			break;
896130f4520SKenneth D. Merry 		case 'j':
897130f4520SKenneth D. Merry 			ctx.mode = CTLSTAT_MODE_JSON;
898130f4520SKenneth D. Merry 			waittime = 30;
899130f4520SKenneth D. Merry 			break;
900130f4520SKenneth D. Merry 		case 'l': {
901130f4520SKenneth D. Merry 			int cur_lun;
902130f4520SKenneth D. Merry 
903130f4520SKenneth D. Merry 			cur_lun = atoi(optarg);
9045e4b2529SBaptiste Daroussin 			if (cur_lun > ctl_stat_bits)
905130f4520SKenneth D. Merry 				errx(1, "Invalid LUN number %d", cur_lun);
906130f4520SKenneth D. Merry 
907bb8f9017SAlexander Motin 			if (!F_MASK(&ctx))
908130f4520SKenneth D. Merry 				ctx.numdevs = 1;
909130f4520SKenneth D. Merry 			else
910130f4520SKenneth D. Merry 				ctx.numdevs++;
911bb8f9017SAlexander Motin 			bit_set(ctx.item_mask, cur_lun);
912bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_MASK;
913bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_LUNS;
914130f4520SKenneth D. Merry 			break;
915130f4520SKenneth D. Merry 		}
916130f4520SKenneth D. Merry 		case 'n':
917130f4520SKenneth D. Merry 			ctx.numdevs = atoi(optarg);
918130f4520SKenneth D. Merry 			break;
91961639a0aSAlexander Motin 		case 'p': {
92061639a0aSAlexander Motin 			int cur_port;
92161639a0aSAlexander Motin 
92261639a0aSAlexander Motin 			cur_port = atoi(optarg);
9235e4b2529SBaptiste Daroussin 			if (cur_port > ctl_stat_bits)
924bb8f9017SAlexander Motin 				errx(1, "Invalid port number %d", cur_port);
92561639a0aSAlexander Motin 
926bb8f9017SAlexander Motin 			if (!F_MASK(&ctx))
927bb8f9017SAlexander Motin 				ctx.numdevs = 1;
928bb8f9017SAlexander Motin 			else
929bb8f9017SAlexander Motin 				ctx.numdevs++;
930bb8f9017SAlexander Motin 			bit_set(ctx.item_mask, cur_port);
931bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_MASK;
932bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_PORTS;
93361639a0aSAlexander Motin 			break;
93461639a0aSAlexander Motin 		}
9351a7f22d9SAlan Somers 		case 'P':
9361a7f22d9SAlan Somers 			ctx.mode = CTLSTAT_MODE_PROMETHEUS;
9371a7f22d9SAlan Somers 			break;
938130f4520SKenneth D. Merry 		case 't':
939130f4520SKenneth D. Merry 			ctx.flags |= CTLSTAT_FLAG_TOTALS;
940130f4520SKenneth D. Merry 			break;
941130f4520SKenneth D. Merry 		case 'w':
942130f4520SKenneth D. Merry 			waittime = atoi(optarg);
943130f4520SKenneth D. Merry 			break;
944130f4520SKenneth D. Merry 		default:
945130f4520SKenneth D. Merry 			retval = 1;
946130f4520SKenneth D. Merry 			usage(retval);
947130f4520SKenneth D. Merry 			exit(retval);
948130f4520SKenneth D. Merry 			break;
949130f4520SKenneth D. Merry 		}
950130f4520SKenneth D. Merry 	}
951130f4520SKenneth D. Merry 
952bb8f9017SAlexander Motin 	if (F_LUNS(&ctx) && F_PORTS(&ctx))
953bb8f9017SAlexander Motin 		errx(1, "Options -p and -l are exclusive.");
954bb8f9017SAlexander Motin 
9551a7f22d9SAlan Somers 	if (ctx.mode == CTLSTAT_MODE_PROMETHEUS) {
9561a7f22d9SAlan Somers 		if ((count != -1) ||
9571a7f22d9SAlan Somers 			(waittime != 1) ||
9584c163a54SAlan Somers 			(F_PORTS(&ctx)) ||
9591a7f22d9SAlan Somers 			/* NB: -P could be compatible with -t in the future */
9601a7f22d9SAlan Somers 			(ctx.flags & CTLSTAT_FLAG_TOTALS))
9611a7f22d9SAlan Somers 		{
9624c163a54SAlan Somers 			errx(1, "Option -P is exclusive with -p, -c, -w, and -t");
9631a7f22d9SAlan Somers 		}
9641a7f22d9SAlan Somers 		count = 1;
9651a7f22d9SAlan Somers 	}
9661a7f22d9SAlan Somers 
967bb8f9017SAlexander Motin 	if (!F_LUNS(&ctx) && !F_PORTS(&ctx)) {
968bb8f9017SAlexander Motin 		if (F_TOTALS(&ctx))
969bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_PORTS;
970bb8f9017SAlexander Motin 		else
971bb8f9017SAlexander Motin 			ctx.flags |= CTLSTAT_FLAG_LUNS;
972bb8f9017SAlexander Motin 	}
973bb8f9017SAlexander Motin 
974130f4520SKenneth D. Merry 	if ((fd = open(CTL_DEFAULT_DEV, O_RDWR)) == -1)
975130f4520SKenneth D. Merry 		err(1, "cannot open %s", CTL_DEFAULT_DEV);
976130f4520SKenneth D. Merry 
9774c163a54SAlan Somers 	if (ctx.mode == CTLSTAT_MODE_PROMETHEUS) {
9784c163a54SAlan Somers 		/*
9794c163a54SAlan Somers 		 * NB: Some clients will print a warning if we don't set
9804c163a54SAlan Somers 		 * Content-Length, but they still work.  And the data still
9814c163a54SAlan Somers 		 * gets into Prometheus.
9824c163a54SAlan Somers 		 */
9834c163a54SAlan Somers 		printf("HTTP/1.1 200 OK\r\n"
9844c163a54SAlan Somers 		       "Connection: close\r\n"
9854c163a54SAlan Somers 		       "Content-Type: text/plain; version=0.0.4\r\n"
9864c163a54SAlan Somers 		       "\r\n");
9874c163a54SAlan Somers 	}
988130f4520SKenneth D. Merry 
9894c163a54SAlan Somers 	for (;count != 0;) {
9904c163a54SAlan Somers 		bool ports;
9914c163a54SAlan Somers 
9924c163a54SAlan Somers 		if (ctx.mode == CTLSTAT_MODE_PROMETHEUS) {
9934c163a54SAlan Somers 			get_and_print_stats(fd, &ctx, false);
9944c163a54SAlan Somers 			get_and_print_stats(fd, &ctx, true);
9954c163a54SAlan Somers 		} else {
9964c163a54SAlan Somers 			ports = ctx.flags & CTLSTAT_FLAG_PORTS;
9974c163a54SAlan Somers 			get_and_print_stats(fd, &ctx, ports);
998130f4520SKenneth D. Merry 		}
999130f4520SKenneth D. Merry 
1000130f4520SKenneth D. Merry 		fprintf(stdout, "\n");
1001fcc87341SAlexander Motin 		fflush(stdout);
1002130f4520SKenneth D. Merry 		ctx.flags &= ~CTLSTAT_FLAG_FIRST_RUN;
1003130f4520SKenneth D. Merry 		if (count != 1)
1004130f4520SKenneth D. Merry 			sleep(waittime);
1005130f4520SKenneth D. Merry 		if (count > 0)
1006130f4520SKenneth D. Merry 			count--;
1007130f4520SKenneth D. Merry 	}
1008130f4520SKenneth D. Merry 
1009130f4520SKenneth D. Merry 	exit (retval);
1010130f4520SKenneth D. Merry }
1011130f4520SKenneth D. Merry 
1012130f4520SKenneth D. Merry /*
1013130f4520SKenneth D. Merry  * vim: ts=8
1014130f4520SKenneth D. Merry  */
1015