xref: /titanic_51/usr/src/cmd/power/sysstat.c (revision c0dd49bdd68c0d758a67d56f07826f3b45cfc664)
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
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
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
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
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
178  last_load_ave_activity(hrtime_t *hr_now)
179  {
180  	return ((*hr_now - last_load_ave_change) / NANOSEC);
181  }
182  
183  int
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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