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 5*3028Smh27603 * Common Development and Distribution License (the "License"). 6*3028Smh27603 * 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*3028Smh27603 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <stdio.h> 280Sstevel@tonic-gate #include <stdlib.h> 290Sstevel@tonic-gate #include <stdarg.h> 300Sstevel@tonic-gate #include <unistd.h> /* sleep() */ 310Sstevel@tonic-gate #include <string.h> 320Sstevel@tonic-gate #include <errno.h> 330Sstevel@tonic-gate #include <syslog.h> 340Sstevel@tonic-gate #include <thread.h> 350Sstevel@tonic-gate #include <time.h> 360Sstevel@tonic-gate #include <kstat.h> 370Sstevel@tonic-gate #include <sys/sysinfo.h> 380Sstevel@tonic-gate #include <sys/sysmacros.h> 390Sstevel@tonic-gate #include "powerd.h" 400Sstevel@tonic-gate 410Sstevel@tonic-gate /* 420Sstevel@tonic-gate * External Variables 430Sstevel@tonic-gate */ 440Sstevel@tonic-gate extern pwr_info_t *info; 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * State Variables 480Sstevel@tonic-gate */ 490Sstevel@tonic-gate static kstat_ctl_t *kc; /* libkstat cookie */ 500Sstevel@tonic-gate static int ncpus; 510Sstevel@tonic-gate static kstat_t **cpu_stats_list = NULL; 520Sstevel@tonic-gate static kstat_t old_cpu_stats, new_cpu_stats; 530Sstevel@tonic-gate static hrtime_t tty_snaptime; 540Sstevel@tonic-gate static kstat_t *load_ave_ksp; 550Sstevel@tonic-gate static ulong_t load_ave; 560Sstevel@tonic-gate static hrtime_t last_load_ave_change; 570Sstevel@tonic-gate static kstat_t *conskbd_ksp, *consms_ksp; 580Sstevel@tonic-gate static kstat_t *nfs_client2_kstat, *nfs_client3_kstat; 590Sstevel@tonic-gate static kstat_t *nfs_server2_kstat, *nfs_server3_kstat; 600Sstevel@tonic-gate static uint64_t old_nfs_calls, new_nfs_calls; 610Sstevel@tonic-gate 620Sstevel@tonic-gate typedef struct activity_data { 630Sstevel@tonic-gate struct activity_data *next; 640Sstevel@tonic-gate struct activity_data *prev; 650Sstevel@tonic-gate int activity_delta; 660Sstevel@tonic-gate hrtime_t snaptime; 670Sstevel@tonic-gate } activity_data_t; 680Sstevel@tonic-gate 690Sstevel@tonic-gate #define NULLACTIVITY (activity_data_t *)0 700Sstevel@tonic-gate static activity_data_t *disk_act_start = NULLACTIVITY; 710Sstevel@tonic-gate static activity_data_t *disk_act_end = NULLACTIVITY; 720Sstevel@tonic-gate static activity_data_t *tty_act_start = NULLACTIVITY; 730Sstevel@tonic-gate static activity_data_t *tty_act_end = NULLACTIVITY; 740Sstevel@tonic-gate static activity_data_t *nfs_act_start = NULLACTIVITY; 750Sstevel@tonic-gate static activity_data_t *nfs_act_end = NULLACTIVITY; 760Sstevel@tonic-gate 770Sstevel@tonic-gate struct diskinfo { 780Sstevel@tonic-gate struct diskinfo *next; 790Sstevel@tonic-gate kstat_t *ks; 800Sstevel@tonic-gate kstat_io_t new_kios, old_kios; 810Sstevel@tonic-gate }; 820Sstevel@tonic-gate 830Sstevel@tonic-gate #define NULLDISK (struct diskinfo *)0 840Sstevel@tonic-gate static struct diskinfo zerodisk = { NULL, NULL }; 850Sstevel@tonic-gate static struct diskinfo *firstdisk = NULLDISK; 860Sstevel@tonic-gate static struct diskinfo *lastdisk = NULLDISK; 870Sstevel@tonic-gate static struct diskinfo *snip = NULLDISK; 880Sstevel@tonic-gate 890Sstevel@tonic-gate #define CPU_STAT(ksp, name) (((kstat_named_t *)safe_kstat_data_lookup( \ 900Sstevel@tonic-gate (ksp), (name)))->value.ui64) 910Sstevel@tonic-gate #define DISK_DELTA(x) (disk->new_kios.x - disk->old_kios.x) 920Sstevel@tonic-gate #define CPU_DELTA(x) (CPU_STAT(&new_cpu_stats, (x)) - \ 930Sstevel@tonic-gate CPU_STAT(&old_cpu_stats, (x))) 940Sstevel@tonic-gate #define FSHIFT 8 950Sstevel@tonic-gate #define FSCALE (1<<FSHIFT) 960Sstevel@tonic-gate 970Sstevel@tonic-gate /* 980Sstevel@tonic-gate * Local Functions 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gate static void init_all(void); 1010Sstevel@tonic-gate static void init_disks(void); 1020Sstevel@tonic-gate static void cpu_stats_init(void); 1030Sstevel@tonic-gate static void load_ave_init(void); 1040Sstevel@tonic-gate static void nfs_init(void); 1050Sstevel@tonic-gate static void conskbd_init(void); 1060Sstevel@tonic-gate static void consms_init(void); 1070Sstevel@tonic-gate static int diskinfo_load(void); 1080Sstevel@tonic-gate static int cpu_stats_load(void); 1090Sstevel@tonic-gate static int load_ave_load(void); 1100Sstevel@tonic-gate static int nfs_load(void); 1110Sstevel@tonic-gate static void fail(char *, ...); 1120Sstevel@tonic-gate static void safe_zalloc(void **, int, int); 1130Sstevel@tonic-gate static void *safe_kstat_data_lookup(kstat_t *, char *); 1140Sstevel@tonic-gate static int kscmp(kstat_t *, kstat_t *); 1150Sstevel@tonic-gate static void keep_activity_data(activity_data_t **, activity_data_t **, 1160Sstevel@tonic-gate int *, int, hrtime_t); 1170Sstevel@tonic-gate static int check_activity(activity_data_t *, int, hrtime_t *, int); 1180Sstevel@tonic-gate static void kstat_copy(kstat_t *, kstat_t *, int); 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate void 1210Sstevel@tonic-gate sysstat_init() 1220Sstevel@tonic-gate { 1230Sstevel@tonic-gate info->pd_ttychars_sum = 0; 1240Sstevel@tonic-gate info->pd_loadaverage = 0; 1250Sstevel@tonic-gate info->pd_diskreads_sum = 0; 1260Sstevel@tonic-gate info->pd_nfsreqs_sum = 0; 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate if ((kc = kstat_open()) == NULL) { 1290Sstevel@tonic-gate fail("kstat_open(): can't open /dev/kstat"); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate init_all(); 1320Sstevel@tonic-gate } 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate static void 1350Sstevel@tonic-gate init_all(void) 1360Sstevel@tonic-gate { 1370Sstevel@tonic-gate char *msg = "kstat_read(): can't read kstat"; 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate init_disks(); 1400Sstevel@tonic-gate if (diskinfo_load() != 0) { 1410Sstevel@tonic-gate fail(msg); 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate cpu_stats_init(); 1450Sstevel@tonic-gate if (cpu_stats_load() != 0) { 1460Sstevel@tonic-gate fail(msg); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate load_ave_init(); 1500Sstevel@tonic-gate last_load_ave_change = gethrtime(); 1510Sstevel@tonic-gate if (load_ave_load() != 0) { 1520Sstevel@tonic-gate fail(msg); 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate nfs_init(); 1560Sstevel@tonic-gate if (nfs_load() != 0) { 1570Sstevel@tonic-gate fail(msg); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate conskbd_init(); 1600Sstevel@tonic-gate consms_init(); 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate int 1640Sstevel@tonic-gate last_disk_activity(hrtime_t *hr_now, int threshold) 1650Sstevel@tonic-gate { 1660Sstevel@tonic-gate return (check_activity(disk_act_start, info->pd_diskreads_sum, hr_now, 1670Sstevel@tonic-gate threshold)); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate int 1710Sstevel@tonic-gate last_tty_activity(hrtime_t *hr_now, int threshold) 1720Sstevel@tonic-gate { 1730Sstevel@tonic-gate return (check_activity(tty_act_start, info->pd_ttychars_sum, hr_now, 1740Sstevel@tonic-gate threshold)); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate int 1780Sstevel@tonic-gate last_load_ave_activity(hrtime_t *hr_now) 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate return ((*hr_now - last_load_ave_change) / NANOSEC); 1810Sstevel@tonic-gate } 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate int 1840Sstevel@tonic-gate last_nfs_activity(hrtime_t *hr_now, int threshold) 1850Sstevel@tonic-gate { 1860Sstevel@tonic-gate return (check_activity(nfs_act_start, info->pd_nfsreqs_sum, hr_now, 1870Sstevel@tonic-gate threshold)); 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate static void 1910Sstevel@tonic-gate init_disks(void) 1920Sstevel@tonic-gate { 1930Sstevel@tonic-gate struct diskinfo *disk, *prevdisk, *comp; 1940Sstevel@tonic-gate kstat_t *ksp; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate disk = &zerodisk; 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate /* 1990Sstevel@tonic-gate * Patch the snip in the diskinfo list (see below) 2000Sstevel@tonic-gate */ 2010Sstevel@tonic-gate if (snip) { 2020Sstevel@tonic-gate lastdisk->next = snip; 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 2060Sstevel@tonic-gate if (ksp->ks_type != KSTAT_TYPE_IO || 2070Sstevel@tonic-gate strcmp(ksp->ks_class, "disk") != 0) { 2080Sstevel@tonic-gate continue; 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate prevdisk = disk; 2110Sstevel@tonic-gate if (disk->next) { 2120Sstevel@tonic-gate disk = disk->next; 2130Sstevel@tonic-gate } else { 2140Sstevel@tonic-gate safe_zalloc((void **)&disk->next, 2150Sstevel@tonic-gate sizeof (struct diskinfo), 0); 2160Sstevel@tonic-gate disk = disk->next; 2170Sstevel@tonic-gate disk->next = NULLDISK; 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate disk->ks = ksp; 2200Sstevel@tonic-gate (void *) memset((void *)&disk->new_kios, 0, 2210Sstevel@tonic-gate sizeof (kstat_io_t)); 2220Sstevel@tonic-gate disk->new_kios.wlastupdate = disk->ks->ks_crtime; 2230Sstevel@tonic-gate disk->new_kios.rlastupdate = disk->ks->ks_crtime; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate /* 2260Sstevel@tonic-gate * Insertion sort on (ks_module, ks_instance, ks_name) 2270Sstevel@tonic-gate */ 2280Sstevel@tonic-gate comp = &zerodisk; 2290Sstevel@tonic-gate while (kscmp(disk->ks, comp->next->ks) > 0) { 2300Sstevel@tonic-gate comp = comp->next; 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate if (prevdisk != comp) { 2330Sstevel@tonic-gate prevdisk->next = disk->next; 2340Sstevel@tonic-gate disk->next = comp->next; 2350Sstevel@tonic-gate comp->next = disk; 2360Sstevel@tonic-gate disk = prevdisk; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate /* 2400Sstevel@tonic-gate * Put a snip in the linked list of diskinfos. The idea: 2410Sstevel@tonic-gate * If there was a state change such that now there are fewer 2420Sstevel@tonic-gate * disks, we snip the list and retain the tail, rather than 2430Sstevel@tonic-gate * freeing it. At the next state change, we clip the tail back on. 2440Sstevel@tonic-gate * This prevents a lot of malloc/free activity, and it's simpler. 2450Sstevel@tonic-gate */ 2460Sstevel@tonic-gate lastdisk = disk; 2470Sstevel@tonic-gate snip = disk->next; 2480Sstevel@tonic-gate disk->next = NULLDISK; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate firstdisk = zerodisk.next; 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate static int 2540Sstevel@tonic-gate diskinfo_load(void) 2550Sstevel@tonic-gate { 2560Sstevel@tonic-gate struct diskinfo *disk; 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate for (disk = firstdisk; disk; disk = disk->next) { 2590Sstevel@tonic-gate disk->old_kios = disk->new_kios; 2600Sstevel@tonic-gate if (kstat_read(kc, disk->ks, 2610Sstevel@tonic-gate (void *)&disk->new_kios) == -1) { 2620Sstevel@tonic-gate return (1); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate return (0); 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate int 2700Sstevel@tonic-gate check_disks(hrtime_t *hr_now, int threshold) 2710Sstevel@tonic-gate { 2720Sstevel@tonic-gate struct diskinfo *disk; 2730Sstevel@tonic-gate int delta = 0; 2740Sstevel@tonic-gate hrtime_t time = 0; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate while (kstat_chain_update(kc) || diskinfo_load()) { 2770Sstevel@tonic-gate init_all(); 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate for (disk = firstdisk; disk; disk = disk->next) { 2800Sstevel@tonic-gate if (time == 0) { 2810Sstevel@tonic-gate time = disk->new_kios.wlastupdate; 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate delta += DISK_DELTA(reads); 2840Sstevel@tonic-gate if (DISK_DELTA(reads) > 0) { 2850Sstevel@tonic-gate time = MAX(time, disk->new_kios.wlastupdate); 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate keep_activity_data(&disk_act_start, &disk_act_end, 2890Sstevel@tonic-gate &info->pd_diskreads_sum, delta, time); 2900Sstevel@tonic-gate #ifdef DEBUG 2910Sstevel@tonic-gate (void) printf(" Disk reads = %d\n", delta); 2920Sstevel@tonic-gate #endif 2930Sstevel@tonic-gate return (check_activity(disk_act_start, info->pd_diskreads_sum, hr_now, 2940Sstevel@tonic-gate threshold)); 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate static void 2980Sstevel@tonic-gate cpu_stats_init(void) 2990Sstevel@tonic-gate { 3000Sstevel@tonic-gate kstat_t *ksp; 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate ncpus = 0; 3030Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 3040Sstevel@tonic-gate if (strcmp(ksp->ks_module, "cpu") == 0 && 3050Sstevel@tonic-gate strcmp(ksp->ks_name, "sys") == 0) 3060Sstevel@tonic-gate ncpus++; 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate safe_zalloc((void **)&cpu_stats_list, ncpus * sizeof (*cpu_stats_list), 3100Sstevel@tonic-gate 1); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate ncpus = 0; 3130Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 3140Sstevel@tonic-gate if (strcmp(ksp->ks_module, "cpu") == 0 && 3150Sstevel@tonic-gate strcmp(ksp->ks_name, "sys") == 0 && 3160Sstevel@tonic-gate kstat_read(kc, ksp, NULL) != -1) 3170Sstevel@tonic-gate cpu_stats_list[ncpus++] = ksp; 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate if (ncpus == 0) 3210Sstevel@tonic-gate fail("can't find any cpu statistics"); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate static int 3250Sstevel@tonic-gate cpu_stats_load(void) 3260Sstevel@tonic-gate { 3270Sstevel@tonic-gate int i, j; 3280Sstevel@tonic-gate kstat_named_t *nkp, *tkp; 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate tty_snaptime = 0; 3310Sstevel@tonic-gate kstat_copy(&new_cpu_stats, &old_cpu_stats, 1); 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate /* 3340Sstevel@tonic-gate * Sum across all cpus 3350Sstevel@tonic-gate */ 3360Sstevel@tonic-gate for (i = 0; i < ncpus; i++) { 3370Sstevel@tonic-gate if (kstat_read(kc, cpu_stats_list[i], NULL) == -1) 3380Sstevel@tonic-gate return (1); 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate if (i == 0) { 3410Sstevel@tonic-gate kstat_copy(cpu_stats_list[i], &new_cpu_stats, 1); 3420Sstevel@tonic-gate continue; 3430Sstevel@tonic-gate } else { 3440Sstevel@tonic-gate /* 3450Sstevel@tonic-gate * Other CPUs' statistics are accumulated in 3460Sstevel@tonic-gate * new_cpu_stats, initialized at the first iteration of 3470Sstevel@tonic-gate * the loop. 3480Sstevel@tonic-gate */ 3490Sstevel@tonic-gate nkp = (kstat_named_t *)new_cpu_stats.ks_data; 3500Sstevel@tonic-gate tkp = (kstat_named_t *)cpu_stats_list[i]->ks_data; 3510Sstevel@tonic-gate for (j = 0; j < cpu_stats_list[i]->ks_ndata; j++) 3520Sstevel@tonic-gate (nkp++)->value.ui64 += (tkp++)->value.ui64; 3530Sstevel@tonic-gate tty_snaptime = MAX(tty_snaptime, 3540Sstevel@tonic-gate cpu_stats_list[i]->ks_snaptime); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate return (0); 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate int 3620Sstevel@tonic-gate check_tty(hrtime_t *hr_now, int threshold) 3630Sstevel@tonic-gate { 3640Sstevel@tonic-gate int delta; 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate while (kstat_chain_update(kc) || cpu_stats_load()) { 3670Sstevel@tonic-gate init_all(); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate delta = CPU_DELTA("rawch") + CPU_DELTA("outch"); 3700Sstevel@tonic-gate keep_activity_data(&tty_act_start, &tty_act_end, 3710Sstevel@tonic-gate &info->pd_ttychars_sum, delta, tty_snaptime); 3720Sstevel@tonic-gate #ifdef DEBUG 3730Sstevel@tonic-gate (void) printf(" Tty chars = %d\n", delta); 3740Sstevel@tonic-gate #endif 3750Sstevel@tonic-gate return (check_activity(tty_act_start, info->pd_ttychars_sum, hr_now, 3760Sstevel@tonic-gate threshold)); 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate static void 3800Sstevel@tonic-gate load_ave_init(void) 3810Sstevel@tonic-gate { 3820Sstevel@tonic-gate if ((load_ave_ksp = kstat_lookup(kc, "unix", 0, "system_misc")) == 3830Sstevel@tonic-gate NULL) { 3840Sstevel@tonic-gate fail("kstat_lookup('unix', 0, 'system_misc') failed"); 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate static int 3890Sstevel@tonic-gate load_ave_load(void) 3900Sstevel@tonic-gate { 3910Sstevel@tonic-gate if (kstat_read(kc, load_ave_ksp, NULL) == -1) { 3920Sstevel@tonic-gate return (1); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate load_ave = ((kstat_named_t *)safe_kstat_data_lookup( 3950Sstevel@tonic-gate load_ave_ksp, "avenrun_1min"))->value.l; 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate return (0); 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate int 4010Sstevel@tonic-gate check_load_ave(hrtime_t *hr_now, float threshold) 4020Sstevel@tonic-gate { 4030Sstevel@tonic-gate while (kstat_chain_update(kc) || load_ave_load()) { 4040Sstevel@tonic-gate init_all(); 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate info->pd_loadaverage = (double)load_ave / FSCALE; 4070Sstevel@tonic-gate if (info->pd_loadaverage > threshold) { 4080Sstevel@tonic-gate last_load_ave_change = load_ave_ksp->ks_snaptime; 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate #ifdef DEBUG 4110Sstevel@tonic-gate (void) printf(" Load average = %f\n", ((double)load_ave / FSCALE)); 4120Sstevel@tonic-gate #endif 4130Sstevel@tonic-gate return ((*hr_now - last_load_ave_change) / NANOSEC); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate static void 4170Sstevel@tonic-gate nfs_init(void) 4180Sstevel@tonic-gate { 4190Sstevel@tonic-gate nfs_client2_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v2"); 4200Sstevel@tonic-gate nfs_client3_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v3"); 4210Sstevel@tonic-gate nfs_server2_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v2"); 4220Sstevel@tonic-gate nfs_server3_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v3"); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate static int 4260Sstevel@tonic-gate nfs_load(void) 4270Sstevel@tonic-gate { 4280Sstevel@tonic-gate kstat_named_t *kstat_ptr; 4290Sstevel@tonic-gate int index; 4300Sstevel@tonic-gate uint64_t total_calls = 0; 4310Sstevel@tonic-gate uint64_t getattr_calls = 0; 4320Sstevel@tonic-gate uint64_t null_calls = 0; 4330Sstevel@tonic-gate uint64_t access_calls = 0; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate if (!nfs_client2_kstat && !nfs_client3_kstat && !nfs_server2_kstat && 4360Sstevel@tonic-gate !nfs_server3_kstat) { 4370Sstevel@tonic-gate return (0); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate /* 4410Sstevel@tonic-gate * NFS client "getattr", NFS3 client "access", and NFS server "null" 4420Sstevel@tonic-gate * requests are excluded from consideration. 4430Sstevel@tonic-gate */ 4440Sstevel@tonic-gate if (nfs_client2_kstat) { 4450Sstevel@tonic-gate if (kstat_read(kc, nfs_client2_kstat, NULL) == -1) { 4460Sstevel@tonic-gate return (1); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate kstat_ptr = KSTAT_NAMED_PTR(nfs_client2_kstat); 4490Sstevel@tonic-gate for (index = 0; index < nfs_client2_kstat->ks_ndata; index++) { 4500Sstevel@tonic-gate total_calls += kstat_ptr[index].value.ui64; 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate getattr_calls = 4530Sstevel@tonic-gate ((kstat_named_t *)safe_kstat_data_lookup( 4540Sstevel@tonic-gate nfs_client2_kstat, "getattr"))->value.ui64; 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate if (nfs_client3_kstat) { 4580Sstevel@tonic-gate if (kstat_read(kc, nfs_client3_kstat, NULL) == -1) { 4590Sstevel@tonic-gate return (1); 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate kstat_ptr = KSTAT_NAMED_PTR(nfs_client3_kstat); 4620Sstevel@tonic-gate for (index = 0; index < nfs_client3_kstat->ks_ndata; index++) { 4630Sstevel@tonic-gate total_calls += kstat_ptr[index].value.ui64; 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate getattr_calls += 4660Sstevel@tonic-gate ((kstat_named_t *)safe_kstat_data_lookup( 4670Sstevel@tonic-gate nfs_client3_kstat, "getattr"))->value.ui64; 4680Sstevel@tonic-gate access_calls = 4690Sstevel@tonic-gate ((kstat_named_t *)safe_kstat_data_lookup( 4700Sstevel@tonic-gate nfs_client3_kstat, "access"))->value.ui64; 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate if (nfs_server2_kstat) { 4740Sstevel@tonic-gate if (kstat_read(kc, nfs_server2_kstat, NULL) == -1) { 4750Sstevel@tonic-gate return (1); 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate kstat_ptr = KSTAT_NAMED_PTR(nfs_server2_kstat); 4780Sstevel@tonic-gate for (index = 0; index < nfs_server2_kstat->ks_ndata; index++) { 4790Sstevel@tonic-gate total_calls += kstat_ptr[index].value.ui64; 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate null_calls = 4820Sstevel@tonic-gate ((kstat_named_t *)safe_kstat_data_lookup( 4830Sstevel@tonic-gate nfs_server2_kstat, "null"))->value.ui64; 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate if (nfs_server3_kstat) { 4870Sstevel@tonic-gate if (kstat_read(kc, nfs_server3_kstat, NULL) == -1) { 4880Sstevel@tonic-gate return (1); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate kstat_ptr = KSTAT_NAMED_PTR(nfs_server3_kstat); 4910Sstevel@tonic-gate for (index = 0; index < nfs_server3_kstat->ks_ndata; index++) { 4920Sstevel@tonic-gate total_calls += kstat_ptr[index].value.ui64; 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate null_calls += 4950Sstevel@tonic-gate ((kstat_named_t *)safe_kstat_data_lookup( 4960Sstevel@tonic-gate nfs_server3_kstat, "null"))->value.ui64; 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate old_nfs_calls = new_nfs_calls; 5000Sstevel@tonic-gate new_nfs_calls = total_calls - 5010Sstevel@tonic-gate (getattr_calls + access_calls + null_calls); 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate return (0); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate int 5070Sstevel@tonic-gate check_nfs(hrtime_t *hr_now, int threshold) 5080Sstevel@tonic-gate { 5090Sstevel@tonic-gate int delta; 5100Sstevel@tonic-gate hrtime_t time = 0; 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate while (kstat_chain_update(kc) || nfs_load()) { 5130Sstevel@tonic-gate init_all(); 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate if (!nfs_client2_kstat && !nfs_client3_kstat && !nfs_server2_kstat && 5170Sstevel@tonic-gate !nfs_server3_kstat) { 5180Sstevel@tonic-gate return (0); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate if (nfs_client2_kstat) { 5220Sstevel@tonic-gate time = MAX(time, nfs_client2_kstat->ks_snaptime); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate if (nfs_client3_kstat) { 5250Sstevel@tonic-gate time = MAX(time, nfs_client3_kstat->ks_snaptime); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate if (nfs_server2_kstat) { 5280Sstevel@tonic-gate time = MAX(time, nfs_server2_kstat->ks_snaptime); 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate if (nfs_server3_kstat) { 5310Sstevel@tonic-gate time = MAX(time, nfs_server3_kstat->ks_snaptime); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate delta = (int)(new_nfs_calls - old_nfs_calls); 5340Sstevel@tonic-gate keep_activity_data(&nfs_act_start, &nfs_act_end, 5350Sstevel@tonic-gate &info->pd_nfsreqs_sum, delta, time); 5360Sstevel@tonic-gate #ifdef DEBUG 5370Sstevel@tonic-gate (void) printf(" NFS requests = %d\n", delta); 5380Sstevel@tonic-gate #endif 5390Sstevel@tonic-gate return (check_activity(nfs_act_start, info->pd_nfsreqs_sum, hr_now, 5400Sstevel@tonic-gate threshold)); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate static void 5440Sstevel@tonic-gate conskbd_init(void) 5450Sstevel@tonic-gate { 5460Sstevel@tonic-gate conskbd_ksp = kstat_lookup(kc, "conskbd", 0, "activity"); 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate /* 5500Sstevel@tonic-gate * Return the number of seconds since the last keystroke on console keyboard. 5510Sstevel@tonic-gate * Caller responsible for error reporting. 5520Sstevel@tonic-gate */ 5530Sstevel@tonic-gate long 5540Sstevel@tonic-gate conskbd_idle_time(void) 5550Sstevel@tonic-gate { 5560Sstevel@tonic-gate void *p; 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate if (conskbd_ksp == NULL || kstat_read(kc, conskbd_ksp, NULL) == -1 || 5590Sstevel@tonic-gate (p = kstat_data_lookup(conskbd_ksp, "idle_sec")) == NULL) 5600Sstevel@tonic-gate return ((time_t)-1); 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate return (((kstat_named_t *)p)->value.l); 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate static void 5660Sstevel@tonic-gate consms_init(void) 5670Sstevel@tonic-gate { 5680Sstevel@tonic-gate consms_ksp = kstat_lookup(kc, "consms", 0, "activity"); 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate /* 5720Sstevel@tonic-gate * Return the number of seconds since the most recent action (movement or 5730Sstevel@tonic-gate * click) of the console mouse. Caller responsible for error reporting. 5740Sstevel@tonic-gate */ 5750Sstevel@tonic-gate long 5760Sstevel@tonic-gate consms_idle_time(void) 5770Sstevel@tonic-gate { 5780Sstevel@tonic-gate void *p; 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate if (consms_ksp == NULL || kstat_read(kc, consms_ksp, NULL) == -1 || 5810Sstevel@tonic-gate (p = kstat_data_lookup(consms_ksp, "idle_sec")) == NULL) 5820Sstevel@tonic-gate return ((time_t)-1); 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate return (((kstat_named_t *)p)->value.l); 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate static void 5880Sstevel@tonic-gate fail(char *fmt, ...) 5890Sstevel@tonic-gate { 5900Sstevel@tonic-gate char new_fmt[256]; 591*3028Smh27603 const char *fmtptr = new_fmt; 5920Sstevel@tonic-gate va_list args; 5930Sstevel@tonic-gate size_t len; 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate len = sizeof (new_fmt); 5960Sstevel@tonic-gate va_start(args, fmt); 5970Sstevel@tonic-gate if (snprintf(new_fmt, len, "powerd: %s", fmt) > len) 5980Sstevel@tonic-gate syslog(LOG_ERR, "powerd: syslog message too large"); 5990Sstevel@tonic-gate else 600*3028Smh27603 vsyslog(LOG_ERR, fmtptr, args); 6010Sstevel@tonic-gate va_end(args); 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate thr_exit((void *) 0); 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate static void 6070Sstevel@tonic-gate safe_zalloc(void **ptr, int size, int free_first) 6080Sstevel@tonic-gate { 6090Sstevel@tonic-gate if (free_first && *ptr != NULL) { 6100Sstevel@tonic-gate free(*ptr); 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate if ((*ptr = (void *) malloc(size)) == NULL) { 6130Sstevel@tonic-gate fail("malloc failed"); 6140Sstevel@tonic-gate } 6150Sstevel@tonic-gate (void *) memset(*ptr, 0, size); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate static void * 6190Sstevel@tonic-gate safe_kstat_data_lookup(kstat_t *ksp, char *name) 6200Sstevel@tonic-gate { 6210Sstevel@tonic-gate void *fp = kstat_data_lookup(ksp, name); 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate if (fp == NULL) { 6240Sstevel@tonic-gate fail("kstat_data_lookup('%s', '%s') failed", 6250Sstevel@tonic-gate ksp->ks_name, name); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate return (fp); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate static int 6310Sstevel@tonic-gate kscmp(kstat_t *ks1, kstat_t *ks2) 6320Sstevel@tonic-gate { 6330Sstevel@tonic-gate int cmp; 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate cmp = strcmp(ks1->ks_module, ks2->ks_module); 6360Sstevel@tonic-gate if (cmp != 0) { 6370Sstevel@tonic-gate return (cmp); 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate cmp = ks1->ks_instance - ks2->ks_instance; 6400Sstevel@tonic-gate if (cmp != 0) { 6410Sstevel@tonic-gate return (cmp); 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate return (strcmp(ks1->ks_name, ks2->ks_name)); 6440Sstevel@tonic-gate } 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate static void 6470Sstevel@tonic-gate keep_activity_data(activity_data_t **act_start, activity_data_t **act_end, 6480Sstevel@tonic-gate int *delta_sum, int delta, hrtime_t time) 6490Sstevel@tonic-gate { 6500Sstevel@tonic-gate activity_data_t *node = NULLACTIVITY; 6510Sstevel@tonic-gate hrtime_t hr_now; 6520Sstevel@tonic-gate int idle_time = info->pd_idle_time * 60; 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate /* 6550Sstevel@tonic-gate * Add new nodes to the beginning of the list. 6560Sstevel@tonic-gate */ 6570Sstevel@tonic-gate safe_zalloc((void **)&node, sizeof (activity_data_t), 0); 6580Sstevel@tonic-gate node->activity_delta = delta; 6590Sstevel@tonic-gate *delta_sum += delta; 6600Sstevel@tonic-gate node->snaptime = time; 6610Sstevel@tonic-gate node->next = *act_start; 6620Sstevel@tonic-gate if (*act_start == NULLACTIVITY) { 6630Sstevel@tonic-gate *act_end = node; 6640Sstevel@tonic-gate } else { 6650Sstevel@tonic-gate (*act_start)->prev = node; 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate *act_start = node; 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate /* 6700Sstevel@tonic-gate * Remove nodes that are time-stamped later than the idle time. 6710Sstevel@tonic-gate */ 6720Sstevel@tonic-gate hr_now = gethrtime(); 6730Sstevel@tonic-gate node = *act_end; 6740Sstevel@tonic-gate while ((int)((hr_now - node->snaptime) / NANOSEC) > idle_time && 6750Sstevel@tonic-gate node->prev != NULLACTIVITY) { 6760Sstevel@tonic-gate *delta_sum -= node->activity_delta; 6770Sstevel@tonic-gate *act_end = node->prev; 6780Sstevel@tonic-gate (*act_end)->next = NULLACTIVITY; 6790Sstevel@tonic-gate free(node); 6800Sstevel@tonic-gate node = *act_end; 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate static int 6850Sstevel@tonic-gate check_activity(activity_data_t *act_start, int delta_sum, hrtime_t *time, 6860Sstevel@tonic-gate int thold) 6870Sstevel@tonic-gate { 6880Sstevel@tonic-gate activity_data_t *node; 6890Sstevel@tonic-gate int sum = 0; 6900Sstevel@tonic-gate int idle_time = info->pd_idle_time * 60; 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate /* 6930Sstevel@tonic-gate * No need to walk the list if the sum of the deltas are not greater 6940Sstevel@tonic-gate * than the threshold value. 6950Sstevel@tonic-gate */ 6960Sstevel@tonic-gate if (delta_sum <= thold) { 6970Sstevel@tonic-gate return (idle_time); 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * Walk through the list and add up the activity deltas. When the 7020Sstevel@tonic-gate * sum is greater than the threshold value, difference of current 7030Sstevel@tonic-gate * time and the snaptime of that node will give us the idle time. 7040Sstevel@tonic-gate */ 7050Sstevel@tonic-gate node = act_start; 7060Sstevel@tonic-gate while (node->next != NULLACTIVITY) { 7070Sstevel@tonic-gate sum += node->activity_delta; 7080Sstevel@tonic-gate if (sum > thold) { 7090Sstevel@tonic-gate return ((*time - node->snaptime) / NANOSEC); 7100Sstevel@tonic-gate } 7110Sstevel@tonic-gate node = node->next; 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate sum += node->activity_delta; 7140Sstevel@tonic-gate if (sum > thold) { 7150Sstevel@tonic-gate return ((*time - node->snaptime) / NANOSEC); 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate return (idle_time); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate static void 7220Sstevel@tonic-gate kstat_copy(kstat_t *src, kstat_t *dst, int fr) 7230Sstevel@tonic-gate { 7240Sstevel@tonic-gate if (fr) 7250Sstevel@tonic-gate free(dst->ks_data); 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate *dst = *src; 7280Sstevel@tonic-gate if (src->ks_data != NULL) { 7290Sstevel@tonic-gate safe_zalloc(&dst->ks_data, src->ks_data_size, 0); 7300Sstevel@tonic-gate (void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size); 7310Sstevel@tonic-gate } else { 7320Sstevel@tonic-gate dst->ks_data = NULL; 7330Sstevel@tonic-gate dst->ks_data_size = 0; 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate } 736