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