Mercurial > illumos > illumos-gate
changeset 12905:f5b5eba6d470
6926795 sadc's intervals drift
author | Ralph Turner - Sun UK - Contractor <Ralph.Turner@Sun.COM> |
---|---|
date | Fri, 23 Jul 2010 08:57:27 +0100 |
parents | c3fa1a3c3799 |
children | 3ca11e9f39b7 |
files | usr/src/cmd/sa/sadc.c |
diffstat | 1 files changed, 101 insertions(+), 19 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/cmd/sa/sadc.c Thu Jul 22 19:44:38 2010 -0700 +++ b/usr/src/cmd/sa/sadc.c Fri Jul 23 08:57:27 2010 +0100 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ @@ -116,6 +112,80 @@ static long ninode; +int caught_cont = 0; + +/* + * Sleep until *wakeup + interval, keeping cadence where desired + * + * *wakeup - The time we last wanted to wake up. Updated. + * interval - We want to sleep until *wakeup + interval + * *caught_cont - Global set by signal handler if we got a SIGCONT + */ +void +sleep_until(hrtime_t *wakeup, hrtime_t interval, int *caught_cont) +{ + hrtime_t now, pause, pause_left; + struct timespec pause_tv; + int status; + now = gethrtime(); + pause = *wakeup + interval - now; + + if (pause <= 0 || pause < (interval / 4)) + if (*caught_cont) { + /* Reset our cadence (see comment below) */ + *wakeup = now + interval; + pause = interval; + } else { + /* + * If we got here, then the time between the + * output we just did, and the scheduled time + * for the next output is < 1/4 of our requested + * interval AND the number of intervals has been + * requested AND we have never caught a SIGCONT + * (so we have never been suspended). In this + * case, we'll try to stay to the desired + * cadence, and we will pause for 1/2 the normal + * interval this time. + */ + pause = interval / 2; + *wakeup += interval; + } + else + *wakeup += interval; + if (pause < 1000) + /* Near enough */ + return; + + /* Now do the actual sleep */ + pause_left = pause; + do { + pause_tv.tv_sec = pause_left / NANOSEC; + pause_tv.tv_nsec = pause_left % NANOSEC; + status = nanosleep(&pause_tv, (struct timespec *)NULL); + if (status < 0) + if (errno == EINTR) { + now = gethrtime(); + pause_left = *wakeup - now; + if (pause_left < 1000) + /* Near enough */ + return; + } else { + fail(1, "nanosleep failed"); + } + } while (status != 0); +} + +/* + * Signal handler - so we can be aware of SIGCONT + */ +void +cont_handler(int sig_number) +{ + /* Re-set the signal handler */ + (void) signal(sig_number, cont_handler); + caught_cont = 1; +} + int main(int argc, char *argv[]) { @@ -127,13 +197,23 @@ char *fname; struct iodevinfo *iodev; off_t flength; + hrtime_t start_n; + hrtime_t period_n; + ct = argc >= 3? atoi(argv[2]): 0; min = time((time_t *)0); ti = argc >= 3? atoi(argv[1]): 0; + period_n = (hrtime_t)ti * NANOSEC; + if ((kc = kstat_open()) == NULL) fail(1, "kstat_open(): can't open /dev/kstat"); + + /* Set up handler for SIGCONT */ + if (signal(SIGCONT, cont_handler) == SIG_ERR) + fail(1, "signal failed"); + all_stat_init(); init_iodevs(); @@ -201,6 +281,8 @@ } } + start_n = gethrtime(); + for (;;) { do { (void) kstat_chain_update(kc); @@ -221,7 +303,7 @@ ftruncate(fp, flength), fail(1, "write failed"); } if (--ct > 0) { - sleep(ti); + sleep_until(&start_n, period_n, &caught_cont); } else { close(fp); return (0); @@ -267,10 +349,10 @@ if (ufs_inode_ksp != NULL) { safe_kstat_read(kc, ufs_inode_ksp, NULL); ufs_inode_size_knp = safe_kstat_data_lookup(ufs_inode_ksp, - "size"); + "size"); ninode = ((kstat_named_t *) - safe_kstat_data_lookup(ufs_inode_ksp, - "maxsize"))->value.l; + safe_kstat_data_lookup(ufs_inode_ksp, + "maxsize"))->value.l; } /* @@ -408,14 +490,14 @@ d.kmi.km_mem[kmi_index] += (ulong_t)mem_total; d.kmi.km_alloc[kmi_index] += - (ulong_t)mem_total - buf_size * buf_avail; + (ulong_t)mem_total - buf_size * buf_avail; d.kmi.km_fail[kmi_index] += (ulong_t)alloc_fail; } safe_kstat_read(kc, kmem_oversize_ksp, NULL); d.kmi.km_alloc[KMEM_OSIZE] = d.kmi.km_mem[KMEM_OSIZE] = - oversize_alloc_knp->value.ui64; + oversize_alloc_knp->value.ui64; d.kmi.km_fail[KMEM_OSIZE] = oversize_fail_knp->value.ui64; /* @@ -472,9 +554,9 @@ if (ksp == NULL) fail(0, "kstat_lookup('%s', %d, '%s') failed", - ks_module == NULL ? "" : ks_module, - ks_instance, - ks_name == NULL ? "" : ks_name); + ks_module == NULL ? "" : ks_module, + ks_instance, + ks_name == NULL ? "" : ks_name); return (ksp); } @@ -485,7 +567,7 @@ if (fp == NULL) fail(0, "kstat_data_lookup('%s', '%s') failed", - ksp->ks_name, name); + ksp->ks_name, name); return (fp); } @@ -493,7 +575,7 @@ safe_kstat_data_index(kstat_t *ksp, char *name) { return ((int)((char *)safe_kstat_data_lookup(ksp, name) - - (char *)ksp->ks_data) / (ksp->ks_data_size / ksp->ks_ndata)); + (char *)ksp->ks_data) / (ksp->ks_data_size / ksp->ks_ndata)); } static int @@ -534,7 +616,7 @@ iodev = iodev->next; else { safe_zalloc((void **) &iodev->next, - sizeof (struct iodevinfo), 0); + sizeof (struct iodevinfo), 0); iodev = iodev->next; iodev->next = NULL; }