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