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