xref: /titanic_50/usr/src/cmd/smbsrv/smbstat/smbstat.c (revision 148c5f43199ca0b43fc8e3b643aab11cd66ea327)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw 
22da6c28aaSamw /*
23*148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw /*
27da6c28aaSamw  * smbstat: Server Message Block File System statistics
28*148c5f43SAlan Wright  *
29*148c5f43SAlan Wright  * The statistics this CLI displays come from two sources:
30*148c5f43SAlan Wright  *
31*148c5f43SAlan Wright  * 1) The kernel module 'smbsrv'.
32*148c5f43SAlan Wright  * 2) The SMB workers task queue statistics the task queue manager of Solaris
33*148c5f43SAlan Wright  *    maintains.
34*148c5f43SAlan Wright  *
35*148c5f43SAlan Wright  * The flow of the code is the following:
36*148c5f43SAlan Wright  *
37*148c5f43SAlan Wright  *
38*148c5f43SAlan Wright  * 			+----------------+
39*148c5f43SAlan Wright  * 			| Initialization |
40*148c5f43SAlan Wright  * 			+----------------+
41*148c5f43SAlan Wright  *				|
42*148c5f43SAlan Wright  *				|
43*148c5f43SAlan Wright  *				v
44*148c5f43SAlan Wright  *		  +--------------------------*
45*148c5f43SAlan Wright  *		  | Take a snapshot the data | <--------+
46*148c5f43SAlan Wright  *		  +--------------------------+		|
47*148c5f43SAlan Wright  *				|			|
48*148c5f43SAlan Wright  * 				|			|
49*148c5f43SAlan Wright  *				v			|
50*148c5f43SAlan Wright  *		    +----------------------+		|
51*148c5f43SAlan Wright  *		    | Process the snapshot |		|
52*148c5f43SAlan Wright  *		    +----------------------+		|
53*148c5f43SAlan Wright  *				|			|
54*148c5f43SAlan Wright  *				|			|
55*148c5f43SAlan Wright  *				v			|
56*148c5f43SAlan Wright  *	     +------------------------------------+	|
57*148c5f43SAlan Wright  *	     | Print the result of the processing |	|
58*148c5f43SAlan Wright  *	     +------------------------------------+	|
59*148c5f43SAlan Wright  *				|			|
60*148c5f43SAlan Wright  *				|			|
61*148c5f43SAlan Wright  *				v			|
62*148c5f43SAlan Wright  *		Yes	---------------			|
63*148c5f43SAlan Wright  *	+------------ < interval == 0 ? >		|
64*148c5f43SAlan Wright  * 	|		---------------			|
65*148c5f43SAlan Wright  *	|		       |			|
66*148c5f43SAlan Wright  * 	|		       | No			|
67*148c5f43SAlan Wright  * 	|		       v			|
68*148c5f43SAlan Wright  *	|	   +------------------------+		|
69*148c5f43SAlan Wright  * 	|	   | Sleep for the duration | ----------+
70*148c5f43SAlan Wright  * 	|	   |   of the interval.     |
71*148c5f43SAlan Wright  * 	|	   +------------------------+
72*148c5f43SAlan Wright  * 	|
73*148c5f43SAlan Wright  * 	+---------------------+
74*148c5f43SAlan Wright  *			      |
75*148c5f43SAlan Wright  *			      v
76*148c5f43SAlan Wright  *
77*148c5f43SAlan Wright  *			    Exit
78*148c5f43SAlan Wright  *
79*148c5f43SAlan Wright  * There are two sets of snapshots. One set for the smbsrv module and the other
80*148c5f43SAlan Wright  * for the task queue (SMB workers). Each set contains 2 snapshots. One is
81*148c5f43SAlan Wright  * labeled 'current' the other one 'previous'. Their role changes after each
82*148c5f43SAlan Wright  * snapshot. The 'current' becomes 'previous' and vice versa.
83*148c5f43SAlan Wright  * The first snapshot taken is compared against the data gathered since the
84*148c5f43SAlan Wright  * smbsrv module was loaded. Subsequent snapshots will be compared against the
85*148c5f43SAlan Wright  * previous snapshot.
86da6c28aaSamw  */
87*148c5f43SAlan Wright 
88da6c28aaSamw #include <stdio.h>
89da6c28aaSamw #include <stdlib.h>
90*148c5f43SAlan Wright #include <unistd.h>
91da6c28aaSamw #include <kstat.h>
92da6c28aaSamw #include <stdarg.h>
93da6c28aaSamw #include <errno.h>
94da6c28aaSamw #include <inttypes.h>
95da6c28aaSamw #include <strings.h>
96da6c28aaSamw #include <utility.h>
97da6c28aaSamw #include <libintl.h>
98da6c28aaSamw #include <zone.h>
99*148c5f43SAlan Wright #include <termios.h>
100*148c5f43SAlan Wright #include <stropts.h>
101*148c5f43SAlan Wright #include <math.h>
102*148c5f43SAlan Wright #include <umem.h>
103*148c5f43SAlan Wright #include <locale.h>
1046537f381Sas200622 #include <smbsrv/smb_kstat.h>
105da6c28aaSamw 
106*148c5f43SAlan Wright #if !defined(TEXT_DOMAIN)
107*148c5f43SAlan Wright #define	TEXT_DOMAIN "SYS_TEST"
108*148c5f43SAlan Wright #endif /* TEXT_DOMAIN */
109da6c28aaSamw 
110*148c5f43SAlan Wright #define	SMBSTAT_ID_NO_CPU	-1
111*148c5f43SAlan Wright #define	SMBSTAT_SNAPSHOT_COUNT	2		/* Must be a power of 2 */
112*148c5f43SAlan Wright #define	SMBSTAT_SNAPSHOT_MASK	(SMBSTAT_SNAPSHOT_COUNT - 1)
113*148c5f43SAlan Wright 
114*148c5f43SAlan Wright #define	SMBSTAT_HELP	\
115*148c5f43SAlan Wright 	"Usage: smbstat [-acnrtuz] [interval]\n" \
116*148c5f43SAlan Wright 	"    -c: display counters\n" \
117*148c5f43SAlan Wright 	"    -t: display throughput\n" \
118*148c5f43SAlan Wright 	"    -u: display utilization\n" \
119*148c5f43SAlan Wright 	"    -r: display requests\n" \
120*148c5f43SAlan Wright 	"        -a: all the requests (supported and unsupported)\n" \
121*148c5f43SAlan Wright 	"        -z: skip the requests not received\n" \
122*148c5f43SAlan Wright 	"        -n: display in alphabetic order\n" \
123*148c5f43SAlan Wright 	"    interval: refresh cycle in seconds\n"
124*148c5f43SAlan Wright 
125*148c5f43SAlan Wright #define	SMBSRV_COUNTERS_BANNER	"\n  nbt   tcp users trees files pipes\n"
126*148c5f43SAlan Wright #define	SMBSRV_COUNTERS_FORMAT	"%5d %5d %5d %5d %5d %5d\n"
127*148c5f43SAlan Wright 
128*148c5f43SAlan Wright #define	SMBSRV_THROUGHPUT_BANNER	\
129*148c5f43SAlan Wright 	"\nrbytes/s   tbytes/s    reqs/s     reads/s   writes/s\n"
130*148c5f43SAlan Wright #define	SMBSRV_THROUGHPUT_FORMAT	\
131*148c5f43SAlan Wright 	"%1.3e  %1.3e  %1.3e  %1.3e  %1.3e\n"
132*148c5f43SAlan Wright 
133*148c5f43SAlan Wright #define	SMBSRV_UTILIZATION_BANNER	\
134*148c5f43SAlan Wright 	"\n  wcnt       rcnt       wtime      rtime" \
135*148c5f43SAlan Wright 	"     w%%   r%%   u%%  sat usr%% sys%%  idle%%\n"
136*148c5f43SAlan Wright #define	SMBSRV_UTILIZATION_FORMAT	\
137*148c5f43SAlan Wright 	"%1.3e  %1.3e  %1.3e  %1.3e  %3.0f  %3.0f  %3.0f  %s " \
138*148c5f43SAlan Wright 	"%3.0f  %3.0f    %3.0f\n"
139*148c5f43SAlan Wright 
140*148c5f43SAlan Wright #define	SMBSRV_REQUESTS_BANNER	\
141*148c5f43SAlan Wright 	"\n%30s code   %%   rbytes/s   tbytes/s     req/s     rt-mean"	\
142*148c5f43SAlan Wright 	"   rt-stddev\n"
143*148c5f43SAlan Wright #define	SMBSRV_REQUESTS_FORMAT	\
144*148c5f43SAlan Wright 	"%30s  %02X   %3.0f  %1.3e  %1.3e  %1.3e  %1.3e  %1.3e\n"
145*148c5f43SAlan Wright 
146*148c5f43SAlan Wright typedef enum {
147*148c5f43SAlan Wright 	CPU_TICKS_IDLE = 0,
148*148c5f43SAlan Wright 	CPU_TICKS_USER,
149*148c5f43SAlan Wright 	CPU_TICKS_KERNEL,
150*148c5f43SAlan Wright 	CPU_TICKS_SENTINEL
151*148c5f43SAlan Wright } cpu_state_idx_t;
152*148c5f43SAlan Wright 
153*148c5f43SAlan Wright typedef struct smbstat_cpu_snapshot {
154*148c5f43SAlan Wright 	processorid_t	cs_id;
155*148c5f43SAlan Wright 	int		cs_state;
156*148c5f43SAlan Wright 	uint64_t	cs_ticks[CPU_TICKS_SENTINEL];
157*148c5f43SAlan Wright } smbstat_cpu_snapshot_t;
158*148c5f43SAlan Wright 
159*148c5f43SAlan Wright typedef struct smbstat_srv_snapshot {
160*148c5f43SAlan Wright 	hrtime_t	ss_snaptime;
161*148c5f43SAlan Wright 	smbsrv_kstats_t	ss_data;
162*148c5f43SAlan Wright } smbstat_srv_snapshot_t;
163*148c5f43SAlan Wright 
164*148c5f43SAlan Wright typedef struct smbstat_wrk_snapshot {
165*148c5f43SAlan Wright 	uint64_t	ws_maxthreads;
166*148c5f43SAlan Wright 	uint64_t	ws_bnalloc;
167*148c5f43SAlan Wright } smbstat_wrk_snapshot_t;
168*148c5f43SAlan Wright 
169*148c5f43SAlan Wright typedef struct smbstat_req_info {
170*148c5f43SAlan Wright 	char		ri_name[KSTAT_STRLEN];
171*148c5f43SAlan Wright 	int		ri_opcode;
172*148c5f43SAlan Wright 	double		ri_pct;
173*148c5f43SAlan Wright 	double		ri_tbs;
174*148c5f43SAlan Wright 	double		ri_rbs;
175*148c5f43SAlan Wright 	double		ri_rqs;
176*148c5f43SAlan Wright 	double		ri_stddev;
177*148c5f43SAlan Wright 	double		ri_mean;
178*148c5f43SAlan Wright } smbstat_req_info_t;
179*148c5f43SAlan Wright 
180*148c5f43SAlan Wright typedef struct smbstat_srv_info {
181*148c5f43SAlan Wright 	double		si_hretime;
182*148c5f43SAlan Wright 	double		si_etime;
183*148c5f43SAlan Wright 	double		si_total_nreqs;
184*148c5f43SAlan Wright 	/*
185*148c5f43SAlan Wright 	 * Counters
186*148c5f43SAlan Wright 	 */
187*148c5f43SAlan Wright 	uint32_t	si_nbt_sess;	/* NBT sessions */
188*148c5f43SAlan Wright 	uint32_t	si_tcp_sess;	/* TCP sessions */
189*148c5f43SAlan Wright 	uint32_t	si_users;	/* Users logged in */
190*148c5f43SAlan Wright 	uint32_t	si_trees;	/* Trees connected */
191*148c5f43SAlan Wright 	uint32_t	si_files;	/* Open files */
192*148c5f43SAlan Wright 	uint32_t	si_pipes;	/* Open pipes */
193*148c5f43SAlan Wright 	/*
194*148c5f43SAlan Wright 	 * Throughput of the server
195*148c5f43SAlan Wright 	 */
196*148c5f43SAlan Wright 	double		si_tbs;		/* Bytes transmitted / second */
197*148c5f43SAlan Wright 	double		si_rbs;		/* Bytes received / second */
198*148c5f43SAlan Wright 	double		si_rqs;		/* Requests treated / second */
199*148c5f43SAlan Wright 	double		si_rds;		/* Reads treated / second */
200*148c5f43SAlan Wright 	double		si_wrs;		/* Writes treated / second */
201*148c5f43SAlan Wright 	/*
202*148c5f43SAlan Wright 	 * Utilization of the server
203*148c5f43SAlan Wright 	 */
204*148c5f43SAlan Wright 	double		si_wpct;	/* */
205*148c5f43SAlan Wright 	double		si_rpct;	/* */
206*148c5f43SAlan Wright 	double		si_upct;	/* Utilization in % */
207*148c5f43SAlan Wright 	double		si_avw;		/* Average number of requests waiting */
208*148c5f43SAlan Wright 	double		si_avr;		/* Average number of requests running */
209*148c5f43SAlan Wright 	double		si_wserv;	/* Average waiting time */
210*148c5f43SAlan Wright 	double		si_rserv;	/* Average running time */
211*148c5f43SAlan Wright 	boolean_t	si_sat;
212*148c5f43SAlan Wright 	double		si_ticks[CPU_TICKS_SENTINEL];
213*148c5f43SAlan Wright 	/*
214*148c5f43SAlan Wright 	 * Latency & Throughput per request
215*148c5f43SAlan Wright 	 */
216*148c5f43SAlan Wright 	smbstat_req_info_t	si_reqs[SMB_COM_NUM];
217*148c5f43SAlan Wright } smbstat_srv_info_t;
218*148c5f43SAlan Wright 
2196537f381Sas200622 static void smbstat_init(void);
2206537f381Sas200622 static void smbstat_fini(void);
221*148c5f43SAlan Wright static void smbstat_kstat_snapshot(void);
222*148c5f43SAlan Wright static void smbstat_kstat_process(void);
223*148c5f43SAlan Wright static void smbstat_kstat_print(void);
224*148c5f43SAlan Wright 
225*148c5f43SAlan Wright static void smbstat_print_counters(void);
226*148c5f43SAlan Wright static void smbstat_print_throughput(void);
227*148c5f43SAlan Wright static void smbstat_print_utilization(void);
228*148c5f43SAlan Wright static void smbstat_print_requests(void);
229*148c5f43SAlan Wright 
230*148c5f43SAlan Wright static void smbstat_cpu_init(void);
231*148c5f43SAlan Wright static void smbstat_cpu_fini(void);
232*148c5f43SAlan Wright static smbstat_cpu_snapshot_t *smbstat_cpu_current_snapshot(void);
233*148c5f43SAlan Wright static smbstat_cpu_snapshot_t *smbstat_cpu_previous_snapshot(void);
234*148c5f43SAlan Wright static void smbstat_cpu_snapshot(void);
235*148c5f43SAlan Wright static void smbstat_cpu_process(void);
236*148c5f43SAlan Wright 
237*148c5f43SAlan Wright static void smbstat_wrk_init(void);
238*148c5f43SAlan Wright static void smbstat_wrk_fini(void);
239*148c5f43SAlan Wright static void smbstat_wrk_snapshot(void);
240*148c5f43SAlan Wright static void smbstat_wrk_process(void);
241*148c5f43SAlan Wright static smbstat_wrk_snapshot_t *smbstat_wrk_current_snapshot(void);
242*148c5f43SAlan Wright 
243*148c5f43SAlan Wright static void smbstat_srv_init(void);
244*148c5f43SAlan Wright static void smbstat_srv_fini(void);
245*148c5f43SAlan Wright static void smbstat_srv_snapshot(void);
246*148c5f43SAlan Wright static void smbstat_srv_process(void);
247*148c5f43SAlan Wright static void smbstat_srv_process_counters(smbstat_srv_snapshot_t *);
248*148c5f43SAlan Wright static void smbstat_srv_process_throughput(smbstat_srv_snapshot_t *,
249*148c5f43SAlan Wright     smbstat_srv_snapshot_t *);
250*148c5f43SAlan Wright static void smbstat_srv_process_utilization(smbstat_srv_snapshot_t *,
251*148c5f43SAlan Wright     smbstat_srv_snapshot_t *);
252*148c5f43SAlan Wright static void smbstat_srv_process_requests(smbstat_srv_snapshot_t *,
253*148c5f43SAlan Wright     smbstat_srv_snapshot_t *);
254*148c5f43SAlan Wright static smbstat_srv_snapshot_t *smbstat_srv_current_snapshot(void);
255*148c5f43SAlan Wright static smbstat_srv_snapshot_t *smbstat_srv_previous_snapshot(void);
256*148c5f43SAlan Wright 
257*148c5f43SAlan Wright static void *smbstat_zalloc(size_t);
258*148c5f43SAlan Wright static void smbstat_free(void *, size_t);
259da6c28aaSamw static void smbstat_fail(int, char *, ...);
260*148c5f43SAlan Wright static void smbstat_snapshot_inc_idx(void);
261*148c5f43SAlan Wright static void smbstat_usage(FILE *, int);
262*148c5f43SAlan Wright static uint_t smbstat_strtoi(char const *, char *);
263*148c5f43SAlan Wright static double smbstat_hrtime_delta(hrtime_t, hrtime_t);
264*148c5f43SAlan Wright static double smbstat_sub_64(uint64_t, uint64_t);
265*148c5f43SAlan Wright static void smbstat_req_order(void);
266*148c5f43SAlan Wright static double smbstat_zero(double);
267*148c5f43SAlan Wright static void smbstat_termio_init(void);
268da6c28aaSamw 
269*148c5f43SAlan Wright #pragma does_not_return(smbstat_fail, smbstat_usage)
270da6c28aaSamw 
271*148c5f43SAlan Wright static char *smbstat_cpu_states[CPU_TICKS_SENTINEL] = {
272*148c5f43SAlan Wright 	"cpu_ticks_idle",
273*148c5f43SAlan Wright 	"cpu_ticks_user",
274*148c5f43SAlan Wright 	"cpu_ticks_kernel"
275*148c5f43SAlan Wright };
276*148c5f43SAlan Wright 
277*148c5f43SAlan Wright static boolean_t	smbstat_opt_a = B_FALSE;	/* all */
278*148c5f43SAlan Wright static boolean_t	smbstat_opt_c = B_FALSE;	/* counters */
279*148c5f43SAlan Wright static boolean_t	smbstat_opt_n = B_FALSE;	/* by name */
280*148c5f43SAlan Wright static boolean_t	smbstat_opt_u = B_FALSE;	/* utilization */
281*148c5f43SAlan Wright static boolean_t	smbstat_opt_t = B_FALSE;	/* throughput */
282*148c5f43SAlan Wright static boolean_t	smbstat_opt_r = B_FALSE;	/* requests */
283*148c5f43SAlan Wright static boolean_t	smbstat_opt_z = B_FALSE;	/* non-zero requests */
284*148c5f43SAlan Wright 
285*148c5f43SAlan Wright static uint_t		smbstat_interval = 0;
286*148c5f43SAlan Wright static long		smbstat_nrcpus = 0;
287*148c5f43SAlan Wright static kstat_ctl_t	*smbstat_ksc = NULL;
288*148c5f43SAlan Wright static kstat_t		*smbstat_srv_ksp = NULL;
289*148c5f43SAlan Wright static kstat_t		*smbstat_wrk_ksp = NULL;
290*148c5f43SAlan Wright static struct winsize	smbstat_ws;
291*148c5f43SAlan Wright static uint16_t		smbstat_rows = 0;
292*148c5f43SAlan Wright 
293*148c5f43SAlan Wright static int smbstat_snapshot_idx = 0;
294*148c5f43SAlan Wright static smbstat_cpu_snapshot_t *smbstat_cpu_snapshots[SMBSTAT_SNAPSHOT_COUNT];
295*148c5f43SAlan Wright static smbstat_srv_snapshot_t smbstat_srv_snapshots[SMBSTAT_SNAPSHOT_COUNT];
296*148c5f43SAlan Wright static smbstat_wrk_snapshot_t smbstat_wrk_snapshots[SMBSTAT_SNAPSHOT_COUNT];
297*148c5f43SAlan Wright static smbstat_srv_info_t smbstat_srv_info;
298*148c5f43SAlan Wright 
299*148c5f43SAlan Wright /*
300*148c5f43SAlan Wright  * main
301*148c5f43SAlan Wright  */
302da6c28aaSamw int
303da6c28aaSamw main(int argc, char *argv[])
304da6c28aaSamw {
305da6c28aaSamw 	int	c;
306*148c5f43SAlan Wright 
307*148c5f43SAlan Wright 	(void) setlocale(LC_ALL, "");
308*148c5f43SAlan Wright 	(void) textdomain(TEXT_DOMAIN);
309da6c28aaSamw 
310da6c28aaSamw 	if (getzoneid() != GLOBAL_ZONEID) {
311da6c28aaSamw 		(void) fprintf(stderr,
312da6c28aaSamw 		    gettext("%s: Cannot execute in non-global zone.\n"),
313da6c28aaSamw 		    argv[0]);
314da6c28aaSamw 		return (0);
315da6c28aaSamw 	}
316da6c28aaSamw 
317da6c28aaSamw 	if (is_system_labeled()) {
318da6c28aaSamw 		(void) fprintf(stderr,
319da6c28aaSamw 		    gettext("%s: Trusted Extensions not supported.\n"),
320da6c28aaSamw 		    argv[0]);
321da6c28aaSamw 		return (0);
322da6c28aaSamw 	}
323da6c28aaSamw 
324*148c5f43SAlan Wright 	while ((c = getopt(argc, argv, "achnrtuz")) != EOF) {
325da6c28aaSamw 		switch (c) {
326*148c5f43SAlan Wright 		case 'a':
327*148c5f43SAlan Wright 			smbstat_opt_a = B_TRUE;
328da6c28aaSamw 			break;
329*148c5f43SAlan Wright 		case 'n':
330*148c5f43SAlan Wright 			smbstat_opt_n = B_TRUE;
331da6c28aaSamw 			break;
332*148c5f43SAlan Wright 		case 'u':
333*148c5f43SAlan Wright 			smbstat_opt_u = B_TRUE;
334*148c5f43SAlan Wright 			break;
335*148c5f43SAlan Wright 		case 'c':
336*148c5f43SAlan Wright 			smbstat_opt_c = B_TRUE;
337*148c5f43SAlan Wright 			break;
338*148c5f43SAlan Wright 		case 'r':
339*148c5f43SAlan Wright 			smbstat_opt_r = B_TRUE;
340*148c5f43SAlan Wright 			break;
341*148c5f43SAlan Wright 		case 't':
342*148c5f43SAlan Wright 			smbstat_opt_t = B_TRUE;
343*148c5f43SAlan Wright 			break;
344*148c5f43SAlan Wright 		case 'z':
345*148c5f43SAlan Wright 			smbstat_opt_z = B_TRUE;
346*148c5f43SAlan Wright 			break;
347*148c5f43SAlan Wright 		case 'h':
348*148c5f43SAlan Wright 			smbstat_usage(stdout, 0);
349da6c28aaSamw 		default:
350*148c5f43SAlan Wright 			smbstat_usage(stderr, 1);
351da6c28aaSamw 		}
352da6c28aaSamw 	}
353da6c28aaSamw 
354*148c5f43SAlan Wright 	if (!smbstat_opt_u &&
355*148c5f43SAlan Wright 	    !smbstat_opt_c &&
356*148c5f43SAlan Wright 	    !smbstat_opt_r &&
357*148c5f43SAlan Wright 	    !smbstat_opt_t) {
358*148c5f43SAlan Wright 		/* Default options when none is specified. */
359*148c5f43SAlan Wright 		smbstat_opt_u = B_TRUE;
360*148c5f43SAlan Wright 		smbstat_opt_t = B_TRUE;
361da6c28aaSamw 	}
362da6c28aaSamw 
363*148c5f43SAlan Wright 	if (optind < argc) {
364*148c5f43SAlan Wright 		smbstat_interval =
365*148c5f43SAlan Wright 		    smbstat_strtoi(argv[optind], "invalid count");
366*148c5f43SAlan Wright 		optind++;
367*148c5f43SAlan Wright 	}
368*148c5f43SAlan Wright 
369*148c5f43SAlan Wright 	if ((argc - optind) > 1)
370*148c5f43SAlan Wright 		smbstat_usage(stderr, 1);
371*148c5f43SAlan Wright 
372*148c5f43SAlan Wright 	(void) atexit(smbstat_fini);
3736537f381Sas200622 	smbstat_init();
374*148c5f43SAlan Wright 	for (;;) {
375*148c5f43SAlan Wright 		smbstat_kstat_snapshot();
376*148c5f43SAlan Wright 		smbstat_kstat_process();
377*148c5f43SAlan Wright 		smbstat_kstat_print();
378*148c5f43SAlan Wright 		if (smbstat_interval == 0)
379*148c5f43SAlan Wright 			break;
380*148c5f43SAlan Wright 		(void) sleep(smbstat_interval);
381*148c5f43SAlan Wright 		smbstat_snapshot_inc_idx();
382da6c28aaSamw 	}
383da6c28aaSamw 	return (0);
384da6c28aaSamw }
385da6c28aaSamw 
386*148c5f43SAlan Wright /*
387*148c5f43SAlan Wright  * smbstat_init
388*148c5f43SAlan Wright  *
389*148c5f43SAlan Wright  * Global initialization.
390*148c5f43SAlan Wright  */
391da6c28aaSamw static void
3926537f381Sas200622 smbstat_init(void)
393da6c28aaSamw {
394*148c5f43SAlan Wright 	if ((smbstat_ksc = kstat_open()) == NULL)
395da6c28aaSamw 		smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat"));
396da6c28aaSamw 
397*148c5f43SAlan Wright 	smbstat_cpu_init();
398*148c5f43SAlan Wright 	smbstat_srv_init();
399*148c5f43SAlan Wright 	smbstat_wrk_init();
400*148c5f43SAlan Wright 	smbstat_req_order();
401da6c28aaSamw }
402da6c28aaSamw 
403*148c5f43SAlan Wright /*
404*148c5f43SAlan Wright  * smbstat_fini
405*148c5f43SAlan Wright  *
406*148c5f43SAlan Wright  * Releases the resources smbstat_init() allocated.
407*148c5f43SAlan Wright  */
4086537f381Sas200622 static void
4096537f381Sas200622 smbstat_fini(void)
4106537f381Sas200622 {
411*148c5f43SAlan Wright 	smbstat_wrk_fini();
412*148c5f43SAlan Wright 	smbstat_srv_fini();
413*148c5f43SAlan Wright 	smbstat_cpu_fini();
414*148c5f43SAlan Wright 	(void) kstat_close(smbstat_ksc);
4156537f381Sas200622 }
4166537f381Sas200622 
417*148c5f43SAlan Wright /*
418*148c5f43SAlan Wright  * smbstat_kstat_snapshot
419*148c5f43SAlan Wright  *
420*148c5f43SAlan Wright  * Takes a snapshot of the data.
421*148c5f43SAlan Wright  */
422*148c5f43SAlan Wright static void
423*148c5f43SAlan Wright smbstat_kstat_snapshot(void)
424da6c28aaSamw {
425*148c5f43SAlan Wright 	smbstat_cpu_snapshot();
426*148c5f43SAlan Wright 	smbstat_srv_snapshot();
427*148c5f43SAlan Wright 	smbstat_wrk_snapshot();
428da6c28aaSamw }
429*148c5f43SAlan Wright 
430*148c5f43SAlan Wright /*
431*148c5f43SAlan Wright  * smbstat_kstat_process
432*148c5f43SAlan Wright  */
433*148c5f43SAlan Wright static void
434*148c5f43SAlan Wright smbstat_kstat_process(void)
435*148c5f43SAlan Wright {
436*148c5f43SAlan Wright 	smbstat_cpu_process();
437*148c5f43SAlan Wright 	smbstat_srv_process();
438*148c5f43SAlan Wright 	smbstat_wrk_process();
439*148c5f43SAlan Wright }
440*148c5f43SAlan Wright 
441*148c5f43SAlan Wright /*
442*148c5f43SAlan Wright  * smbstat_kstat_print
443*148c5f43SAlan Wright  *
444*148c5f43SAlan Wright  * Print the data processed.
445*148c5f43SAlan Wright  */
446*148c5f43SAlan Wright static void
447*148c5f43SAlan Wright smbstat_kstat_print(void)
448*148c5f43SAlan Wright {
449*148c5f43SAlan Wright 	smbstat_termio_init();
450*148c5f43SAlan Wright 	smbstat_print_counters();
451*148c5f43SAlan Wright 	smbstat_print_throughput();
452*148c5f43SAlan Wright 	smbstat_print_utilization();
453*148c5f43SAlan Wright 	smbstat_print_requests();
454*148c5f43SAlan Wright }
455*148c5f43SAlan Wright 
456*148c5f43SAlan Wright /*
457*148c5f43SAlan Wright  * smbstat_print_counters
458*148c5f43SAlan Wright  *
459*148c5f43SAlan Wright  * Displays the SMB server counters (session, users...).
460*148c5f43SAlan Wright  */
461*148c5f43SAlan Wright static void
462*148c5f43SAlan Wright smbstat_print_counters(void)
463*148c5f43SAlan Wright {
464*148c5f43SAlan Wright 	if (!smbstat_opt_c)
465*148c5f43SAlan Wright 		return;
466*148c5f43SAlan Wright 
467*148c5f43SAlan Wright 	if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_t ||
468*148c5f43SAlan Wright 	    (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
469*148c5f43SAlan Wright 		(void) printf(SMBSRV_COUNTERS_BANNER);
470*148c5f43SAlan Wright 		smbstat_rows = 1;
471*148c5f43SAlan Wright 	}
472*148c5f43SAlan Wright 
473*148c5f43SAlan Wright 	(void) printf(SMBSRV_COUNTERS_FORMAT,
474*148c5f43SAlan Wright 	    smbstat_srv_info.si_nbt_sess,
475*148c5f43SAlan Wright 	    smbstat_srv_info.si_tcp_sess,
476*148c5f43SAlan Wright 	    smbstat_srv_info.si_users,
477*148c5f43SAlan Wright 	    smbstat_srv_info.si_trees,
478*148c5f43SAlan Wright 	    smbstat_srv_info.si_files,
479*148c5f43SAlan Wright 	    smbstat_srv_info.si_pipes);
480*148c5f43SAlan Wright 
481*148c5f43SAlan Wright 	++smbstat_rows;
482*148c5f43SAlan Wright }
483*148c5f43SAlan Wright /*
484*148c5f43SAlan Wright  * smbstat_print_throughput
485*148c5f43SAlan Wright  *
486*148c5f43SAlan Wright  * Formats the SMB server throughput output.
487*148c5f43SAlan Wright  */
488*148c5f43SAlan Wright static void
489*148c5f43SAlan Wright smbstat_print_throughput(void)
490*148c5f43SAlan Wright {
491*148c5f43SAlan Wright 	if (!smbstat_opt_t)
492*148c5f43SAlan Wright 		return;
493*148c5f43SAlan Wright 
494*148c5f43SAlan Wright 	if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_c ||
495*148c5f43SAlan Wright 	    (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
496*148c5f43SAlan Wright 		(void) printf(SMBSRV_THROUGHPUT_BANNER);
497*148c5f43SAlan Wright 		smbstat_rows = 1;
498*148c5f43SAlan Wright 	}
499*148c5f43SAlan Wright 	(void) printf(SMBSRV_THROUGHPUT_FORMAT,
500*148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_rbs),
501*148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_tbs),
502*148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_rqs),
503*148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_rds),
504*148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_wrs));
505*148c5f43SAlan Wright 
506*148c5f43SAlan Wright 	++smbstat_rows;
507*148c5f43SAlan Wright }
508*148c5f43SAlan Wright 
509*148c5f43SAlan Wright /*
510*148c5f43SAlan Wright  * smbstat_print_utilization
511*148c5f43SAlan Wright  */
512*148c5f43SAlan Wright static void
513*148c5f43SAlan Wright smbstat_print_utilization(void)
514*148c5f43SAlan Wright {
515*148c5f43SAlan Wright 	char	*sat;
516*148c5f43SAlan Wright 	if (!smbstat_opt_u)
517*148c5f43SAlan Wright 		return;
518*148c5f43SAlan Wright 
519*148c5f43SAlan Wright 	if (smbstat_opt_t || smbstat_opt_r || smbstat_opt_c ||
520*148c5f43SAlan Wright 	    (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
521*148c5f43SAlan Wright 		(void) printf(SMBSRV_UTILIZATION_BANNER);
522*148c5f43SAlan Wright 		smbstat_rows = 1;
523*148c5f43SAlan Wright 	}
524*148c5f43SAlan Wright 
525*148c5f43SAlan Wright 	if (smbstat_srv_info.si_sat)
526*148c5f43SAlan Wright 		sat = "yes";
527*148c5f43SAlan Wright 	else
528*148c5f43SAlan Wright 		sat = "no ";
529*148c5f43SAlan Wright 
530*148c5f43SAlan Wright 	(void) printf(SMBSRV_UTILIZATION_FORMAT,
531*148c5f43SAlan Wright 	    smbstat_srv_info.si_avw,
532*148c5f43SAlan Wright 	    smbstat_srv_info.si_avr,
533*148c5f43SAlan Wright 	    smbstat_srv_info.si_wserv,
534*148c5f43SAlan Wright 	    smbstat_srv_info.si_rserv,
535*148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_wpct),
536*148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_rpct),
537*148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_upct),
538*148c5f43SAlan Wright 	    sat,
539*148c5f43SAlan Wright 	    smbstat_srv_info.si_ticks[CPU_TICKS_USER],
540*148c5f43SAlan Wright 	    smbstat_srv_info.si_ticks[CPU_TICKS_KERNEL],
541*148c5f43SAlan Wright 	    smbstat_srv_info.si_ticks[CPU_TICKS_IDLE]);
542*148c5f43SAlan Wright 
543*148c5f43SAlan Wright 	++smbstat_rows;
544*148c5f43SAlan Wright }
545*148c5f43SAlan Wright 
546*148c5f43SAlan Wright /*
547*148c5f43SAlan Wright  * smbstat_print_requests
548*148c5f43SAlan Wright  */
549*148c5f43SAlan Wright static void
550*148c5f43SAlan Wright smbstat_print_requests(void)
551*148c5f43SAlan Wright {
552*148c5f43SAlan Wright 	smbstat_req_info_t	*prq;
553*148c5f43SAlan Wright 	int			i;
554*148c5f43SAlan Wright 
555*148c5f43SAlan Wright 	if (!smbstat_opt_r)
556*148c5f43SAlan Wright 		return;
557*148c5f43SAlan Wright 
558*148c5f43SAlan Wright 	prq = smbstat_srv_info.si_reqs;
559*148c5f43SAlan Wright 
560*148c5f43SAlan Wright 	(void) printf(SMBSRV_REQUESTS_BANNER, "       ");
561*148c5f43SAlan Wright 
562*148c5f43SAlan Wright 	for (i = 0; i < SMB_COM_NUM; i++) {
563*148c5f43SAlan Wright 		if (!smbstat_opt_a &&
564*148c5f43SAlan Wright 		    strncmp(prq[i].ri_name, "Invalid", sizeof ("Invalid")) == 0)
565*148c5f43SAlan Wright 			continue;
566*148c5f43SAlan Wright 
567*148c5f43SAlan Wright 		if (!smbstat_opt_z || (prq[i].ri_pct != 0)) {
568*148c5f43SAlan Wright 			(void) printf(SMBSRV_REQUESTS_FORMAT,
569*148c5f43SAlan Wright 			    prq[i].ri_name,
570*148c5f43SAlan Wright 			    prq[i].ri_opcode,
571*148c5f43SAlan Wright 			    smbstat_zero(prq[i].ri_pct),
572*148c5f43SAlan Wright 			    smbstat_zero(prq[i].ri_rbs),
573*148c5f43SAlan Wright 			    smbstat_zero(prq[i].ri_tbs),
574*148c5f43SAlan Wright 			    smbstat_zero(prq[i].ri_rqs),
575*148c5f43SAlan Wright 			    prq[i].ri_mean,
576*148c5f43SAlan Wright 			    prq[i].ri_stddev);
577*148c5f43SAlan Wright 		}
578*148c5f43SAlan Wright 	}
579*148c5f43SAlan Wright }
580*148c5f43SAlan Wright 
581*148c5f43SAlan Wright /*
582*148c5f43SAlan Wright  * smbstat_cpu_init
583*148c5f43SAlan Wright  */
584*148c5f43SAlan Wright static void
585*148c5f43SAlan Wright smbstat_cpu_init(void)
586*148c5f43SAlan Wright {
587*148c5f43SAlan Wright 	size_t	size;
588*148c5f43SAlan Wright 	int	i;
589*148c5f43SAlan Wright 
590*148c5f43SAlan Wright 	smbstat_nrcpus = sysconf(_SC_CPUID_MAX) + 1;
591*148c5f43SAlan Wright 	size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t);
592*148c5f43SAlan Wright 
593*148c5f43SAlan Wright 	for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++)
594*148c5f43SAlan Wright 		smbstat_cpu_snapshots[i] = smbstat_zalloc(size);
595*148c5f43SAlan Wright }
596*148c5f43SAlan Wright 
597*148c5f43SAlan Wright /*
598*148c5f43SAlan Wright  * smbstat_cpu_fini
599*148c5f43SAlan Wright  */
600*148c5f43SAlan Wright static void
601*148c5f43SAlan Wright smbstat_cpu_fini(void)
602*148c5f43SAlan Wright {
603*148c5f43SAlan Wright 	size_t	size;
604*148c5f43SAlan Wright 	int	i;
605*148c5f43SAlan Wright 
606*148c5f43SAlan Wright 	size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t);
607*148c5f43SAlan Wright 
608*148c5f43SAlan Wright 	for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++)
609*148c5f43SAlan Wright 		smbstat_free(smbstat_cpu_snapshots[i], size);
610*148c5f43SAlan Wright }
611*148c5f43SAlan Wright 
612*148c5f43SAlan Wright /*
613*148c5f43SAlan Wright  * smbstat_cpu_current_snapshot
614*148c5f43SAlan Wright  */
615*148c5f43SAlan Wright static smbstat_cpu_snapshot_t *
616*148c5f43SAlan Wright smbstat_cpu_current_snapshot(void)
617*148c5f43SAlan Wright {
618*148c5f43SAlan Wright 	return (smbstat_cpu_snapshots[smbstat_snapshot_idx]);
619*148c5f43SAlan Wright }
620*148c5f43SAlan Wright 
621*148c5f43SAlan Wright /*
622*148c5f43SAlan Wright  * smbstat_cpu_previous_snapshot
623*148c5f43SAlan Wright  */
624*148c5f43SAlan Wright static smbstat_cpu_snapshot_t *
625*148c5f43SAlan Wright smbstat_cpu_previous_snapshot(void)
626*148c5f43SAlan Wright {
627*148c5f43SAlan Wright 	int	idx;
628*148c5f43SAlan Wright 
629*148c5f43SAlan Wright 	idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK;
630*148c5f43SAlan Wright 	return (smbstat_cpu_snapshots[idx]);
631*148c5f43SAlan Wright }
632*148c5f43SAlan Wright 
633*148c5f43SAlan Wright /*
634*148c5f43SAlan Wright  * smbstat_cpu_snapshot
635*148c5f43SAlan Wright  */
636*148c5f43SAlan Wright static void
637*148c5f43SAlan Wright smbstat_cpu_snapshot(void)
638*148c5f43SAlan Wright {
639*148c5f43SAlan Wright 	kstat_t			*ksp;
640*148c5f43SAlan Wright 	kstat_named_t		*ksn;
641*148c5f43SAlan Wright 	smbstat_cpu_snapshot_t	*curr;
642*148c5f43SAlan Wright 	long			i;
643*148c5f43SAlan Wright 	int			j;
644*148c5f43SAlan Wright 
645*148c5f43SAlan Wright 	curr =  smbstat_cpu_current_snapshot();
646*148c5f43SAlan Wright 
647*148c5f43SAlan Wright 	for (i = 0; i < smbstat_nrcpus;	i++, curr++) {
648*148c5f43SAlan Wright 		curr->cs_id = SMBSTAT_ID_NO_CPU;
649*148c5f43SAlan Wright 		curr->cs_state = p_online(i, P_STATUS);
650*148c5f43SAlan Wright 		/* If no valid CPU is present, move on to the next one */
651*148c5f43SAlan Wright 		if (curr->cs_state == -1)
652*148c5f43SAlan Wright 			continue;
653*148c5f43SAlan Wright 
654*148c5f43SAlan Wright 		curr->cs_id = i;
655*148c5f43SAlan Wright 
656*148c5f43SAlan Wright 		ksp = kstat_lookup(smbstat_ksc, "cpu", i, "sys");
657*148c5f43SAlan Wright 		if (ksp == NULL)
658*148c5f43SAlan Wright 			smbstat_fail(1,
659*148c5f43SAlan Wright 			    gettext("kstat_lookup('cpu sys %d') failed"), i);
660*148c5f43SAlan Wright 
661*148c5f43SAlan Wright 		if (kstat_read(smbstat_ksc, ksp, NULL) == -1)
662*148c5f43SAlan Wright 			smbstat_fail(1,
663*148c5f43SAlan Wright 			    gettext("kstat_read('cpu sys %d') failed"), i);
664*148c5f43SAlan Wright 
665*148c5f43SAlan Wright 		for (j = 0; j < CPU_TICKS_SENTINEL; j++) {
666*148c5f43SAlan Wright 			ksn = kstat_data_lookup(ksp, smbstat_cpu_states[j]);
667*148c5f43SAlan Wright 			if (ksn == NULL)
668*148c5f43SAlan Wright 				smbstat_fail(1,
669*148c5f43SAlan Wright 				    gettext("kstat_data_lookup('%s') failed"),
670*148c5f43SAlan Wright 				    smbstat_cpu_states[j]);
671*148c5f43SAlan Wright 			curr->cs_ticks[j] = ksn->value.ui64;
672*148c5f43SAlan Wright 		}
673*148c5f43SAlan Wright 	}
674*148c5f43SAlan Wright }
675*148c5f43SAlan Wright 
676*148c5f43SAlan Wright /*
677*148c5f43SAlan Wright  * smbstat_cpu_process
678*148c5f43SAlan Wright  */
679*148c5f43SAlan Wright static void
680*148c5f43SAlan Wright smbstat_cpu_process(void)
681*148c5f43SAlan Wright {
682*148c5f43SAlan Wright 	smbstat_cpu_snapshot_t	*curr, *prev;
683*148c5f43SAlan Wright 	double			total_ticks;
684*148c5f43SAlan Wright 	double			agg_ticks[CPU_TICKS_SENTINEL];
685*148c5f43SAlan Wright 	int			i, j;
686*148c5f43SAlan Wright 
687*148c5f43SAlan Wright 	curr =  smbstat_cpu_current_snapshot();
688*148c5f43SAlan Wright 	prev =  smbstat_cpu_previous_snapshot();
689*148c5f43SAlan Wright 	bzero(agg_ticks, sizeof (agg_ticks));
690*148c5f43SAlan Wright 	total_ticks = 0;
691*148c5f43SAlan Wright 
692*148c5f43SAlan Wright 	for (i = 0; i < smbstat_nrcpus; i++, curr++, prev++) {
693*148c5f43SAlan Wright 		for (j = 0; j < CPU_TICKS_SENTINEL; j++) {
694*148c5f43SAlan Wright 			agg_ticks[j] +=	smbstat_sub_64(curr->cs_ticks[j],
695*148c5f43SAlan Wright 			    prev->cs_ticks[j]);
696*148c5f43SAlan Wright 			total_ticks += smbstat_sub_64(curr->cs_ticks[j],
697*148c5f43SAlan Wright 			    prev->cs_ticks[j]);
698*148c5f43SAlan Wright 		}
699*148c5f43SAlan Wright 	}
700*148c5f43SAlan Wright 
701*148c5f43SAlan Wright 	for (j = 0; j < CPU_TICKS_SENTINEL; j++)
702*148c5f43SAlan Wright 		smbstat_srv_info.si_ticks[j] =
703*148c5f43SAlan Wright 		    (agg_ticks[j] * 100.0) / total_ticks;
704*148c5f43SAlan Wright }
705*148c5f43SAlan Wright 
706*148c5f43SAlan Wright /*
707*148c5f43SAlan Wright  * smbstat_wrk_init
708*148c5f43SAlan Wright  */
709*148c5f43SAlan Wright static void
710*148c5f43SAlan Wright smbstat_wrk_init(void)
711*148c5f43SAlan Wright {
712*148c5f43SAlan Wright 	smbstat_wrk_ksp =
713*148c5f43SAlan Wright 	    kstat_lookup(smbstat_ksc, "unix", -1, SMBSRV_KSTAT_WORKERS);
714*148c5f43SAlan Wright 	if (smbstat_wrk_ksp == NULL)
715*148c5f43SAlan Wright 		smbstat_fail(1,
716*148c5f43SAlan Wright 		    gettext("cannot retrieve smbsrv workers kstat\n"));
717da6c28aaSamw }
718da6c28aaSamw 
719da6c28aaSamw static void
720*148c5f43SAlan Wright smbstat_wrk_fini(void)
721da6c28aaSamw {
722*148c5f43SAlan Wright 	smbstat_wrk_ksp = NULL;
723da6c28aaSamw }
724da6c28aaSamw 
725*148c5f43SAlan Wright /*
726*148c5f43SAlan Wright  * smbstat_wrk_snapshot
727*148c5f43SAlan Wright  */
728da6c28aaSamw static void
729*148c5f43SAlan Wright smbstat_wrk_snapshot(void)
730da6c28aaSamw {
731*148c5f43SAlan Wright 	smbstat_wrk_snapshot_t	*curr;
732*148c5f43SAlan Wright 	kstat_named_t		*kn;
733*148c5f43SAlan Wright 
734*148c5f43SAlan Wright 	curr = smbstat_wrk_current_snapshot();
735*148c5f43SAlan Wright 
736*148c5f43SAlan Wright 	if (kstat_read(smbstat_ksc, smbstat_wrk_ksp, NULL) == -1)
737*148c5f43SAlan Wright 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
738*148c5f43SAlan Wright 		    smbstat_wrk_ksp->ks_name);
739*148c5f43SAlan Wright 
740*148c5f43SAlan Wright 	kn = kstat_data_lookup(smbstat_wrk_ksp, "maxthreads");
741*148c5f43SAlan Wright 	if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64))
742*148c5f43SAlan Wright 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
743*148c5f43SAlan Wright 		    "maxthreads");
744*148c5f43SAlan Wright 	curr->ws_maxthreads = kn->value.ui64;
745*148c5f43SAlan Wright 
746*148c5f43SAlan Wright 	kn = kstat_data_lookup(smbstat_wrk_ksp, "bnalloc");
747*148c5f43SAlan Wright 	if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64))
748*148c5f43SAlan Wright 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
749*148c5f43SAlan Wright 		    "bnalloc");
750*148c5f43SAlan Wright 	curr->ws_bnalloc = kn->value.ui64;
751da6c28aaSamw }
752da6c28aaSamw 
753*148c5f43SAlan Wright /*
754*148c5f43SAlan Wright  * smbstat_wrk_process
755*148c5f43SAlan Wright  */
756*148c5f43SAlan Wright static void
757*148c5f43SAlan Wright smbstat_wrk_process(void)
758*148c5f43SAlan Wright {
759*148c5f43SAlan Wright 	smbstat_wrk_snapshot_t	*curr;
760*148c5f43SAlan Wright 
761*148c5f43SAlan Wright 	curr = smbstat_wrk_current_snapshot();
762*148c5f43SAlan Wright 
763*148c5f43SAlan Wright 	if (curr->ws_maxthreads >= curr->ws_bnalloc)
764*148c5f43SAlan Wright 		smbstat_srv_info.si_sat = B_TRUE;
765*148c5f43SAlan Wright 	else
766*148c5f43SAlan Wright 		smbstat_srv_info.si_sat = B_FALSE;
767*148c5f43SAlan Wright }
768*148c5f43SAlan Wright 
769*148c5f43SAlan Wright /*
770*148c5f43SAlan Wright  * smbstat_wrk_current_snapshot
771*148c5f43SAlan Wright  */
772*148c5f43SAlan Wright static smbstat_wrk_snapshot_t *
773*148c5f43SAlan Wright smbstat_wrk_current_snapshot(void)
774*148c5f43SAlan Wright {
775*148c5f43SAlan Wright 	return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]);
776*148c5f43SAlan Wright }
777*148c5f43SAlan Wright 
778*148c5f43SAlan Wright /*
779*148c5f43SAlan Wright  * smbstat_srv_init
780*148c5f43SAlan Wright  */
781*148c5f43SAlan Wright static void
782*148c5f43SAlan Wright smbstat_srv_init(void)
783*148c5f43SAlan Wright {
784*148c5f43SAlan Wright 	smbstat_srv_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE,
785*148c5f43SAlan Wright 	    getzoneid(), SMBSRV_KSTAT_STATISTICS);
786*148c5f43SAlan Wright 	if (smbstat_srv_ksp == NULL)
787*148c5f43SAlan Wright 		smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n"));
788*148c5f43SAlan Wright }
789*148c5f43SAlan Wright 
790*148c5f43SAlan Wright /*
791*148c5f43SAlan Wright  * smbstat_srv_fini
792*148c5f43SAlan Wright  */
793*148c5f43SAlan Wright static void
794*148c5f43SAlan Wright smbstat_srv_fini(void)
795*148c5f43SAlan Wright {
796*148c5f43SAlan Wright 	smbstat_srv_ksp = NULL;
797*148c5f43SAlan Wright }
798*148c5f43SAlan Wright 
799*148c5f43SAlan Wright /*
800*148c5f43SAlan Wright  * smbstat_srv_snapshot
801*148c5f43SAlan Wright  *
802*148c5f43SAlan Wright  * Take a snapshot of the smbsrv module statistics.
803*148c5f43SAlan Wright  */
804*148c5f43SAlan Wright static void
805*148c5f43SAlan Wright smbstat_srv_snapshot(void)
806*148c5f43SAlan Wright {
807*148c5f43SAlan Wright 	smbstat_srv_snapshot_t	*curr;
808*148c5f43SAlan Wright 
809*148c5f43SAlan Wright 	curr = smbstat_srv_current_snapshot();
810*148c5f43SAlan Wright 
811*148c5f43SAlan Wright 	if ((kstat_read(smbstat_ksc, smbstat_srv_ksp, NULL) == -1) ||
812*148c5f43SAlan Wright 	    (smbstat_srv_ksp->ks_data_size != sizeof (curr->ss_data)))
813*148c5f43SAlan Wright 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
814*148c5f43SAlan Wright 		    smbstat_srv_ksp->ks_name);
815*148c5f43SAlan Wright 
816*148c5f43SAlan Wright 	curr->ss_snaptime = smbstat_srv_ksp->ks_snaptime;
817*148c5f43SAlan Wright 	bcopy(smbstat_srv_ksp->ks_data, &curr->ss_data, sizeof (curr->ss_data));
818*148c5f43SAlan Wright }
819*148c5f43SAlan Wright 
820*148c5f43SAlan Wright /*
821*148c5f43SAlan Wright  * smbstat_srv_process
822*148c5f43SAlan Wright  *
823*148c5f43SAlan Wright  * Processes the snapshot data.
824*148c5f43SAlan Wright  */
825*148c5f43SAlan Wright static void
826*148c5f43SAlan Wright smbstat_srv_process(void)
827*148c5f43SAlan Wright {
828*148c5f43SAlan Wright 	smbstat_srv_snapshot_t	*curr, *prev;
829*148c5f43SAlan Wright 
830*148c5f43SAlan Wright 	curr = smbstat_srv_current_snapshot();
831*148c5f43SAlan Wright 	prev = smbstat_srv_previous_snapshot();
832*148c5f43SAlan Wright 
833*148c5f43SAlan Wright 	if (prev->ss_snaptime == 0)
834*148c5f43SAlan Wright 		smbstat_srv_info.si_hretime =
835*148c5f43SAlan Wright 		    smbstat_hrtime_delta(curr->ss_data.ks_start_time,
836*148c5f43SAlan Wright 		    curr->ss_snaptime);
837*148c5f43SAlan Wright 	else
838*148c5f43SAlan Wright 		smbstat_srv_info.si_hretime =
839*148c5f43SAlan Wright 		    smbstat_hrtime_delta(prev->ss_snaptime, curr->ss_snaptime);
840*148c5f43SAlan Wright 
841*148c5f43SAlan Wright 	smbstat_srv_info.si_etime = smbstat_srv_info.si_hretime / NANOSEC;
842*148c5f43SAlan Wright 	smbstat_srv_info.si_total_nreqs =
843*148c5f43SAlan Wright 	    smbstat_sub_64(curr->ss_data.ks_nreq, prev->ss_data.ks_nreq);
844*148c5f43SAlan Wright 
845*148c5f43SAlan Wright 	if (smbstat_opt_c)
846*148c5f43SAlan Wright 		smbstat_srv_process_counters(curr);
847*148c5f43SAlan Wright 	if (smbstat_opt_t)
848*148c5f43SAlan Wright 		smbstat_srv_process_throughput(curr, prev);
849*148c5f43SAlan Wright 	if (smbstat_opt_u)
850*148c5f43SAlan Wright 		smbstat_srv_process_utilization(curr, prev);
851*148c5f43SAlan Wright 	if (smbstat_opt_r)
852*148c5f43SAlan Wright 		smbstat_srv_process_requests(curr, prev);
853*148c5f43SAlan Wright }
854*148c5f43SAlan Wright 
855*148c5f43SAlan Wright /*
856*148c5f43SAlan Wright  * smbstat_srv_process_counters
857*148c5f43SAlan Wright  */
858*148c5f43SAlan Wright static void
859*148c5f43SAlan Wright smbstat_srv_process_counters(smbstat_srv_snapshot_t *curr)
860*148c5f43SAlan Wright {
861*148c5f43SAlan Wright 	smbstat_srv_info.si_nbt_sess = curr->ss_data.ks_nbt_sess;
862*148c5f43SAlan Wright 	smbstat_srv_info.si_tcp_sess = curr->ss_data.ks_tcp_sess;
863*148c5f43SAlan Wright 	smbstat_srv_info.si_users = curr->ss_data.ks_users;
864*148c5f43SAlan Wright 	smbstat_srv_info.si_trees = curr->ss_data.ks_trees;
865*148c5f43SAlan Wright 	smbstat_srv_info.si_files = curr->ss_data.ks_files;
866*148c5f43SAlan Wright 	smbstat_srv_info.si_pipes = curr->ss_data.ks_pipes;
867*148c5f43SAlan Wright }
868*148c5f43SAlan Wright 
869*148c5f43SAlan Wright /*
870*148c5f43SAlan Wright  * smbstat_srv_process_throughput
871*148c5f43SAlan Wright  *
872*148c5f43SAlan Wright  * Processes the data relative to the throughput of the smbsrv module and
873*148c5f43SAlan Wright  * stores the results in the structure smbstat_srv_info.
874*148c5f43SAlan Wright  */
875*148c5f43SAlan Wright static void
876*148c5f43SAlan Wright smbstat_srv_process_throughput(
877*148c5f43SAlan Wright     smbstat_srv_snapshot_t	*curr,
878*148c5f43SAlan Wright     smbstat_srv_snapshot_t	*prev)
879*148c5f43SAlan Wright {
880*148c5f43SAlan Wright 	smbstat_srv_info.si_tbs =
881*148c5f43SAlan Wright 	    smbstat_sub_64(curr->ss_data.ks_txb, prev->ss_data.ks_txb);
882*148c5f43SAlan Wright 	smbstat_srv_info.si_tbs /= smbstat_srv_info.si_etime;
883*148c5f43SAlan Wright 	smbstat_srv_info.si_rbs =
884*148c5f43SAlan Wright 	    smbstat_sub_64(curr->ss_data.ks_rxb, prev->ss_data.ks_rxb);
885*148c5f43SAlan Wright 	smbstat_srv_info.si_rbs /= smbstat_srv_info.si_etime;
886*148c5f43SAlan Wright 	smbstat_srv_info.si_rqs = smbstat_srv_info.si_total_nreqs;
887*148c5f43SAlan Wright 	smbstat_srv_info.si_rqs /= smbstat_srv_info.si_etime;
888*148c5f43SAlan Wright 
889*148c5f43SAlan Wright 	smbstat_srv_info.si_rds = smbstat_sub_64(
890*148c5f43SAlan Wright 	    curr->ss_data.ks_reqs[SMB_COM_READ].kr_nreq,
891*148c5f43SAlan Wright 	    prev->ss_data.ks_reqs[SMB_COM_READ].kr_nreq);
892*148c5f43SAlan Wright 	smbstat_srv_info.si_rds += smbstat_sub_64(
893*148c5f43SAlan Wright 	    curr->ss_data.ks_reqs[SMB_COM_LOCK_AND_READ].kr_nreq,
894*148c5f43SAlan Wright 	    prev->ss_data.ks_reqs[SMB_COM_LOCK_AND_READ].kr_nreq);
895*148c5f43SAlan Wright 	smbstat_srv_info.si_rds += smbstat_sub_64(
896*148c5f43SAlan Wright 	    curr->ss_data.ks_reqs[SMB_COM_READ_RAW].kr_nreq,
897*148c5f43SAlan Wright 	    prev->ss_data.ks_reqs[SMB_COM_READ_RAW].kr_nreq);
898*148c5f43SAlan Wright 	smbstat_srv_info.si_rds += smbstat_sub_64(
899*148c5f43SAlan Wright 	    curr->ss_data.ks_reqs[SMB_COM_READ_ANDX].kr_nreq,
900*148c5f43SAlan Wright 	    prev->ss_data.ks_reqs[SMB_COM_READ_ANDX].kr_nreq);
901*148c5f43SAlan Wright 	smbstat_srv_info.si_rds /= smbstat_srv_info.si_etime;
902*148c5f43SAlan Wright 
903*148c5f43SAlan Wright 	smbstat_srv_info.si_wrs = smbstat_sub_64(
904*148c5f43SAlan Wright 	    curr->ss_data.ks_reqs[SMB_COM_WRITE].kr_nreq,
905*148c5f43SAlan Wright 	    prev->ss_data.ks_reqs[SMB_COM_WRITE].kr_nreq);
906*148c5f43SAlan Wright 	smbstat_srv_info.si_wrs += smbstat_sub_64(
907*148c5f43SAlan Wright 	    curr->ss_data.ks_reqs[SMB_COM_WRITE_AND_UNLOCK].kr_nreq,
908*148c5f43SAlan Wright 	    prev->ss_data.ks_reqs[SMB_COM_WRITE_AND_UNLOCK].kr_nreq);
909*148c5f43SAlan Wright 	smbstat_srv_info.si_wrs += smbstat_sub_64(
910*148c5f43SAlan Wright 	    curr->ss_data.ks_reqs[SMB_COM_WRITE_RAW].kr_nreq,
911*148c5f43SAlan Wright 	    prev->ss_data.ks_reqs[SMB_COM_WRITE_RAW].kr_nreq);
912*148c5f43SAlan Wright 	smbstat_srv_info.si_wrs += smbstat_sub_64(
913*148c5f43SAlan Wright 	    curr->ss_data.ks_reqs[SMB_COM_WRITE_AND_CLOSE].kr_nreq,
914*148c5f43SAlan Wright 	    prev->ss_data.ks_reqs[SMB_COM_WRITE_AND_CLOSE].kr_nreq);
915*148c5f43SAlan Wright 	smbstat_srv_info.si_wrs += smbstat_sub_64(
916*148c5f43SAlan Wright 	    curr->ss_data.ks_reqs[SMB_COM_WRITE_ANDX].kr_nreq,
917*148c5f43SAlan Wright 	    prev->ss_data.ks_reqs[SMB_COM_WRITE_ANDX].kr_nreq);
918*148c5f43SAlan Wright 	smbstat_srv_info.si_wrs /= smbstat_srv_info.si_etime;
919*148c5f43SAlan Wright }
920*148c5f43SAlan Wright 
921*148c5f43SAlan Wright /*
922*148c5f43SAlan Wright  * smbstat_srv_process_utilization
923*148c5f43SAlan Wright  *
924*148c5f43SAlan Wright  * Processes the data relative to the utilization of the smbsrv module and
925*148c5f43SAlan Wright  * stores the results in the structure smbstat_srv_info.
926*148c5f43SAlan Wright  */
927*148c5f43SAlan Wright static void
928*148c5f43SAlan Wright smbstat_srv_process_utilization(
929*148c5f43SAlan Wright     smbstat_srv_snapshot_t	*curr,
930*148c5f43SAlan Wright     smbstat_srv_snapshot_t	*prev)
931*148c5f43SAlan Wright {
932*148c5f43SAlan Wright 	double	tw_delta, tr_delta;
933*148c5f43SAlan Wright 	double	w_delta, r_delta;
934*148c5f43SAlan Wright 	double	tps, rqs;
935*148c5f43SAlan Wright 
936*148c5f43SAlan Wright 	w_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wlentime,
937*148c5f43SAlan Wright 	    curr->ss_data.ks_utilization.ku_wlentime);
938*148c5f43SAlan Wright 	r_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rlentime,
939*148c5f43SAlan Wright 	    curr->ss_data.ks_utilization.ku_rlentime);
940*148c5f43SAlan Wright 	tw_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wtime,
941*148c5f43SAlan Wright 	    curr->ss_data.ks_utilization.ku_wtime);
942*148c5f43SAlan Wright 	tr_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rtime,
943*148c5f43SAlan Wright 	    curr->ss_data.ks_utilization.ku_rtime);
944*148c5f43SAlan Wright 	rqs = smbstat_srv_info.si_total_nreqs / smbstat_srv_info.si_etime;
945*148c5f43SAlan Wright 
946*148c5f43SAlan Wright 	/* Average number of requests waiting */
947*148c5f43SAlan Wright 	if (w_delta != 0)
948*148c5f43SAlan Wright 		smbstat_srv_info.si_avw = w_delta / smbstat_srv_info.si_hretime;
949*148c5f43SAlan Wright 	else
950*148c5f43SAlan Wright 		smbstat_srv_info.si_avw = 0.0;
951*148c5f43SAlan Wright 
952*148c5f43SAlan Wright 	/* Average number of request running */
953*148c5f43SAlan Wright 	if (r_delta != 0)
954*148c5f43SAlan Wright 		smbstat_srv_info.si_avr = r_delta / smbstat_srv_info.si_hretime;
955*148c5f43SAlan Wright 	else
956*148c5f43SAlan Wright 		smbstat_srv_info.si_avr = 0.0;
957*148c5f43SAlan Wright 
958*148c5f43SAlan Wright 	/* Utilization */
959*148c5f43SAlan Wright 	smbstat_srv_info.si_upct =
960*148c5f43SAlan Wright 	    (smbstat_srv_info.si_avr / curr->ss_data.ks_maxreqs) * 100;
961*148c5f43SAlan Wright 
962*148c5f43SAlan Wright 	/* Average wait service time in milliseconds */
963*148c5f43SAlan Wright 	smbstat_srv_info.si_rserv = 0.0;
964*148c5f43SAlan Wright 	smbstat_srv_info.si_wserv = 0.0;
965*148c5f43SAlan Wright 	if (rqs > 0.0 &&
966*148c5f43SAlan Wright 	    (smbstat_srv_info.si_avw != 0.0 ||
967*148c5f43SAlan Wright 	    smbstat_srv_info.si_avr != 0.0)) {
968*148c5f43SAlan Wright 		tps = 1 / rqs;
969*148c5f43SAlan Wright 		if (smbstat_srv_info.si_avw != 0.0)
970*148c5f43SAlan Wright 			smbstat_srv_info.si_wserv =
971*148c5f43SAlan Wright 			    smbstat_srv_info.si_avw * tps;
972*148c5f43SAlan Wright 		if (smbstat_srv_info.si_avr != 0.0)
973*148c5f43SAlan Wright 			smbstat_srv_info.si_rserv =
974*148c5f43SAlan Wright 			    smbstat_srv_info.si_avr * tps;
975*148c5f43SAlan Wright 	}
976*148c5f43SAlan Wright 
977*148c5f43SAlan Wright 	/* % of time there is a transaction waiting for service */
978*148c5f43SAlan Wright 	if (tw_delta != 0) {
979*148c5f43SAlan Wright 		smbstat_srv_info.si_wpct = tw_delta;
980*148c5f43SAlan Wright 		smbstat_srv_info.si_wpct /= smbstat_srv_info.si_hretime;
981*148c5f43SAlan Wright 		smbstat_srv_info.si_wpct *= 100.0;
982*148c5f43SAlan Wright 	} else {
983*148c5f43SAlan Wright 		smbstat_srv_info.si_wpct = 0.0;
984*148c5f43SAlan Wright 	}
985*148c5f43SAlan Wright 
986*148c5f43SAlan Wright 	/* % of time there is a transaction running */
987*148c5f43SAlan Wright 	if (tr_delta != 0) {
988*148c5f43SAlan Wright 		smbstat_srv_info.si_rpct = tr_delta;
989*148c5f43SAlan Wright 		smbstat_srv_info.si_rpct /= smbstat_srv_info.si_hretime;
990*148c5f43SAlan Wright 		smbstat_srv_info.si_rpct *= 100.0;
991*148c5f43SAlan Wright 	} else {
992*148c5f43SAlan Wright 		smbstat_srv_info.si_rpct = 0.0;
993*148c5f43SAlan Wright 	}
994*148c5f43SAlan Wright }
995*148c5f43SAlan Wright 
996*148c5f43SAlan Wright /*
997*148c5f43SAlan Wright  * smbstat_srv_process_requests
998*148c5f43SAlan Wright  *
999*148c5f43SAlan Wright  * Processes the data relative to the SMB requests and stores the results in
1000*148c5f43SAlan Wright  * the structure smbstat_srv_info.
1001*148c5f43SAlan Wright  */
1002*148c5f43SAlan Wright static void
1003*148c5f43SAlan Wright smbstat_srv_process_requests(
1004*148c5f43SAlan Wright     smbstat_srv_snapshot_t	*curr,
1005*148c5f43SAlan Wright     smbstat_srv_snapshot_t	*prev)
1006*148c5f43SAlan Wright {
1007*148c5f43SAlan Wright 	smbstat_req_info_t	*info;
1008*148c5f43SAlan Wright 	double			nrqs;
1009*148c5f43SAlan Wright 	int			i, idx;
1010*148c5f43SAlan Wright 
1011*148c5f43SAlan Wright 	info = smbstat_srv_info.si_reqs;
1012*148c5f43SAlan Wright 
1013*148c5f43SAlan Wright 	for (i = 0; i < SMB_COM_NUM; i++) {
1014*148c5f43SAlan Wright 		idx = info[i].ri_opcode;
1015*148c5f43SAlan Wright 
1016*148c5f43SAlan Wright 		nrqs = smbstat_sub_64(curr->ss_data.ks_reqs[idx].kr_nreq,
1017*148c5f43SAlan Wright 		    prev->ss_data.ks_reqs[idx].kr_nreq);
1018*148c5f43SAlan Wright 
1019*148c5f43SAlan Wright 		info[i].ri_rqs = nrqs / smbstat_srv_info.si_etime;
1020*148c5f43SAlan Wright 
1021*148c5f43SAlan Wright 		info[i].ri_rbs = smbstat_sub_64(
1022*148c5f43SAlan Wright 		    curr->ss_data.ks_reqs[idx].kr_rxb,
1023*148c5f43SAlan Wright 		    prev->ss_data.ks_reqs[idx].kr_rxb) /
1024*148c5f43SAlan Wright 		    smbstat_srv_info.si_etime;
1025*148c5f43SAlan Wright 
1026*148c5f43SAlan Wright 		info[i].ri_tbs = smbstat_sub_64(
1027*148c5f43SAlan Wright 		    curr->ss_data.ks_reqs[idx].kr_txb,
1028*148c5f43SAlan Wright 		    prev->ss_data.ks_reqs[idx].kr_txb) /
1029*148c5f43SAlan Wright 		    smbstat_srv_info.si_etime;
1030*148c5f43SAlan Wright 
1031*148c5f43SAlan Wright 		info[i].ri_pct = nrqs * 100;
1032*148c5f43SAlan Wright 		if (smbstat_srv_info.si_total_nreqs > 0)
1033*148c5f43SAlan Wright 			info[i].ri_pct /= smbstat_srv_info.si_total_nreqs;
1034*148c5f43SAlan Wright 
1035*148c5f43SAlan Wright 		if (prev->ss_snaptime == 0) {
1036*148c5f43SAlan Wright 			/* First time. Take the aggregate */
1037*148c5f43SAlan Wright 			info[i].ri_stddev =
1038*148c5f43SAlan Wright 			    curr->ss_data.ks_reqs[idx].kr_a_stddev;
1039*148c5f43SAlan Wright 			info[i].ri_mean = curr->ss_data.ks_reqs[idx].kr_a_mean;
1040*148c5f43SAlan Wright 		} else {
1041*148c5f43SAlan Wright 			/* Take the differential */
1042*148c5f43SAlan Wright 			info[i].ri_stddev =
1043*148c5f43SAlan Wright 			    curr->ss_data.ks_reqs[idx].kr_d_stddev;
1044*148c5f43SAlan Wright 			info[i].ri_mean = curr->ss_data.ks_reqs[idx].kr_d_mean;
1045*148c5f43SAlan Wright 		}
1046*148c5f43SAlan Wright 		if (nrqs > 0) {
1047*148c5f43SAlan Wright 			info[i].ri_stddev /= nrqs;
1048*148c5f43SAlan Wright 			info[i].ri_stddev = sqrt(info[i].ri_stddev);
1049*148c5f43SAlan Wright 		} else {
1050*148c5f43SAlan Wright 			info[i].ri_stddev = 0;
1051*148c5f43SAlan Wright 		}
1052*148c5f43SAlan Wright 		info[i].ri_stddev /= NANOSEC;
1053*148c5f43SAlan Wright 		info[i].ri_mean /= NANOSEC;
1054*148c5f43SAlan Wright 	}
1055*148c5f43SAlan Wright }
1056*148c5f43SAlan Wright 
1057*148c5f43SAlan Wright /*
1058*148c5f43SAlan Wright  * smbstat_srv_current_snapshot
1059*148c5f43SAlan Wright  *
1060*148c5f43SAlan Wright  * Returns the current snapshot.
1061*148c5f43SAlan Wright  */
1062*148c5f43SAlan Wright static smbstat_srv_snapshot_t *
1063*148c5f43SAlan Wright smbstat_srv_current_snapshot(void)
1064*148c5f43SAlan Wright {
1065*148c5f43SAlan Wright 	return (&smbstat_srv_snapshots[smbstat_snapshot_idx]);
1066*148c5f43SAlan Wright }
1067*148c5f43SAlan Wright 
1068*148c5f43SAlan Wright /*
1069*148c5f43SAlan Wright  * smbstat_srv_previous_snapshot
1070*148c5f43SAlan Wright  *
1071*148c5f43SAlan Wright  * Returns the previous snapshot.
1072*148c5f43SAlan Wright  */
1073*148c5f43SAlan Wright static smbstat_srv_snapshot_t *
1074*148c5f43SAlan Wright smbstat_srv_previous_snapshot(void)
1075*148c5f43SAlan Wright {
1076*148c5f43SAlan Wright 	int	idx;
1077*148c5f43SAlan Wright 
1078*148c5f43SAlan Wright 	idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK;
1079*148c5f43SAlan Wright 	return (&smbstat_srv_snapshots[idx]);
1080*148c5f43SAlan Wright }
1081*148c5f43SAlan Wright 
1082*148c5f43SAlan Wright /*
1083*148c5f43SAlan Wright  * smbstat_usage
1084*148c5f43SAlan Wright  *
1085*148c5f43SAlan Wright  * Prints out a help message.
1086*148c5f43SAlan Wright  */
1087*148c5f43SAlan Wright static void
1088*148c5f43SAlan Wright smbstat_usage(FILE *fd, int exit_code)
1089*148c5f43SAlan Wright {
1090*148c5f43SAlan Wright 	(void) fprintf(fd, gettext(SMBSTAT_HELP));
1091*148c5f43SAlan Wright 	exit(exit_code);
1092*148c5f43SAlan Wright }
1093*148c5f43SAlan Wright 
1094*148c5f43SAlan Wright /*
1095*148c5f43SAlan Wright  * smbstat_fail
1096*148c5f43SAlan Wright  *
1097*148c5f43SAlan Wright  * Prints out to stderr an error message and exits the process.
1098*148c5f43SAlan Wright  */
1099da6c28aaSamw static void
1100da6c28aaSamw smbstat_fail(int do_perror, char *message, ...)
1101da6c28aaSamw {
1102da6c28aaSamw 	va_list args;
1103da6c28aaSamw 
1104da6c28aaSamw 	va_start(args, message);
1105da6c28aaSamw 	(void) fprintf(stderr, gettext("smbstat: "));
1106da6c28aaSamw 	/* LINTED E_SEC_PRINTF_VAR_FMT */
1107da6c28aaSamw 	(void) vfprintf(stderr, message, args);
1108da6c28aaSamw 	va_end(args);
1109da6c28aaSamw 	if (do_perror)
1110da6c28aaSamw 		(void) fprintf(stderr, ": %s", strerror(errno));
1111da6c28aaSamw 	(void) fprintf(stderr, "\n");
1112da6c28aaSamw 	exit(1);
1113da6c28aaSamw }
1114da6c28aaSamw 
1115*148c5f43SAlan Wright /*
1116*148c5f43SAlan Wright  * smbstat_sub_64
1117*148c5f43SAlan Wright  *
1118*148c5f43SAlan Wright  * Substract 2 uint64_t and returns a double.
1119*148c5f43SAlan Wright  */
1120*148c5f43SAlan Wright static double
1121*148c5f43SAlan Wright smbstat_sub_64(uint64_t a, uint64_t b)
1122da6c28aaSamw {
1123*148c5f43SAlan Wright 	return ((double)(a - b));
1124da6c28aaSamw }
1125da6c28aaSamw 
1126da6c28aaSamw /*
1127*148c5f43SAlan Wright  * smbstat_zero
1128*148c5f43SAlan Wright  *
1129*148c5f43SAlan Wright  * Returns zero if the value passed in is less than 1.
1130da6c28aaSamw  */
1131*148c5f43SAlan Wright static double
1132*148c5f43SAlan Wright smbstat_zero(double value)
1133da6c28aaSamw {
1134*148c5f43SAlan Wright 	if (value < 1)
1135*148c5f43SAlan Wright 		value = 0;
1136*148c5f43SAlan Wright 	return (value);
1137da6c28aaSamw }
1138da6c28aaSamw 
1139*148c5f43SAlan Wright /*
1140*148c5f43SAlan Wright  * smbstat_strtoi
1141*148c5f43SAlan Wright  *
1142*148c5f43SAlan Wright  * Converts a string representing an integer value into its binary value.
1143*148c5f43SAlan Wright  * If the conversion fails this routine exits the process.
1144*148c5f43SAlan Wright  */
1145*148c5f43SAlan Wright static uint_t
1146*148c5f43SAlan Wright smbstat_strtoi(char const *val, char *errmsg)
1147da6c28aaSamw {
1148*148c5f43SAlan Wright 	char	*end;
1149*148c5f43SAlan Wright 	long	tmp;
1150*148c5f43SAlan Wright 
1151*148c5f43SAlan Wright 	errno = 0;
1152*148c5f43SAlan Wright 	tmp = strtol(val, &end, 10);
1153*148c5f43SAlan Wright 	if (*end != '\0' || errno)
1154*148c5f43SAlan Wright 		smbstat_fail(1, "%s %s", errmsg, val);
1155*148c5f43SAlan Wright 	return ((uint_t)tmp);
1156da6c28aaSamw }
1157*148c5f43SAlan Wright 
1158*148c5f43SAlan Wright /*
1159*148c5f43SAlan Wright  * smbstat_termio_init
1160*148c5f43SAlan Wright  *
1161*148c5f43SAlan Wright  * Determines the size of the terminal associated with the process.
1162*148c5f43SAlan Wright  */
1163*148c5f43SAlan Wright static void
1164*148c5f43SAlan Wright smbstat_termio_init(void)
1165*148c5f43SAlan Wright {
1166*148c5f43SAlan Wright 	char	*envp;
1167*148c5f43SAlan Wright 
1168*148c5f43SAlan Wright 	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &smbstat_ws) != -1) {
1169*148c5f43SAlan Wright 		if (smbstat_ws.ws_row == 0) {
1170*148c5f43SAlan Wright 			envp = getenv("LINES");
1171*148c5f43SAlan Wright 			if (envp != NULL)
1172*148c5f43SAlan Wright 				smbstat_ws.ws_row = atoi(envp);
1173*148c5f43SAlan Wright 		}
1174*148c5f43SAlan Wright 
1175*148c5f43SAlan Wright 		if (smbstat_ws.ws_col == 0) {
1176*148c5f43SAlan Wright 			envp = getenv("COLUMNS");
1177*148c5f43SAlan Wright 			if (envp != NULL)
1178*148c5f43SAlan Wright 				smbstat_ws.ws_row = atoi(envp);
1179*148c5f43SAlan Wright 		}
1180*148c5f43SAlan Wright 	}
1181*148c5f43SAlan Wright 	if (smbstat_ws.ws_col == 0)
1182*148c5f43SAlan Wright 		smbstat_ws.ws_col = 80;
1183*148c5f43SAlan Wright 	if (smbstat_ws.ws_row == 0)
1184*148c5f43SAlan Wright 		smbstat_ws.ws_row = 25;
1185*148c5f43SAlan Wright }
1186*148c5f43SAlan Wright 
1187*148c5f43SAlan Wright /*
1188*148c5f43SAlan Wright  * smbstat_snapshot_idx_inc
1189*148c5f43SAlan Wright  *
1190*148c5f43SAlan Wright  * Increments the snapshot index.
1191*148c5f43SAlan Wright  */
1192*148c5f43SAlan Wright static void
1193*148c5f43SAlan Wright smbstat_snapshot_inc_idx(void)
1194*148c5f43SAlan Wright {
1195*148c5f43SAlan Wright 	smbstat_snapshot_idx++;
1196*148c5f43SAlan Wright 	smbstat_snapshot_idx &= SMBSTAT_SNAPSHOT_MASK;
1197*148c5f43SAlan Wright }
1198*148c5f43SAlan Wright 
1199*148c5f43SAlan Wright /*
1200*148c5f43SAlan Wright  * smbstat_req_cmp_name
1201*148c5f43SAlan Wright  *
1202*148c5f43SAlan Wright  * Call back function passed to qsort() when the list of requests must be sorted
1203*148c5f43SAlan Wright  * by name.
1204*148c5f43SAlan Wright  */
1205*148c5f43SAlan Wright static int
1206*148c5f43SAlan Wright smbstat_req_cmp_name(const void *obj1, const void *obj2)
1207*148c5f43SAlan Wright {
1208*148c5f43SAlan Wright 	return (strncasecmp(
1209*148c5f43SAlan Wright 	    ((smbstat_req_info_t *)obj1)->ri_name,
1210*148c5f43SAlan Wright 	    ((smbstat_req_info_t *)obj2)->ri_name,
1211*148c5f43SAlan Wright 	    sizeof (((smbstat_req_info_t *)obj2)->ri_name)));
1212*148c5f43SAlan Wright }
1213*148c5f43SAlan Wright 
1214*148c5f43SAlan Wright /*
1215*148c5f43SAlan Wright  * smbstat_req_order
1216*148c5f43SAlan Wright  *
1217*148c5f43SAlan Wright  * Snapshots the smbsrv module statistics once to get the name of the requests.
1218*148c5f43SAlan Wright  * The request list is smbstat_srv_info is then sorted by name or by code
1219*148c5f43SAlan Wright  * depending on the boolean smbstat_opt_a.
1220*148c5f43SAlan Wright  * The function should be called once during initialization.
1221*148c5f43SAlan Wright  */
1222*148c5f43SAlan Wright static void
1223*148c5f43SAlan Wright smbstat_req_order(void)
1224*148c5f43SAlan Wright {
1225*148c5f43SAlan Wright 	smbstat_req_info_t	*info;
1226*148c5f43SAlan Wright 	smb_kstat_req_t		*reqs;
1227*148c5f43SAlan Wright 	int			i;
1228*148c5f43SAlan Wright 
1229*148c5f43SAlan Wright 	smbstat_srv_snapshot();
1230*148c5f43SAlan Wright 	reqs = smbstat_srv_current_snapshot()->ss_data.ks_reqs;
1231*148c5f43SAlan Wright 	info = smbstat_srv_info.si_reqs;
1232*148c5f43SAlan Wright 
1233*148c5f43SAlan Wright 	for (i = 0; i < SMB_COM_NUM; i++) {
1234*148c5f43SAlan Wright 		(void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1235*148c5f43SAlan Wright 		    sizeof (reqs[i].kr_name));
1236*148c5f43SAlan Wright 		info[i].ri_opcode = i;
1237*148c5f43SAlan Wright 	}
1238*148c5f43SAlan Wright 	if (smbstat_opt_n)
1239*148c5f43SAlan Wright 		qsort(info, SMB_COM_NUM, sizeof (smbstat_req_info_t),
1240*148c5f43SAlan Wright 		    smbstat_req_cmp_name);
1241*148c5f43SAlan Wright }
1242*148c5f43SAlan Wright 
1243*148c5f43SAlan Wright /*
1244*148c5f43SAlan Wright  * Return the number of ticks delta between two hrtime_t
1245*148c5f43SAlan Wright  * values. Attempt to cater for various kinds of overflow
1246*148c5f43SAlan Wright  * in hrtime_t - no matter how improbable.
1247*148c5f43SAlan Wright  */
1248*148c5f43SAlan Wright static double
1249*148c5f43SAlan Wright smbstat_hrtime_delta(hrtime_t old, hrtime_t new)
1250*148c5f43SAlan Wright {
1251*148c5f43SAlan Wright 	uint64_t	del;
1252*148c5f43SAlan Wright 
1253*148c5f43SAlan Wright 	if ((new >= old) && (old >= 0L))
1254*148c5f43SAlan Wright 		return ((double)(new - old));
1255*148c5f43SAlan Wright 	/*
1256*148c5f43SAlan Wright 	 * We've overflowed the positive portion of an hrtime_t.
1257*148c5f43SAlan Wright 	 */
1258*148c5f43SAlan Wright 	if (new < 0L) {
1259*148c5f43SAlan Wright 		/*
1260*148c5f43SAlan Wright 		 * The new value is negative. Handle the case where the old
1261*148c5f43SAlan Wright 		 * value is positive or negative.
1262*148c5f43SAlan Wright 		 */
1263*148c5f43SAlan Wright 		uint64_t n1;
1264*148c5f43SAlan Wright 		uint64_t o1;
1265*148c5f43SAlan Wright 
1266*148c5f43SAlan Wright 		n1 = -new;
1267*148c5f43SAlan Wright 		if (old > 0L)
1268*148c5f43SAlan Wright 			return ((double)(n1 - old));
1269*148c5f43SAlan Wright 
1270*148c5f43SAlan Wright 		o1 = -old;
1271*148c5f43SAlan Wright 		del = n1 - o1;
1272*148c5f43SAlan Wright 		return ((double)del);
1273*148c5f43SAlan Wright 	}
1274*148c5f43SAlan Wright 
1275*148c5f43SAlan Wright 	/*
1276*148c5f43SAlan Wright 	 * Either we've just gone from being negative to positive *or* the last
1277*148c5f43SAlan Wright 	 * entry was positive and the new entry is also positive but *less* than
1278*148c5f43SAlan Wright 	 * the old entry. This implies we waited quite a few days on a very fast
1279*148c5f43SAlan Wright 	 * system between displays.
1280*148c5f43SAlan Wright 	 */
1281*148c5f43SAlan Wright 	if (old < 0L) {
1282*148c5f43SAlan Wright 		uint64_t o2;
1283*148c5f43SAlan Wright 		o2 = -old;
1284*148c5f43SAlan Wright 		del = UINT64_MAX - o2;
1285*148c5f43SAlan Wright 	} else {
1286*148c5f43SAlan Wright 		del = UINT64_MAX - old;
1287*148c5f43SAlan Wright 	}
1288*148c5f43SAlan Wright 	del += new;
1289*148c5f43SAlan Wright 	return ((double)del);
1290*148c5f43SAlan Wright }
1291*148c5f43SAlan Wright 
1292*148c5f43SAlan Wright static void *
1293*148c5f43SAlan Wright smbstat_zalloc(size_t size)
1294*148c5f43SAlan Wright {
1295*148c5f43SAlan Wright 	void	*ptr;
1296*148c5f43SAlan Wright 
1297*148c5f43SAlan Wright 	ptr = umem_zalloc(size, UMEM_DEFAULT);
1298*148c5f43SAlan Wright 	if (ptr == NULL)
1299*148c5f43SAlan Wright 		smbstat_fail(1,	gettext("out of memory"));
1300*148c5f43SAlan Wright 	return (ptr);
1301*148c5f43SAlan Wright }
1302*148c5f43SAlan Wright 
1303*148c5f43SAlan Wright static void
1304*148c5f43SAlan Wright smbstat_free(void *ptr, size_t size)
1305*148c5f43SAlan Wright {
1306*148c5f43SAlan Wright 	umem_free(ptr, size);
1307*148c5f43SAlan Wright }
1308