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