1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 1995-2002 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate #include <stdio.h> 29*0Sstevel@tonic-gate #include <stdlib.h> 30*0Sstevel@tonic-gate #include <stdarg.h> 31*0Sstevel@tonic-gate #include <unistd.h> /* sleep() */ 32*0Sstevel@tonic-gate #include <string.h> 33*0Sstevel@tonic-gate #include <errno.h> 34*0Sstevel@tonic-gate #include <syslog.h> 35*0Sstevel@tonic-gate #include <thread.h> 36*0Sstevel@tonic-gate #include <time.h> 37*0Sstevel@tonic-gate #include <kstat.h> 38*0Sstevel@tonic-gate #include <sys/sysinfo.h> 39*0Sstevel@tonic-gate #include <sys/sysmacros.h> 40*0Sstevel@tonic-gate #include "powerd.h" 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate /* 43*0Sstevel@tonic-gate * External Variables 44*0Sstevel@tonic-gate */ 45*0Sstevel@tonic-gate extern pwr_info_t *info; 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate /* 48*0Sstevel@tonic-gate * State Variables 49*0Sstevel@tonic-gate */ 50*0Sstevel@tonic-gate static kstat_ctl_t *kc; /* libkstat cookie */ 51*0Sstevel@tonic-gate static int ncpus; 52*0Sstevel@tonic-gate static kstat_t **cpu_stats_list = NULL; 53*0Sstevel@tonic-gate static kstat_t old_cpu_stats, new_cpu_stats; 54*0Sstevel@tonic-gate static hrtime_t tty_snaptime; 55*0Sstevel@tonic-gate static kstat_t *load_ave_ksp; 56*0Sstevel@tonic-gate static ulong_t load_ave; 57*0Sstevel@tonic-gate static hrtime_t last_load_ave_change; 58*0Sstevel@tonic-gate static kstat_t *conskbd_ksp, *consms_ksp; 59*0Sstevel@tonic-gate static kstat_t *nfs_client2_kstat, *nfs_client3_kstat; 60*0Sstevel@tonic-gate static kstat_t *nfs_server2_kstat, *nfs_server3_kstat; 61*0Sstevel@tonic-gate static uint64_t old_nfs_calls, new_nfs_calls; 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate typedef struct activity_data { 64*0Sstevel@tonic-gate struct activity_data *next; 65*0Sstevel@tonic-gate struct activity_data *prev; 66*0Sstevel@tonic-gate int activity_delta; 67*0Sstevel@tonic-gate hrtime_t snaptime; 68*0Sstevel@tonic-gate } activity_data_t; 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate #define NULLACTIVITY (activity_data_t *)0 71*0Sstevel@tonic-gate static activity_data_t *disk_act_start = NULLACTIVITY; 72*0Sstevel@tonic-gate static activity_data_t *disk_act_end = NULLACTIVITY; 73*0Sstevel@tonic-gate static activity_data_t *tty_act_start = NULLACTIVITY; 74*0Sstevel@tonic-gate static activity_data_t *tty_act_end = NULLACTIVITY; 75*0Sstevel@tonic-gate static activity_data_t *nfs_act_start = NULLACTIVITY; 76*0Sstevel@tonic-gate static activity_data_t *nfs_act_end = NULLACTIVITY; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate struct diskinfo { 79*0Sstevel@tonic-gate struct diskinfo *next; 80*0Sstevel@tonic-gate kstat_t *ks; 81*0Sstevel@tonic-gate kstat_io_t new_kios, old_kios; 82*0Sstevel@tonic-gate }; 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate #define NULLDISK (struct diskinfo *)0 85*0Sstevel@tonic-gate static struct diskinfo zerodisk = { NULL, NULL }; 86*0Sstevel@tonic-gate static struct diskinfo *firstdisk = NULLDISK; 87*0Sstevel@tonic-gate static struct diskinfo *lastdisk = NULLDISK; 88*0Sstevel@tonic-gate static struct diskinfo *snip = NULLDISK; 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate #define CPU_STAT(ksp, name) (((kstat_named_t *)safe_kstat_data_lookup( \ 91*0Sstevel@tonic-gate (ksp), (name)))->value.ui64) 92*0Sstevel@tonic-gate #define DISK_DELTA(x) (disk->new_kios.x - disk->old_kios.x) 93*0Sstevel@tonic-gate #define CPU_DELTA(x) (CPU_STAT(&new_cpu_stats, (x)) - \ 94*0Sstevel@tonic-gate CPU_STAT(&old_cpu_stats, (x))) 95*0Sstevel@tonic-gate #define FSHIFT 8 96*0Sstevel@tonic-gate #define FSCALE (1<<FSHIFT) 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate /* 99*0Sstevel@tonic-gate * Local Functions 100*0Sstevel@tonic-gate */ 101*0Sstevel@tonic-gate static void init_all(void); 102*0Sstevel@tonic-gate static void init_disks(void); 103*0Sstevel@tonic-gate static void cpu_stats_init(void); 104*0Sstevel@tonic-gate static void load_ave_init(void); 105*0Sstevel@tonic-gate static void nfs_init(void); 106*0Sstevel@tonic-gate static void conskbd_init(void); 107*0Sstevel@tonic-gate static void consms_init(void); 108*0Sstevel@tonic-gate static int diskinfo_load(void); 109*0Sstevel@tonic-gate static int cpu_stats_load(void); 110*0Sstevel@tonic-gate static int load_ave_load(void); 111*0Sstevel@tonic-gate static int nfs_load(void); 112*0Sstevel@tonic-gate static void fail(char *, ...); 113*0Sstevel@tonic-gate static void safe_zalloc(void **, int, int); 114*0Sstevel@tonic-gate static void *safe_kstat_data_lookup(kstat_t *, char *); 115*0Sstevel@tonic-gate static int kscmp(kstat_t *, kstat_t *); 116*0Sstevel@tonic-gate static void keep_activity_data(activity_data_t **, activity_data_t **, 117*0Sstevel@tonic-gate int *, int, hrtime_t); 118*0Sstevel@tonic-gate static int check_activity(activity_data_t *, int, hrtime_t *, int); 119*0Sstevel@tonic-gate static void kstat_copy(kstat_t *, kstat_t *, int); 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate void 122*0Sstevel@tonic-gate sysstat_init() 123*0Sstevel@tonic-gate { 124*0Sstevel@tonic-gate info->pd_ttychars_sum = 0; 125*0Sstevel@tonic-gate info->pd_loadaverage = 0; 126*0Sstevel@tonic-gate info->pd_diskreads_sum = 0; 127*0Sstevel@tonic-gate info->pd_nfsreqs_sum = 0; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate if ((kc = kstat_open()) == NULL) { 130*0Sstevel@tonic-gate fail("kstat_open(): can't open /dev/kstat"); 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate init_all(); 133*0Sstevel@tonic-gate } 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate static void 136*0Sstevel@tonic-gate init_all(void) 137*0Sstevel@tonic-gate { 138*0Sstevel@tonic-gate char *msg = "kstat_read(): can't read kstat"; 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate init_disks(); 141*0Sstevel@tonic-gate if (diskinfo_load() != 0) { 142*0Sstevel@tonic-gate fail(msg); 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate cpu_stats_init(); 146*0Sstevel@tonic-gate if (cpu_stats_load() != 0) { 147*0Sstevel@tonic-gate fail(msg); 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate load_ave_init(); 151*0Sstevel@tonic-gate last_load_ave_change = gethrtime(); 152*0Sstevel@tonic-gate if (load_ave_load() != 0) { 153*0Sstevel@tonic-gate fail(msg); 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate nfs_init(); 157*0Sstevel@tonic-gate if (nfs_load() != 0) { 158*0Sstevel@tonic-gate fail(msg); 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate conskbd_init(); 161*0Sstevel@tonic-gate consms_init(); 162*0Sstevel@tonic-gate } 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate int 165*0Sstevel@tonic-gate last_disk_activity(hrtime_t *hr_now, int threshold) 166*0Sstevel@tonic-gate { 167*0Sstevel@tonic-gate return (check_activity(disk_act_start, info->pd_diskreads_sum, hr_now, 168*0Sstevel@tonic-gate threshold)); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate int 172*0Sstevel@tonic-gate last_tty_activity(hrtime_t *hr_now, int threshold) 173*0Sstevel@tonic-gate { 174*0Sstevel@tonic-gate return (check_activity(tty_act_start, info->pd_ttychars_sum, hr_now, 175*0Sstevel@tonic-gate threshold)); 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate int 179*0Sstevel@tonic-gate last_load_ave_activity(hrtime_t *hr_now) 180*0Sstevel@tonic-gate { 181*0Sstevel@tonic-gate return ((*hr_now - last_load_ave_change) / NANOSEC); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate int 185*0Sstevel@tonic-gate last_nfs_activity(hrtime_t *hr_now, int threshold) 186*0Sstevel@tonic-gate { 187*0Sstevel@tonic-gate return (check_activity(nfs_act_start, info->pd_nfsreqs_sum, hr_now, 188*0Sstevel@tonic-gate threshold)); 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate static void 192*0Sstevel@tonic-gate init_disks(void) 193*0Sstevel@tonic-gate { 194*0Sstevel@tonic-gate struct diskinfo *disk, *prevdisk, *comp; 195*0Sstevel@tonic-gate kstat_t *ksp; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate disk = &zerodisk; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate /* 200*0Sstevel@tonic-gate * Patch the snip in the diskinfo list (see below) 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate if (snip) { 203*0Sstevel@tonic-gate lastdisk->next = snip; 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 207*0Sstevel@tonic-gate if (ksp->ks_type != KSTAT_TYPE_IO || 208*0Sstevel@tonic-gate strcmp(ksp->ks_class, "disk") != 0) { 209*0Sstevel@tonic-gate continue; 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate prevdisk = disk; 212*0Sstevel@tonic-gate if (disk->next) { 213*0Sstevel@tonic-gate disk = disk->next; 214*0Sstevel@tonic-gate } else { 215*0Sstevel@tonic-gate safe_zalloc((void **)&disk->next, 216*0Sstevel@tonic-gate sizeof (struct diskinfo), 0); 217*0Sstevel@tonic-gate disk = disk->next; 218*0Sstevel@tonic-gate disk->next = NULLDISK; 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate disk->ks = ksp; 221*0Sstevel@tonic-gate (void *) memset((void *)&disk->new_kios, 0, 222*0Sstevel@tonic-gate sizeof (kstat_io_t)); 223*0Sstevel@tonic-gate disk->new_kios.wlastupdate = disk->ks->ks_crtime; 224*0Sstevel@tonic-gate disk->new_kios.rlastupdate = disk->ks->ks_crtime; 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate /* 227*0Sstevel@tonic-gate * Insertion sort on (ks_module, ks_instance, ks_name) 228*0Sstevel@tonic-gate */ 229*0Sstevel@tonic-gate comp = &zerodisk; 230*0Sstevel@tonic-gate while (kscmp(disk->ks, comp->next->ks) > 0) { 231*0Sstevel@tonic-gate comp = comp->next; 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate if (prevdisk != comp) { 234*0Sstevel@tonic-gate prevdisk->next = disk->next; 235*0Sstevel@tonic-gate disk->next = comp->next; 236*0Sstevel@tonic-gate comp->next = disk; 237*0Sstevel@tonic-gate disk = prevdisk; 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate } 240*0Sstevel@tonic-gate /* 241*0Sstevel@tonic-gate * Put a snip in the linked list of diskinfos. The idea: 242*0Sstevel@tonic-gate * If there was a state change such that now there are fewer 243*0Sstevel@tonic-gate * disks, we snip the list and retain the tail, rather than 244*0Sstevel@tonic-gate * freeing it. At the next state change, we clip the tail back on. 245*0Sstevel@tonic-gate * This prevents a lot of malloc/free activity, and it's simpler. 246*0Sstevel@tonic-gate */ 247*0Sstevel@tonic-gate lastdisk = disk; 248*0Sstevel@tonic-gate snip = disk->next; 249*0Sstevel@tonic-gate disk->next = NULLDISK; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate firstdisk = zerodisk.next; 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate static int 255*0Sstevel@tonic-gate diskinfo_load(void) 256*0Sstevel@tonic-gate { 257*0Sstevel@tonic-gate struct diskinfo *disk; 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate for (disk = firstdisk; disk; disk = disk->next) { 260*0Sstevel@tonic-gate disk->old_kios = disk->new_kios; 261*0Sstevel@tonic-gate if (kstat_read(kc, disk->ks, 262*0Sstevel@tonic-gate (void *)&disk->new_kios) == -1) { 263*0Sstevel@tonic-gate return (1); 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate return (0); 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate int 271*0Sstevel@tonic-gate check_disks(hrtime_t *hr_now, int threshold) 272*0Sstevel@tonic-gate { 273*0Sstevel@tonic-gate struct diskinfo *disk; 274*0Sstevel@tonic-gate int delta = 0; 275*0Sstevel@tonic-gate hrtime_t time = 0; 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate while (kstat_chain_update(kc) || diskinfo_load()) { 278*0Sstevel@tonic-gate init_all(); 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate for (disk = firstdisk; disk; disk = disk->next) { 281*0Sstevel@tonic-gate if (time == 0) { 282*0Sstevel@tonic-gate time = disk->new_kios.wlastupdate; 283*0Sstevel@tonic-gate } 284*0Sstevel@tonic-gate delta += DISK_DELTA(reads); 285*0Sstevel@tonic-gate if (DISK_DELTA(reads) > 0) { 286*0Sstevel@tonic-gate time = MAX(time, disk->new_kios.wlastupdate); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate keep_activity_data(&disk_act_start, &disk_act_end, 290*0Sstevel@tonic-gate &info->pd_diskreads_sum, delta, time); 291*0Sstevel@tonic-gate #ifdef DEBUG 292*0Sstevel@tonic-gate (void) printf(" Disk reads = %d\n", delta); 293*0Sstevel@tonic-gate #endif 294*0Sstevel@tonic-gate return (check_activity(disk_act_start, info->pd_diskreads_sum, hr_now, 295*0Sstevel@tonic-gate threshold)); 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate static void 299*0Sstevel@tonic-gate cpu_stats_init(void) 300*0Sstevel@tonic-gate { 301*0Sstevel@tonic-gate kstat_t *ksp; 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate ncpus = 0; 304*0Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 305*0Sstevel@tonic-gate if (strcmp(ksp->ks_module, "cpu") == 0 && 306*0Sstevel@tonic-gate strcmp(ksp->ks_name, "sys") == 0) 307*0Sstevel@tonic-gate ncpus++; 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate safe_zalloc((void **)&cpu_stats_list, ncpus * sizeof (*cpu_stats_list), 311*0Sstevel@tonic-gate 1); 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate ncpus = 0; 314*0Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 315*0Sstevel@tonic-gate if (strcmp(ksp->ks_module, "cpu") == 0 && 316*0Sstevel@tonic-gate strcmp(ksp->ks_name, "sys") == 0 && 317*0Sstevel@tonic-gate kstat_read(kc, ksp, NULL) != -1) 318*0Sstevel@tonic-gate cpu_stats_list[ncpus++] = ksp; 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate if (ncpus == 0) 322*0Sstevel@tonic-gate fail("can't find any cpu statistics"); 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate static int 326*0Sstevel@tonic-gate cpu_stats_load(void) 327*0Sstevel@tonic-gate { 328*0Sstevel@tonic-gate int i, j; 329*0Sstevel@tonic-gate kstat_named_t *nkp, *tkp; 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate tty_snaptime = 0; 332*0Sstevel@tonic-gate kstat_copy(&new_cpu_stats, &old_cpu_stats, 1); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate /* 335*0Sstevel@tonic-gate * Sum across all cpus 336*0Sstevel@tonic-gate */ 337*0Sstevel@tonic-gate for (i = 0; i < ncpus; i++) { 338*0Sstevel@tonic-gate if (kstat_read(kc, cpu_stats_list[i], NULL) == -1) 339*0Sstevel@tonic-gate return (1); 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate if (i == 0) { 342*0Sstevel@tonic-gate kstat_copy(cpu_stats_list[i], &new_cpu_stats, 1); 343*0Sstevel@tonic-gate continue; 344*0Sstevel@tonic-gate } else { 345*0Sstevel@tonic-gate /* 346*0Sstevel@tonic-gate * Other CPUs' statistics are accumulated in 347*0Sstevel@tonic-gate * new_cpu_stats, initialized at the first iteration of 348*0Sstevel@tonic-gate * the loop. 349*0Sstevel@tonic-gate */ 350*0Sstevel@tonic-gate nkp = (kstat_named_t *)new_cpu_stats.ks_data; 351*0Sstevel@tonic-gate tkp = (kstat_named_t *)cpu_stats_list[i]->ks_data; 352*0Sstevel@tonic-gate for (j = 0; j < cpu_stats_list[i]->ks_ndata; j++) 353*0Sstevel@tonic-gate (nkp++)->value.ui64 += (tkp++)->value.ui64; 354*0Sstevel@tonic-gate tty_snaptime = MAX(tty_snaptime, 355*0Sstevel@tonic-gate cpu_stats_list[i]->ks_snaptime); 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate return (0); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate int 363*0Sstevel@tonic-gate check_tty(hrtime_t *hr_now, int threshold) 364*0Sstevel@tonic-gate { 365*0Sstevel@tonic-gate int delta; 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate while (kstat_chain_update(kc) || cpu_stats_load()) { 368*0Sstevel@tonic-gate init_all(); 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate delta = CPU_DELTA("rawch") + CPU_DELTA("outch"); 371*0Sstevel@tonic-gate keep_activity_data(&tty_act_start, &tty_act_end, 372*0Sstevel@tonic-gate &info->pd_ttychars_sum, delta, tty_snaptime); 373*0Sstevel@tonic-gate #ifdef DEBUG 374*0Sstevel@tonic-gate (void) printf(" Tty chars = %d\n", delta); 375*0Sstevel@tonic-gate #endif 376*0Sstevel@tonic-gate return (check_activity(tty_act_start, info->pd_ttychars_sum, hr_now, 377*0Sstevel@tonic-gate threshold)); 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate static void 381*0Sstevel@tonic-gate load_ave_init(void) 382*0Sstevel@tonic-gate { 383*0Sstevel@tonic-gate if ((load_ave_ksp = kstat_lookup(kc, "unix", 0, "system_misc")) == 384*0Sstevel@tonic-gate NULL) { 385*0Sstevel@tonic-gate fail("kstat_lookup('unix', 0, 'system_misc') failed"); 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate static int 390*0Sstevel@tonic-gate load_ave_load(void) 391*0Sstevel@tonic-gate { 392*0Sstevel@tonic-gate if (kstat_read(kc, load_ave_ksp, NULL) == -1) { 393*0Sstevel@tonic-gate return (1); 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate load_ave = ((kstat_named_t *)safe_kstat_data_lookup( 396*0Sstevel@tonic-gate load_ave_ksp, "avenrun_1min"))->value.l; 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate return (0); 399*0Sstevel@tonic-gate } 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate int 402*0Sstevel@tonic-gate check_load_ave(hrtime_t *hr_now, float threshold) 403*0Sstevel@tonic-gate { 404*0Sstevel@tonic-gate while (kstat_chain_update(kc) || load_ave_load()) { 405*0Sstevel@tonic-gate init_all(); 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate info->pd_loadaverage = (double)load_ave / FSCALE; 408*0Sstevel@tonic-gate if (info->pd_loadaverage > threshold) { 409*0Sstevel@tonic-gate last_load_ave_change = load_ave_ksp->ks_snaptime; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate #ifdef DEBUG 412*0Sstevel@tonic-gate (void) printf(" Load average = %f\n", ((double)load_ave / FSCALE)); 413*0Sstevel@tonic-gate #endif 414*0Sstevel@tonic-gate return ((*hr_now - last_load_ave_change) / NANOSEC); 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate static void 418*0Sstevel@tonic-gate nfs_init(void) 419*0Sstevel@tonic-gate { 420*0Sstevel@tonic-gate nfs_client2_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v2"); 421*0Sstevel@tonic-gate nfs_client3_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v3"); 422*0Sstevel@tonic-gate nfs_server2_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v2"); 423*0Sstevel@tonic-gate nfs_server3_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v3"); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate static int 427*0Sstevel@tonic-gate nfs_load(void) 428*0Sstevel@tonic-gate { 429*0Sstevel@tonic-gate kstat_named_t *kstat_ptr; 430*0Sstevel@tonic-gate int index; 431*0Sstevel@tonic-gate uint64_t total_calls = 0; 432*0Sstevel@tonic-gate uint64_t getattr_calls = 0; 433*0Sstevel@tonic-gate uint64_t null_calls = 0; 434*0Sstevel@tonic-gate uint64_t access_calls = 0; 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate if (!nfs_client2_kstat && !nfs_client3_kstat && !nfs_server2_kstat && 437*0Sstevel@tonic-gate !nfs_server3_kstat) { 438*0Sstevel@tonic-gate return (0); 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate /* 442*0Sstevel@tonic-gate * NFS client "getattr", NFS3 client "access", and NFS server "null" 443*0Sstevel@tonic-gate * requests are excluded from consideration. 444*0Sstevel@tonic-gate */ 445*0Sstevel@tonic-gate if (nfs_client2_kstat) { 446*0Sstevel@tonic-gate if (kstat_read(kc, nfs_client2_kstat, NULL) == -1) { 447*0Sstevel@tonic-gate return (1); 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate kstat_ptr = KSTAT_NAMED_PTR(nfs_client2_kstat); 450*0Sstevel@tonic-gate for (index = 0; index < nfs_client2_kstat->ks_ndata; index++) { 451*0Sstevel@tonic-gate total_calls += kstat_ptr[index].value.ui64; 452*0Sstevel@tonic-gate } 453*0Sstevel@tonic-gate getattr_calls = 454*0Sstevel@tonic-gate ((kstat_named_t *)safe_kstat_data_lookup( 455*0Sstevel@tonic-gate nfs_client2_kstat, "getattr"))->value.ui64; 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate if (nfs_client3_kstat) { 459*0Sstevel@tonic-gate if (kstat_read(kc, nfs_client3_kstat, NULL) == -1) { 460*0Sstevel@tonic-gate return (1); 461*0Sstevel@tonic-gate } 462*0Sstevel@tonic-gate kstat_ptr = KSTAT_NAMED_PTR(nfs_client3_kstat); 463*0Sstevel@tonic-gate for (index = 0; index < nfs_client3_kstat->ks_ndata; index++) { 464*0Sstevel@tonic-gate total_calls += kstat_ptr[index].value.ui64; 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate getattr_calls += 467*0Sstevel@tonic-gate ((kstat_named_t *)safe_kstat_data_lookup( 468*0Sstevel@tonic-gate nfs_client3_kstat, "getattr"))->value.ui64; 469*0Sstevel@tonic-gate access_calls = 470*0Sstevel@tonic-gate ((kstat_named_t *)safe_kstat_data_lookup( 471*0Sstevel@tonic-gate nfs_client3_kstat, "access"))->value.ui64; 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate if (nfs_server2_kstat) { 475*0Sstevel@tonic-gate if (kstat_read(kc, nfs_server2_kstat, NULL) == -1) { 476*0Sstevel@tonic-gate return (1); 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate kstat_ptr = KSTAT_NAMED_PTR(nfs_server2_kstat); 479*0Sstevel@tonic-gate for (index = 0; index < nfs_server2_kstat->ks_ndata; index++) { 480*0Sstevel@tonic-gate total_calls += kstat_ptr[index].value.ui64; 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate null_calls = 483*0Sstevel@tonic-gate ((kstat_named_t *)safe_kstat_data_lookup( 484*0Sstevel@tonic-gate nfs_server2_kstat, "null"))->value.ui64; 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate if (nfs_server3_kstat) { 488*0Sstevel@tonic-gate if (kstat_read(kc, nfs_server3_kstat, NULL) == -1) { 489*0Sstevel@tonic-gate return (1); 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate kstat_ptr = KSTAT_NAMED_PTR(nfs_server3_kstat); 492*0Sstevel@tonic-gate for (index = 0; index < nfs_server3_kstat->ks_ndata; index++) { 493*0Sstevel@tonic-gate total_calls += kstat_ptr[index].value.ui64; 494*0Sstevel@tonic-gate } 495*0Sstevel@tonic-gate null_calls += 496*0Sstevel@tonic-gate ((kstat_named_t *)safe_kstat_data_lookup( 497*0Sstevel@tonic-gate nfs_server3_kstat, "null"))->value.ui64; 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate old_nfs_calls = new_nfs_calls; 501*0Sstevel@tonic-gate new_nfs_calls = total_calls - 502*0Sstevel@tonic-gate (getattr_calls + access_calls + null_calls); 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate return (0); 505*0Sstevel@tonic-gate } 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate int 508*0Sstevel@tonic-gate check_nfs(hrtime_t *hr_now, int threshold) 509*0Sstevel@tonic-gate { 510*0Sstevel@tonic-gate int delta; 511*0Sstevel@tonic-gate hrtime_t time = 0; 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate while (kstat_chain_update(kc) || nfs_load()) { 514*0Sstevel@tonic-gate init_all(); 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate 517*0Sstevel@tonic-gate if (!nfs_client2_kstat && !nfs_client3_kstat && !nfs_server2_kstat && 518*0Sstevel@tonic-gate !nfs_server3_kstat) { 519*0Sstevel@tonic-gate return (0); 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate if (nfs_client2_kstat) { 523*0Sstevel@tonic-gate time = MAX(time, nfs_client2_kstat->ks_snaptime); 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate if (nfs_client3_kstat) { 526*0Sstevel@tonic-gate time = MAX(time, nfs_client3_kstat->ks_snaptime); 527*0Sstevel@tonic-gate } 528*0Sstevel@tonic-gate if (nfs_server2_kstat) { 529*0Sstevel@tonic-gate time = MAX(time, nfs_server2_kstat->ks_snaptime); 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate if (nfs_server3_kstat) { 532*0Sstevel@tonic-gate time = MAX(time, nfs_server3_kstat->ks_snaptime); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate delta = (int)(new_nfs_calls - old_nfs_calls); 535*0Sstevel@tonic-gate keep_activity_data(&nfs_act_start, &nfs_act_end, 536*0Sstevel@tonic-gate &info->pd_nfsreqs_sum, delta, time); 537*0Sstevel@tonic-gate #ifdef DEBUG 538*0Sstevel@tonic-gate (void) printf(" NFS requests = %d\n", delta); 539*0Sstevel@tonic-gate #endif 540*0Sstevel@tonic-gate return (check_activity(nfs_act_start, info->pd_nfsreqs_sum, hr_now, 541*0Sstevel@tonic-gate threshold)); 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate static void 545*0Sstevel@tonic-gate conskbd_init(void) 546*0Sstevel@tonic-gate { 547*0Sstevel@tonic-gate conskbd_ksp = kstat_lookup(kc, "conskbd", 0, "activity"); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate /* 551*0Sstevel@tonic-gate * Return the number of seconds since the last keystroke on console keyboard. 552*0Sstevel@tonic-gate * Caller responsible for error reporting. 553*0Sstevel@tonic-gate */ 554*0Sstevel@tonic-gate long 555*0Sstevel@tonic-gate conskbd_idle_time(void) 556*0Sstevel@tonic-gate { 557*0Sstevel@tonic-gate void *p; 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate if (conskbd_ksp == NULL || kstat_read(kc, conskbd_ksp, NULL) == -1 || 560*0Sstevel@tonic-gate (p = kstat_data_lookup(conskbd_ksp, "idle_sec")) == NULL) 561*0Sstevel@tonic-gate return ((time_t)-1); 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate return (((kstat_named_t *)p)->value.l); 564*0Sstevel@tonic-gate } 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate static void 567*0Sstevel@tonic-gate consms_init(void) 568*0Sstevel@tonic-gate { 569*0Sstevel@tonic-gate consms_ksp = kstat_lookup(kc, "consms", 0, "activity"); 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate /* 573*0Sstevel@tonic-gate * Return the number of seconds since the most recent action (movement or 574*0Sstevel@tonic-gate * click) of the console mouse. Caller responsible for error reporting. 575*0Sstevel@tonic-gate */ 576*0Sstevel@tonic-gate long 577*0Sstevel@tonic-gate consms_idle_time(void) 578*0Sstevel@tonic-gate { 579*0Sstevel@tonic-gate void *p; 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate if (consms_ksp == NULL || kstat_read(kc, consms_ksp, NULL) == -1 || 582*0Sstevel@tonic-gate (p = kstat_data_lookup(consms_ksp, "idle_sec")) == NULL) 583*0Sstevel@tonic-gate return ((time_t)-1); 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate return (((kstat_named_t *)p)->value.l); 586*0Sstevel@tonic-gate } 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate static void 589*0Sstevel@tonic-gate fail(char *fmt, ...) 590*0Sstevel@tonic-gate { 591*0Sstevel@tonic-gate char new_fmt[256]; 592*0Sstevel@tonic-gate va_list args; 593*0Sstevel@tonic-gate size_t len; 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate len = sizeof (new_fmt); 596*0Sstevel@tonic-gate va_start(args, fmt); 597*0Sstevel@tonic-gate if (snprintf(new_fmt, len, "powerd: %s", fmt) > len) 598*0Sstevel@tonic-gate syslog(LOG_ERR, "powerd: syslog message too large"); 599*0Sstevel@tonic-gate else 600*0Sstevel@tonic-gate vsyslog(LOG_ERR, new_fmt, args); 601*0Sstevel@tonic-gate va_end(args); 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate thr_exit((void *) 0); 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate static void 607*0Sstevel@tonic-gate safe_zalloc(void **ptr, int size, int free_first) 608*0Sstevel@tonic-gate { 609*0Sstevel@tonic-gate if (free_first && *ptr != NULL) { 610*0Sstevel@tonic-gate free(*ptr); 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate if ((*ptr = (void *) malloc(size)) == NULL) { 613*0Sstevel@tonic-gate fail("malloc failed"); 614*0Sstevel@tonic-gate } 615*0Sstevel@tonic-gate (void *) memset(*ptr, 0, size); 616*0Sstevel@tonic-gate } 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate static void * 619*0Sstevel@tonic-gate safe_kstat_data_lookup(kstat_t *ksp, char *name) 620*0Sstevel@tonic-gate { 621*0Sstevel@tonic-gate void *fp = kstat_data_lookup(ksp, name); 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate if (fp == NULL) { 624*0Sstevel@tonic-gate fail("kstat_data_lookup('%s', '%s') failed", 625*0Sstevel@tonic-gate ksp->ks_name, name); 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate return (fp); 628*0Sstevel@tonic-gate } 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate static int 631*0Sstevel@tonic-gate kscmp(kstat_t *ks1, kstat_t *ks2) 632*0Sstevel@tonic-gate { 633*0Sstevel@tonic-gate int cmp; 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate cmp = strcmp(ks1->ks_module, ks2->ks_module); 636*0Sstevel@tonic-gate if (cmp != 0) { 637*0Sstevel@tonic-gate return (cmp); 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate cmp = ks1->ks_instance - ks2->ks_instance; 640*0Sstevel@tonic-gate if (cmp != 0) { 641*0Sstevel@tonic-gate return (cmp); 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate return (strcmp(ks1->ks_name, ks2->ks_name)); 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate static void 647*0Sstevel@tonic-gate keep_activity_data(activity_data_t **act_start, activity_data_t **act_end, 648*0Sstevel@tonic-gate int *delta_sum, int delta, hrtime_t time) 649*0Sstevel@tonic-gate { 650*0Sstevel@tonic-gate activity_data_t *node = NULLACTIVITY; 651*0Sstevel@tonic-gate hrtime_t hr_now; 652*0Sstevel@tonic-gate int idle_time = info->pd_idle_time * 60; 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate /* 655*0Sstevel@tonic-gate * Add new nodes to the beginning of the list. 656*0Sstevel@tonic-gate */ 657*0Sstevel@tonic-gate safe_zalloc((void **)&node, sizeof (activity_data_t), 0); 658*0Sstevel@tonic-gate node->activity_delta = delta; 659*0Sstevel@tonic-gate *delta_sum += delta; 660*0Sstevel@tonic-gate node->snaptime = time; 661*0Sstevel@tonic-gate node->next = *act_start; 662*0Sstevel@tonic-gate if (*act_start == NULLACTIVITY) { 663*0Sstevel@tonic-gate *act_end = node; 664*0Sstevel@tonic-gate } else { 665*0Sstevel@tonic-gate (*act_start)->prev = node; 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate *act_start = node; 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate /* 670*0Sstevel@tonic-gate * Remove nodes that are time-stamped later than the idle time. 671*0Sstevel@tonic-gate */ 672*0Sstevel@tonic-gate hr_now = gethrtime(); 673*0Sstevel@tonic-gate node = *act_end; 674*0Sstevel@tonic-gate while ((int)((hr_now - node->snaptime) / NANOSEC) > idle_time && 675*0Sstevel@tonic-gate node->prev != NULLACTIVITY) { 676*0Sstevel@tonic-gate *delta_sum -= node->activity_delta; 677*0Sstevel@tonic-gate *act_end = node->prev; 678*0Sstevel@tonic-gate (*act_end)->next = NULLACTIVITY; 679*0Sstevel@tonic-gate free(node); 680*0Sstevel@tonic-gate node = *act_end; 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate static int 685*0Sstevel@tonic-gate check_activity(activity_data_t *act_start, int delta_sum, hrtime_t *time, 686*0Sstevel@tonic-gate int thold) 687*0Sstevel@tonic-gate { 688*0Sstevel@tonic-gate activity_data_t *node; 689*0Sstevel@tonic-gate int sum = 0; 690*0Sstevel@tonic-gate int idle_time = info->pd_idle_time * 60; 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate /* 693*0Sstevel@tonic-gate * No need to walk the list if the sum of the deltas are not greater 694*0Sstevel@tonic-gate * than the threshold value. 695*0Sstevel@tonic-gate */ 696*0Sstevel@tonic-gate if (delta_sum <= thold) { 697*0Sstevel@tonic-gate return (idle_time); 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate /* 701*0Sstevel@tonic-gate * Walk through the list and add up the activity deltas. When the 702*0Sstevel@tonic-gate * sum is greater than the threshold value, difference of current 703*0Sstevel@tonic-gate * time and the snaptime of that node will give us the idle time. 704*0Sstevel@tonic-gate */ 705*0Sstevel@tonic-gate node = act_start; 706*0Sstevel@tonic-gate while (node->next != NULLACTIVITY) { 707*0Sstevel@tonic-gate sum += node->activity_delta; 708*0Sstevel@tonic-gate if (sum > thold) { 709*0Sstevel@tonic-gate return ((*time - node->snaptime) / NANOSEC); 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate node = node->next; 712*0Sstevel@tonic-gate } 713*0Sstevel@tonic-gate sum += node->activity_delta; 714*0Sstevel@tonic-gate if (sum > thold) { 715*0Sstevel@tonic-gate return ((*time - node->snaptime) / NANOSEC); 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate return (idle_time); 719*0Sstevel@tonic-gate } 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate static void 722*0Sstevel@tonic-gate kstat_copy(kstat_t *src, kstat_t *dst, int fr) 723*0Sstevel@tonic-gate { 724*0Sstevel@tonic-gate if (fr) 725*0Sstevel@tonic-gate free(dst->ks_data); 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate *dst = *src; 728*0Sstevel@tonic-gate if (src->ks_data != NULL) { 729*0Sstevel@tonic-gate safe_zalloc(&dst->ks_data, src->ks_data_size, 0); 730*0Sstevel@tonic-gate (void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size); 731*0Sstevel@tonic-gate } else { 732*0Sstevel@tonic-gate dst->ks_data = NULL; 733*0Sstevel@tonic-gate dst->ks_data_size = 0; 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate } 736