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 while ((c
= getopt(argc
, argv
, "achnrtuz")) != EOF
) {
318 smbstat_opt_a
= B_TRUE
;
321 smbstat_opt_n
= B_TRUE
;
324 smbstat_opt_u
= B_TRUE
;
327 smbstat_opt_c
= B_TRUE
;
330 smbstat_opt_r
= B_TRUE
;
333 smbstat_opt_t
= B_TRUE
;
336 smbstat_opt_z
= B_TRUE
;
339 smbstat_usage(stdout
, 0);
341 smbstat_usage(stderr
, 1);
345 if (!smbstat_opt_u
&&
349 /* Default options when none is specified. */
350 smbstat_opt_u
= B_TRUE
;
351 smbstat_opt_t
= B_TRUE
;
356 smbstat_strtoi(argv
[optind
], "invalid count");
360 if ((argc
- optind
) > 1)
361 smbstat_usage(stderr
, 1);
363 (void) atexit(smbstat_fini
);
366 smbstat_kstat_snapshot();
367 smbstat_kstat_process();
368 smbstat_kstat_print();
369 if (smbstat_interval
== 0)
371 (void) sleep(smbstat_interval
);
372 smbstat_snapshot_inc_idx();
380 * Global initialization.
385 if ((smbstat_ksc
= kstat_open()) == NULL
)
386 smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat"));
397 * Releases the resources smbstat_init() allocated.
405 (void) kstat_close(smbstat_ksc
);
409 * smbstat_kstat_snapshot
411 * Takes a snapshot of the data.
414 smbstat_kstat_snapshot(void)
416 smbstat_cpu_snapshot();
417 smbstat_srv_snapshot();
418 smbstat_wrk_snapshot();
422 * smbstat_kstat_process
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.
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...).
454 smbstat_print_counters(void)
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
);
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
);
476 * smbstat_print_throughput
478 * Formats the SMB server throughput output.
481 smbstat_print_throughput(void)
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
);
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
));
502 * smbstat_print_utilization
505 smbstat_print_utilization(void)
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
);
517 if (smbstat_srv_info
.si_sat
)
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
),
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
]);
539 * smbstat_print_requests
542 smbstat_print_requests(void)
544 smbstat_req_info_t
*prq
;
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)
558 if (!smbstat_opt_z
|| (prq
[i
].ri_pct
!= 0)) {
559 (void) printf(SMBSRV_REQUESTS_FORMAT
,
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
),
571 prq
= smbstat_srv_info
.si_reqs2
;
572 for (i
= 0; i
< SMB2__NCMDS
; i
++) {
573 if (!smbstat_opt_a
&& i
== SMB2_INVALID_CMD
)
576 if (!smbstat_opt_z
|| (prq
[i
].ri_pct
!= 0)) {
577 (void) printf(SMBSRV_REQUESTS_FORMAT
,
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
),
594 smbstat_cpu_init(void)
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
);
610 smbstat_cpu_fini(void)
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)
638 idx
= (smbstat_snapshot_idx
- 1) & SMBSTAT_SNAPSHOT_MASK
;
639 return (smbstat_cpu_snapshots
[idx
]);
643 * smbstat_cpu_snapshot
646 smbstat_cpu_snapshot(void)
650 smbstat_cpu_snapshot_t
*curr
;
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)
665 ksp
= kstat_lookup(smbstat_ksc
, "cpu", i
, "sys");
668 gettext("kstat_lookup('cpu sys %d') failed"), i
);
670 if (kstat_read(smbstat_ksc
, ksp
, NULL
) == -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
]);
678 gettext("kstat_data_lookup('%s') failed"),
679 smbstat_cpu_states
[j
]);
680 curr
->cs_ticks
[j
] = ksn
->value
.ui64
;
686 * smbstat_cpu_process
689 smbstat_cpu_process(void)
691 smbstat_cpu_snapshot_t
*curr
, *prev
;
693 double agg_ticks
[CPU_TICKS_SENTINEL
];
696 curr
= smbstat_cpu_current_snapshot();
697 prev
= smbstat_cpu_previous_snapshot();
698 bzero(agg_ticks
, sizeof (agg_ticks
));
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
],
705 total_ticks
+= smbstat_sub_64(curr
->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
;
719 smbstat_wrk_init(void)
722 kstat_lookup(smbstat_ksc
, "unix", -1, SMBSRV_KSTAT_WORKERS
);
723 if (smbstat_wrk_ksp
== NULL
)
725 gettext("cannot retrieve smbsrv workers kstat\n"));
729 smbstat_wrk_fini(void)
731 smbstat_wrk_ksp
= NULL
;
735 * smbstat_wrk_snapshot
738 smbstat_wrk_snapshot(void)
740 smbstat_wrk_snapshot_t
*curr
;
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"),
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"),
759 curr
->ws_bnalloc
= kn
->value
.ui64
;
763 * smbstat_wrk_process
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
;
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
]);
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"));
803 smbstat_srv_fini(void)
805 smbstat_srv_ksp
= NULL
;
809 * smbstat_srv_snapshot
811 * Take a snapshot of the smbsrv module statistics.
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.
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
,
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
);
855 smbstat_srv_process_counters(curr
);
857 smbstat_srv_process_throughput(curr
, prev
);
859 smbstat_srv_process_utilization(curr
, prev
);
861 smbstat_srv_process_requests(curr
, prev
);
865 * smbstat_srv_process_counters
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.
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.
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
;
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 */
963 smbstat_srv_info
.si_avw
= w_delta
/ smbstat_srv_info
.si_hretime
;
965 smbstat_srv_info
.si_avw
= 0.0;
967 /* Average number of request running */
969 smbstat_srv_info
.si_avr
= r_delta
/ smbstat_srv_info
.si_hretime
;
971 smbstat_srv_info
.si_avr
= 0.0;
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;
981 (smbstat_srv_info
.si_avw
!= 0.0 ||
982 smbstat_srv_info
.si_avr
!= 0.0)) {
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 */
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;
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;
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.
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
;
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
);
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
)
1055 nrqs
= smbstat_sub_64(curr_req
->kr_nreq
,
1058 info
->ri_rqs
= nrqs
/ smbstat_srv_info
.si_etime
;
1060 info
->ri_rbs
= smbstat_sub_64(
1063 smbstat_srv_info
.si_etime
;
1065 info
->ri_tbs
= smbstat_sub_64(
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
;
1075 /* First time. Take the aggregate */
1077 curr_req
->kr_a_stddev
;
1078 info
->ri_mean
= curr_req
->kr_a_mean
;
1080 /* Take the differential */
1082 curr_req
->kr_d_stddev
;
1083 info
->ri_mean
= curr_req
->kr_d_mean
;
1086 info
->ri_stddev
/= nrqs
;
1087 info
->ri_stddev
= sqrt(info
->ri_stddev
);
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)
1117 idx
= (smbstat_snapshot_idx
- 1) & SMBSTAT_SNAPSHOT_MASK
;
1118 return (&smbstat_srv_snapshots
[idx
]);
1124 * Prints out a help message.
1127 smbstat_usage(FILE *fd
, int exit_code
)
1129 (void) fprintf(fd
, gettext(SMBSTAT_HELP
));
1136 * Prints out to stderr an error message and exits the process.
1139 smbstat_fail(int do_perror
, char *message
, ...)
1143 va_start(args
, message
);
1144 (void) fprintf(stderr
, gettext("smbstat: "));
1145 /* LINTED E_SEC_PRINTF_VAR_FMT */
1146 (void) vfprintf(stderr
, message
, args
);
1149 (void) fprintf(stderr
, ": %s", strerror(errno
));
1150 (void) fprintf(stderr
, "\n");
1157 * Substract 2 uint64_t and returns a double.
1160 smbstat_sub_64(uint64_t a
, uint64_t b
)
1162 return ((double)(a
- b
));
1168 * Returns zero if the value passed in is less than 1.
1171 smbstat_zero(double value
)
1181 * Converts a string representing an integer value into its binary value.
1182 * If the conversion fails this routine exits the process.
1185 smbstat_strtoi(char const *val
, char *errmsg
)
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.
1203 smbstat_termio_init(void)
1207 if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &smbstat_ws
) != -1) {
1208 if (smbstat_ws
.ws_row
== 0) {
1209 envp
= getenv("LINES");
1211 smbstat_ws
.ws_row
= atoi(envp
);
1214 if (smbstat_ws
.ws_col
== 0) {
1215 envp
= getenv("COLUMNS");
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.
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
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
)));
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.
1262 smbstat_req_order(void)
1264 smbstat_srv_snapshot_t
*ss
;
1265 smbstat_req_info_t
*info
;
1266 smb_kstat_req_t
*reqs
;
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
;
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
;
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.
1301 smbstat_hrtime_delta(hrtime_t old
, hrtime_t
new)
1305 if ((new >= old
) && (old
>= 0L))
1306 return ((double)(new - old
));
1308 * We've overflowed the positive portion of an hrtime_t.
1312 * The new value is negative. Handle the case where the old
1313 * value is positive or negative.
1320 return ((double)(n1
- old
));
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.
1336 del
= UINT64_MAX
- o2
;
1338 del
= UINT64_MAX
- old
;
1341 return ((double)del
);
1345 smbstat_zalloc(size_t size
)
1349 ptr
= umem_zalloc(size
, UMEM_DEFAULT
);
1351 smbstat_fail(1, gettext("out of memory"));
1356 smbstat_free(void *ptr
, size_t size
)
1358 umem_free(ptr
, size
);