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 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include "statcommon.h" 26 #include "dsr.h" 27 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <strings.h> 31 #include <errno.h> 32 #include <limits.h> 33 #include <poll.h> 34 35 #define ARRAY_SIZE(a) (sizeof (a) / sizeof (*a)) 36 37 /* 38 * The time we delay before retrying after an allocation 39 * failure, in milliseconds 40 */ 41 #define RETRY_DELAY 200 42 43 static char *cpu_states[] = { 44 "cpu_ticks_idle", 45 "cpu_ticks_user", 46 "cpu_ticks_kernel", 47 "cpu_ticks_wait" 48 }; 49 50 static kstat_t * 51 kstat_lookup_read(kstat_ctl_t *kc, char *module, 52 int instance, char *name) 53 { 54 kstat_t *ksp = kstat_lookup(kc, module, instance, name); 55 if (ksp == NULL) 56 return (NULL); 57 if (kstat_read(kc, ksp, NULL) == -1) 58 return (NULL); 59 return (ksp); 60 } 61 62 /* 63 * Note: the following helpers do not clean up on the failure case, 64 * because it is left to the free_snapshot() in the acquire_snapshot() 65 * failure path. 66 */ 67 68 static int 69 acquire_cpus(struct snapshot *ss, kstat_ctl_t *kc) 70 { 71 size_t i; 72 73 ss->s_nr_cpus = sysconf(_SC_CPUID_MAX) + 1; 74 ss->s_cpus = calloc(ss->s_nr_cpus, sizeof (struct cpu_snapshot)); 75 if (ss->s_cpus == NULL) 76 goto out; 77 78 for (i = 0; i < ss->s_nr_cpus; i++) { 79 kstat_t *ksp; 80 81 ss->s_cpus[i].cs_id = ID_NO_CPU; 82 ss->s_cpus[i].cs_state = p_online(i, P_STATUS); 83 /* If no valid CPU is present, move on to the next one */ 84 if (ss->s_cpus[i].cs_state == -1) 85 continue; 86 ss->s_cpus[i].cs_id = i; 87 88 if ((ksp = kstat_lookup_read(kc, "cpu_info", i, NULL)) == NULL) 89 goto out; 90 91 (void) pset_assign(PS_QUERY, i, &ss->s_cpus[i].cs_pset_id); 92 if (ss->s_cpus[i].cs_pset_id == PS_NONE) 93 ss->s_cpus[i].cs_pset_id = ID_NO_PSET; 94 95 if (!CPU_ACTIVE(&ss->s_cpus[i])) 96 continue; 97 98 if ((ksp = kstat_lookup_read(kc, "cpu", i, "vm")) == NULL) 99 goto out; 100 101 if (kstat_copy(ksp, &ss->s_cpus[i].cs_vm)) 102 goto out; 103 104 if ((ksp = kstat_lookup_read(kc, "cpu", i, "sys")) == NULL) 105 goto out; 106 107 if (kstat_copy(ksp, &ss->s_cpus[i].cs_sys)) 108 goto out; 109 } 110 111 errno = 0; 112 out: 113 return (errno); 114 } 115 116 static int 117 acquire_psets(struct snapshot *ss) 118 { 119 psetid_t *pids = NULL; 120 struct pset_snapshot *ps; 121 size_t pids_nr; 122 size_t i, j; 123 124 /* 125 * Careful in this code. We have to use pset_list 126 * twice, but inbetween pids_nr can change at will. 127 * We delay the setting of s_nr_psets until we have 128 * the "final" value of pids_nr. 129 */ 130 131 if (pset_list(NULL, &pids_nr) < 0) 132 return (errno); 133 134 if ((pids = calloc(pids_nr, sizeof (psetid_t))) == NULL) 135 goto out; 136 137 if (pset_list(pids, &pids_nr) < 0) 138 goto out; 139 140 ss->s_psets = calloc(pids_nr + 1, sizeof (struct pset_snapshot)); 141 if (ss->s_psets == NULL) 142 goto out; 143 ss->s_nr_psets = pids_nr + 1; 144 145 /* CPUs not in any actual pset */ 146 ps = &ss->s_psets[0]; 147 ps->ps_id = 0; 148 ps->ps_cpus = calloc(ss->s_nr_cpus, sizeof (struct cpu_snapshot *)); 149 if (ps->ps_cpus == NULL) 150 goto out; 151 152 /* CPUs in a a pset */ 153 for (i = 1; i < ss->s_nr_psets; i++) { 154 ps = &ss->s_psets[i]; 155 156 ps->ps_id = pids[i - 1]; 157 ps->ps_cpus = 158 calloc(ss->s_nr_cpus, sizeof (struct cpu_snapshot *)); 159 if (ps->ps_cpus == NULL) 160 goto out; 161 } 162 163 for (i = 0; i < ss->s_nr_psets; i++) { 164 ps = &ss->s_psets[i]; 165 166 for (j = 0; j < ss->s_nr_cpus; j++) { 167 if (!CPU_ACTIVE(&ss->s_cpus[j])) 168 continue; 169 if (ss->s_cpus[j].cs_pset_id != ps->ps_id) 170 continue; 171 172 ps->ps_cpus[ps->ps_nr_cpus++] = &ss->s_cpus[j]; 173 } 174 } 175 176 errno = 0; 177 out: 178 free(pids); 179 return (errno); 180 } 181 182 static int 183 acquire_intrs(struct snapshot *ss, kstat_ctl_t *kc) 184 { 185 kstat_t *ksp; 186 size_t i = 0; 187 kstat_t *sys_misc; 188 kstat_named_t *clock; 189 190 /* clock interrupt */ 191 ss->s_nr_intrs = 1; 192 193 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 194 if (ksp->ks_type == KSTAT_TYPE_INTR) 195 ss->s_nr_intrs++; 196 } 197 198 ss->s_intrs = calloc(ss->s_nr_intrs, sizeof (struct intr_snapshot)); 199 if (ss->s_intrs == NULL) 200 return (errno); 201 202 sys_misc = kstat_lookup_read(kc, "unix", 0, "system_misc"); 203 if (sys_misc == NULL) 204 goto out; 205 206 clock = (kstat_named_t *)kstat_data_lookup(sys_misc, "clk_intr"); 207 if (clock == NULL) 208 goto out; 209 210 (void) strlcpy(ss->s_intrs[0].is_name, "clock", KSTAT_STRLEN); 211 ss->s_intrs[0].is_total = clock->value.ui32; 212 213 i = 1; 214 215 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 216 kstat_intr_t *ki; 217 int j; 218 219 if (ksp->ks_type != KSTAT_TYPE_INTR) 220 continue; 221 if (kstat_read(kc, ksp, NULL) == -1) 222 goto out; 223 224 ki = KSTAT_INTR_PTR(ksp); 225 226 (void) strlcpy(ss->s_intrs[i].is_name, ksp->ks_name, 227 KSTAT_STRLEN); 228 ss->s_intrs[i].is_total = 0; 229 230 for (j = 0; j < KSTAT_NUM_INTRS; j++) 231 ss->s_intrs[i].is_total += ki->intrs[j]; 232 233 i++; 234 } 235 236 errno = 0; 237 out: 238 return (errno); 239 } 240 241 int 242 acquire_sys(struct snapshot *ss, kstat_ctl_t *kc) 243 { 244 size_t i; 245 kstat_named_t *knp; 246 kstat_t *ksp; 247 248 if ((ksp = kstat_lookup(kc, "unix", 0, "sysinfo")) == NULL) 249 return (errno); 250 251 if (kstat_read(kc, ksp, &ss->s_sys.ss_sysinfo) == -1) 252 return (errno); 253 254 if ((ksp = kstat_lookup(kc, "unix", 0, "vminfo")) == NULL) 255 return (errno); 256 257 if (kstat_read(kc, ksp, &ss->s_sys.ss_vminfo) == -1) 258 return (errno); 259 260 if ((ksp = kstat_lookup(kc, "unix", 0, "dnlcstats")) == NULL) 261 return (errno); 262 263 if (kstat_read(kc, ksp, &ss->s_sys.ss_nc) == -1) 264 return (errno); 265 266 if ((ksp = kstat_lookup(kc, "unix", 0, "system_misc")) == NULL) 267 return (errno); 268 269 if (kstat_read(kc, ksp, NULL) == -1) 270 return (errno); 271 272 knp = (kstat_named_t *)kstat_data_lookup(ksp, "clk_intr"); 273 if (knp == NULL) 274 return (errno); 275 276 ss->s_sys.ss_ticks = knp->value.l; 277 278 knp = (kstat_named_t *)kstat_data_lookup(ksp, "deficit"); 279 if (knp == NULL) 280 return (errno); 281 282 ss->s_sys.ss_deficit = knp->value.l; 283 284 for (i = 0; i < ss->s_nr_cpus; i++) { 285 if (!CPU_ACTIVE(&ss->s_cpus[i])) 286 continue; 287 288 if (kstat_add(&ss->s_cpus[i].cs_sys, &ss->s_sys.ss_agg_sys)) 289 return (errno); 290 if (kstat_add(&ss->s_cpus[i].cs_vm, &ss->s_sys.ss_agg_vm)) 291 return (errno); 292 } 293 294 return (0); 295 } 296 297 struct snapshot * 298 acquire_snapshot(kstat_ctl_t *kc, int types, struct iodev_filter *iodev_filter) 299 { 300 struct snapshot *ss = NULL; 301 int err; 302 303 retry: 304 err = 0; 305 /* ensure any partial resources are freed on a retry */ 306 free_snapshot(ss); 307 308 ss = safe_alloc(sizeof (struct snapshot)); 309 310 (void) memset(ss, 0, sizeof (struct snapshot)); 311 312 ss->s_types = types; 313 314 /* wait for a possibly up-to-date chain */ 315 while (kstat_chain_update(kc) == -1) { 316 if (errno == EAGAIN) 317 (void) poll(NULL, 0, RETRY_DELAY); 318 else 319 fail(1, "kstat_chain_update failed"); 320 } 321 322 if (!err && (types & SNAP_INTERRUPTS)) 323 err = acquire_intrs(ss, kc); 324 325 if (!err && (types & (SNAP_CPUS | SNAP_SYSTEM | SNAP_PSETS))) 326 err = acquire_cpus(ss, kc); 327 328 if (!err && (types & SNAP_PSETS)) 329 err = acquire_psets(ss); 330 331 if (!err && (types & (SNAP_IODEVS | SNAP_CONTROLLERS | 332 SNAP_IOPATHS_LI | SNAP_IOPATHS_LTI))) 333 err = acquire_iodevs(ss, kc, iodev_filter); 334 335 if (!err && (types & SNAP_SYSTEM)) 336 err = acquire_sys(ss, kc); 337 338 switch (err) { 339 case 0: 340 break; 341 case EAGAIN: 342 (void) poll(NULL, 0, RETRY_DELAY); 343 /* a kstat disappeared from under us */ 344 /*FALLTHRU*/ 345 case ENXIO: 346 case ENOENT: 347 goto retry; 348 default: 349 fail(1, "acquiring snapshot failed"); 350 } 351 352 return (ss); 353 } 354 355 void 356 free_snapshot(struct snapshot *ss) 357 { 358 size_t i; 359 360 if (ss == NULL) 361 return; 362 363 while (ss->s_iodevs) { 364 struct iodev_snapshot *tmp = ss->s_iodevs; 365 ss->s_iodevs = ss->s_iodevs->is_next; 366 free_iodev(tmp); 367 } 368 369 if (ss->s_cpus) { 370 for (i = 0; i < ss->s_nr_cpus; i++) { 371 free(ss->s_cpus[i].cs_vm.ks_data); 372 free(ss->s_cpus[i].cs_sys.ks_data); 373 } 374 free(ss->s_cpus); 375 } 376 377 if (ss->s_psets) { 378 for (i = 0; i < ss->s_nr_psets; i++) 379 free(ss->s_psets[i].ps_cpus); 380 free(ss->s_psets); 381 } 382 383 free(ss->s_sys.ss_agg_sys.ks_data); 384 free(ss->s_sys.ss_agg_vm.ks_data); 385 free(ss); 386 } 387 388 kstat_ctl_t * 389 open_kstat(void) 390 { 391 kstat_ctl_t *kc; 392 393 while ((kc = kstat_open()) == NULL) { 394 if (errno == EAGAIN) 395 (void) poll(NULL, 0, RETRY_DELAY); 396 else 397 fail(1, "kstat_open failed"); 398 } 399 400 return (kc); 401 } 402 403 void * 404 safe_alloc(size_t size) 405 { 406 void *ptr; 407 408 while ((ptr = malloc(size)) == NULL) { 409 if (errno == EAGAIN) 410 (void) poll(NULL, 0, RETRY_DELAY); 411 else 412 fail(1, "malloc failed"); 413 } 414 return (ptr); 415 } 416 417 char * 418 safe_strdup(char *str) 419 { 420 char *ret; 421 422 if (str == NULL) 423 return (NULL); 424 425 while ((ret = strdup(str)) == NULL) { 426 if (errno == EAGAIN) 427 (void) poll(NULL, 0, RETRY_DELAY); 428 else 429 fail(1, "malloc failed"); 430 } 431 return (ret); 432 } 433 434 uint64_t 435 kstat_delta(kstat_t *old, kstat_t *new, char *name) 436 { 437 kstat_named_t *knew = kstat_data_lookup(new, name); 438 if (old && old->ks_data) { 439 kstat_named_t *kold = kstat_data_lookup(old, name); 440 return (knew->value.ui64 - kold->value.ui64); 441 } 442 return (knew->value.ui64); 443 } 444 445 int 446 kstat_copy(const kstat_t *src, kstat_t *dst) 447 { 448 *dst = *src; 449 450 if (src->ks_data != NULL) { 451 if ((dst->ks_data = malloc(src->ks_data_size)) == NULL) 452 return (-1); 453 bcopy(src->ks_data, dst->ks_data, src->ks_data_size); 454 } else { 455 dst->ks_data = NULL; 456 dst->ks_data_size = 0; 457 } 458 return (0); 459 } 460 461 int 462 kstat_add(const kstat_t *src, kstat_t *dst) 463 { 464 size_t i; 465 kstat_named_t *from; 466 kstat_named_t *to; 467 468 if (dst->ks_data == NULL) 469 return (kstat_copy(src, dst)); 470 471 from = src->ks_data; 472 to = dst->ks_data; 473 474 for (i = 0; i < src->ks_ndata; i++) { 475 /* "addition" makes little sense for strings */ 476 if (from->data_type != KSTAT_DATA_CHAR && 477 from->data_type != KSTAT_DATA_STRING) 478 (to)->value.ui64 += (from)->value.ui64; 479 from++; 480 to++; 481 } 482 483 return (0); 484 } 485 486 uint64_t 487 cpu_ticks_delta(kstat_t *old, kstat_t *new) 488 { 489 uint64_t ticks = 0; 490 size_t i; 491 for (i = 0; i < ARRAY_SIZE(cpu_states); i++) 492 ticks += kstat_delta(old, new, cpu_states[i]); 493 return (ticks); 494 } 495 496 int 497 nr_active_cpus(struct snapshot *ss) 498 { 499 size_t i; 500 int count = 0; 501 for (i = 0; i < ss->s_nr_cpus; i++) { 502 if (CPU_ACTIVE(&ss->s_cpus[i])) 503 count++; 504 } 505 506 return (count); 507 } 508 509 /* 510 * Return the number of ticks delta between two hrtime_t 511 * values. Attempt to cater for various kinds of overflow 512 * in hrtime_t - no matter how improbable. 513 */ 514 uint64_t 515 hrtime_delta(hrtime_t old, hrtime_t new) 516 { 517 uint64_t del; 518 519 if ((new >= old) && (old >= 0L)) 520 return (new - old); 521 else { 522 /* 523 * We've overflowed the positive portion of an 524 * hrtime_t. 525 */ 526 if (new < 0L) { 527 /* 528 * The new value is negative. Handle the 529 * case where the old value is positive or 530 * negative. 531 */ 532 uint64_t n1; 533 uint64_t o1; 534 535 n1 = -new; 536 if (old > 0L) 537 return (n1 - old); 538 else { 539 o1 = -old; 540 del = n1 - o1; 541 return (del); 542 } 543 } else { 544 /* 545 * Either we've just gone from being negative 546 * to positive *or* the last entry was positive 547 * and the new entry is also positive but *less* 548 * than the old entry. This implies we waited 549 * quite a few days on a very fast system between 550 * iostat displays. 551 */ 552 if (old < 0L) { 553 uint64_t o2; 554 555 o2 = -old; 556 del = UINT64_MAX - o2; 557 } else { 558 del = UINT64_MAX - old; 559 } 560 del += new; 561 return (del); 562 } 563 } 564 } 565