dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / smbsrv / smbstat / smbstat.c
blob19159ef57dbf8f2fd89305820fa808f9e58ea6da
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 * smbstat: Server Message Block File System statistics
30 * The statistics this CLI displays come from two sources:
32 * 1) The kernel module 'smbsrv'.
33 * 2) The SMB workers task queue statistics the task queue manager of Solaris
34 * maintains.
36 * The flow of the code is the following:
39 * +----------------+
40 * | Initialization |
41 * +----------------+
42 * |
43 * |
44 * v
45 * +--------------------------*
46 * | Take a snapshot the data | <--------+
47 * +--------------------------+ |
48 * | |
49 * | |
50 * v |
51 * +----------------------+ |
52 * | Process the snapshot | |
53 * +----------------------+ |
54 * | |
55 * | |
56 * v |
57 * +------------------------------------+ |
58 * | Print the result of the processing | |
59 * +------------------------------------+ |
60 * | |
61 * | |
62 * v |
63 * Yes --------------- |
64 * +------------ < interval == 0 ? > |
65 * | --------------- |
66 * | | |
67 * | | No |
68 * | v |
69 * | +------------------------+ |
70 * | | Sleep for the duration | ----------+
71 * | | of the interval. |
72 * | +------------------------+
73 * |
74 * +---------------------+
75 * |
76 * v
78 * Exit
80 * There are two sets of snapshots. One set for the smbsrv module and the other
81 * for the task queue (SMB workers). Each set contains 2 snapshots. One is
82 * labeled 'current' the other one 'previous'. Their role changes after each
83 * snapshot. The 'current' becomes 'previous' and vice versa.
84 * The first snapshot taken is compared against the data gathered since the
85 * smbsrv module was loaded. Subsequent snapshots will be compared against the
86 * previous snapshot.
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <unistd.h>
92 #include <kstat.h>
93 #include <stdarg.h>
94 #include <errno.h>
95 #include <inttypes.h>
96 #include <strings.h>
98 #include <libintl.h>
99 #include <zone.h>
100 #include <termios.h>
101 #include <stropts.h>
102 #include <math.h>
103 #include <umem.h>
104 #include <locale.h>
105 #include <smbsrv/smb_kstat.h>
107 #if !defined(TEXT_DOMAIN)
108 #define TEXT_DOMAIN "SYS_TEST"
109 #endif /* TEXT_DOMAIN */
111 #define SMBSTAT_ID_NO_CPU -1
112 #define SMBSTAT_SNAPSHOT_COUNT 2 /* Must be a power of 2 */
113 #define SMBSTAT_SNAPSHOT_MASK (SMBSTAT_SNAPSHOT_COUNT - 1)
115 #define SMBSTAT_HELP \
116 "Usage: smbstat [-acnrtuz] [interval]\n" \
117 " -c: display counters\n" \
118 " -t: display throughput\n" \
119 " -u: display utilization\n" \
120 " -r: display requests\n" \
121 " -a: all the requests (supported and unsupported)\n" \
122 " -z: skip the requests not received\n" \
123 " -n: display in alphabetic order\n" \
124 " interval: refresh cycle in seconds\n"
126 #define SMBSRV_COUNTERS_BANNER "\n nbt tcp users trees files pipes\n"
127 #define SMBSRV_COUNTERS_FORMAT "%5d %5d %5d %5d %5d %5d\n"
129 #define SMBSRV_THROUGHPUT_BANNER \
130 "\nrbytes/s tbytes/s reqs/s reads/s writes/s\n"
131 #define SMBSRV_THROUGHPUT_FORMAT \
132 "%1.3e %1.3e %1.3e %1.3e %1.3e\n"
134 #define SMBSRV_UTILIZATION_BANNER \
135 "\n wcnt rcnt wtime rtime" \
136 " w%% r%% u%% sat usr%% sys%% idle%%\n"
137 #define SMBSRV_UTILIZATION_FORMAT \
138 "%1.3e %1.3e %1.3e %1.3e %3.0f %3.0f %3.0f %s " \
139 "%3.0f %3.0f %3.0f\n"
141 #define SMBSRV_REQUESTS_BANNER \
142 "\n%30s code %% rbytes/s tbytes/s req/s rt-mean" \
143 " rt-stddev\n"
144 #define SMBSRV_REQUESTS_FORMAT \
145 "%30s %02X %3.0f %1.3e %1.3e %1.3e %1.3e %1.3e\n"
147 typedef enum {
148 CPU_TICKS_IDLE = 0,
149 CPU_TICKS_USER,
150 CPU_TICKS_KERNEL,
151 CPU_TICKS_SENTINEL
152 } cpu_state_idx_t;
154 typedef struct smbstat_cpu_snapshot {
155 processorid_t cs_id;
156 int cs_state;
157 uint64_t cs_ticks[CPU_TICKS_SENTINEL];
158 } smbstat_cpu_snapshot_t;
160 typedef struct smbstat_srv_snapshot {
161 hrtime_t ss_snaptime;
162 smbsrv_kstats_t ss_data;
163 } smbstat_srv_snapshot_t;
165 typedef struct smbstat_wrk_snapshot {
166 uint64_t ws_maxthreads;
167 uint64_t ws_bnalloc;
168 } smbstat_wrk_snapshot_t;
170 typedef struct smbstat_req_info {
171 char ri_name[KSTAT_STRLEN];
172 int ri_opcode;
173 double ri_pct;
174 double ri_tbs;
175 double ri_rbs;
176 double ri_rqs;
177 double ri_stddev;
178 double ri_mean;
179 } smbstat_req_info_t;
181 typedef struct smbstat_srv_info {
182 double si_hretime;
183 double si_etime;
184 double si_total_nreqs;
186 * Counters
188 uint32_t si_nbt_sess; /* NBT sessions */
189 uint32_t si_tcp_sess; /* TCP sessions */
190 uint32_t si_users; /* Users logged in */
191 uint32_t si_trees; /* Trees connected */
192 uint32_t si_files; /* Open files */
193 uint32_t si_pipes; /* Open pipes */
195 * Throughput of the server
197 double si_tbs; /* Bytes transmitted / second */
198 double si_rbs; /* Bytes received / second */
199 double si_rqs; /* Requests treated / second */
200 double si_rds; /* Reads treated / second */
201 double si_wrs; /* Writes treated / second */
203 * Utilization of the server
205 double si_wpct; /* */
206 double si_rpct; /* */
207 double si_upct; /* Utilization in % */
208 double si_avw; /* Average number of requests waiting */
209 double si_avr; /* Average number of requests running */
210 double si_wserv; /* Average waiting time */
211 double si_rserv; /* Average running time */
212 boolean_t si_sat;
213 double si_ticks[CPU_TICKS_SENTINEL];
215 * Latency & Throughput per request
217 smbstat_req_info_t si_reqs1[SMB_COM_NUM];
218 smbstat_req_info_t si_reqs2[SMB2__NCMDS];
219 } smbstat_srv_info_t;
221 static void smbstat_init(void);
222 static void smbstat_fini(void);
223 static void smbstat_kstat_snapshot(void);
224 static void smbstat_kstat_process(void);
225 static void smbstat_kstat_print(void);
227 static void smbstat_print_counters(void);
228 static void smbstat_print_throughput(void);
229 static void smbstat_print_utilization(void);
230 static void smbstat_print_requests(void);
232 static void smbstat_cpu_init(void);
233 static void smbstat_cpu_fini(void);
234 static smbstat_cpu_snapshot_t *smbstat_cpu_current_snapshot(void);
235 static smbstat_cpu_snapshot_t *smbstat_cpu_previous_snapshot(void);
236 static void smbstat_cpu_snapshot(void);
237 static void smbstat_cpu_process(void);
239 static void smbstat_wrk_init(void);
240 static void smbstat_wrk_fini(void);
241 static void smbstat_wrk_snapshot(void);
242 static void smbstat_wrk_process(void);
243 static smbstat_wrk_snapshot_t *smbstat_wrk_current_snapshot(void);
245 static void smbstat_srv_init(void);
246 static void smbstat_srv_fini(void);
247 static void smbstat_srv_snapshot(void);
248 static void smbstat_srv_process(void);
249 static void smbstat_srv_process_counters(smbstat_srv_snapshot_t *);
250 static void smbstat_srv_process_throughput(smbstat_srv_snapshot_t *,
251 smbstat_srv_snapshot_t *);
252 static void smbstat_srv_process_utilization(smbstat_srv_snapshot_t *,
253 smbstat_srv_snapshot_t *);
254 static void smbstat_srv_process_requests(smbstat_srv_snapshot_t *,
255 smbstat_srv_snapshot_t *);
256 static void smbstat_srv_process_one_req(smbstat_req_info_t *,
257 smb_kstat_req_t *, smb_kstat_req_t *, boolean_t);
259 static smbstat_srv_snapshot_t *smbstat_srv_current_snapshot(void);
260 static smbstat_srv_snapshot_t *smbstat_srv_previous_snapshot(void);
262 static void *smbstat_zalloc(size_t);
263 static void smbstat_free(void *, size_t);
264 static void smbstat_fail(int, char *, ...);
265 static void smbstat_snapshot_inc_idx(void);
266 static void smbstat_usage(FILE *, int);
267 static uint_t smbstat_strtoi(char const *, char *);
268 static double smbstat_hrtime_delta(hrtime_t, hrtime_t);
269 static double smbstat_sub_64(uint64_t, uint64_t);
270 static void smbstat_req_order(void);
271 static double smbstat_zero(double);
272 static void smbstat_termio_init(void);
274 #pragma does_not_return(smbstat_fail, smbstat_usage)
276 static char *smbstat_cpu_states[CPU_TICKS_SENTINEL] = {
277 "cpu_ticks_idle",
278 "cpu_ticks_user",
279 "cpu_ticks_kernel"
282 static boolean_t smbstat_opt_a = B_FALSE; /* all */
283 static boolean_t smbstat_opt_c = B_FALSE; /* counters */
284 static boolean_t smbstat_opt_n = B_FALSE; /* by name */
285 static boolean_t smbstat_opt_u = B_FALSE; /* utilization */
286 static boolean_t smbstat_opt_t = B_FALSE; /* throughput */
287 static boolean_t smbstat_opt_r = B_FALSE; /* requests */
288 static boolean_t smbstat_opt_z = B_FALSE; /* non-zero requests */
290 static uint_t smbstat_interval = 0;
291 static long smbstat_nrcpus = 0;
292 static kstat_ctl_t *smbstat_ksc = NULL;
293 static kstat_t *smbstat_srv_ksp = NULL;
294 static kstat_t *smbstat_wrk_ksp = NULL;
295 static struct winsize smbstat_ws;
296 static uint16_t smbstat_rows = 0;
298 static int smbstat_snapshot_idx = 0;
299 static smbstat_cpu_snapshot_t *smbstat_cpu_snapshots[SMBSTAT_SNAPSHOT_COUNT];
300 static smbstat_srv_snapshot_t smbstat_srv_snapshots[SMBSTAT_SNAPSHOT_COUNT];
301 static smbstat_wrk_snapshot_t smbstat_wrk_snapshots[SMBSTAT_SNAPSHOT_COUNT];
302 static smbstat_srv_info_t smbstat_srv_info;
305 * main
308 main(int argc, char *argv[])
310 int c;
312 (void) setlocale(LC_ALL, "");
313 (void) textdomain(TEXT_DOMAIN);
315 while ((c = getopt(argc, argv, "achnrtuz")) != EOF) {
316 switch (c) {
317 case 'a':
318 smbstat_opt_a = B_TRUE;
319 break;
320 case 'n':
321 smbstat_opt_n = B_TRUE;
322 break;
323 case 'u':
324 smbstat_opt_u = B_TRUE;
325 break;
326 case 'c':
327 smbstat_opt_c = B_TRUE;
328 break;
329 case 'r':
330 smbstat_opt_r = B_TRUE;
331 break;
332 case 't':
333 smbstat_opt_t = B_TRUE;
334 break;
335 case 'z':
336 smbstat_opt_z = B_TRUE;
337 break;
338 case 'h':
339 smbstat_usage(stdout, 0);
340 default:
341 smbstat_usage(stderr, 1);
345 if (!smbstat_opt_u &&
346 !smbstat_opt_c &&
347 !smbstat_opt_r &&
348 !smbstat_opt_t) {
349 /* Default options when none is specified. */
350 smbstat_opt_u = B_TRUE;
351 smbstat_opt_t = B_TRUE;
354 if (optind < argc) {
355 smbstat_interval =
356 smbstat_strtoi(argv[optind], "invalid count");
357 optind++;
360 if ((argc - optind) > 1)
361 smbstat_usage(stderr, 1);
363 (void) atexit(smbstat_fini);
364 smbstat_init();
365 for (;;) {
366 smbstat_kstat_snapshot();
367 smbstat_kstat_process();
368 smbstat_kstat_print();
369 if (smbstat_interval == 0)
370 break;
371 (void) sleep(smbstat_interval);
372 smbstat_snapshot_inc_idx();
374 return (0);
378 * smbstat_init
380 * Global initialization.
382 static void
383 smbstat_init(void)
385 if ((smbstat_ksc = kstat_open()) == NULL)
386 smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat"));
388 smbstat_cpu_init();
389 smbstat_srv_init();
390 smbstat_wrk_init();
391 smbstat_req_order();
395 * smbstat_fini
397 * Releases the resources smbstat_init() allocated.
399 static void
400 smbstat_fini(void)
402 smbstat_wrk_fini();
403 smbstat_srv_fini();
404 smbstat_cpu_fini();
405 (void) kstat_close(smbstat_ksc);
409 * smbstat_kstat_snapshot
411 * Takes a snapshot of the data.
413 static void
414 smbstat_kstat_snapshot(void)
416 smbstat_cpu_snapshot();
417 smbstat_srv_snapshot();
418 smbstat_wrk_snapshot();
422 * smbstat_kstat_process
424 static void
425 smbstat_kstat_process(void)
427 smbstat_cpu_process();
428 smbstat_srv_process();
429 smbstat_wrk_process();
433 * smbstat_kstat_print
435 * Print the data processed.
437 static void
438 smbstat_kstat_print(void)
440 smbstat_termio_init();
441 smbstat_print_counters();
442 smbstat_print_throughput();
443 smbstat_print_utilization();
444 smbstat_print_requests();
445 (void) fflush(stdout);
449 * smbstat_print_counters
451 * Displays the SMB server counters (session, users...).
453 static void
454 smbstat_print_counters(void)
456 if (!smbstat_opt_c)
457 return;
459 if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_t ||
460 (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
461 (void) printf(SMBSRV_COUNTERS_BANNER);
462 smbstat_rows = 1;
465 (void) printf(SMBSRV_COUNTERS_FORMAT,
466 smbstat_srv_info.si_nbt_sess,
467 smbstat_srv_info.si_tcp_sess,
468 smbstat_srv_info.si_users,
469 smbstat_srv_info.si_trees,
470 smbstat_srv_info.si_files,
471 smbstat_srv_info.si_pipes);
473 ++smbstat_rows;
476 * smbstat_print_throughput
478 * Formats the SMB server throughput output.
480 static void
481 smbstat_print_throughput(void)
483 if (!smbstat_opt_t)
484 return;
486 if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_c ||
487 (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
488 (void) printf(SMBSRV_THROUGHPUT_BANNER);
489 smbstat_rows = 1;
491 (void) printf(SMBSRV_THROUGHPUT_FORMAT,
492 smbstat_zero(smbstat_srv_info.si_rbs),
493 smbstat_zero(smbstat_srv_info.si_tbs),
494 smbstat_zero(smbstat_srv_info.si_rqs),
495 smbstat_zero(smbstat_srv_info.si_rds),
496 smbstat_zero(smbstat_srv_info.si_wrs));
498 ++smbstat_rows;
502 * smbstat_print_utilization
504 static void
505 smbstat_print_utilization(void)
507 char *sat;
508 if (!smbstat_opt_u)
509 return;
511 if (smbstat_opt_t || smbstat_opt_r || smbstat_opt_c ||
512 (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
513 (void) printf(SMBSRV_UTILIZATION_BANNER);
514 smbstat_rows = 1;
517 if (smbstat_srv_info.si_sat)
518 sat = "yes";
519 else
520 sat = "no ";
522 (void) printf(SMBSRV_UTILIZATION_FORMAT,
523 smbstat_srv_info.si_avw,
524 smbstat_srv_info.si_avr,
525 smbstat_srv_info.si_wserv,
526 smbstat_srv_info.si_rserv,
527 smbstat_zero(smbstat_srv_info.si_wpct),
528 smbstat_zero(smbstat_srv_info.si_rpct),
529 smbstat_zero(smbstat_srv_info.si_upct),
530 sat,
531 smbstat_srv_info.si_ticks[CPU_TICKS_USER],
532 smbstat_srv_info.si_ticks[CPU_TICKS_KERNEL],
533 smbstat_srv_info.si_ticks[CPU_TICKS_IDLE]);
535 ++smbstat_rows;
539 * smbstat_print_requests
541 static void
542 smbstat_print_requests(void)
544 smbstat_req_info_t *prq;
545 int i;
547 if (!smbstat_opt_r)
548 return;
550 (void) printf(SMBSRV_REQUESTS_BANNER, " ");
552 prq = smbstat_srv_info.si_reqs1;
553 for (i = 0; i < SMB_COM_NUM; i++) {
554 if (!smbstat_opt_a &&
555 strncmp(prq[i].ri_name, "Invalid", sizeof ("Invalid")) == 0)
556 continue;
558 if (!smbstat_opt_z || (prq[i].ri_pct != 0)) {
559 (void) printf(SMBSRV_REQUESTS_FORMAT,
560 prq[i].ri_name,
561 prq[i].ri_opcode,
562 smbstat_zero(prq[i].ri_pct),
563 smbstat_zero(prq[i].ri_rbs),
564 smbstat_zero(prq[i].ri_tbs),
565 smbstat_zero(prq[i].ri_rqs),
566 prq[i].ri_mean,
567 prq[i].ri_stddev);
571 prq = smbstat_srv_info.si_reqs2;
572 for (i = 0; i < SMB2__NCMDS; i++) {
573 if (!smbstat_opt_a && i == SMB2_INVALID_CMD)
574 continue;
576 if (!smbstat_opt_z || (prq[i].ri_pct != 0)) {
577 (void) printf(SMBSRV_REQUESTS_FORMAT,
578 prq[i].ri_name,
579 prq[i].ri_opcode,
580 smbstat_zero(prq[i].ri_pct),
581 smbstat_zero(prq[i].ri_rbs),
582 smbstat_zero(prq[i].ri_tbs),
583 smbstat_zero(prq[i].ri_rqs),
584 prq[i].ri_mean,
585 prq[i].ri_stddev);
591 * smbstat_cpu_init
593 static void
594 smbstat_cpu_init(void)
596 size_t size;
597 int i;
599 smbstat_nrcpus = sysconf(_SC_CPUID_MAX) + 1;
600 size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t);
602 for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++)
603 smbstat_cpu_snapshots[i] = smbstat_zalloc(size);
607 * smbstat_cpu_fini
609 static void
610 smbstat_cpu_fini(void)
612 size_t size;
613 int i;
615 size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t);
617 for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++)
618 smbstat_free(smbstat_cpu_snapshots[i], size);
622 * smbstat_cpu_current_snapshot
624 static smbstat_cpu_snapshot_t *
625 smbstat_cpu_current_snapshot(void)
627 return (smbstat_cpu_snapshots[smbstat_snapshot_idx]);
631 * smbstat_cpu_previous_snapshot
633 static smbstat_cpu_snapshot_t *
634 smbstat_cpu_previous_snapshot(void)
636 int idx;
638 idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK;
639 return (smbstat_cpu_snapshots[idx]);
643 * smbstat_cpu_snapshot
645 static void
646 smbstat_cpu_snapshot(void)
648 kstat_t *ksp;
649 kstat_named_t *ksn;
650 smbstat_cpu_snapshot_t *curr;
651 long i;
652 int j;
654 curr = smbstat_cpu_current_snapshot();
656 for (i = 0; i < smbstat_nrcpus; i++, curr++) {
657 curr->cs_id = SMBSTAT_ID_NO_CPU;
658 curr->cs_state = p_online(i, P_STATUS);
659 /* If no valid CPU is present, move on to the next one */
660 if (curr->cs_state == -1)
661 continue;
663 curr->cs_id = i;
665 ksp = kstat_lookup(smbstat_ksc, "cpu", i, "sys");
666 if (ksp == NULL)
667 smbstat_fail(1,
668 gettext("kstat_lookup('cpu sys %d') failed"), i);
670 if (kstat_read(smbstat_ksc, ksp, NULL) == -1)
671 smbstat_fail(1,
672 gettext("kstat_read('cpu sys %d') failed"), i);
674 for (j = 0; j < CPU_TICKS_SENTINEL; j++) {
675 ksn = kstat_data_lookup(ksp, smbstat_cpu_states[j]);
676 if (ksn == NULL)
677 smbstat_fail(1,
678 gettext("kstat_data_lookup('%s') failed"),
679 smbstat_cpu_states[j]);
680 curr->cs_ticks[j] = ksn->value.ui64;
686 * smbstat_cpu_process
688 static void
689 smbstat_cpu_process(void)
691 smbstat_cpu_snapshot_t *curr, *prev;
692 double total_ticks;
693 double agg_ticks[CPU_TICKS_SENTINEL];
694 int i, j;
696 curr = smbstat_cpu_current_snapshot();
697 prev = smbstat_cpu_previous_snapshot();
698 bzero(agg_ticks, sizeof (agg_ticks));
699 total_ticks = 0;
701 for (i = 0; i < smbstat_nrcpus; i++, curr++, prev++) {
702 for (j = 0; j < CPU_TICKS_SENTINEL; j++) {
703 agg_ticks[j] += smbstat_sub_64(curr->cs_ticks[j],
704 prev->cs_ticks[j]);
705 total_ticks += smbstat_sub_64(curr->cs_ticks[j],
706 prev->cs_ticks[j]);
710 for (j = 0; j < CPU_TICKS_SENTINEL; j++)
711 smbstat_srv_info.si_ticks[j] =
712 (agg_ticks[j] * 100.0) / total_ticks;
716 * smbstat_wrk_init
718 static void
719 smbstat_wrk_init(void)
721 smbstat_wrk_ksp =
722 kstat_lookup(smbstat_ksc, "unix", -1, SMBSRV_KSTAT_WORKERS);
723 if (smbstat_wrk_ksp == NULL)
724 smbstat_fail(1,
725 gettext("cannot retrieve smbsrv workers kstat\n"));
728 static void
729 smbstat_wrk_fini(void)
731 smbstat_wrk_ksp = NULL;
735 * smbstat_wrk_snapshot
737 static void
738 smbstat_wrk_snapshot(void)
740 smbstat_wrk_snapshot_t *curr;
741 kstat_named_t *kn;
743 curr = smbstat_wrk_current_snapshot();
745 if (kstat_read(smbstat_ksc, smbstat_wrk_ksp, NULL) == -1)
746 smbstat_fail(1, gettext("kstat_read('%s') failed"),
747 smbstat_wrk_ksp->ks_name);
749 kn = kstat_data_lookup(smbstat_wrk_ksp, "maxthreads");
750 if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64))
751 smbstat_fail(1, gettext("kstat_read('%s') failed"),
752 "maxthreads");
753 curr->ws_maxthreads = kn->value.ui64;
755 kn = kstat_data_lookup(smbstat_wrk_ksp, "bnalloc");
756 if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64))
757 smbstat_fail(1, gettext("kstat_read('%s') failed"),
758 "bnalloc");
759 curr->ws_bnalloc = kn->value.ui64;
763 * smbstat_wrk_process
765 static void
766 smbstat_wrk_process(void)
768 smbstat_wrk_snapshot_t *curr;
770 curr = smbstat_wrk_current_snapshot();
772 if (curr->ws_bnalloc >= curr->ws_maxthreads)
773 smbstat_srv_info.si_sat = B_TRUE;
774 else
775 smbstat_srv_info.si_sat = B_FALSE;
779 * smbstat_wrk_current_snapshot
781 static smbstat_wrk_snapshot_t *
782 smbstat_wrk_current_snapshot(void)
784 return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]);
788 * smbstat_srv_init
790 static void
791 smbstat_srv_init(void)
793 smbstat_srv_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE,
794 getzoneid(), SMBSRV_KSTAT_STATISTICS);
795 if (smbstat_srv_ksp == NULL)
796 smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n"));
800 * smbstat_srv_fini
802 static void
803 smbstat_srv_fini(void)
805 smbstat_srv_ksp = NULL;
809 * smbstat_srv_snapshot
811 * Take a snapshot of the smbsrv module statistics.
813 static void
814 smbstat_srv_snapshot(void)
816 smbstat_srv_snapshot_t *curr;
818 curr = smbstat_srv_current_snapshot();
820 if ((kstat_read(smbstat_ksc, smbstat_srv_ksp, NULL) == -1) ||
821 (smbstat_srv_ksp->ks_data_size != sizeof (curr->ss_data)))
822 smbstat_fail(1, gettext("kstat_read('%s') failed"),
823 smbstat_srv_ksp->ks_name);
825 curr->ss_snaptime = smbstat_srv_ksp->ks_snaptime;
826 bcopy(smbstat_srv_ksp->ks_data, &curr->ss_data, sizeof (curr->ss_data));
830 * smbstat_srv_process
832 * Processes the snapshot data.
834 static void
835 smbstat_srv_process(void)
837 smbstat_srv_snapshot_t *curr, *prev;
839 curr = smbstat_srv_current_snapshot();
840 prev = smbstat_srv_previous_snapshot();
842 if (prev->ss_snaptime == 0)
843 smbstat_srv_info.si_hretime =
844 smbstat_hrtime_delta(curr->ss_data.ks_start_time,
845 curr->ss_snaptime);
846 else
847 smbstat_srv_info.si_hretime =
848 smbstat_hrtime_delta(prev->ss_snaptime, curr->ss_snaptime);
850 smbstat_srv_info.si_etime = smbstat_srv_info.si_hretime / NANOSEC;
851 smbstat_srv_info.si_total_nreqs =
852 smbstat_sub_64(curr->ss_data.ks_nreq, prev->ss_data.ks_nreq);
854 if (smbstat_opt_c)
855 smbstat_srv_process_counters(curr);
856 if (smbstat_opt_t)
857 smbstat_srv_process_throughput(curr, prev);
858 if (smbstat_opt_u)
859 smbstat_srv_process_utilization(curr, prev);
860 if (smbstat_opt_r)
861 smbstat_srv_process_requests(curr, prev);
865 * smbstat_srv_process_counters
867 static void
868 smbstat_srv_process_counters(smbstat_srv_snapshot_t *curr)
870 smbstat_srv_info.si_nbt_sess = curr->ss_data.ks_nbt_sess;
871 smbstat_srv_info.si_tcp_sess = curr->ss_data.ks_tcp_sess;
872 smbstat_srv_info.si_users = curr->ss_data.ks_users;
873 smbstat_srv_info.si_trees = curr->ss_data.ks_trees;
874 smbstat_srv_info.si_files = curr->ss_data.ks_files;
875 smbstat_srv_info.si_pipes = curr->ss_data.ks_pipes;
879 * smbstat_srv_process_throughput
881 * Processes the data relative to the throughput of the smbsrv module and
882 * stores the results in the structure smbstat_srv_info.
884 static void
885 smbstat_srv_process_throughput(
886 smbstat_srv_snapshot_t *curr,
887 smbstat_srv_snapshot_t *prev)
889 smbstat_srv_info.si_tbs =
890 smbstat_sub_64(curr->ss_data.ks_txb, prev->ss_data.ks_txb);
891 smbstat_srv_info.si_tbs /= smbstat_srv_info.si_etime;
892 smbstat_srv_info.si_rbs =
893 smbstat_sub_64(curr->ss_data.ks_rxb, prev->ss_data.ks_rxb);
894 smbstat_srv_info.si_rbs /= smbstat_srv_info.si_etime;
895 smbstat_srv_info.si_rqs = smbstat_srv_info.si_total_nreqs;
896 smbstat_srv_info.si_rqs /= smbstat_srv_info.si_etime;
898 smbstat_srv_info.si_rds = smbstat_sub_64(
899 curr->ss_data.ks_reqs1[SMB_COM_READ].kr_nreq,
900 prev->ss_data.ks_reqs1[SMB_COM_READ].kr_nreq);
901 smbstat_srv_info.si_rds += smbstat_sub_64(
902 curr->ss_data.ks_reqs1[SMB_COM_LOCK_AND_READ].kr_nreq,
903 prev->ss_data.ks_reqs1[SMB_COM_LOCK_AND_READ].kr_nreq);
904 smbstat_srv_info.si_rds += smbstat_sub_64(
905 curr->ss_data.ks_reqs1[SMB_COM_READ_RAW].kr_nreq,
906 prev->ss_data.ks_reqs1[SMB_COM_READ_RAW].kr_nreq);
907 smbstat_srv_info.si_rds += smbstat_sub_64(
908 curr->ss_data.ks_reqs1[SMB_COM_READ_ANDX].kr_nreq,
909 prev->ss_data.ks_reqs1[SMB_COM_READ_ANDX].kr_nreq);
910 smbstat_srv_info.si_rds += smbstat_sub_64(
911 curr->ss_data.ks_reqs2[SMB2_READ].kr_nreq,
912 prev->ss_data.ks_reqs2[SMB2_READ].kr_nreq);
913 smbstat_srv_info.si_rds /= smbstat_srv_info.si_etime;
915 smbstat_srv_info.si_wrs = smbstat_sub_64(
916 curr->ss_data.ks_reqs1[SMB_COM_WRITE].kr_nreq,
917 prev->ss_data.ks_reqs1[SMB_COM_WRITE].kr_nreq);
918 smbstat_srv_info.si_wrs += smbstat_sub_64(
919 curr->ss_data.ks_reqs1[SMB_COM_WRITE_AND_UNLOCK].kr_nreq,
920 prev->ss_data.ks_reqs1[SMB_COM_WRITE_AND_UNLOCK].kr_nreq);
921 smbstat_srv_info.si_wrs += smbstat_sub_64(
922 curr->ss_data.ks_reqs1[SMB_COM_WRITE_RAW].kr_nreq,
923 prev->ss_data.ks_reqs1[SMB_COM_WRITE_RAW].kr_nreq);
924 smbstat_srv_info.si_wrs += smbstat_sub_64(
925 curr->ss_data.ks_reqs1[SMB_COM_WRITE_AND_CLOSE].kr_nreq,
926 prev->ss_data.ks_reqs1[SMB_COM_WRITE_AND_CLOSE].kr_nreq);
927 smbstat_srv_info.si_wrs += smbstat_sub_64(
928 curr->ss_data.ks_reqs1[SMB_COM_WRITE_ANDX].kr_nreq,
929 prev->ss_data.ks_reqs1[SMB_COM_WRITE_ANDX].kr_nreq);
930 smbstat_srv_info.si_wrs += smbstat_sub_64(
931 curr->ss_data.ks_reqs2[SMB2_WRITE].kr_nreq,
932 prev->ss_data.ks_reqs2[SMB2_WRITE].kr_nreq);
933 smbstat_srv_info.si_wrs /= smbstat_srv_info.si_etime;
937 * smbstat_srv_process_utilization
939 * Processes the data relative to the utilization of the smbsrv module and
940 * stores the results in the structure smbstat_srv_info.
942 static void
943 smbstat_srv_process_utilization(
944 smbstat_srv_snapshot_t *curr,
945 smbstat_srv_snapshot_t *prev)
947 double tw_delta, tr_delta;
948 double w_delta, r_delta;
949 double tps, rqs;
951 w_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wlentime,
952 curr->ss_data.ks_utilization.ku_wlentime);
953 r_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rlentime,
954 curr->ss_data.ks_utilization.ku_rlentime);
955 tw_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wtime,
956 curr->ss_data.ks_utilization.ku_wtime);
957 tr_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rtime,
958 curr->ss_data.ks_utilization.ku_rtime);
959 rqs = smbstat_srv_info.si_total_nreqs / smbstat_srv_info.si_etime;
961 /* Average number of requests waiting */
962 if (w_delta != 0)
963 smbstat_srv_info.si_avw = w_delta / smbstat_srv_info.si_hretime;
964 else
965 smbstat_srv_info.si_avw = 0.0;
967 /* Average number of request running */
968 if (r_delta != 0)
969 smbstat_srv_info.si_avr = r_delta / smbstat_srv_info.si_hretime;
970 else
971 smbstat_srv_info.si_avr = 0.0;
973 /* Utilization */
974 smbstat_srv_info.si_upct =
975 (smbstat_srv_info.si_avr / curr->ss_data.ks_maxreqs) * 100;
977 /* Average wait service time in milliseconds */
978 smbstat_srv_info.si_rserv = 0.0;
979 smbstat_srv_info.si_wserv = 0.0;
980 if (rqs > 0.0 &&
981 (smbstat_srv_info.si_avw != 0.0 ||
982 smbstat_srv_info.si_avr != 0.0)) {
983 tps = 1 / rqs;
984 if (smbstat_srv_info.si_avw != 0.0)
985 smbstat_srv_info.si_wserv =
986 smbstat_srv_info.si_avw * tps;
987 if (smbstat_srv_info.si_avr != 0.0)
988 smbstat_srv_info.si_rserv =
989 smbstat_srv_info.si_avr * tps;
992 /* % of time there is a transaction waiting for service */
993 if (tw_delta != 0) {
994 smbstat_srv_info.si_wpct = tw_delta;
995 smbstat_srv_info.si_wpct /= smbstat_srv_info.si_hretime;
996 smbstat_srv_info.si_wpct *= 100.0;
997 } else {
998 smbstat_srv_info.si_wpct = 0.0;
1001 /* % of time there is a transaction running */
1002 if (tr_delta != 0) {
1003 smbstat_srv_info.si_rpct = tr_delta;
1004 smbstat_srv_info.si_rpct /= smbstat_srv_info.si_hretime;
1005 smbstat_srv_info.si_rpct *= 100.0;
1006 } else {
1007 smbstat_srv_info.si_rpct = 0.0;
1012 * smbstat_srv_process_requests
1014 * Processes the data relative to the SMB requests and stores the results in
1015 * the structure smbstat_srv_info.
1017 static void
1018 smbstat_srv_process_requests(
1019 smbstat_srv_snapshot_t *curr,
1020 smbstat_srv_snapshot_t *prev)
1022 smbstat_req_info_t *info;
1023 smb_kstat_req_t *curr_req;
1024 smb_kstat_req_t *prev_req;
1025 int i, idx;
1026 boolean_t firstcall = (prev->ss_snaptime == 0);
1028 for (i = 0; i < SMB_COM_NUM; i++) {
1029 info = &smbstat_srv_info.si_reqs1[i];
1030 idx = info[i].ri_opcode & 0xFF;
1031 curr_req = &curr->ss_data.ks_reqs1[idx];
1032 prev_req = &prev->ss_data.ks_reqs1[idx];
1033 smbstat_srv_process_one_req(
1034 info, curr_req, prev_req, firstcall);
1037 for (i = 0; i < SMB2__NCMDS; i++) {
1038 info = &smbstat_srv_info.si_reqs2[i];
1039 curr_req = &curr->ss_data.ks_reqs2[i];
1040 prev_req = &prev->ss_data.ks_reqs2[i];
1041 smbstat_srv_process_one_req(
1042 info, curr_req, prev_req, firstcall);
1046 static void
1047 smbstat_srv_process_one_req(
1048 smbstat_req_info_t *info,
1049 smb_kstat_req_t *curr_req,
1050 smb_kstat_req_t *prev_req,
1051 boolean_t firstcall)
1053 double nrqs;
1055 nrqs = smbstat_sub_64(curr_req->kr_nreq,
1056 prev_req->kr_nreq);
1058 info->ri_rqs = nrqs / smbstat_srv_info.si_etime;
1060 info->ri_rbs = smbstat_sub_64(
1061 curr_req->kr_rxb,
1062 prev_req->kr_rxb) /
1063 smbstat_srv_info.si_etime;
1065 info->ri_tbs = smbstat_sub_64(
1066 curr_req->kr_txb,
1067 prev_req->kr_txb) /
1068 smbstat_srv_info.si_etime;
1070 info->ri_pct = nrqs * 100;
1071 if (smbstat_srv_info.si_total_nreqs > 0)
1072 info->ri_pct /= smbstat_srv_info.si_total_nreqs;
1074 if (firstcall) {
1075 /* First time. Take the aggregate */
1076 info->ri_stddev =
1077 curr_req->kr_a_stddev;
1078 info->ri_mean = curr_req->kr_a_mean;
1079 } else {
1080 /* Take the differential */
1081 info->ri_stddev =
1082 curr_req->kr_d_stddev;
1083 info->ri_mean = curr_req->kr_d_mean;
1085 if (nrqs > 0) {
1086 info->ri_stddev /= nrqs;
1087 info->ri_stddev = sqrt(info->ri_stddev);
1088 } else {
1089 info->ri_stddev = 0;
1091 info->ri_stddev /= NANOSEC;
1092 info->ri_mean /= NANOSEC;
1097 * smbstat_srv_current_snapshot
1099 * Returns the current snapshot.
1101 static smbstat_srv_snapshot_t *
1102 smbstat_srv_current_snapshot(void)
1104 return (&smbstat_srv_snapshots[smbstat_snapshot_idx]);
1108 * smbstat_srv_previous_snapshot
1110 * Returns the previous snapshot.
1112 static smbstat_srv_snapshot_t *
1113 smbstat_srv_previous_snapshot(void)
1115 int idx;
1117 idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK;
1118 return (&smbstat_srv_snapshots[idx]);
1122 * smbstat_usage
1124 * Prints out a help message.
1126 static void
1127 smbstat_usage(FILE *fd, int exit_code)
1129 (void) fprintf(fd, gettext(SMBSTAT_HELP));
1130 exit(exit_code);
1134 * smbstat_fail
1136 * Prints out to stderr an error message and exits the process.
1138 static void
1139 smbstat_fail(int do_perror, char *message, ...)
1141 va_list args;
1143 va_start(args, message);
1144 (void) fprintf(stderr, gettext("smbstat: "));
1145 /* LINTED E_SEC_PRINTF_VAR_FMT */
1146 (void) vfprintf(stderr, message, args);
1147 va_end(args);
1148 if (do_perror)
1149 (void) fprintf(stderr, ": %s", strerror(errno));
1150 (void) fprintf(stderr, "\n");
1151 exit(1);
1155 * smbstat_sub_64
1157 * Substract 2 uint64_t and returns a double.
1159 static double
1160 smbstat_sub_64(uint64_t a, uint64_t b)
1162 return ((double)(a - b));
1166 * smbstat_zero
1168 * Returns zero if the value passed in is less than 1.
1170 static double
1171 smbstat_zero(double value)
1173 if (value < 1)
1174 value = 0;
1175 return (value);
1179 * smbstat_strtoi
1181 * Converts a string representing an integer value into its binary value.
1182 * If the conversion fails this routine exits the process.
1184 static uint_t
1185 smbstat_strtoi(char const *val, char *errmsg)
1187 char *end;
1188 long tmp;
1190 errno = 0;
1191 tmp = strtol(val, &end, 10);
1192 if (*end != '\0' || errno)
1193 smbstat_fail(1, "%s %s", errmsg, val);
1194 return ((uint_t)tmp);
1198 * smbstat_termio_init
1200 * Determines the size of the terminal associated with the process.
1202 static void
1203 smbstat_termio_init(void)
1205 char *envp;
1207 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &smbstat_ws) != -1) {
1208 if (smbstat_ws.ws_row == 0) {
1209 envp = getenv("LINES");
1210 if (envp != NULL)
1211 smbstat_ws.ws_row = atoi(envp);
1214 if (smbstat_ws.ws_col == 0) {
1215 envp = getenv("COLUMNS");
1216 if (envp != NULL)
1217 smbstat_ws.ws_row = atoi(envp);
1220 if (smbstat_ws.ws_col == 0)
1221 smbstat_ws.ws_col = 80;
1222 if (smbstat_ws.ws_row == 0)
1223 smbstat_ws.ws_row = 25;
1227 * smbstat_snapshot_idx_inc
1229 * Increments the snapshot index.
1231 static void
1232 smbstat_snapshot_inc_idx(void)
1234 smbstat_snapshot_idx++;
1235 smbstat_snapshot_idx &= SMBSTAT_SNAPSHOT_MASK;
1239 * smbstat_req_cmp_name
1241 * Call back function passed to qsort() when the list of requests must be sorted
1242 * by name.
1244 static int
1245 smbstat_req_cmp_name(const void *obj1, const void *obj2)
1247 return (strncasecmp(
1248 ((smbstat_req_info_t *)obj1)->ri_name,
1249 ((smbstat_req_info_t *)obj2)->ri_name,
1250 sizeof (((smbstat_req_info_t *)obj2)->ri_name)));
1254 * smbstat_req_order
1256 * Snapshots the smbsrv module statistics once to get the name of the requests.
1257 * The request list is smbstat_srv_info is then sorted by name or by code
1258 * depending on the boolean smbstat_opt_a.
1259 * The function should be called once during initialization.
1261 static void
1262 smbstat_req_order(void)
1264 smbstat_srv_snapshot_t *ss;
1265 smbstat_req_info_t *info;
1266 smb_kstat_req_t *reqs;
1267 int i;
1269 smbstat_srv_snapshot();
1270 ss = smbstat_srv_current_snapshot();
1272 reqs = ss->ss_data.ks_reqs1;
1273 info = smbstat_srv_info.si_reqs1;
1274 for (i = 0; i < SMB_COM_NUM; i++) {
1275 (void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1276 sizeof (reqs[i].kr_name));
1277 info[i].ri_opcode = i;
1279 if (smbstat_opt_n)
1280 qsort(info, SMB_COM_NUM, sizeof (smbstat_req_info_t),
1281 smbstat_req_cmp_name);
1283 reqs = ss->ss_data.ks_reqs2;
1284 info = smbstat_srv_info.si_reqs2;
1285 for (i = 0; i < SMB2__NCMDS; i++) {
1286 (void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1287 sizeof (reqs[i].kr_name));
1288 info[i].ri_opcode = i;
1290 if (smbstat_opt_n)
1291 qsort(info, SMB2__NCMDS, sizeof (smbstat_req_info_t),
1292 smbstat_req_cmp_name);
1296 * Return the number of ticks delta between two hrtime_t
1297 * values. Attempt to cater for various kinds of overflow
1298 * in hrtime_t - no matter how improbable.
1300 static double
1301 smbstat_hrtime_delta(hrtime_t old, hrtime_t new)
1303 uint64_t del;
1305 if ((new >= old) && (old >= 0L))
1306 return ((double)(new - old));
1308 * We've overflowed the positive portion of an hrtime_t.
1310 if (new < 0L) {
1312 * The new value is negative. Handle the case where the old
1313 * value is positive or negative.
1315 uint64_t n1;
1316 uint64_t o1;
1318 n1 = -new;
1319 if (old > 0L)
1320 return ((double)(n1 - old));
1322 o1 = -old;
1323 del = n1 - o1;
1324 return ((double)del);
1328 * Either we've just gone from being negative to positive *or* the last
1329 * entry was positive and the new entry is also positive but *less* than
1330 * the old entry. This implies we waited quite a few days on a very fast
1331 * system between displays.
1333 if (old < 0L) {
1334 uint64_t o2;
1335 o2 = -old;
1336 del = UINT64_MAX - o2;
1337 } else {
1338 del = UINT64_MAX - old;
1340 del += new;
1341 return ((double)del);
1344 static void *
1345 smbstat_zalloc(size_t size)
1347 void *ptr;
1349 ptr = umem_zalloc(size, UMEM_DEFAULT);
1350 if (ptr == NULL)
1351 smbstat_fail(1, gettext("out of memory"));
1352 return (ptr);
1355 static void
1356 smbstat_free(void *ptr, size_t size)
1358 umem_free(ptr, size);