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]
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
36 * The flow of the code is the following:
45 * +--------------------------*
46 * | Take a snapshot the data | <--------+
47 * +--------------------------+ |
51 * +----------------------+ |
52 * | Process the snapshot | |
53 * +----------------------+ |
57 * +------------------------------------+ |
58 * | Print the result of the processing | |
59 * +------------------------------------+ |
63 * Yes --------------- |
64 * +------------ < interval == 0 ? > |
69 * | +------------------------+ |
70 * | | Sleep for the duration | ----------+
71 * | | of the interval. |
72 * | +------------------------+
74 * +---------------------+
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
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" \
144 #define SMBSRV_REQUESTS_FORMAT \
145 "%30s %02X %3.0f %1.3e %1.3e %1.3e %1.3e %1.3e\n"
154 typedef struct smbstat_cpu_snapshot
{
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
;
168 } smbstat_wrk_snapshot_t
;
170 typedef struct smbstat_req_info
{
171 char ri_name
[KSTAT_STRLEN
];
179 } smbstat_req_info_t
;
181 typedef struct smbstat_srv_info
{
184 double si_total_nreqs
;
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 */
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
] = {
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
;
308 main(int argc
, char *argv
[])
312 (void) setlocale(LC_ALL
, "");
313 (void) textdomain(TEXT_DOMAIN
);
315 if (is_system_labeled()) {
316 (void) fprintf(stderr
,
317 gettext("%s: Trusted Extensions not supported.\n"),
322 while ((c
= getopt(argc
, argv
, "achnrtuz")) != EOF
) {
325 smbstat_opt_a
= B_TRUE
;
328 smbstat_opt_n
= B_TRUE
;
331 smbstat_opt_u
= B_TRUE
;
334 smbstat_opt_c
= B_TRUE
;
337 smbstat_opt_r
= B_TRUE
;
340 smbstat_opt_t
= B_TRUE
;
343 smbstat_opt_z
= B_TRUE
;
346 smbstat_usage(stdout
, 0);
348 smbstat_usage(stderr
, 1);
352 if (!smbstat_opt_u
&&
356 /* Default options when none is specified. */
357 smbstat_opt_u
= B_TRUE
;
358 smbstat_opt_t
= B_TRUE
;
363 smbstat_strtoi(argv
[optind
], "invalid count");
367 if ((argc
- optind
) > 1)
368 smbstat_usage(stderr
, 1);
370 (void) atexit(smbstat_fini
);
373 smbstat_kstat_snapshot();
374 smbstat_kstat_process();
375 smbstat_kstat_print();
376 if (smbstat_interval
== 0)
378 (void) sleep(smbstat_interval
);
379 smbstat_snapshot_inc_idx();
387 * Global initialization.
392 if ((smbstat_ksc
= kstat_open()) == NULL
)
393 smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat"));
404 * Releases the resources smbstat_init() allocated.
412 (void) kstat_close(smbstat_ksc
);
416 * smbstat_kstat_snapshot
418 * Takes a snapshot of the data.
421 smbstat_kstat_snapshot(void)
423 smbstat_cpu_snapshot();
424 smbstat_srv_snapshot();
425 smbstat_wrk_snapshot();
429 * smbstat_kstat_process
432 smbstat_kstat_process(void)
434 smbstat_cpu_process();
435 smbstat_srv_process();
436 smbstat_wrk_process();
440 * smbstat_kstat_print
442 * Print the data processed.
445 smbstat_kstat_print(void)
447 smbstat_termio_init();
448 smbstat_print_counters();
449 smbstat_print_throughput();
450 smbstat_print_utilization();
451 smbstat_print_requests();
452 (void) fflush(stdout
);
456 * smbstat_print_counters
458 * Displays the SMB server counters (session, users...).
461 smbstat_print_counters(void)
466 if (smbstat_opt_u
|| smbstat_opt_r
|| smbstat_opt_t
||
467 (smbstat_rows
== 0) || (smbstat_rows
>= smbstat_ws
.ws_row
)) {
468 (void) printf(SMBSRV_COUNTERS_BANNER
);
472 (void) printf(SMBSRV_COUNTERS_FORMAT
,
473 smbstat_srv_info
.si_nbt_sess
,
474 smbstat_srv_info
.si_tcp_sess
,
475 smbstat_srv_info
.si_users
,
476 smbstat_srv_info
.si_trees
,
477 smbstat_srv_info
.si_files
,
478 smbstat_srv_info
.si_pipes
);
483 * smbstat_print_throughput
485 * Formats the SMB server throughput output.
488 smbstat_print_throughput(void)
493 if (smbstat_opt_u
|| smbstat_opt_r
|| smbstat_opt_c
||
494 (smbstat_rows
== 0) || (smbstat_rows
>= smbstat_ws
.ws_row
)) {
495 (void) printf(SMBSRV_THROUGHPUT_BANNER
);
498 (void) printf(SMBSRV_THROUGHPUT_FORMAT
,
499 smbstat_zero(smbstat_srv_info
.si_rbs
),
500 smbstat_zero(smbstat_srv_info
.si_tbs
),
501 smbstat_zero(smbstat_srv_info
.si_rqs
),
502 smbstat_zero(smbstat_srv_info
.si_rds
),
503 smbstat_zero(smbstat_srv_info
.si_wrs
));
509 * smbstat_print_utilization
512 smbstat_print_utilization(void)
518 if (smbstat_opt_t
|| smbstat_opt_r
|| smbstat_opt_c
||
519 (smbstat_rows
== 0) || (smbstat_rows
>= smbstat_ws
.ws_row
)) {
520 (void) printf(SMBSRV_UTILIZATION_BANNER
);
524 if (smbstat_srv_info
.si_sat
)
529 (void) printf(SMBSRV_UTILIZATION_FORMAT
,
530 smbstat_srv_info
.si_avw
,
531 smbstat_srv_info
.si_avr
,
532 smbstat_srv_info
.si_wserv
,
533 smbstat_srv_info
.si_rserv
,
534 smbstat_zero(smbstat_srv_info
.si_wpct
),
535 smbstat_zero(smbstat_srv_info
.si_rpct
),
536 smbstat_zero(smbstat_srv_info
.si_upct
),
538 smbstat_srv_info
.si_ticks
[CPU_TICKS_USER
],
539 smbstat_srv_info
.si_ticks
[CPU_TICKS_KERNEL
],
540 smbstat_srv_info
.si_ticks
[CPU_TICKS_IDLE
]);
546 * smbstat_print_requests
549 smbstat_print_requests(void)
551 smbstat_req_info_t
*prq
;
557 (void) printf(SMBSRV_REQUESTS_BANNER
, " ");
559 prq
= smbstat_srv_info
.si_reqs1
;
560 for (i
= 0; i
< SMB_COM_NUM
; i
++) {
561 if (!smbstat_opt_a
&&
562 strncmp(prq
[i
].ri_name
, "Invalid", sizeof ("Invalid")) == 0)
565 if (!smbstat_opt_z
|| (prq
[i
].ri_pct
!= 0)) {
566 (void) printf(SMBSRV_REQUESTS_FORMAT
,
569 smbstat_zero(prq
[i
].ri_pct
),
570 smbstat_zero(prq
[i
].ri_rbs
),
571 smbstat_zero(prq
[i
].ri_tbs
),
572 smbstat_zero(prq
[i
].ri_rqs
),
578 prq
= smbstat_srv_info
.si_reqs2
;
579 for (i
= 0; i
< SMB2__NCMDS
; i
++) {
580 if (!smbstat_opt_a
&& i
== SMB2_INVALID_CMD
)
583 if (!smbstat_opt_z
|| (prq
[i
].ri_pct
!= 0)) {
584 (void) printf(SMBSRV_REQUESTS_FORMAT
,
587 smbstat_zero(prq
[i
].ri_pct
),
588 smbstat_zero(prq
[i
].ri_rbs
),
589 smbstat_zero(prq
[i
].ri_tbs
),
590 smbstat_zero(prq
[i
].ri_rqs
),
601 smbstat_cpu_init(void)
606 smbstat_nrcpus
= sysconf(_SC_CPUID_MAX
) + 1;
607 size
= smbstat_nrcpus
* sizeof (smbstat_cpu_snapshot_t
);
609 for (i
= 0; i
< SMBSTAT_SNAPSHOT_COUNT
; i
++)
610 smbstat_cpu_snapshots
[i
] = smbstat_zalloc(size
);
617 smbstat_cpu_fini(void)
622 size
= smbstat_nrcpus
* sizeof (smbstat_cpu_snapshot_t
);
624 for (i
= 0; i
< SMBSTAT_SNAPSHOT_COUNT
; i
++)
625 smbstat_free(smbstat_cpu_snapshots
[i
], size
);
629 * smbstat_cpu_current_snapshot
631 static smbstat_cpu_snapshot_t
*
632 smbstat_cpu_current_snapshot(void)
634 return (smbstat_cpu_snapshots
[smbstat_snapshot_idx
]);
638 * smbstat_cpu_previous_snapshot
640 static smbstat_cpu_snapshot_t
*
641 smbstat_cpu_previous_snapshot(void)
645 idx
= (smbstat_snapshot_idx
- 1) & SMBSTAT_SNAPSHOT_MASK
;
646 return (smbstat_cpu_snapshots
[idx
]);
650 * smbstat_cpu_snapshot
653 smbstat_cpu_snapshot(void)
657 smbstat_cpu_snapshot_t
*curr
;
661 curr
= smbstat_cpu_current_snapshot();
663 for (i
= 0; i
< smbstat_nrcpus
; i
++, curr
++) {
664 curr
->cs_id
= SMBSTAT_ID_NO_CPU
;
665 curr
->cs_state
= p_online(i
, P_STATUS
);
666 /* If no valid CPU is present, move on to the next one */
667 if (curr
->cs_state
== -1)
672 ksp
= kstat_lookup(smbstat_ksc
, "cpu", i
, "sys");
675 gettext("kstat_lookup('cpu sys %d') failed"), i
);
677 if (kstat_read(smbstat_ksc
, ksp
, NULL
) == -1)
679 gettext("kstat_read('cpu sys %d') failed"), i
);
681 for (j
= 0; j
< CPU_TICKS_SENTINEL
; j
++) {
682 ksn
= kstat_data_lookup(ksp
, smbstat_cpu_states
[j
]);
685 gettext("kstat_data_lookup('%s') failed"),
686 smbstat_cpu_states
[j
]);
687 curr
->cs_ticks
[j
] = ksn
->value
.ui64
;
693 * smbstat_cpu_process
696 smbstat_cpu_process(void)
698 smbstat_cpu_snapshot_t
*curr
, *prev
;
700 double agg_ticks
[CPU_TICKS_SENTINEL
];
703 curr
= smbstat_cpu_current_snapshot();
704 prev
= smbstat_cpu_previous_snapshot();
705 bzero(agg_ticks
, sizeof (agg_ticks
));
708 for (i
= 0; i
< smbstat_nrcpus
; i
++, curr
++, prev
++) {
709 for (j
= 0; j
< CPU_TICKS_SENTINEL
; j
++) {
710 agg_ticks
[j
] += smbstat_sub_64(curr
->cs_ticks
[j
],
712 total_ticks
+= smbstat_sub_64(curr
->cs_ticks
[j
],
717 for (j
= 0; j
< CPU_TICKS_SENTINEL
; j
++)
718 smbstat_srv_info
.si_ticks
[j
] =
719 (agg_ticks
[j
] * 100.0) / total_ticks
;
726 smbstat_wrk_init(void)
729 kstat_lookup(smbstat_ksc
, "unix", -1, SMBSRV_KSTAT_WORKERS
);
730 if (smbstat_wrk_ksp
== NULL
)
732 gettext("cannot retrieve smbsrv workers kstat\n"));
736 smbstat_wrk_fini(void)
738 smbstat_wrk_ksp
= NULL
;
742 * smbstat_wrk_snapshot
745 smbstat_wrk_snapshot(void)
747 smbstat_wrk_snapshot_t
*curr
;
750 curr
= smbstat_wrk_current_snapshot();
752 if (kstat_read(smbstat_ksc
, smbstat_wrk_ksp
, NULL
) == -1)
753 smbstat_fail(1, gettext("kstat_read('%s') failed"),
754 smbstat_wrk_ksp
->ks_name
);
756 kn
= kstat_data_lookup(smbstat_wrk_ksp
, "maxthreads");
757 if ((kn
== NULL
) || (kn
->data_type
!= KSTAT_DATA_UINT64
))
758 smbstat_fail(1, gettext("kstat_read('%s') failed"),
760 curr
->ws_maxthreads
= kn
->value
.ui64
;
762 kn
= kstat_data_lookup(smbstat_wrk_ksp
, "bnalloc");
763 if ((kn
== NULL
) || (kn
->data_type
!= KSTAT_DATA_UINT64
))
764 smbstat_fail(1, gettext("kstat_read('%s') failed"),
766 curr
->ws_bnalloc
= kn
->value
.ui64
;
770 * smbstat_wrk_process
773 smbstat_wrk_process(void)
775 smbstat_wrk_snapshot_t
*curr
;
777 curr
= smbstat_wrk_current_snapshot();
779 if (curr
->ws_bnalloc
>= curr
->ws_maxthreads
)
780 smbstat_srv_info
.si_sat
= B_TRUE
;
782 smbstat_srv_info
.si_sat
= B_FALSE
;
786 * smbstat_wrk_current_snapshot
788 static smbstat_wrk_snapshot_t
*
789 smbstat_wrk_current_snapshot(void)
791 return (&smbstat_wrk_snapshots
[smbstat_snapshot_idx
]);
798 smbstat_srv_init(void)
800 smbstat_srv_ksp
= kstat_lookup(smbstat_ksc
, SMBSRV_KSTAT_MODULE
,
801 getzoneid(), SMBSRV_KSTAT_STATISTICS
);
802 if (smbstat_srv_ksp
== NULL
)
803 smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n"));
810 smbstat_srv_fini(void)
812 smbstat_srv_ksp
= NULL
;
816 * smbstat_srv_snapshot
818 * Take a snapshot of the smbsrv module statistics.
821 smbstat_srv_snapshot(void)
823 smbstat_srv_snapshot_t
*curr
;
825 curr
= smbstat_srv_current_snapshot();
827 if ((kstat_read(smbstat_ksc
, smbstat_srv_ksp
, NULL
) == -1) ||
828 (smbstat_srv_ksp
->ks_data_size
!= sizeof (curr
->ss_data
)))
829 smbstat_fail(1, gettext("kstat_read('%s') failed"),
830 smbstat_srv_ksp
->ks_name
);
832 curr
->ss_snaptime
= smbstat_srv_ksp
->ks_snaptime
;
833 bcopy(smbstat_srv_ksp
->ks_data
, &curr
->ss_data
, sizeof (curr
->ss_data
));
837 * smbstat_srv_process
839 * Processes the snapshot data.
842 smbstat_srv_process(void)
844 smbstat_srv_snapshot_t
*curr
, *prev
;
846 curr
= smbstat_srv_current_snapshot();
847 prev
= smbstat_srv_previous_snapshot();
849 if (prev
->ss_snaptime
== 0)
850 smbstat_srv_info
.si_hretime
=
851 smbstat_hrtime_delta(curr
->ss_data
.ks_start_time
,
854 smbstat_srv_info
.si_hretime
=
855 smbstat_hrtime_delta(prev
->ss_snaptime
, curr
->ss_snaptime
);
857 smbstat_srv_info
.si_etime
= smbstat_srv_info
.si_hretime
/ NANOSEC
;
858 smbstat_srv_info
.si_total_nreqs
=
859 smbstat_sub_64(curr
->ss_data
.ks_nreq
, prev
->ss_data
.ks_nreq
);
862 smbstat_srv_process_counters(curr
);
864 smbstat_srv_process_throughput(curr
, prev
);
866 smbstat_srv_process_utilization(curr
, prev
);
868 smbstat_srv_process_requests(curr
, prev
);
872 * smbstat_srv_process_counters
875 smbstat_srv_process_counters(smbstat_srv_snapshot_t
*curr
)
877 smbstat_srv_info
.si_nbt_sess
= curr
->ss_data
.ks_nbt_sess
;
878 smbstat_srv_info
.si_tcp_sess
= curr
->ss_data
.ks_tcp_sess
;
879 smbstat_srv_info
.si_users
= curr
->ss_data
.ks_users
;
880 smbstat_srv_info
.si_trees
= curr
->ss_data
.ks_trees
;
881 smbstat_srv_info
.si_files
= curr
->ss_data
.ks_files
;
882 smbstat_srv_info
.si_pipes
= curr
->ss_data
.ks_pipes
;
886 * smbstat_srv_process_throughput
888 * Processes the data relative to the throughput of the smbsrv module and
889 * stores the results in the structure smbstat_srv_info.
892 smbstat_srv_process_throughput(
893 smbstat_srv_snapshot_t
*curr
,
894 smbstat_srv_snapshot_t
*prev
)
896 smbstat_srv_info
.si_tbs
=
897 smbstat_sub_64(curr
->ss_data
.ks_txb
, prev
->ss_data
.ks_txb
);
898 smbstat_srv_info
.si_tbs
/= smbstat_srv_info
.si_etime
;
899 smbstat_srv_info
.si_rbs
=
900 smbstat_sub_64(curr
->ss_data
.ks_rxb
, prev
->ss_data
.ks_rxb
);
901 smbstat_srv_info
.si_rbs
/= smbstat_srv_info
.si_etime
;
902 smbstat_srv_info
.si_rqs
= smbstat_srv_info
.si_total_nreqs
;
903 smbstat_srv_info
.si_rqs
/= smbstat_srv_info
.si_etime
;
905 smbstat_srv_info
.si_rds
= smbstat_sub_64(
906 curr
->ss_data
.ks_reqs1
[SMB_COM_READ
].kr_nreq
,
907 prev
->ss_data
.ks_reqs1
[SMB_COM_READ
].kr_nreq
);
908 smbstat_srv_info
.si_rds
+= smbstat_sub_64(
909 curr
->ss_data
.ks_reqs1
[SMB_COM_LOCK_AND_READ
].kr_nreq
,
910 prev
->ss_data
.ks_reqs1
[SMB_COM_LOCK_AND_READ
].kr_nreq
);
911 smbstat_srv_info
.si_rds
+= smbstat_sub_64(
912 curr
->ss_data
.ks_reqs1
[SMB_COM_READ_RAW
].kr_nreq
,
913 prev
->ss_data
.ks_reqs1
[SMB_COM_READ_RAW
].kr_nreq
);
914 smbstat_srv_info
.si_rds
+= smbstat_sub_64(
915 curr
->ss_data
.ks_reqs1
[SMB_COM_READ_ANDX
].kr_nreq
,
916 prev
->ss_data
.ks_reqs1
[SMB_COM_READ_ANDX
].kr_nreq
);
917 smbstat_srv_info
.si_rds
+= smbstat_sub_64(
918 curr
->ss_data
.ks_reqs2
[SMB2_READ
].kr_nreq
,
919 prev
->ss_data
.ks_reqs2
[SMB2_READ
].kr_nreq
);
920 smbstat_srv_info
.si_rds
/= smbstat_srv_info
.si_etime
;
922 smbstat_srv_info
.si_wrs
= smbstat_sub_64(
923 curr
->ss_data
.ks_reqs1
[SMB_COM_WRITE
].kr_nreq
,
924 prev
->ss_data
.ks_reqs1
[SMB_COM_WRITE
].kr_nreq
);
925 smbstat_srv_info
.si_wrs
+= smbstat_sub_64(
926 curr
->ss_data
.ks_reqs1
[SMB_COM_WRITE_AND_UNLOCK
].kr_nreq
,
927 prev
->ss_data
.ks_reqs1
[SMB_COM_WRITE_AND_UNLOCK
].kr_nreq
);
928 smbstat_srv_info
.si_wrs
+= smbstat_sub_64(
929 curr
->ss_data
.ks_reqs1
[SMB_COM_WRITE_RAW
].kr_nreq
,
930 prev
->ss_data
.ks_reqs1
[SMB_COM_WRITE_RAW
].kr_nreq
);
931 smbstat_srv_info
.si_wrs
+= smbstat_sub_64(
932 curr
->ss_data
.ks_reqs1
[SMB_COM_WRITE_AND_CLOSE
].kr_nreq
,
933 prev
->ss_data
.ks_reqs1
[SMB_COM_WRITE_AND_CLOSE
].kr_nreq
);
934 smbstat_srv_info
.si_wrs
+= smbstat_sub_64(
935 curr
->ss_data
.ks_reqs1
[SMB_COM_WRITE_ANDX
].kr_nreq
,
936 prev
->ss_data
.ks_reqs1
[SMB_COM_WRITE_ANDX
].kr_nreq
);
937 smbstat_srv_info
.si_wrs
+= smbstat_sub_64(
938 curr
->ss_data
.ks_reqs2
[SMB2_WRITE
].kr_nreq
,
939 prev
->ss_data
.ks_reqs2
[SMB2_WRITE
].kr_nreq
);
940 smbstat_srv_info
.si_wrs
/= smbstat_srv_info
.si_etime
;
944 * smbstat_srv_process_utilization
946 * Processes the data relative to the utilization of the smbsrv module and
947 * stores the results in the structure smbstat_srv_info.
950 smbstat_srv_process_utilization(
951 smbstat_srv_snapshot_t
*curr
,
952 smbstat_srv_snapshot_t
*prev
)
954 double tw_delta
, tr_delta
;
955 double w_delta
, r_delta
;
958 w_delta
= smbstat_hrtime_delta(prev
->ss_data
.ks_utilization
.ku_wlentime
,
959 curr
->ss_data
.ks_utilization
.ku_wlentime
);
960 r_delta
= smbstat_hrtime_delta(prev
->ss_data
.ks_utilization
.ku_rlentime
,
961 curr
->ss_data
.ks_utilization
.ku_rlentime
);
962 tw_delta
= smbstat_hrtime_delta(prev
->ss_data
.ks_utilization
.ku_wtime
,
963 curr
->ss_data
.ks_utilization
.ku_wtime
);
964 tr_delta
= smbstat_hrtime_delta(prev
->ss_data
.ks_utilization
.ku_rtime
,
965 curr
->ss_data
.ks_utilization
.ku_rtime
);
966 rqs
= smbstat_srv_info
.si_total_nreqs
/ smbstat_srv_info
.si_etime
;
968 /* Average number of requests waiting */
970 smbstat_srv_info
.si_avw
= w_delta
/ smbstat_srv_info
.si_hretime
;
972 smbstat_srv_info
.si_avw
= 0.0;
974 /* Average number of request running */
976 smbstat_srv_info
.si_avr
= r_delta
/ smbstat_srv_info
.si_hretime
;
978 smbstat_srv_info
.si_avr
= 0.0;
981 smbstat_srv_info
.si_upct
=
982 (smbstat_srv_info
.si_avr
/ curr
->ss_data
.ks_maxreqs
) * 100;
984 /* Average wait service time in milliseconds */
985 smbstat_srv_info
.si_rserv
= 0.0;
986 smbstat_srv_info
.si_wserv
= 0.0;
988 (smbstat_srv_info
.si_avw
!= 0.0 ||
989 smbstat_srv_info
.si_avr
!= 0.0)) {
991 if (smbstat_srv_info
.si_avw
!= 0.0)
992 smbstat_srv_info
.si_wserv
=
993 smbstat_srv_info
.si_avw
* tps
;
994 if (smbstat_srv_info
.si_avr
!= 0.0)
995 smbstat_srv_info
.si_rserv
=
996 smbstat_srv_info
.si_avr
* tps
;
999 /* % of time there is a transaction waiting for service */
1000 if (tw_delta
!= 0) {
1001 smbstat_srv_info
.si_wpct
= tw_delta
;
1002 smbstat_srv_info
.si_wpct
/= smbstat_srv_info
.si_hretime
;
1003 smbstat_srv_info
.si_wpct
*= 100.0;
1005 smbstat_srv_info
.si_wpct
= 0.0;
1008 /* % of time there is a transaction running */
1009 if (tr_delta
!= 0) {
1010 smbstat_srv_info
.si_rpct
= tr_delta
;
1011 smbstat_srv_info
.si_rpct
/= smbstat_srv_info
.si_hretime
;
1012 smbstat_srv_info
.si_rpct
*= 100.0;
1014 smbstat_srv_info
.si_rpct
= 0.0;
1019 * smbstat_srv_process_requests
1021 * Processes the data relative to the SMB requests and stores the results in
1022 * the structure smbstat_srv_info.
1025 smbstat_srv_process_requests(
1026 smbstat_srv_snapshot_t
*curr
,
1027 smbstat_srv_snapshot_t
*prev
)
1029 smbstat_req_info_t
*info
;
1030 smb_kstat_req_t
*curr_req
;
1031 smb_kstat_req_t
*prev_req
;
1033 boolean_t firstcall
= (prev
->ss_snaptime
== 0);
1035 for (i
= 0; i
< SMB_COM_NUM
; i
++) {
1036 info
= &smbstat_srv_info
.si_reqs1
[i
];
1037 idx
= info
[i
].ri_opcode
& 0xFF;
1038 curr_req
= &curr
->ss_data
.ks_reqs1
[idx
];
1039 prev_req
= &prev
->ss_data
.ks_reqs1
[idx
];
1040 smbstat_srv_process_one_req(
1041 info
, curr_req
, prev_req
, firstcall
);
1044 for (i
= 0; i
< SMB2__NCMDS
; i
++) {
1045 info
= &smbstat_srv_info
.si_reqs2
[i
];
1046 curr_req
= &curr
->ss_data
.ks_reqs2
[i
];
1047 prev_req
= &prev
->ss_data
.ks_reqs2
[i
];
1048 smbstat_srv_process_one_req(
1049 info
, curr_req
, prev_req
, firstcall
);
1054 smbstat_srv_process_one_req(
1055 smbstat_req_info_t
*info
,
1056 smb_kstat_req_t
*curr_req
,
1057 smb_kstat_req_t
*prev_req
,
1058 boolean_t firstcall
)
1062 nrqs
= smbstat_sub_64(curr_req
->kr_nreq
,
1065 info
->ri_rqs
= nrqs
/ smbstat_srv_info
.si_etime
;
1067 info
->ri_rbs
= smbstat_sub_64(
1070 smbstat_srv_info
.si_etime
;
1072 info
->ri_tbs
= smbstat_sub_64(
1075 smbstat_srv_info
.si_etime
;
1077 info
->ri_pct
= nrqs
* 100;
1078 if (smbstat_srv_info
.si_total_nreqs
> 0)
1079 info
->ri_pct
/= smbstat_srv_info
.si_total_nreqs
;
1082 /* First time. Take the aggregate */
1084 curr_req
->kr_a_stddev
;
1085 info
->ri_mean
= curr_req
->kr_a_mean
;
1087 /* Take the differential */
1089 curr_req
->kr_d_stddev
;
1090 info
->ri_mean
= curr_req
->kr_d_mean
;
1093 info
->ri_stddev
/= nrqs
;
1094 info
->ri_stddev
= sqrt(info
->ri_stddev
);
1096 info
->ri_stddev
= 0;
1098 info
->ri_stddev
/= NANOSEC
;
1099 info
->ri_mean
/= NANOSEC
;
1104 * smbstat_srv_current_snapshot
1106 * Returns the current snapshot.
1108 static smbstat_srv_snapshot_t
*
1109 smbstat_srv_current_snapshot(void)
1111 return (&smbstat_srv_snapshots
[smbstat_snapshot_idx
]);
1115 * smbstat_srv_previous_snapshot
1117 * Returns the previous snapshot.
1119 static smbstat_srv_snapshot_t
*
1120 smbstat_srv_previous_snapshot(void)
1124 idx
= (smbstat_snapshot_idx
- 1) & SMBSTAT_SNAPSHOT_MASK
;
1125 return (&smbstat_srv_snapshots
[idx
]);
1131 * Prints out a help message.
1134 smbstat_usage(FILE *fd
, int exit_code
)
1136 (void) fprintf(fd
, gettext(SMBSTAT_HELP
));
1143 * Prints out to stderr an error message and exits the process.
1146 smbstat_fail(int do_perror
, char *message
, ...)
1150 va_start(args
, message
);
1151 (void) fprintf(stderr
, gettext("smbstat: "));
1152 /* LINTED E_SEC_PRINTF_VAR_FMT */
1153 (void) vfprintf(stderr
, message
, args
);
1156 (void) fprintf(stderr
, ": %s", strerror(errno
));
1157 (void) fprintf(stderr
, "\n");
1164 * Substract 2 uint64_t and returns a double.
1167 smbstat_sub_64(uint64_t a
, uint64_t b
)
1169 return ((double)(a
- b
));
1175 * Returns zero if the value passed in is less than 1.
1178 smbstat_zero(double value
)
1188 * Converts a string representing an integer value into its binary value.
1189 * If the conversion fails this routine exits the process.
1192 smbstat_strtoi(char const *val
, char *errmsg
)
1198 tmp
= strtol(val
, &end
, 10);
1199 if (*end
!= '\0' || errno
)
1200 smbstat_fail(1, "%s %s", errmsg
, val
);
1201 return ((uint_t
)tmp
);
1205 * smbstat_termio_init
1207 * Determines the size of the terminal associated with the process.
1210 smbstat_termio_init(void)
1214 if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &smbstat_ws
) != -1) {
1215 if (smbstat_ws
.ws_row
== 0) {
1216 envp
= getenv("LINES");
1218 smbstat_ws
.ws_row
= atoi(envp
);
1221 if (smbstat_ws
.ws_col
== 0) {
1222 envp
= getenv("COLUMNS");
1224 smbstat_ws
.ws_row
= atoi(envp
);
1227 if (smbstat_ws
.ws_col
== 0)
1228 smbstat_ws
.ws_col
= 80;
1229 if (smbstat_ws
.ws_row
== 0)
1230 smbstat_ws
.ws_row
= 25;
1234 * smbstat_snapshot_idx_inc
1236 * Increments the snapshot index.
1239 smbstat_snapshot_inc_idx(void)
1241 smbstat_snapshot_idx
++;
1242 smbstat_snapshot_idx
&= SMBSTAT_SNAPSHOT_MASK
;
1246 * smbstat_req_cmp_name
1248 * Call back function passed to qsort() when the list of requests must be sorted
1252 smbstat_req_cmp_name(const void *obj1
, const void *obj2
)
1254 return (strncasecmp(
1255 ((smbstat_req_info_t
*)obj1
)->ri_name
,
1256 ((smbstat_req_info_t
*)obj2
)->ri_name
,
1257 sizeof (((smbstat_req_info_t
*)obj2
)->ri_name
)));
1263 * Snapshots the smbsrv module statistics once to get the name of the requests.
1264 * The request list is smbstat_srv_info is then sorted by name or by code
1265 * depending on the boolean smbstat_opt_a.
1266 * The function should be called once during initialization.
1269 smbstat_req_order(void)
1271 smbstat_srv_snapshot_t
*ss
;
1272 smbstat_req_info_t
*info
;
1273 smb_kstat_req_t
*reqs
;
1276 smbstat_srv_snapshot();
1277 ss
= smbstat_srv_current_snapshot();
1279 reqs
= ss
->ss_data
.ks_reqs1
;
1280 info
= smbstat_srv_info
.si_reqs1
;
1281 for (i
= 0; i
< SMB_COM_NUM
; i
++) {
1282 (void) strlcpy(info
[i
].ri_name
, reqs
[i
].kr_name
,
1283 sizeof (reqs
[i
].kr_name
));
1284 info
[i
].ri_opcode
= i
;
1287 qsort(info
, SMB_COM_NUM
, sizeof (smbstat_req_info_t
),
1288 smbstat_req_cmp_name
);
1290 reqs
= ss
->ss_data
.ks_reqs2
;
1291 info
= smbstat_srv_info
.si_reqs2
;
1292 for (i
= 0; i
< SMB2__NCMDS
; i
++) {
1293 (void) strlcpy(info
[i
].ri_name
, reqs
[i
].kr_name
,
1294 sizeof (reqs
[i
].kr_name
));
1295 info
[i
].ri_opcode
= i
;
1298 qsort(info
, SMB2__NCMDS
, sizeof (smbstat_req_info_t
),
1299 smbstat_req_cmp_name
);
1303 * Return the number of ticks delta between two hrtime_t
1304 * values. Attempt to cater for various kinds of overflow
1305 * in hrtime_t - no matter how improbable.
1308 smbstat_hrtime_delta(hrtime_t old
, hrtime_t
new)
1312 if ((new >= old
) && (old
>= 0L))
1313 return ((double)(new - old
));
1315 * We've overflowed the positive portion of an hrtime_t.
1319 * The new value is negative. Handle the case where the old
1320 * value is positive or negative.
1327 return ((double)(n1
- old
));
1331 return ((double)del
);
1335 * Either we've just gone from being negative to positive *or* the last
1336 * entry was positive and the new entry is also positive but *less* than
1337 * the old entry. This implies we waited quite a few days on a very fast
1338 * system between displays.
1343 del
= UINT64_MAX
- o2
;
1345 del
= UINT64_MAX
- old
;
1348 return ((double)del
);
1352 smbstat_zalloc(size_t size
)
1356 ptr
= umem_zalloc(size
, UMEM_DEFAULT
);
1358 smbstat_fail(1, gettext("out of memory"));
1363 smbstat_free(void *ptr
, size_t size
)
1365 umem_free(ptr
, size
);