Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 6 Oct 2000 17:16:59 -0700 (PDT)
From:      Romain Kang <romain@kzsu.stanford.edu>
To:        rh@matriplex.com
Cc:        freebsd-hackers@FreeBSD.ORG
Subject:   Re: A decent way to get CPU idle time?
Message-ID:  <200010070016.RAA17529@kzsu.stanford.edu>

next in thread | raw e-mail | index | archive | help
I am loathe to call kmem readers clean and decent, but I coincidentally
did something similar today, ripping out code from vmstat.  See below.
It doesn't look difficult to implement a sysctl() interface, but I
guess if someone considered the data really important, it would have
been done already.

IMHO, getloadavg() is flagrantly meaningless.  There are plenty of
ways to skew the numbers without actually changing CPU activity.


Romain Kang                             Disclaimer: I speak for myself alone,
romain@kzsu.stanford.edu                except when indicated otherwise.

| Is there a clean and decent way to find out the percentage
| of CPU idle time, like top and systat give?  I have browsed
| the source for both, and neither appear to have a simple
| way of finding this information.

| I have already tried and rejected getloadavg.  In my 
| application, two main processes will always account 
| for 95% or more of the activity.

| I suppose I could use RDTSC to grab the clock on my system
| calls, and figure a rudimentary sum of CPU activity, but
| that won't help me with the expensive file and socket calls.
| And I would pretty much have to guess about the CPU time spent
| in the kernel.

| Any ideas?  Thanks.

#include <sys/param.h>
#include <sys/dkstat.h>
#include <kvm.h>
#include <nlist.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>

struct nlist namelist[] = {
#define X_CPTIME        0 
        { "_cp_time" },
	{""}
};
char *nlistf = NULL, *memf = NULL;

kvm_t	*kd;
void	kread();

void	cpu_init();
void	cpu_idle();

main()
{
	cpu_init();
	cpu_idle();
}

void
cpu_init()
{

	int c;
	static char errbuf[BUFSIZ];

	/*
	 * Discard setgid privileges if not the running kernel so that bad
	 * guys can't print interesting stuff from kernel memory.
	 */
	if (nlistf != NULL || memf != NULL)
		setgid(getgid());

	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
	if (kd == 0) 
		errx(1, "kvm_openfiles: %s", errbuf);

	if ((c = kvm_nlist(kd, namelist)) != 0) {
		if (c > 0) {
			warnx("undefined symbols:");
			for (c = 0;
			    c < sizeof(namelist)/sizeof(namelist[0]); c++)
				if (namelist[c].n_type == 0)
					fprintf(stderr, " %s",
					    namelist[c].n_name);
			(void)fputc('\n', stderr);
		} else
			warnx("kvm_nlist: %s", kvm_geterr(kd));
		exit(1);
	}

}


void
cpu_idle()
{
	register int state;
	double pct, total;
	long cp_time[CPUSTATES];
	int idle_percent;

	kread(X_CPTIME, cp_time, sizeof(cp_time));

	total = 0;
	for (state = 0; state < CPUSTATES; ++state)
		total += cp_time[state];
	if (total)
		pct = 100 / total;
	else
		pct = 0;

	idle_percent =  cp_time[CP_IDLE] * pct;

	printf("idle%%=%d\n", idle_percent);
}


/*
 * kread reads something from the kernel, given its nlist index.
 */
void
kread(nlx, addr, size)
	int nlx;
	void *addr;
	size_t size;
{
	char *sym;

	if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
		sym = namelist[nlx].n_name;
		if (*sym == '_')
			++sym;
		errx(1, "symbol %s not defined", sym);
	}
	if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) {
		sym = namelist[nlx].n_name;
		if (*sym == '_')
			++sym;
		errx(1, "%s: %s", sym, kvm_geterr(kd));
	}
}



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200010070016.RAA17529>