10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52907Scth * Common Development and Distribution License (the "License").
62907Scth * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12607Sjohn.levon@sun.com * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include "statcommon.h"
260Sstevel@tonic-gate #include "dsr.h"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <stdlib.h>
290Sstevel@tonic-gate #include <unistd.h>
300Sstevel@tonic-gate #include <strings.h>
310Sstevel@tonic-gate #include <errno.h>
322907Scth #include <limits.h>
330Sstevel@tonic-gate #include <poll.h>
340Sstevel@tonic-gate
350Sstevel@tonic-gate #define ARRAY_SIZE(a) (sizeof (a) / sizeof (*a))
360Sstevel@tonic-gate
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate * The time we delay before retrying after an allocation
390Sstevel@tonic-gate * failure, in milliseconds
400Sstevel@tonic-gate */
410Sstevel@tonic-gate #define RETRY_DELAY 200
420Sstevel@tonic-gate
430Sstevel@tonic-gate static char *cpu_states[] = {
440Sstevel@tonic-gate "cpu_ticks_idle",
450Sstevel@tonic-gate "cpu_ticks_user",
460Sstevel@tonic-gate "cpu_ticks_kernel",
470Sstevel@tonic-gate "cpu_ticks_wait"
480Sstevel@tonic-gate };
490Sstevel@tonic-gate
500Sstevel@tonic-gate static kstat_t *
kstat_lookup_read(kstat_ctl_t * kc,char * module,int instance,char * name)510Sstevel@tonic-gate kstat_lookup_read(kstat_ctl_t *kc, char *module,
520Sstevel@tonic-gate int instance, char *name)
530Sstevel@tonic-gate {
540Sstevel@tonic-gate kstat_t *ksp = kstat_lookup(kc, module, instance, name);
550Sstevel@tonic-gate if (ksp == NULL)
560Sstevel@tonic-gate return (NULL);
570Sstevel@tonic-gate if (kstat_read(kc, ksp, NULL) == -1)
580Sstevel@tonic-gate return (NULL);
590Sstevel@tonic-gate return (ksp);
600Sstevel@tonic-gate }
610Sstevel@tonic-gate
620Sstevel@tonic-gate /*
630Sstevel@tonic-gate * Note: the following helpers do not clean up on the failure case,
640Sstevel@tonic-gate * because it is left to the free_snapshot() in the acquire_snapshot()
650Sstevel@tonic-gate * failure path.
660Sstevel@tonic-gate */
670Sstevel@tonic-gate
680Sstevel@tonic-gate static int
acquire_cpus(struct snapshot * ss,kstat_ctl_t * kc)690Sstevel@tonic-gate acquire_cpus(struct snapshot *ss, kstat_ctl_t *kc)
700Sstevel@tonic-gate {
710Sstevel@tonic-gate size_t i;
720Sstevel@tonic-gate
730Sstevel@tonic-gate ss->s_nr_cpus = sysconf(_SC_CPUID_MAX) + 1;
740Sstevel@tonic-gate ss->s_cpus = calloc(ss->s_nr_cpus, sizeof (struct cpu_snapshot));
750Sstevel@tonic-gate if (ss->s_cpus == NULL)
760Sstevel@tonic-gate goto out;
770Sstevel@tonic-gate
780Sstevel@tonic-gate for (i = 0; i < ss->s_nr_cpus; i++) {
790Sstevel@tonic-gate kstat_t *ksp;
800Sstevel@tonic-gate
810Sstevel@tonic-gate ss->s_cpus[i].cs_id = ID_NO_CPU;
820Sstevel@tonic-gate ss->s_cpus[i].cs_state = p_online(i, P_STATUS);
830Sstevel@tonic-gate /* If no valid CPU is present, move on to the next one */
840Sstevel@tonic-gate if (ss->s_cpus[i].cs_state == -1)
850Sstevel@tonic-gate continue;
860Sstevel@tonic-gate ss->s_cpus[i].cs_id = i;
870Sstevel@tonic-gate
880Sstevel@tonic-gate if ((ksp = kstat_lookup_read(kc, "cpu_info", i, NULL)) == NULL)
890Sstevel@tonic-gate goto out;
900Sstevel@tonic-gate
910Sstevel@tonic-gate (void) pset_assign(PS_QUERY, i, &ss->s_cpus[i].cs_pset_id);
920Sstevel@tonic-gate if (ss->s_cpus[i].cs_pset_id == PS_NONE)
930Sstevel@tonic-gate ss->s_cpus[i].cs_pset_id = ID_NO_PSET;
940Sstevel@tonic-gate
950Sstevel@tonic-gate if (!CPU_ACTIVE(&ss->s_cpus[i]))
960Sstevel@tonic-gate continue;
970Sstevel@tonic-gate
980Sstevel@tonic-gate if ((ksp = kstat_lookup_read(kc, "cpu", i, "vm")) == NULL)
990Sstevel@tonic-gate goto out;
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate if (kstat_copy(ksp, &ss->s_cpus[i].cs_vm))
1020Sstevel@tonic-gate goto out;
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate if ((ksp = kstat_lookup_read(kc, "cpu", i, "sys")) == NULL)
1050Sstevel@tonic-gate goto out;
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate if (kstat_copy(ksp, &ss->s_cpus[i].cs_sys))
1080Sstevel@tonic-gate goto out;
1090Sstevel@tonic-gate }
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate errno = 0;
1120Sstevel@tonic-gate out:
1130Sstevel@tonic-gate return (errno);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate static int
acquire_psets(struct snapshot * ss)1170Sstevel@tonic-gate acquire_psets(struct snapshot *ss)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate psetid_t *pids = NULL;
1200Sstevel@tonic-gate struct pset_snapshot *ps;
1210Sstevel@tonic-gate size_t pids_nr;
1220Sstevel@tonic-gate size_t i, j;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate * Careful in this code. We have to use pset_list
1260Sstevel@tonic-gate * twice, but inbetween pids_nr can change at will.
1270Sstevel@tonic-gate * We delay the setting of s_nr_psets until we have
1280Sstevel@tonic-gate * the "final" value of pids_nr.
1290Sstevel@tonic-gate */
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate if (pset_list(NULL, &pids_nr) < 0)
1320Sstevel@tonic-gate return (errno);
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate if ((pids = calloc(pids_nr, sizeof (psetid_t))) == NULL)
1350Sstevel@tonic-gate goto out;
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate if (pset_list(pids, &pids_nr) < 0)
1380Sstevel@tonic-gate goto out;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate ss->s_psets = calloc(pids_nr + 1, sizeof (struct pset_snapshot));
1410Sstevel@tonic-gate if (ss->s_psets == NULL)
1420Sstevel@tonic-gate goto out;
1430Sstevel@tonic-gate ss->s_nr_psets = pids_nr + 1;
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate /* CPUs not in any actual pset */
1460Sstevel@tonic-gate ps = &ss->s_psets[0];
1470Sstevel@tonic-gate ps->ps_id = 0;
1480Sstevel@tonic-gate ps->ps_cpus = calloc(ss->s_nr_cpus, sizeof (struct cpu_snapshot *));
1490Sstevel@tonic-gate if (ps->ps_cpus == NULL)
1500Sstevel@tonic-gate goto out;
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate /* CPUs in a a pset */
1530Sstevel@tonic-gate for (i = 1; i < ss->s_nr_psets; i++) {
1540Sstevel@tonic-gate ps = &ss->s_psets[i];
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate ps->ps_id = pids[i - 1];
1570Sstevel@tonic-gate ps->ps_cpus =
158*12607Sjohn.levon@sun.com calloc(ss->s_nr_cpus, sizeof (struct cpu_snapshot *));
1590Sstevel@tonic-gate if (ps->ps_cpus == NULL)
1600Sstevel@tonic-gate goto out;
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate for (i = 0; i < ss->s_nr_psets; i++) {
1640Sstevel@tonic-gate ps = &ss->s_psets[i];
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate for (j = 0; j < ss->s_nr_cpus; j++) {
1670Sstevel@tonic-gate if (!CPU_ACTIVE(&ss->s_cpus[j]))
1680Sstevel@tonic-gate continue;
1690Sstevel@tonic-gate if (ss->s_cpus[j].cs_pset_id != ps->ps_id)
1700Sstevel@tonic-gate continue;
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate ps->ps_cpus[ps->ps_nr_cpus++] = &ss->s_cpus[j];
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate errno = 0;
1770Sstevel@tonic-gate out:
1780Sstevel@tonic-gate free(pids);
1790Sstevel@tonic-gate return (errno);
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate static int
acquire_intrs(struct snapshot * ss,kstat_ctl_t * kc)1830Sstevel@tonic-gate acquire_intrs(struct snapshot *ss, kstat_ctl_t *kc)
1840Sstevel@tonic-gate {
1850Sstevel@tonic-gate kstat_t *ksp;
1860Sstevel@tonic-gate size_t i = 0;
1870Sstevel@tonic-gate kstat_t *sys_misc;
1880Sstevel@tonic-gate kstat_named_t *clock;
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate /* clock interrupt */
1910Sstevel@tonic-gate ss->s_nr_intrs = 1;
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1940Sstevel@tonic-gate if (ksp->ks_type == KSTAT_TYPE_INTR)
1950Sstevel@tonic-gate ss->s_nr_intrs++;
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate ss->s_intrs = calloc(ss->s_nr_intrs, sizeof (struct intr_snapshot));
1990Sstevel@tonic-gate if (ss->s_intrs == NULL)
2000Sstevel@tonic-gate return (errno);
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate sys_misc = kstat_lookup_read(kc, "unix", 0, "system_misc");
2030Sstevel@tonic-gate if (sys_misc == NULL)
2040Sstevel@tonic-gate goto out;
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate clock = (kstat_named_t *)kstat_data_lookup(sys_misc, "clk_intr");
2070Sstevel@tonic-gate if (clock == NULL)
2080Sstevel@tonic-gate goto out;
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate (void) strlcpy(ss->s_intrs[0].is_name, "clock", KSTAT_STRLEN);
2110Sstevel@tonic-gate ss->s_intrs[0].is_total = clock->value.ui32;
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate i = 1;
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
2160Sstevel@tonic-gate kstat_intr_t *ki;
2170Sstevel@tonic-gate int j;
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate if (ksp->ks_type != KSTAT_TYPE_INTR)
2200Sstevel@tonic-gate continue;
2210Sstevel@tonic-gate if (kstat_read(kc, ksp, NULL) == -1)
2220Sstevel@tonic-gate goto out;
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate ki = KSTAT_INTR_PTR(ksp);
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate (void) strlcpy(ss->s_intrs[i].is_name, ksp->ks_name,
227*12607Sjohn.levon@sun.com KSTAT_STRLEN);
2280Sstevel@tonic-gate ss->s_intrs[i].is_total = 0;
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate for (j = 0; j < KSTAT_NUM_INTRS; j++)
2310Sstevel@tonic-gate ss->s_intrs[i].is_total += ki->intrs[j];
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate i++;
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate errno = 0;
2370Sstevel@tonic-gate out:
2380Sstevel@tonic-gate return (errno);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate int
acquire_sys(struct snapshot * ss,kstat_ctl_t * kc)2420Sstevel@tonic-gate acquire_sys(struct snapshot *ss, kstat_ctl_t *kc)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate size_t i;
2450Sstevel@tonic-gate kstat_named_t *knp;
2460Sstevel@tonic-gate kstat_t *ksp;
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate if ((ksp = kstat_lookup(kc, "unix", 0, "sysinfo")) == NULL)
2490Sstevel@tonic-gate return (errno);
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate if (kstat_read(kc, ksp, &ss->s_sys.ss_sysinfo) == -1)
2520Sstevel@tonic-gate return (errno);
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate if ((ksp = kstat_lookup(kc, "unix", 0, "vminfo")) == NULL)
2550Sstevel@tonic-gate return (errno);
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate if (kstat_read(kc, ksp, &ss->s_sys.ss_vminfo) == -1)
2580Sstevel@tonic-gate return (errno);
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate if ((ksp = kstat_lookup(kc, "unix", 0, "dnlcstats")) == NULL)
2610Sstevel@tonic-gate return (errno);
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate if (kstat_read(kc, ksp, &ss->s_sys.ss_nc) == -1)
2640Sstevel@tonic-gate return (errno);
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate if ((ksp = kstat_lookup(kc, "unix", 0, "system_misc")) == NULL)
2670Sstevel@tonic-gate return (errno);
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate if (kstat_read(kc, ksp, NULL) == -1)
2700Sstevel@tonic-gate return (errno);
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate knp = (kstat_named_t *)kstat_data_lookup(ksp, "clk_intr");
2730Sstevel@tonic-gate if (knp == NULL)
2740Sstevel@tonic-gate return (errno);
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate ss->s_sys.ss_ticks = knp->value.l;
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate knp = (kstat_named_t *)kstat_data_lookup(ksp, "deficit");
2790Sstevel@tonic-gate if (knp == NULL)
2800Sstevel@tonic-gate return (errno);
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate ss->s_sys.ss_deficit = knp->value.l;
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate for (i = 0; i < ss->s_nr_cpus; i++) {
2850Sstevel@tonic-gate if (!CPU_ACTIVE(&ss->s_cpus[i]))
2860Sstevel@tonic-gate continue;
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate if (kstat_add(&ss->s_cpus[i].cs_sys, &ss->s_sys.ss_agg_sys))
2890Sstevel@tonic-gate return (errno);
2900Sstevel@tonic-gate if (kstat_add(&ss->s_cpus[i].cs_vm, &ss->s_sys.ss_agg_vm))
2910Sstevel@tonic-gate return (errno);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate return (0);
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate struct snapshot *
acquire_snapshot(kstat_ctl_t * kc,int types,struct iodev_filter * iodev_filter)2980Sstevel@tonic-gate acquire_snapshot(kstat_ctl_t *kc, int types, struct iodev_filter *iodev_filter)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate struct snapshot *ss = NULL;
3010Sstevel@tonic-gate int err;
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate retry:
3040Sstevel@tonic-gate err = 0;
3050Sstevel@tonic-gate /* ensure any partial resources are freed on a retry */
3060Sstevel@tonic-gate free_snapshot(ss);
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate ss = safe_alloc(sizeof (struct snapshot));
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate (void) memset(ss, 0, sizeof (struct snapshot));
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate ss->s_types = types;
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate /* wait for a possibly up-to-date chain */
3150Sstevel@tonic-gate while (kstat_chain_update(kc) == -1) {
3160Sstevel@tonic-gate if (errno == EAGAIN)
3170Sstevel@tonic-gate (void) poll(NULL, 0, RETRY_DELAY);
3180Sstevel@tonic-gate else
3190Sstevel@tonic-gate fail(1, "kstat_chain_update failed");
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate if (!err && (types & SNAP_INTERRUPTS))
3230Sstevel@tonic-gate err = acquire_intrs(ss, kc);
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate if (!err && (types & (SNAP_CPUS | SNAP_SYSTEM | SNAP_PSETS)))
3260Sstevel@tonic-gate err = acquire_cpus(ss, kc);
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate if (!err && (types & SNAP_PSETS))
3290Sstevel@tonic-gate err = acquire_psets(ss);
3300Sstevel@tonic-gate
3312907Scth if (!err && (types & (SNAP_IODEVS | SNAP_CONTROLLERS |
3322907Scth SNAP_IOPATHS_LI | SNAP_IOPATHS_LTI)))
3330Sstevel@tonic-gate err = acquire_iodevs(ss, kc, iodev_filter);
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate if (!err && (types & SNAP_SYSTEM))
3360Sstevel@tonic-gate err = acquire_sys(ss, kc);
3370Sstevel@tonic-gate
3380Sstevel@tonic-gate switch (err) {
3390Sstevel@tonic-gate case 0:
3400Sstevel@tonic-gate break;
3410Sstevel@tonic-gate case EAGAIN:
3420Sstevel@tonic-gate (void) poll(NULL, 0, RETRY_DELAY);
3430Sstevel@tonic-gate /* a kstat disappeared from under us */
3440Sstevel@tonic-gate /*FALLTHRU*/
3450Sstevel@tonic-gate case ENXIO:
3460Sstevel@tonic-gate case ENOENT:
3470Sstevel@tonic-gate goto retry;
3480Sstevel@tonic-gate default:
3490Sstevel@tonic-gate fail(1, "acquiring snapshot failed");
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate return (ss);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate void
free_snapshot(struct snapshot * ss)3560Sstevel@tonic-gate free_snapshot(struct snapshot *ss)
3570Sstevel@tonic-gate {
3580Sstevel@tonic-gate size_t i;
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate if (ss == NULL)
3610Sstevel@tonic-gate return;
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate while (ss->s_iodevs) {
3640Sstevel@tonic-gate struct iodev_snapshot *tmp = ss->s_iodevs;
3650Sstevel@tonic-gate ss->s_iodevs = ss->s_iodevs->is_next;
3660Sstevel@tonic-gate free_iodev(tmp);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate if (ss->s_cpus) {
3700Sstevel@tonic-gate for (i = 0; i < ss->s_nr_cpus; i++) {
3710Sstevel@tonic-gate free(ss->s_cpus[i].cs_vm.ks_data);
3720Sstevel@tonic-gate free(ss->s_cpus[i].cs_sys.ks_data);
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate free(ss->s_cpus);
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate if (ss->s_psets) {
3780Sstevel@tonic-gate for (i = 0; i < ss->s_nr_psets; i++)
3790Sstevel@tonic-gate free(ss->s_psets[i].ps_cpus);
3800Sstevel@tonic-gate free(ss->s_psets);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate free(ss->s_sys.ss_agg_sys.ks_data);
3840Sstevel@tonic-gate free(ss->s_sys.ss_agg_vm.ks_data);
3850Sstevel@tonic-gate free(ss);
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate kstat_ctl_t *
open_kstat(void)3890Sstevel@tonic-gate open_kstat(void)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate kstat_ctl_t *kc;
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate while ((kc = kstat_open()) == NULL) {
3940Sstevel@tonic-gate if (errno == EAGAIN)
3950Sstevel@tonic-gate (void) poll(NULL, 0, RETRY_DELAY);
3960Sstevel@tonic-gate else
3970Sstevel@tonic-gate fail(1, "kstat_open failed");
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate return (kc);
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate void *
safe_alloc(size_t size)4040Sstevel@tonic-gate safe_alloc(size_t size)
4050Sstevel@tonic-gate {
4060Sstevel@tonic-gate void *ptr;
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate while ((ptr = malloc(size)) == NULL) {
4090Sstevel@tonic-gate if (errno == EAGAIN)
4100Sstevel@tonic-gate (void) poll(NULL, 0, RETRY_DELAY);
4110Sstevel@tonic-gate else
4120Sstevel@tonic-gate fail(1, "malloc failed");
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate return (ptr);
4150Sstevel@tonic-gate }
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate char *
safe_strdup(char * str)4180Sstevel@tonic-gate safe_strdup(char *str)
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate char *ret;
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate if (str == NULL)
4230Sstevel@tonic-gate return (NULL);
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate while ((ret = strdup(str)) == NULL) {
4260Sstevel@tonic-gate if (errno == EAGAIN)
4270Sstevel@tonic-gate (void) poll(NULL, 0, RETRY_DELAY);
4280Sstevel@tonic-gate else
4290Sstevel@tonic-gate fail(1, "malloc failed");
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate return (ret);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate uint64_t
kstat_delta(kstat_t * old,kstat_t * new,char * name)4350Sstevel@tonic-gate kstat_delta(kstat_t *old, kstat_t *new, char *name)
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate kstat_named_t *knew = kstat_data_lookup(new, name);
4380Sstevel@tonic-gate if (old && old->ks_data) {
4390Sstevel@tonic-gate kstat_named_t *kold = kstat_data_lookup(old, name);
4400Sstevel@tonic-gate return (knew->value.ui64 - kold->value.ui64);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate return (knew->value.ui64);
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate int
kstat_copy(const kstat_t * src,kstat_t * dst)4460Sstevel@tonic-gate kstat_copy(const kstat_t *src, kstat_t *dst)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate *dst = *src;
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate if (src->ks_data != NULL) {
4510Sstevel@tonic-gate if ((dst->ks_data = malloc(src->ks_data_size)) == NULL)
4520Sstevel@tonic-gate return (-1);
4530Sstevel@tonic-gate bcopy(src->ks_data, dst->ks_data, src->ks_data_size);
4540Sstevel@tonic-gate } else {
4550Sstevel@tonic-gate dst->ks_data = NULL;
4560Sstevel@tonic-gate dst->ks_data_size = 0;
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate return (0);
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate int
kstat_add(const kstat_t * src,kstat_t * dst)4620Sstevel@tonic-gate kstat_add(const kstat_t *src, kstat_t *dst)
4630Sstevel@tonic-gate {
4640Sstevel@tonic-gate size_t i;
4650Sstevel@tonic-gate kstat_named_t *from;
4660Sstevel@tonic-gate kstat_named_t *to;
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate if (dst->ks_data == NULL)
4690Sstevel@tonic-gate return (kstat_copy(src, dst));
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate from = src->ks_data;
4720Sstevel@tonic-gate to = dst->ks_data;
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate for (i = 0; i < src->ks_ndata; i++) {
4750Sstevel@tonic-gate /* "addition" makes little sense for strings */
4760Sstevel@tonic-gate if (from->data_type != KSTAT_DATA_CHAR &&
477*12607Sjohn.levon@sun.com from->data_type != KSTAT_DATA_STRING)
4780Sstevel@tonic-gate (to)->value.ui64 += (from)->value.ui64;
4790Sstevel@tonic-gate from++;
4800Sstevel@tonic-gate to++;
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate return (0);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate uint64_t
cpu_ticks_delta(kstat_t * old,kstat_t * new)4870Sstevel@tonic-gate cpu_ticks_delta(kstat_t *old, kstat_t *new)
4880Sstevel@tonic-gate {
4890Sstevel@tonic-gate uint64_t ticks = 0;
4900Sstevel@tonic-gate size_t i;
4910Sstevel@tonic-gate for (i = 0; i < ARRAY_SIZE(cpu_states); i++)
4920Sstevel@tonic-gate ticks += kstat_delta(old, new, cpu_states[i]);
4930Sstevel@tonic-gate return (ticks);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate int
nr_active_cpus(struct snapshot * ss)4970Sstevel@tonic-gate nr_active_cpus(struct snapshot *ss)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate size_t i;
5000Sstevel@tonic-gate int count = 0;
5010Sstevel@tonic-gate for (i = 0; i < ss->s_nr_cpus; i++) {
5020Sstevel@tonic-gate if (CPU_ACTIVE(&ss->s_cpus[i]))
5030Sstevel@tonic-gate count++;
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate return (count);
5070Sstevel@tonic-gate }
5082907Scth
5092907Scth /*
5102907Scth * Return the number of ticks delta between two hrtime_t
5112907Scth * values. Attempt to cater for various kinds of overflow
5122907Scth * in hrtime_t - no matter how improbable.
5132907Scth */
5142907Scth uint64_t
hrtime_delta(hrtime_t old,hrtime_t new)5152907Scth hrtime_delta(hrtime_t old, hrtime_t new)
5162907Scth {
5172907Scth uint64_t del;
5182907Scth
5192907Scth if ((new >= old) && (old >= 0L))
5202907Scth return (new - old);
5212907Scth else {
5222907Scth /*
5232907Scth * We've overflowed the positive portion of an
5242907Scth * hrtime_t.
5252907Scth */
5262907Scth if (new < 0L) {
5272907Scth /*
5282907Scth * The new value is negative. Handle the
5292907Scth * case where the old value is positive or
5302907Scth * negative.
5312907Scth */
5322907Scth uint64_t n1;
5332907Scth uint64_t o1;
5342907Scth
5352907Scth n1 = -new;
5362907Scth if (old > 0L)
5372907Scth return (n1 - old);
5382907Scth else {
5392907Scth o1 = -old;
5402907Scth del = n1 - o1;
5412907Scth return (del);
5422907Scth }
5432907Scth } else {
5442907Scth /*
5452907Scth * Either we've just gone from being negative
5462907Scth * to positive *or* the last entry was positive
5472907Scth * and the new entry is also positive but *less*
5482907Scth * than the old entry. This implies we waited
5492907Scth * quite a few days on a very fast system between
5502907Scth * iostat displays.
5512907Scth */
5522907Scth if (old < 0L) {
5532907Scth uint64_t o2;
5542907Scth
5552907Scth o2 = -old;
5562907Scth del = UINT64_MAX - o2;
5572907Scth } else {
5582907Scth del = UINT64_MAX - old;
5592907Scth }
5602907Scth del += new;
5612907Scth return (del);
5622907Scth }
5632907Scth }
5642907Scth }
565