示例#1
0
void
fetchiostat(void)
{
	struct devinfo *tmp_dinfo;

	if (kinfo_get_sched_cputime(&cp_time))
		err(1, "kinfo_get_sched_cputime");
	tmp_dinfo = last.dinfo;
	last.dinfo = cur.dinfo;
	cur.dinfo = tmp_dinfo;
         
	last.busy_time = cur.busy_time;

	/*
	 * Here what we want to do is refresh our device stats.
	 * getdevs() returns 1 when the device list has changed.
	 * If the device list has changed, we want to go through
	 * the selection process again, in case a device that we
	 * were previously displaying has gone away.
	 */
	switch (getdevs(&cur)) {
	case -1:
		errx(1, "%s", devstat_errbuf);
		break;
	case 1:
		cmdiostat("refresh", NULL);
		break;
	default:
		break;
	}
	num_devices = cur.dinfo->numdevs;
	generation = cur.dinfo->generation;

}
示例#2
0
void
updatexfers(int numdevs, int *devs)
{
	register int i, j, t;
	struct statinfo stats;
	int num_devices = 0;
	u_int64_t total_transfers;

	if ((num_devices = getnumdevs()) < 0) {
		syslog(LOG_ERR, "rstatd: can't get number of devices: %s",
		       devstat_errbuf);
		exit(1);
	}

	if (checkversion() < 0) {
		syslog(LOG_ERR, "rstatd: %s", devstat_errbuf);
		exit(1);
	}

	stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
	bzero(stats.dinfo, sizeof(struct devinfo));

	if (getdevs(&stats) == -1) {
		syslog(LOG_ERR, "rstatd: can't get device list: %s",
		       devstat_errbuf);
		exit(1);
	}

	for (i = 0, j = 0; i < stats.dinfo->numdevs && j < numdevs; i++) {
		if (((stats.dinfo->devices[i].device_type
		      & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT)
		 && ((stats.dinfo->devices[i].device_type
		      & DEVSTAT_TYPE_PASS) == 0)) {
			total_transfers = stats.dinfo->devices[i].num_reads +
					  stats.dinfo->devices[i].num_writes +
					  stats.dinfo->devices[i].num_other;
			/*
			 * XXX KDM If the total transfers for this device
			 * are greater than the amount we can fit in a
			 * signed integer, just set them to the maximum
			 * amount we can fit in a signed integer.  I have a
			 * feeling that the rstat protocol assumes 32-bit
			 * integers, so this could well break on a 64-bit
			 * architecture like the Alpha.
			 */
			if (total_transfers > INT_MAX)
				t = INT_MAX;
			else
				t = total_transfers;
			devs[j] = t;
			j++;
		}
	}

	if (stats.dinfo->mem_ptr)
		free(stats.dinfo->mem_ptr);

	free(stats.dinfo);
}
示例#3
0
void
gkrellm_sys_disk_read_data(void)
	{
	int			ndevs;
	int			num_selected;
	int			num_selections;
	int			maxshowdevs = 10;
	struct device_selection	*dev_select = NULL;
	long			select_generation;
	int			dn;
	gchar		name[32];

	if (getdevs(&statinfo_cur) < 0)
		return;
	ndevs = statinfo_cur.dinfo->numdevs;
	if (selectdevs(&dev_select, &num_selected, &num_selections,
		       &select_generation, statinfo_cur.dinfo->generation,
		       statinfo_cur.dinfo->devices, ndevs,
		       NULL, 0, NULL, 0,
		       DS_SELECT_ONLY, maxshowdevs, 1) >= 0)
		{
		for (dn = 0; dn < ndevs; ++dn)
			{
			int		di;
			struct devstat	*dev;
//			int		block_size;
//			int		blocks_read, blocks_written;

			di = dev_select[dn].position;
			dev = &statinfo_cur.dinfo->devices[di];
//			block_size = (dev->block_size > 0)
//				   ? dev->block_size : 512;
//			blocks_read = dev->bytes_read / block_size;
//			blocks_written = dev->bytes_written / block_size;

			/* to use gkrellm_disk_assign_data_by_device() would need
			   gkrellm_sys_disk_name_from_device() implemented */
			snprintf(name, sizeof(name), "%s%d", dev->device_name,
					dev->unit_number);
			gkrellm_disk_assign_data_by_name(name,
					dev->bytes_read, dev->bytes_written, FALSE);
			}
		free(dev_select);
		}
	}
示例#4
0
/*
 * returns true if have a disk
 */
int
haveadisk(void)
{
	register int i;
	struct statinfo stats;
	int num_devices, retval = 0;

	if ((num_devices = getnumdevs()) < 0) {
		syslog(LOG_ERR, "rstatd: can't get number of devices: %s",
		       devstat_errbuf);
		exit(1);
	}

	if (checkversion() < 0) {
		syslog(LOG_ERR, "rstatd: %s", devstat_errbuf);
		exit(1);
	}

	stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
	bzero(stats.dinfo, sizeof(struct devinfo));

	if (getdevs(&stats) == -1) {
		syslog(LOG_ERR, "rstatd: can't get device list: %s",
		       devstat_errbuf);
		exit(1);
	}
	for (i = 0; i < stats.dinfo->numdevs; i++) {
		if (((stats.dinfo->devices[i].device_type
		      & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT)
		 && ((stats.dinfo->devices[i].device_type
		      & DEVSTAT_TYPE_PASS) == 0)) {
			retval = 1;
			break;
		}
	}

	if (stats.dinfo->mem_ptr)
		free(stats.dinfo->mem_ptr);

	free(stats.dinfo);
	return(retval);
}
示例#5
0
int br_getunit(char *arg, int *house, int *devs)
{
/*
 * Get units to be accessed from the command line in native BottleRocket style
 */

    if (strlen(arg) < 2) {
        errno = EINVAL;
        return -1;
    }

    if ((*devs = getdevs(arg + 1)) < 0)
        return -1;

    *(arg + 1) = '\0';

    if ((*house = gethouse(arg)) < 0)
        return -1;

    return 0;
}
示例#6
0
int	get_diskstat(const char *devname, zbx_uint64_t *dstat)
{
	int		i;
	struct devstat	*ds = NULL;
	int		ret = FAIL;
	char		dev[DEVSTAT_NAME_LEN + 10];
	const char	*pd;	/* pointer to device name without '/dev/' prefix, e.g. 'da0' */

	assert(devname);

	for (i = 0; i < ZBX_DSTAT_MAX; i++)
		dstat[i] = (zbx_uint64_t)__UINT64_C(0);

	if (NULL == si)
	{
		si = (struct statinfo *)zbx_malloc(si, sizeof(struct statinfo));
		si->dinfo = (struct devinfo *)zbx_malloc(NULL, sizeof(struct devinfo));
		memset(si->dinfo, 0, sizeof(struct devinfo));
	}

	pd = devname;

	/* skip prefix ZBX_DEV_PFX, if present */
	if ('\0' != *devname && 0 == strncmp(pd, ZBX_DEV_PFX, sizeof(ZBX_DEV_PFX) - 1))
			pd += sizeof(ZBX_DEV_PFX) - 1;

#if DEVSTAT_USER_API_VER >= 5
	if (-1 == devstat_getdevs(NULL, si))
#else
	if (-1 == getdevs(si))
#endif
		return FAIL;

	for (i = 0; i < si->dinfo->numdevs; i++)
	{
		ds = &si->dinfo->devices[i];

		/* empty '*devname' string means adding statistics for all disks together */
		if ('\0' != *devname)
		{
			zbx_snprintf(dev, sizeof(dev), "%s%d", ds->device_name, ds->unit_number);
			if (0 != strcmp(dev, pd))
				continue;
		}

#if DEVSTAT_USER_API_VER >= 5
		dstat[ZBX_DSTAT_R_OPER] += (zbx_uint64_t)ds->operations[DEVSTAT_READ];
		dstat[ZBX_DSTAT_W_OPER] += (zbx_uint64_t)ds->operations[DEVSTAT_WRITE];
		dstat[ZBX_DSTAT_R_BYTE] += (zbx_uint64_t)ds->bytes[DEVSTAT_READ];
		dstat[ZBX_DSTAT_W_BYTE] += (zbx_uint64_t)ds->bytes[DEVSTAT_WRITE];
#else
		dstat[ZBX_DSTAT_R_OPER] += (zbx_uint64_t)ds->num_reads;
		dstat[ZBX_DSTAT_W_OPER] += (zbx_uint64_t)ds->num_writes;
		dstat[ZBX_DSTAT_R_BYTE] += (zbx_uint64_t)ds->bytes_read;
		dstat[ZBX_DSTAT_W_BYTE] += (zbx_uint64_t)ds->bytes_written;
#endif
		ret = SUCCEED;

		if ('\0' != *devname)
			break;
	}

	return ret;
}
示例#7
0
static void
getinfo(struct Info *ls)
{
	struct devinfo *tmp_dinfo;
	struct nchstats *nch_tmp;
	size_t size;
	size_t vms_size = sizeof(ls->Vms);
	size_t vmm_size = sizeof(ls->Vmm);
	size_t nch_size = sizeof(ls->nchstats) * SMP_MAXCPU;

        if (sysctlbyname("vm.vmstats", &ls->Vms, &vms_size, NULL, 0)) {
                perror("sysctlbyname: vm.vmstats");
                exit(1);
        }
        if (sysctlbyname("vm.vmmeter", &ls->Vmm, &vmm_size, NULL, 0)) {
                perror("sysctlbyname: vm.vmstats");
                exit(1);
        }

	if (kinfo_get_sched_cputime(&ls->cp_time))
		err(1, "kinfo_get_sched_cputime");
	if (kinfo_get_sched_cputime(&cp_time))
		err(1, "kinfo_get_sched_cputime");
	NREAD(X_BUFFERSPACE, &ls->bufspace, sizeof(ls->bufspace));
	NREAD(X_DESIREDVNODES, &ls->desiredvnodes, sizeof(ls->desiredvnodes));
	NREAD(X_NUMVNODES, &ls->numvnodes, sizeof(ls->numvnodes));
	NREAD(X_FREEVNODES, &ls->freevnodes, sizeof(ls->freevnodes));
	NREAD(X_NUMDIRTYBUFFERS, &ls->dirtybufspace, sizeof(ls->dirtybufspace));

	if (nintr) {
		size = nintr * sizeof(ls->intrcnt[0]);
		sysctlbyname("hw.intrcnt_all", ls->intrcnt, &size, NULL, 0);
	}
	size = sizeof(ls->Total);
	if (sysctlbyname("vm.vmtotal", &ls->Total, &size, NULL, 0) < 0) {
		error("Can't get kernel info: %s\n", strerror(errno));
		bzero(&ls->Total, sizeof(ls->Total));
	}

	if ((nch_tmp = malloc(nch_size)) == NULL) {
		perror("malloc");
		exit(1);
	} else {
		if (sysctlbyname("vfs.cache.nchstats", nch_tmp, &nch_size, NULL, 0)) {
			perror("sysctlbyname vfs.cache.nchstats");
			free(nch_tmp);
			exit(1);
		} else {
			if ((nch_tmp = realloc(nch_tmp, nch_size)) == NULL) {
				perror("realloc");
				exit(1);
			}
		}
	}

	if (kinfo_get_cpus(&ncpu))
		err(1, "kinfo_get_cpus");
	kvm_nch_cpuagg(nch_tmp, &ls->nchstats, ncpu);
	free(nch_tmp);

	tmp_dinfo = last.dinfo;
	last.dinfo = cur.dinfo;
	cur.dinfo = tmp_dinfo;

	last.busy_time = cur.busy_time;
	switch (getdevs(&cur)) {
	case -1:
		errx(1, "%s", devstat_errbuf);
		break;
	case 1:
		num_devices = cur.dinfo->numdevs;
		generation = cur.dinfo->generation;
		cmdkre("refresh", NULL);
		break;
	default:
		break;
	}
}
示例#8
0
int
cmdkre(const char *cmd, char *args)
{
	int retval;

	if (prefix(cmd, "run")) {
		retval = 1;
		copyinfo(&s2, &s1);
		switch (getdevs(&run)) {
		case -1:
			errx(1, "%s", devstat_errbuf);
			break;
		case 1:
			num_devices = run.dinfo->numdevs;
			generation = run.dinfo->generation;
			retval = dscmd("refresh", NULL, MAXDRIVES, &cur);
			if (retval == 2)
				labelkre();
			break;
		default:
			break;
		}
		state = RUN;
		return (retval);
	}
	if (prefix(cmd, "boot")) {
		state = BOOT;
		copyinfo(&z, &s1);
		return (1);
	}
	if (prefix(cmd, "time")) {
		state = TIME;
		return (1);
	}
	if (prefix(cmd, "zero")) {
		retval = 1;
		if (state == RUN) {
			getinfo(&s1);
			switch (getdevs(&run)) {
			case -1:
				errx(1, "%s", devstat_errbuf);
				break;
			case 1:
				num_devices = run.dinfo->numdevs;
				generation = run.dinfo->generation;
				retval = dscmd("refresh",NULL, MAXDRIVES, &cur);
				if (retval == 2)
					labelkre();
				break;
			default:
				break;
			}
		}
		return (retval);
	}
	retval = dscmd(cmd, args, MAXDRIVES, &cur);

	if (retval == 2)
		labelkre();

	return(retval);
}
示例#9
0
sg_fs_stats *sg_get_fs_stats(int *entries){
	VECTOR_DECLARE_STATIC(disk_stats, sg_fs_stats, 10,
			      disk_stat_init, disk_stat_destroy);

	int num_disks=0;
#if defined(LINUX) || defined (SOLARIS) || defined(CYGWIN) || defined(HPUX)
	FILE *f;
#endif

	sg_fs_stats *disk_ptr;

#ifdef SOLARIS
	struct mnttab mp;
	struct statvfs fs;
#endif
#if defined(LINUX) || defined(CYGWIN) || defined(HPUX)
	struct mntent *mp;
	struct statvfs fs;
#endif
#ifdef ALLBSD
	int nummnt;
#ifdef HAVE_STATVFS
	struct statvfs *mp, **fs;
#else
	struct statfs *mp, **fs;
#endif
#endif
#ifdef WIN32
	char lp_buf[MAX_PATH];
	char volume_name_buf[BUFSIZE];
	char filesys_name_buf[BUFSIZE];
	char drive[4] = " :\\";
	char *p;
	int drive_type; //@
	lp_buf[0]='\0';
#endif

#ifdef ALLBSD
	nummnt=getmntinfo(&mp, MNT_WAIT);
	if (nummnt<=0){
		sg_set_error_with_errno(SG_ERROR_GETMNTINFO, NULL);
		return NULL;
	}
	for(fs = &mp; nummnt--; (*fs)++){
#endif

#if defined(LINUX) || defined(CYGWIN) || defined(HPUX)
#ifdef MNT_MNTTAB
	if ((f=setmntent(MNT_MNTTAB, "r" ))==NULL){
#else
	if ((f=setmntent("/etc/mtab", "r" ))==NULL){
#endif
		sg_set_error(SG_ERROR_SETMNTENT, NULL);
		return NULL;
	}

	while((mp=getmntent(f))){
		if((statvfs(mp->mnt_dir, &fs)) !=0){
			continue;
		}	

#endif

#ifdef SOLARIS
	if ((f=fopen("/etc/mnttab", "r" ))==NULL){
		sg_set_error_with_errno(SG_ERROR_OPEN, "/etc/mnttab");
		return NULL;
	}
	while((getmntent(f, &mp)) == 0){
		if ((statvfs(mp.mnt_mountp, &fs)) !=0){
			continue;
		}
#endif

#ifdef WIN32
	if (!(GetLogicalDriveStringsA(BUFSIZE-1, lp_buf))) {
		sg_set_error(SG_ERROR_GETMNTINFO, "GetLogicalDriveStrings");
		return NULL;
	}
	p = lp_buf;
	do {
		// Copy drive letter to template string
		*drive = *p;
		// Only interested in harddrives.
		drive_type = GetDriveTypeA(drive);

		if(drive_type == DRIVE_FIXED) {
#else
		if(is_valid_fs_type(SG_MP_FSTYPENAME(mp))){
#endif
			if (VECTOR_RESIZE(disk_stats, num_disks + 1) < 0) {
				return NULL;
			}
			disk_ptr=disk_stats+num_disks;

#ifndef WIN32
			/* Maybe make this char[bigenough] and do strncpy's and put a null in the end? 
			 * Downside is its a bit hungry for a lot of mounts, as MNT_MAX_SIZE would prob 
			 * be upwards of a k each 
			 */
			if (sg_update_string(&disk_ptr->device_name, SG_MP_DEVNAME(mp)) < 0) {
				return NULL;
			}
			if (sg_update_string(&disk_ptr->fs_type, SG_MP_FSTYPENAME(mp)) < 0) {
				return NULL;
			}
			if (sg_update_string(&disk_ptr->mnt_point, SG_MP_MOUNTP(mp)) < 0) {
				return NULL;
			}

			disk_ptr->size  = SG_FS_FRSIZE(fs) * SG_FS_BLOCKS(fs);
			disk_ptr->avail = SG_FS_FRSIZE(fs) * SG_FS_BAVAIL(fs);
			disk_ptr->used  = (disk_ptr->size) - (SG_FS_FRSIZE(fs) * SG_FS_BFREE(fs));
		
			disk_ptr->total_inodes = SG_FS_FILES(fs);
			disk_ptr->free_inodes  = SG_FS_FFREE(fs);
			/* Linux, FreeBSD don't have a "available" inodes */
			disk_ptr->used_inodes  = disk_ptr->total_inodes - disk_ptr->free_inodes;
			disk_ptr->avail_inodes = SG_FS_FAVAIL(fs);

			disk_ptr->io_size      = SG_FS_BSIZE(fs);
			disk_ptr->block_size   = SG_FS_FRSIZE(fs);
			disk_ptr->total_blocks = SG_FS_BLOCKS(fs);
			disk_ptr->free_blocks  = SG_FS_BFREE(fs);
			disk_ptr->avail_blocks = SG_FS_BAVAIL(fs);
			disk_ptr->used_blocks  = disk_ptr->total_blocks - disk_ptr->free_blocks;
#else
			if(!GetVolumeInformationA(drive, volume_name_buf, BUFSIZE,
						NULL, NULL, NULL, 
						filesys_name_buf, BUFSIZE)) {
				sg_set_error_with_errno(SG_ERROR_DISKINFO, 
					"GetVolumeInformation");
				return NULL;
			}

			if (sg_update_string(&disk_ptr->device_name, 
						volume_name_buf) < 0) {
				return NULL;
			}
			if (sg_update_string(&disk_ptr->fs_type, 
						filesys_name_buf) < 0) {
				return NULL;
			}
			if (sg_update_string(&disk_ptr->mnt_point,
						drive) < 0) {
				return NULL;
			}
			if (!GetDiskFreeSpaceExA(drive, NULL,
					(PULARGE_INTEGER)&disk_ptr->size,
					(PULARGE_INTEGER)&disk_ptr->avail)) {
				sg_set_error_with_errno(SG_ERROR_DISKINFO,
					"GetDiskFreeSpaceEx");
				return NULL;
			}
			disk_ptr->used = disk_ptr->size - disk_ptr->avail;
			disk_ptr->total_inodes = 0;
			disk_ptr->free_inodes  = 0;
			disk_ptr->used_inodes  = 0;
			disk_ptr->avail_inodes = 0;

			/* I dunno what to do with these... so have nothing */
			disk_ptr->io_size = 0;
			disk_ptr->block_size = 0;
			disk_ptr->total_blocks = 0;
			disk_ptr->free_blocks = 0;
			disk_ptr->avail_blocks = 0;
			disk_ptr->used_blocks = 0;
#endif
			num_disks++;
		}
#ifdef WIN32
		while(*p++);
	} while(*p);
#else
	}
#endif

	*entries=num_disks;	

	/* If this fails, there is very little i can do about it, so
	   I'll ignore it :) */
#if defined(LINUX) || defined(CYGWIN) || defined(HPUX)
	endmntent(f);
#endif
#if defined(SOLARIS)
	fclose(f);
#endif

	return disk_stats;

}

int sg_fs_compare_device_name(const void *va, const void *vb) {
	const sg_fs_stats *a = (const sg_fs_stats *)va;
	const sg_fs_stats *b = (const sg_fs_stats *)vb;

	return strcmp(a->device_name, b->device_name);
}

int sg_fs_compare_mnt_point(const void *va, const void *vb) {
	const sg_fs_stats *a = (const sg_fs_stats *)va;
	const sg_fs_stats *b = (const sg_fs_stats *)vb;

	return strcmp(a->mnt_point, b->mnt_point);
}

static void diskio_stat_init(sg_disk_io_stats *d) {
	d->disk_name = NULL;
}

static void diskio_stat_destroy(sg_disk_io_stats *d) {
	free(d->disk_name);
}

VECTOR_DECLARE_STATIC(diskio_stats, sg_disk_io_stats, 10,
		      diskio_stat_init, diskio_stat_destroy);

#ifdef LINUX
typedef struct {
	int major;
	int minor;
} partition;
#endif

sg_disk_io_stats *sg_get_disk_io_stats(int *entries){
	int num_diskio;
#ifndef LINUX
	sg_disk_io_stats *diskio_stats_ptr;
#endif

#ifdef HPUX
	long long rbytes = 0, wbytes = 0;
	struct dirent *dinfo = NULL;
	struct stat lstatinfo;
	struct pst_diskinfo pstat_diskinfo[DISK_BATCH];
	char fullpathbuf[1024] = {0};
	dev_t diskid;
	DIR *dh = NULL;
	int diskidx = 0;
	int num, i;
#endif
#ifdef SOLARIS
	kstat_ctl_t *kc;
	kstat_t *ksp;
	kstat_io_t kios;
#endif
#ifdef LINUX
	FILE *f;
	char *line_ptr;
	int major, minor;
	int has_pp_stats = 1;
	VECTOR_DECLARE_STATIC(parts, partition, 16, NULL, NULL);
	int i, n;
	time_t now;
	const char *format;
	static regex_t not_part_re, part_re;
	static int re_compiled = 0;
#endif
#if defined(FREEBSD) || defined(DFBSD)
	static struct statinfo stats;
	static int stats_init = 0;
	int counter;
	struct device_selection *dev_sel = NULL;
	int n_selected, n_selections;
	long sel_gen;
	struct devstat *dev_ptr;
#endif
#ifdef NETBSD
	struct disk_sysctl *stats;
#endif
#ifdef OPENBSD
	int diskcount;
	char *disknames, *name, *bufpp;
	char **dk_name;
	struct diskstats *stats;
#endif
#ifdef NETBSD
#define MIBSIZE 3
#endif
#ifdef OPENBSD
#define MIBSIZE 2
#endif
#if defined(NETBSD) || defined(OPENBSD)
	int num_disks, i;
	int mib[MIBSIZE];
	size_t size;
#endif
#ifdef WIN32
	char *name;
	long long rbytes;
	long long wbytes;
#endif

	num_diskio=0;

#ifdef HPUX
	while (1) {
		num = pstat_getdisk(pstat_diskinfo, sizeof pstat_diskinfo[0],
		                    DISK_BATCH, diskidx);
		if (num == -1) {
			sg_set_error_with_errno(SG_ERROR_PSTAT,
			                        "pstat_getdisk");
			return NULL;
		} else if (num == 0) {
			break;
		}

		for (i = 0; i < num; i++) {
			struct pst_diskinfo *di = &pstat_diskinfo[i];

			/* Skip "disabled" disks. */
			if (di->psd_status == 0) {
				continue;
			}
	
			/* We can't seperate the reads from the writes, we'll
			 * just give the same to each. (This value is in
			 * 64-byte chunks according to the pstat header file,
			 * and can wrap to be negative.)
			 */
			rbytes = wbytes = ((unsigned long) di->psd_dkwds) * 64LL;
	
			/* Skip unused disks. */
			if (rbytes == 0 && wbytes == 0) {
				continue;
			}
	
			if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) {
				return NULL;
			}
	
			diskio_stats_ptr = diskio_stats + num_diskio;
	
			diskio_stats_ptr->read_bytes = rbytes;
			diskio_stats_ptr->write_bytes = wbytes;
	
			diskio_stats_ptr->systime = time(NULL);
	
			num_diskio++;
	
			/* FIXME This should use a static cache, like the Linux
			 * code below. */
			if (diskio_stats_ptr->disk_name == NULL) {
				dh = opendir("/dev/dsk");
				if (dh == NULL) {
					continue;
				}
	
				diskid = (di->psd_dev.psd_major << 24) | di->psd_dev.psd_minor;
				while (1) {
					dinfo = readdir(dh);
					if (dinfo == NULL) {
						break;
					}
					snprintf(fullpathbuf, sizeof(fullpathbuf), "/dev/dsk/%s", dinfo->d_name);
					if (lstat(fullpathbuf, &lstatinfo) < 0) {
						continue;
					}
	
					if (lstatinfo.st_rdev == diskid) {
						if (sg_update_string(&diskio_stats_ptr->disk_name, dinfo->d_name) < 0) {
							return NULL;
						}
						break;
					}
				}
				closedir(dh);
	
				if (diskio_stats_ptr->disk_name == NULL) {
					if (sg_update_string(&diskio_stats_ptr->disk_name, di->psd_hw_path.psh_name) < 0) {
						return NULL;
					}
				}
			}
		}
		diskidx = pstat_diskinfo[num - 1].psd_idx + 1;
	}
#endif
#ifdef OPENBSD
	mib[0] = CTL_HW;
	mib[1] = HW_DISKCOUNT;

	size = sizeof(diskcount);
	if (sysctl(mib, MIBSIZE, &diskcount, &size, NULL, 0) < 0) {
		sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKCOUNT");
		return NULL;
	}

	mib[0] = CTL_HW;
	mib[1] = HW_DISKNAMES;

	if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) {
		sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKNAMES");
		return NULL;
	}

	disknames = sg_malloc(size);
	if (disknames == NULL) {
		return NULL;
	}

	if (sysctl(mib, MIBSIZE, disknames, &size, NULL, 0) < 0) {
		sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKNAMES");
		return NULL;
	}

	dk_name = sg_malloc(diskcount * sizeof(char *));
	bufpp = disknames;
	for (i = 0; i < diskcount && (name = strsep(&bufpp, ",")) != NULL; i++) {
		dk_name[i] = name;
	}
#endif

#if defined(NETBSD) || defined(OPENBSD)
	mib[0] = CTL_HW;
	mib[1] = HW_DISKSTATS;
#ifdef NETBSD
	mib[2] = sizeof(struct disk_sysctl);
#endif

	if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) {
		sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKSTATS");
		return NULL;
	}

#ifdef NETBSD
	num_disks = size / sizeof(struct disk_sysctl);
#else
	num_disks = size / sizeof(struct diskstats);
#endif

	stats = sg_malloc(size);
	if (stats == NULL) {
		return NULL;
	}

	if (sysctl(mib, MIBSIZE, stats, &size, NULL, 0) < 0) {
		sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKSTATS");
		return NULL;
	}

	for (i = 0; i < num_disks; i++) {
		const char *name;
		u_int64_t rbytes, wbytes;

#ifdef NETBSD
#ifdef HAVE_DK_RBYTES
		rbytes = stats[i].dk_rbytes;
		wbytes = stats[i].dk_wbytes;
#else
		/* Before 2.0, NetBSD merged reads and writes. */
		rbytes = wbytes = stats[i].dk_bytes;
#endif
#else
#ifdef HAVE_DS_RBYTES
		rbytes = stats[i].ds_rbytes;
		wbytes = stats[i].ds_wbytes;
#else
		/* Before 3.5, OpenBSD merged reads and writes */
		rbytes = wbytes = stats[i].ds_bytes;
#endif
#endif

		/* Don't keep stats for disks that have never been used. */
		if (rbytes == 0 && wbytes == 0) {
			continue;
		}

		if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) {
			return NULL;
		}
		diskio_stats_ptr = diskio_stats + num_diskio;
		
		diskio_stats_ptr->read_bytes = rbytes;
		diskio_stats_ptr->write_bytes = wbytes;
#ifdef NETBSD
		name = stats[i].dk_name;
#else
		name = dk_name[i];
#endif
		if (sg_update_string(&diskio_stats_ptr->disk_name, name) < 0) {
			return NULL;
		}
		diskio_stats_ptr->systime = time(NULL);
	
		num_diskio++;	
	}

	free(stats);
#ifdef OPENBSD
	free(dk_name);
	free(disknames);
#endif
#endif

#if defined(FREEBSD) || defined(DFBSD)
	if (!stats_init) {
		stats.dinfo=sg_malloc(sizeof(struct devinfo));
		if(stats.dinfo==NULL) return NULL;
		bzero(stats.dinfo, sizeof(struct devinfo));
		stats_init = 1;
	}
#ifdef FREEBSD5
	if ((devstat_getdevs(NULL, &stats)) < 0) {
		/* FIXME devstat functions return a string error in
		   devstat_errbuf */
		sg_set_error(SG_ERROR_DEVSTAT_GETDEVS, NULL);
		return NULL;
	}
	/* Not aware of a get all devices, so i said 999. If we ever
	 * find a machine with more than 999 disks, then i'll change
	 * this number :)
	 */
	if (devstat_selectdevs(&dev_sel, &n_selected, &n_selections, &sel_gen, stats.dinfo->generation, stats.dinfo->devices, stats.dinfo->numdevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, 999, 1) < 0) {
		sg_set_error(SG_ERROR_DEVSTAT_SELECTDEVS, NULL);
		return NULL;
	}
#else
	if ((getdevs(&stats)) < 0) {
		sg_set_error(SG_ERROR_DEVSTAT_GETDEVS, NULL);
		return NULL;
	}
	/* Not aware of a get all devices, so i said 999. If we ever
	 * find a machine with more than 999 disks, then i'll change
	 * this number :)
	 */
	if (selectdevs(&dev_sel, &n_selected, &n_selections, &sel_gen, stats.dinfo->generation, stats.dinfo->devices, stats.dinfo->numdevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, 999, 1) < 0) {
		sg_set_error(SG_ERROR_DEVSTAT_SELECTDEVS, NULL);
		return NULL;
	}
#endif

	for(counter=0;counter<stats.dinfo->numdevs;counter++){
		dev_ptr=&stats.dinfo->devices[dev_sel[counter].position];

		/* Throw away devices that have done nothing, ever.. Eg "odd" 
		 * devices.. like mem, proc.. and also doesn't report floppy
		 * drives etc unless they are doing stuff :)
		 */
#ifdef FREEBSD5
		if((dev_ptr->bytes[DEVSTAT_READ]==0) && (dev_ptr->bytes[DEVSTAT_WRITE]==0)) continue;
#else
		if((dev_ptr->bytes_read==0) && (dev_ptr->bytes_written==0)) continue;
#endif

		if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) {
			return NULL;
		}
		diskio_stats_ptr=diskio_stats+num_diskio;

#ifdef FREEBSD5		
		diskio_stats_ptr->read_bytes=dev_ptr->bytes[DEVSTAT_READ];
		diskio_stats_ptr->write_bytes=dev_ptr->bytes[DEVSTAT_WRITE];
#else
		diskio_stats_ptr->read_bytes=dev_ptr->bytes_read;
		diskio_stats_ptr->write_bytes=dev_ptr->bytes_written;
#endif
		if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
		if (asprintf((&diskio_stats_ptr->disk_name), "%s%d", dev_ptr->device_name, dev_ptr->unit_number) == -1) {
			sg_set_error_with_errno(SG_ERROR_ASPRINTF, NULL);
			return NULL;
		}
		diskio_stats_ptr->systime=time(NULL);

		num_diskio++;
	}
	free(dev_sel);

#endif
#ifdef SOLARIS
	if ((kc = kstat_open()) == NULL) {
		sg_set_error(SG_ERROR_KSTAT_OPEN, NULL);
		return NULL;
	}

	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
		if (!strcmp(ksp->ks_class, "disk")) {

			if(ksp->ks_type != KSTAT_TYPE_IO) continue;
			/* We dont want metadevices appearins as num_diskio */
			if(strcmp(ksp->ks_module, "md")==0) continue;
			if((kstat_read(kc, ksp, &kios))==-1){	
			}
			
			if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) {
				kstat_close(kc);
				return NULL;
			}
			diskio_stats_ptr=diskio_stats+num_diskio;
			
			diskio_stats_ptr->read_bytes=kios.nread;
			diskio_stats_ptr->write_bytes=kios.nwritten;
			if (sg_update_string(&diskio_stats_ptr->disk_name,
					     sg_get_svr_from_bsd(ksp->ks_name)) < 0) {
				kstat_close(kc);
				return NULL;
			}
			diskio_stats_ptr->systime=time(NULL);

			num_diskio++;
		}
	}

	kstat_close(kc);
#endif

#ifdef LINUX
	num_diskio = 0;
	n = 0;

	/* Read /proc/partitions to find what devices exist. Recent 2.4 kernels
	   have statistics in here too, so we can use those directly.
	   2.6 kernels have /proc/diskstats instead with almost (but not quite)
	   the same format. */

	f = fopen("/proc/diskstats", "r");
	format = " %d %d %99s %*d %*d %lld %*d %*d %*d %lld";
	if (f == NULL) {
		f = fopen("/proc/partitions", "r");
		format = " %d %d %*d %99s %*d %*d %lld %*d %*d %*d %lld";
	}
	if (f == NULL) goto out;
	now = time(NULL);

	if (!re_compiled) {
		if (regcomp(&part_re, "^(.*/)?[^/]*[0-9]$", REG_EXTENDED | REG_NOSUB) != 0) {
			sg_set_error(SG_ERROR_PARSE, NULL);
			goto out;
		}
		if (regcomp(&not_part_re, "^(.*/)?[^/0-9]+[0-9]+d[0-9]+$", REG_EXTENDED | REG_NOSUB) != 0) {
			sg_set_error(SG_ERROR_PARSE, NULL);
			goto out;
		}
		re_compiled = 1;
	}

	while ((line_ptr = sg_f_read_line(f, "")) != NULL) {
		char name[100];
		long long rsect, wsect;

		int nr = sscanf(line_ptr, format,
			&major, &minor, name, &rsect, &wsect);
		if (nr < 3) continue;

		/* Skip device names ending in numbers, since they're
		   partitions, unless they match the c0d0 pattern that some
		   RAID devices use. */
		/* FIXME: For 2.6+, we should probably be using sysfs to detect
		   this... */
		if ((regexec(&part_re, name, 0, NULL, 0) == 0)
		    && (regexec(&not_part_re, name, 0, NULL, 0) != 0)) {
			continue;
		}

		if (nr < 5) {
			has_pp_stats = 0;
			rsect = 0;
			wsect = 0;
		}

		if (VECTOR_RESIZE(diskio_stats, n + 1) < 0) {
			goto out;
		}
		if (VECTOR_RESIZE(parts, n + 1) < 0) {
			goto out;
		}

		if (sg_update_string(&diskio_stats[n].disk_name, name) < 0) {
			goto out;
		}
		diskio_stats[n].read_bytes = rsect * 512;
		diskio_stats[n].write_bytes = wsect * 512;
		diskio_stats[n].systime = now;
		parts[n].major = major;
		parts[n].minor = minor;

		n++;
	}

	fclose(f);
	f = NULL;

	if (!has_pp_stats) {
		/* This is an older kernel where /proc/partitions doesn't
		   contain stats. Read what we can from /proc/stat instead, and
		   fill in the appropriate bits of the list allocated above. */

		f = fopen("/proc/stat", "r");
		if (f == NULL) goto out;
		now = time(NULL);

		line_ptr = sg_f_read_line(f, "disk_io:");
		if (line_ptr == NULL) goto out;

		while((line_ptr=strchr(line_ptr, ' '))!=NULL){
			long long rsect, wsect;

			if (*++line_ptr == '\0') break;

			if((sscanf(line_ptr,
				"(%d,%d):(%*d, %*d, %lld, %*d, %lld)",
				&major, &minor, &rsect, &wsect)) != 4) {
					continue;
			}

			/* Find the corresponding device from earlier.
			   Just to add to the fun, "minor" is actually the disk
			   number, not the device minor, so we need to figure
			   out the real minor number based on the major!
			   This list is not exhaustive; if you're running
			   an older kernel you probably don't have fancy
			   I2O hardware anyway... */
			switch (major) {
			case 3:
			case 21:
			case 22:
			case 33:
			case 34:
			case 36:
			case 56:
			case 57:
			case 88:
			case 89:
			case 90:
			case 91:
				minor *= 64;
				break;
			case 9:
			case 43:
				break;
			default:
				minor *= 16;
				break;
			}
			for (i = 0; i < n; i++) {
				if (major == parts[i].major
					&& minor == parts[i].minor)
					break;
			}
			if (i == n) continue;

			/* We read the number of blocks. Blocks are stored in
			   512 bytes */
			diskio_stats[i].read_bytes = rsect * 512;
			diskio_stats[i].write_bytes = wsect * 512;
			diskio_stats[i].systime = now;
		}
	}

	num_diskio = n;
out:
	if (f != NULL) fclose(f);
#endif

#ifdef CYGWIN
	sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin");
	return NULL;
#endif

#ifdef WIN32
	sg_set_error(SG_ERROR_NONE, NULL);

	while((name = get_diskio(num_diskio, &rbytes, &wbytes)) != NULL) {
		if (VECTOR_RESIZE(diskio_stats, num_diskio+1)) {
			return NULL;
		}

		diskio_stats_ptr = diskio_stats + num_diskio;

		if (sg_update_string(&diskio_stats_ptr->disk_name, name) < 0) {
			return NULL;
		}
		sg_update_string(&name, NULL);
		diskio_stats_ptr->read_bytes = rbytes;
		diskio_stats_ptr->write_bytes = wbytes;

		diskio_stats_ptr->systime = 0;

		num_diskio++;
	}
#endif

	*entries=num_diskio;

	return diskio_stats;
}

sg_disk_io_stats *sg_get_disk_io_stats_diff(int *entries){
#ifndef WIN32
	VECTOR_DECLARE_STATIC(diff, sg_disk_io_stats, 1,
			      diskio_stat_init, diskio_stat_destroy);
	sg_disk_io_stats *src = NULL, *dest;
	int i, j, diff_count, new_count;

	if (diskio_stats == NULL) {
		/* No previous stats, so we can't calculate a difference. */
		return sg_get_disk_io_stats(entries);
	}

	/* Resize the results array to match the previous stats. */
	diff_count = VECTOR_SIZE(diskio_stats);
	if (VECTOR_RESIZE(diff, diff_count) < 0) {
		return NULL;
	}

	/* Copy the previous stats into the result. */
	for (i = 0; i < diff_count; i++) {
		src = &diskio_stats[i];
		dest = &diff[i];

		if (sg_update_string(&dest->disk_name, src->disk_name) < 0) {
			return NULL;
		}
		dest->read_bytes = src->read_bytes;
		dest->write_bytes = src->write_bytes;
		dest->systime = src->systime;
	}

	/* Get a new set of stats. */
	if (sg_get_disk_io_stats(&new_count) == NULL) {
		return NULL;
	}

	/* For each previous stat... */
	for (i = 0; i < diff_count; i++) {
		dest = &diff[i];

		/* ... find the corresponding new stat ... */
		for (j = 0; j < new_count; j++) {
			/* Try the new stat in the same position first,
			   since that's most likely to be it. */
			src = &diskio_stats[(i + j) % new_count];
			if (strcmp(src->disk_name, dest->disk_name) == 0) {
				break;
			}
		}
		if (j == new_count) {
			/* No match found. */
			continue;
		}

		/* ... and subtract the previous stat from it to get the
		   difference. */
		dest->read_bytes = src->read_bytes - dest->read_bytes;
		dest->write_bytes = src->write_bytes - dest->write_bytes;
		dest->systime = src->systime - dest->systime;
	}

	*entries = diff_count;
	return diff;
#else /* WIN32 */
	return sg_get_disk_io_stats(entries);
#endif
}

int sg_disk_io_compare_name(const void *va, const void *vb) {
	const sg_disk_io_stats *a = (const sg_disk_io_stats *)va;
	const sg_disk_io_stats *b = (const sg_disk_io_stats *)vb;

	return strcmp(a->disk_name, b->disk_name);
}
示例#10
0
int main(int argc, char **argv)
{
    char *port_source = "at compile time";
    char *tmp_port;
    int opt;
    int house = 0;
    int repeat;
    int devs;
    int dimlevel = 0;
    br_control_info *cinfo = NULL;
    int tmperrno;
    
#ifdef HAVE_GETOPT_LONG    
    int opt_index;
    static struct option long_options[] = {
        {"help",  	no_argument, 	    	0, 'h'},
        {"port",  	required_argument, 	0, 'x'},
        {"repeat",	required_argument, 	0, 'r'},
        {"on", 		required_argument, 	0, 'n'},
        {"off", 	required_argument, 	0, 'f'},
        {"ON", 		no_argument, 		0, 'N'},
        {"OFF", 	no_argument, 		0, 'F'},
        {"dim", 	required_argument, 	0, 'd'},
        {"lamps_on", 	no_argument, 		0, 'B'},
        {"lamps_off", 	no_argument, 		0, 'D'},
        {"inverse", 	no_argument, 		0, 'i'},
	{"house",	required_argument,	0, 'c'},
	{"verbose",	no_argument,		0, 'v'},
	{0, 0, 0, 0}
    };
#endif

#define OPT_STRING	"x:hvr:ic:n:Nf:Fd:BD"
    
    /*
     * It's possible to do an exec without even passing argv[0];
     *  this is just to make sure we don't make any bad
     *  output decisions without accounting for that
     */     
            
    if (argc)
        MyName = argv[0];

    if (argc < 2) {
        usage();
        exit(EINVAL);
    }
    
    if ((cinfo = malloc(sizeof(br_control_info))) == NULL) {
	tmperrno = errno;
        fprintf(stderr, "%s: Error (%s) allocating memory.\n", MyName,
          strerror(errno));
        exit(tmperrno);
    }
    
    CINFO_CLR(cinfo);
    cinfo->port = X10_PORTNAME;
    cinfo->repeat = 1;
    
    if ((tmp_port = getenv("X10_PORTNAME"))) {
        port_source = "in the environment variable X10_PORTNAME";
        if (!checkimmutableport(port_source))
            cinfo->port = tmp_port;
    }
    
#ifdef HAVE_GETOPT_LONG
    while ((opt = getopt_long(argc, argv, OPT_STRING, long_options, &opt_index)) != -1) 
    {
#else
    while ((opt = getopt(argc, argv, OPT_STRING)) != -1) {
#endif        
        switch (opt) {
        case 'x':
            port_source = "on the command line";
            if (checkimmutableport(port_source) < 0)
                exit(errno);
            cinfo->port = optarg;
            break;
        case 'r':
            repeat = atoi(optarg);
            if (!repeat && !isdigit(*optarg)) {
                fprintf(stderr, "%s:  Invalid repeat value specified.\n", 
                  MyName);
                exit(EINVAL);
            }
            cinfo->repeat = (repeat ? repeat:INT_MAX);
            break;
        case 'v':
            if (Verbose++ == 10)
                fprintf(stderr, "\nGet a LIFE already.  "
                  "I've got enough v's, thanks.\n\n");
            break;
        case 'i':
            cinfo->inverse++;    /* no this isn't documented. 
                                  *   your free gift for reading the source.
                                  */
            break;
        case 'c':
            if ((house = gethouse(optarg)) < 0)
                exit(errno);
            break;
        case 'n':
            if ((devs = getdevs(optarg)) < 0)
                exit(errno);
            if (addcmd(cinfo, ON, house, devs, 0) < 0)
                exit(errno);
            break;
        case 'N':
            if (addcmd(cinfo, ALL_ON, house, 0, 0) < 0)
                exit(errno);
            break;
        case 'f':
            if ((devs = getdevs(optarg)) < 0)
                exit(errno);
            if (addcmd(cinfo, OFF, house, devs, 0) < 0)
                exit(errno);
            break;
        case 'F':
            if (addcmd(cinfo, ALL_OFF, house, 0, 0) < 0)
                exit(errno);
            break;
        case 'd':
            if ((devs = getdim(optarg, &dimlevel)) < 0)
                exit(errno);
            if (addcmd(cinfo, DIM, house, devs, dimlevel) < 0)
                exit(errno);
            break;
        case 'B':
            if (addcmd(cinfo, ALL_LAMPS_ON, house, 0, 0) < 0)
                exit(errno);
            break;
        case 'D':
            if (addcmd(cinfo, ALL_LAMPS_OFF, house, 0, 0) < 0)
                exit(errno);
            break;
        case 'h':
            usage();
            exit(0);
        default:
            usage();
            exit(EINVAL);
        }
    }

    if (argc > optind) {
        /*
         * Must be using the native BottleRocket command line...
         */
    
        if (native_br(cinfo, argc, argv, optind) < 0)
            exit(errno);
    }

    if (open_port(cinfo) < 0)
        exit(errno);

    if (br_execute(cinfo) < 0)
        exit(errno);
            
    if (close_port(cinfo) < 0)
        exit(errno);
    
    free(cinfo);

    return 0;
}
示例#11
0
static void
dovmstat(u_int interval, int reps)
{
	struct vmtotal total;
	struct devinfo *tmp_dinfo;
	size_t vmm_size = sizeof(vmm);
	size_t vms_size = sizeof(vms);
	size_t vmt_size = sizeof(total);
	int initial = 1;

	signal(SIGCONT, needhdr);

	for (hdrcnt = 1;;) {
		if (!--hdrcnt)
			printhdr();
		if (kinfo_get_sched_cputime(&cp_time))
			err(1, "kinfo_get_sched_cputime");

		tmp_dinfo = last.dinfo;
		last.dinfo = cur.dinfo;
		cur.dinfo = tmp_dinfo;
		last.busy_time = cur.busy_time;

		/*
		 * Here what we want to do is refresh our device stats.
		 * getdevs() returns 1 when the device list has changed.
		 * If the device list has changed, we want to go through
		 * the selection process again, in case a device that we
		 * were previously displaying has gone away.
		 */
		switch (getdevs(&cur)) {
		case -1:
			errx(1, "%s", devstat_errbuf);
			break;
		case 1: {
			int retval;

			num_devices = cur.dinfo->numdevs;
			generation = cur.dinfo->generation;

			retval = selectdevs(&dev_select, &num_selected,
					    &num_selections, &select_generation,
					    generation, cur.dinfo->devices,
					    num_devices, matches, num_matches,
					    specified_devices,
					    num_devices_specified, select_mode,
					    maxshowdevs, 0);
			switch (retval) {
			case -1:
				errx(1, "%s", devstat_errbuf);
				break;
			case 1:
				printhdr();
				break;
			default:
				break;
			}
		}
		default:
			break;
		}

		if (sysctlbyname("vm.vmstats", &vms, &vms_size, NULL, 0)) {
			perror("sysctlbyname: vm.vmstats");
			exit(1);
		}
		if (sysctlbyname("vm.vmmeter", &vmm, &vmm_size, NULL, 0)) {
			perror("sysctlbyname: vm.vmmeter");
			exit(1);
		} 
		if (sysctlbyname("vm.vmtotal", &total, &vmt_size, NULL, 0)) {
			perror("sysctlbyname: vm.vmtotal");
			exit(1);
		} 
		printf("%2ld %1ld %1ld",
		    total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);

#define vmstat_pgtok(a)	\
	(intmax_t)(((intmax_t)(a) * vms.v_page_size) >> 10)
#define rate(x)		\
	(intmax_t)(initial ? (x) : ((intmax_t)(x) * 1000 + interval / 2) \
				   / interval)

		printf(" %7jd %6jd ",
		       vmstat_pgtok(total.t_avm),
		       vmstat_pgtok(total.t_free));
		printf("%4ju ",
		       rate(vmm.v_vm_faults - ovmm.v_vm_faults));
		printf("%3ju ",
		       rate(vmm.v_reactivated - ovmm.v_reactivated));
		printf("%3ju ",
		       rate(vmm.v_swapin + vmm.v_vnodein -
			    (ovmm.v_swapin + ovmm.v_vnodein)));
		printf("%3ju ",
		       rate(vmm.v_swapout + vmm.v_vnodeout -
			    (ovmm.v_swapout + ovmm.v_vnodeout)));
		printf("%3ju ",
		       rate(vmm.v_tfree - ovmm.v_tfree));
		printf("%3ju ",
		       rate(vmm.v_pdpages - ovmm.v_pdpages));
		devstats();
		printf("%4ju %4ju %3ju ",
		       rate(vmm.v_intr - ovmm.v_intr),
		       rate(vmm.v_syscall - ovmm.v_syscall),
		       rate(vmm.v_swtch - ovmm.v_swtch));
		cpustats();
		printf("\n");
		fflush(stdout);
		if (reps >= 0 && --reps <= 0)
			break;
		ovmm = vmm;
		usleep(interval * 1000);
		initial = 0;
	}
}