smbstat.c revision a90cf9f29973990687fa61de9f1f6ea22e924e40
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
* smbstat: Server Message Block File System statistics
*
* The statistics this CLI displays come from two sources:
*
* 1) The kernel module 'smbsrv'.
* 2) The SMB workers task queue statistics the task queue manager of Solaris
* maintains.
*
* The flow of the code is the following:
*
*
* +----------------+
* | Initialization |
* +----------------+
* |
* |
* v
* +--------------------------*
* | Take a snapshot the data | <--------+
* +--------------------------+ |
* | |
* | |
* v |
* +----------------------+ |
* | Process the snapshot | |
* +----------------------+ |
* | |
* | |
* v |
* +------------------------------------+ |
* | Print the result of the processing | |
* +------------------------------------+ |
* | |
* | |
* v |
* Yes --------------- |
* +------------ < interval == 0 ? > |
* | --------------- |
* | | |
* | | No |
* | v |
* | +------------------------+ |
* | | Sleep for the duration | ----------+
* | | of the interval. |
* | +------------------------+
* |
* +---------------------+
* |
* v
*
* Exit
*
* There are two sets of snapshots. One set for the smbsrv module and the other
* for the task queue (SMB workers). Each set contains 2 snapshots. One is
* labeled 'current' the other one 'previous'. Their role changes after each
* snapshot. The 'current' becomes 'previous' and vice versa.
* The first snapshot taken is compared against the data gathered since the
* smbsrv module was loaded. Subsequent snapshots will be compared against the
* previous snapshot.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <kstat.h>
#include <stdarg.h>
#include <errno.h>
#include <inttypes.h>
#include <strings.h>
#include <utility.h>
#include <libintl.h>
#include <zone.h>
#include <termios.h>
#include <stropts.h>
#include <math.h>
#include <umem.h>
#include <locale.h>
#include <smbsrv/smb_kstat.h>
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif /* TEXT_DOMAIN */
#define SMBSTAT_ID_NO_CPU -1
#define SMBSTAT_HELP \
"Usage: smbstat [-acnrtuz] [interval]\n" \
" -c: display counters\n" \
" -t: display throughput\n" \
" -u: display utilization\n" \
" -r: display requests\n" \
" -a: all the requests (supported and unsupported)\n" \
" -z: skip the requests not received\n" \
" -n: display in alphabetic order\n" \
" interval: refresh cycle in seconds\n"
#define SMBSRV_COUNTERS_BANNER "\n nbt tcp users trees files pipes\n"
#define SMBSRV_COUNTERS_FORMAT "%5d %5d %5d %5d %5d %5d\n"
#define SMBSRV_THROUGHPUT_BANNER \
"\nrbytes/s tbytes/s reqs/s reads/s writes/s\n"
#define SMBSRV_THROUGHPUT_FORMAT \
"%1.3e %1.3e %1.3e %1.3e %1.3e\n"
#define SMBSRV_UTILIZATION_BANNER \
"\n wcnt rcnt wtime rtime" \
" w%% r%% u%% sat usr%% sys%% idle%%\n"
#define SMBSRV_UTILIZATION_FORMAT \
"%1.3e %1.3e %1.3e %1.3e %3.0f %3.0f %3.0f %s " \
"%3.0f %3.0f %3.0f\n"
#define SMBSRV_REQUESTS_BANNER \
"\n%30s code %% rbytes/s tbytes/s req/s rt-mean" \
" rt-stddev\n"
#define SMBSRV_REQUESTS_FORMAT \
"%30s %02X %3.0f %1.3e %1.3e %1.3e %1.3e %1.3e\n"
typedef enum {
CPU_TICKS_IDLE = 0,
typedef struct smbstat_cpu_snapshot {
int cs_state;
typedef struct smbstat_srv_snapshot {
typedef struct smbstat_wrk_snapshot {
typedef struct smbstat_req_info {
char ri_name[KSTAT_STRLEN];
int ri_opcode;
double ri_pct;
double ri_tbs;
double ri_rbs;
double ri_rqs;
double ri_stddev;
double ri_mean;
typedef struct smbstat_srv_info {
double si_hretime;
double si_etime;
double si_total_nreqs;
/*
* Counters
*/
/*
* Throughput of the server
*/
double si_tbs; /* Bytes transmitted / second */
double si_rbs; /* Bytes received / second */
double si_rqs; /* Requests treated / second */
double si_rds; /* Reads treated / second */
double si_wrs; /* Writes treated / second */
/*
* Utilization of the server
*/
double si_wpct; /* */
double si_rpct; /* */
double si_upct; /* Utilization in % */
double si_avw; /* Average number of requests waiting */
double si_avr; /* Average number of requests running */
double si_wserv; /* Average waiting time */
double si_rserv; /* Average running time */
double si_ticks[CPU_TICKS_SENTINEL];
/*
* Latency & Throughput per request
*/
static void smbstat_init(void);
static void smbstat_fini(void);
static void smbstat_kstat_snapshot(void);
static void smbstat_kstat_process(void);
static void smbstat_kstat_print(void);
static void smbstat_print_counters(void);
static void smbstat_print_throughput(void);
static void smbstat_print_utilization(void);
static void smbstat_print_requests(void);
static void smbstat_cpu_init(void);
static void smbstat_cpu_fini(void);
static smbstat_cpu_snapshot_t *smbstat_cpu_current_snapshot(void);
static smbstat_cpu_snapshot_t *smbstat_cpu_previous_snapshot(void);
static void smbstat_cpu_snapshot(void);
static void smbstat_cpu_process(void);
static void smbstat_wrk_init(void);
static void smbstat_wrk_fini(void);
static void smbstat_wrk_snapshot(void);
static void smbstat_wrk_process(void);
static smbstat_wrk_snapshot_t *smbstat_wrk_current_snapshot(void);
static void smbstat_srv_init(void);
static void smbstat_srv_fini(void);
static void smbstat_srv_snapshot(void);
static void smbstat_srv_process(void);
static void smbstat_srv_process_counters(smbstat_srv_snapshot_t *);
static void smbstat_srv_process_throughput(smbstat_srv_snapshot_t *,
static void smbstat_srv_process_utilization(smbstat_srv_snapshot_t *,
static void smbstat_srv_process_requests(smbstat_srv_snapshot_t *,
static void smbstat_srv_process_one_req(smbstat_req_info_t *,
static smbstat_srv_snapshot_t *smbstat_srv_current_snapshot(void);
static smbstat_srv_snapshot_t *smbstat_srv_previous_snapshot(void);
static void *smbstat_zalloc(size_t);
static void smbstat_free(void *, size_t);
static void smbstat_fail(int, char *, ...);
static void smbstat_snapshot_inc_idx(void);
static void smbstat_usage(FILE *, int);
static uint_t smbstat_strtoi(char const *, char *);
static void smbstat_req_order(void);
static double smbstat_zero(double);
static void smbstat_termio_init(void);
static char *smbstat_cpu_states[CPU_TICKS_SENTINEL] = {
"cpu_ticks_idle",
"cpu_ticks_user",
"cpu_ticks_kernel"
};
static uint_t smbstat_interval = 0;
static long smbstat_nrcpus = 0;
static struct winsize smbstat_ws;
static uint16_t smbstat_rows = 0;
static int smbstat_snapshot_idx = 0;
static smbstat_srv_info_t smbstat_srv_info;
/*
* main
*/
int
{
int c;
(void) textdomain(TEXT_DOMAIN);
if (is_system_labeled()) {
gettext("%s: Trusted Extensions not supported.\n"),
argv[0]);
return (1);
}
switch (c) {
case 'a':
break;
case 'n':
break;
case 'u':
break;
case 'c':
break;
case 'r':
break;
case 't':
break;
case 'z':
break;
case 'h':
smbstat_usage(stdout, 0);
default:
}
}
if (!smbstat_opt_u &&
!smbstat_opt_c &&
!smbstat_opt_r &&
!smbstat_opt_t) {
/* Default options when none is specified. */
}
optind++;
}
(void) atexit(smbstat_fini);
smbstat_init();
for (;;) {
if (smbstat_interval == 0)
break;
(void) sleep(smbstat_interval);
}
return (0);
}
/*
* smbstat_init
*
* Global initialization.
*/
static void
smbstat_init(void)
{
}
/*
* smbstat_fini
*
* Releases the resources smbstat_init() allocated.
*/
static void
smbstat_fini(void)
{
(void) kstat_close(smbstat_ksc);
}
/*
* smbstat_kstat_snapshot
*
* Takes a snapshot of the data.
*/
static void
smbstat_kstat_snapshot(void)
{
}
/*
* smbstat_kstat_process
*/
static void
smbstat_kstat_process(void)
{
}
/*
* smbstat_kstat_print
*
* Print the data processed.
*/
static void
smbstat_kstat_print(void)
{
}
/*
* smbstat_print_counters
*
* Displays the SMB server counters (session, users...).
*/
static void
smbstat_print_counters(void)
{
if (!smbstat_opt_c)
return;
(void) printf(SMBSRV_COUNTERS_BANNER);
smbstat_rows = 1;
}
(void) printf(SMBSRV_COUNTERS_FORMAT,
++smbstat_rows;
}
/*
* smbstat_print_throughput
*
* Formats the SMB server throughput output.
*/
static void
smbstat_print_throughput(void)
{
if (!smbstat_opt_t)
return;
(void) printf(SMBSRV_THROUGHPUT_BANNER);
smbstat_rows = 1;
}
(void) printf(SMBSRV_THROUGHPUT_FORMAT,
++smbstat_rows;
}
/*
* smbstat_print_utilization
*/
static void
{
char *sat;
if (!smbstat_opt_u)
return;
(void) printf(SMBSRV_UTILIZATION_BANNER);
smbstat_rows = 1;
}
if (smbstat_srv_info.si_sat)
sat = "yes";
else
sat = "no ";
(void) printf(SMBSRV_UTILIZATION_FORMAT,
sat,
++smbstat_rows;
}
/*
* smbstat_print_requests
*/
static void
smbstat_print_requests(void)
{
int i;
if (!smbstat_opt_r)
return;
for (i = 0; i < SMB_COM_NUM; i++) {
if (!smbstat_opt_a &&
continue;
(void) printf(SMBSRV_REQUESTS_FORMAT,
}
}
for (i = 0; i < SMB2__NCMDS; i++) {
if (!smbstat_opt_a && i == SMB2_INVALID_CMD)
continue;
(void) printf(SMBSRV_REQUESTS_FORMAT,
}
}
}
/*
* smbstat_cpu_init
*/
static void
smbstat_cpu_init(void)
{
int i;
for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++)
}
/*
* smbstat_cpu_fini
*/
static void
smbstat_cpu_fini(void)
{
int i;
for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++)
}
/*
* smbstat_cpu_current_snapshot
*/
static smbstat_cpu_snapshot_t *
{
return (smbstat_cpu_snapshots[smbstat_snapshot_idx]);
}
/*
* smbstat_cpu_previous_snapshot
*/
static smbstat_cpu_snapshot_t *
{
int idx;
return (smbstat_cpu_snapshots[idx]);
}
/*
* smbstat_cpu_snapshot
*/
static void
smbstat_cpu_snapshot(void)
{
long i;
int j;
for (i = 0; i < smbstat_nrcpus; i++, curr++) {
/* If no valid CPU is present, move on to the next one */
continue;
smbstat_fail(1,
gettext("kstat_lookup('cpu sys %d') failed"), i);
smbstat_fail(1,
gettext("kstat_read('cpu sys %d') failed"), i);
for (j = 0; j < CPU_TICKS_SENTINEL; j++) {
smbstat_fail(1,
gettext("kstat_data_lookup('%s') failed"),
smbstat_cpu_states[j]);
}
}
}
/*
* smbstat_cpu_process
*/
static void
smbstat_cpu_process(void)
{
double total_ticks;
double agg_ticks[CPU_TICKS_SENTINEL];
int i, j;
total_ticks = 0;
for (j = 0; j < CPU_TICKS_SENTINEL; j++) {
}
}
for (j = 0; j < CPU_TICKS_SENTINEL; j++)
smbstat_srv_info.si_ticks[j] =
}
/*
* smbstat_wrk_init
*/
static void
smbstat_wrk_init(void)
{
if (smbstat_wrk_ksp == NULL)
smbstat_fail(1,
gettext("cannot retrieve smbsrv workers kstat\n"));
}
static void
smbstat_wrk_fini(void)
{
}
/*
* smbstat_wrk_snapshot
*/
static void
smbstat_wrk_snapshot(void)
{
"maxthreads");
"bnalloc");
}
/*
* smbstat_wrk_process
*/
static void
smbstat_wrk_process(void)
{
else
}
/*
* smbstat_wrk_current_snapshot
*/
static smbstat_wrk_snapshot_t *
{
return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]);
}
/*
* smbstat_srv_init
*/
static void
smbstat_srv_init(void)
{
if (smbstat_srv_ksp == NULL)
}
/*
* smbstat_srv_fini
*/
static void
smbstat_srv_fini(void)
{
}
/*
* smbstat_srv_snapshot
*
* Take a snapshot of the smbsrv module statistics.
*/
static void
smbstat_srv_snapshot(void)
{
}
/*
* smbstat_srv_process
*
* Processes the snapshot data.
*/
static void
smbstat_srv_process(void)
{
if (prev->ss_snaptime == 0)
curr->ss_snaptime);
else
if (smbstat_opt_c)
if (smbstat_opt_t)
if (smbstat_opt_u)
if (smbstat_opt_r)
}
/*
* smbstat_srv_process_counters
*/
static void
{
}
/*
* smbstat_srv_process_throughput
*
* Processes the data relative to the throughput of the smbsrv module and
* stores the results in the structure smbstat_srv_info.
*/
static void
{
}
/*
* smbstat_srv_process_utilization
*
* Processes the data relative to the utilization of the smbsrv module and
* stores the results in the structure smbstat_srv_info.
*/
static void
{
/* Average number of requests waiting */
if (w_delta != 0)
else
/* Average number of request running */
if (r_delta != 0)
else
/* Utilization */
/* Average wait service time in milliseconds */
if (rqs > 0.0 &&
}
/* % of time there is a transaction waiting for service */
if (tw_delta != 0) {
} else {
}
/* % of time there is a transaction running */
if (tr_delta != 0) {
} else {
}
}
/*
* smbstat_srv_process_requests
*
* Processes the data relative to the SMB requests and stores the results in
* the structure smbstat_srv_info.
*/
static void
{
int i, idx;
for (i = 0; i < SMB_COM_NUM; i++) {
}
for (i = 0; i < SMB2__NCMDS; i++) {
}
}
static void
{
double nrqs;
if (smbstat_srv_info.si_total_nreqs > 0)
if (firstcall) {
/* First time. Take the aggregate */
} else {
/* Take the differential */
}
if (nrqs > 0) {
} else {
}
}
/*
* smbstat_srv_current_snapshot
*
* Returns the current snapshot.
*/
static smbstat_srv_snapshot_t *
{
return (&smbstat_srv_snapshots[smbstat_snapshot_idx]);
}
/*
* smbstat_srv_previous_snapshot
*
* Returns the previous snapshot.
*/
static smbstat_srv_snapshot_t *
{
int idx;
return (&smbstat_srv_snapshots[idx]);
}
/*
* smbstat_usage
*
* Prints out a help message.
*/
static void
{
}
/*
* smbstat_fail
*
* Prints out to stderr an error message and exits the process.
*/
static void
{
/* LINTED E_SEC_PRINTF_VAR_FMT */
if (do_perror)
exit(1);
}
/*
* smbstat_sub_64
*
* Substract 2 uint64_t and returns a double.
*/
static double
{
return ((double)(a - b));
}
/*
* smbstat_zero
*
* Returns zero if the value passed in is less than 1.
*/
static double
smbstat_zero(double value)
{
if (value < 1)
value = 0;
return (value);
}
/*
* smbstat_strtoi
*
* Converts a string representing an integer value into its binary value.
* If the conversion fails this routine exits the process.
*/
static uint_t
{
char *end;
long tmp;
errno = 0;
}
/*
* smbstat_termio_init
*
* Determines the size of the terminal associated with the process.
*/
static void
smbstat_termio_init(void)
{
char *envp;
if (smbstat_ws.ws_row == 0) {
}
if (smbstat_ws.ws_col == 0) {
}
}
if (smbstat_ws.ws_col == 0)
if (smbstat_ws.ws_row == 0)
}
/*
* smbstat_snapshot_idx_inc
*
* Increments the snapshot index.
*/
static void
smbstat_snapshot_inc_idx(void)
{
}
/*
* smbstat_req_cmp_name
*
* Call back function passed to qsort() when the list of requests must be sorted
* by name.
*/
static int
{
return (strncasecmp(
}
/*
* smbstat_req_order
*
* Snapshots the smbsrv module statistics once to get the name of the requests.
* The request list is smbstat_srv_info is then sorted by name or by code
* depending on the boolean smbstat_opt_a.
* The function should be called once during initialization.
*/
static void
smbstat_req_order(void)
{
int i;
for (i = 0; i < SMB_COM_NUM; i++) {
}
if (smbstat_opt_n)
for (i = 0; i < SMB2__NCMDS; i++) {
}
if (smbstat_opt_n)
}
/*
* Return the number of ticks delta between two hrtime_t
* values. Attempt to cater for various kinds of overflow
* in hrtime_t - no matter how improbable.
*/
static double
{
/*
* We've overflowed the positive portion of an hrtime_t.
*/
if (new < 0L) {
/*
* The new value is negative. Handle the case where the old
* value is positive or negative.
*/
if (old > 0L)
return ((double)del);
}
/*
* Either we've just gone from being negative to positive *or* the last
* entry was positive and the new entry is also positive but *less* than
* the old entry. This implies we waited quite a few days on a very fast
* system between displays.
*/
if (old < 0L) {
} else {
}
return ((double)del);
}
static void *
{
void *ptr;
return (ptr);
}
static void
{
}