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