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