diff options
Diffstat (limited to 'sysutils/xperfmon3/files/freebsd_system.c')
-rw-r--r-- | sysutils/xperfmon3/files/freebsd_system.c | 1528 |
1 files changed, 775 insertions, 753 deletions
diff --git a/sysutils/xperfmon3/files/freebsd_system.c b/sysutils/xperfmon3/files/freebsd_system.c index d20ec2c08751..2e28cbfd3256 100644 --- a/sysutils/xperfmon3/files/freebsd_system.c +++ b/sysutils/xperfmon3/files/freebsd_system.c @@ -1,889 +1,911 @@ + /* - * Perfmon Performance Monitor + * freebsd_system.c für FreeBSD-3.X + * COPYRIGHT 1998 by Lars Köller <Lars.Koeller@Uni-Bielefeld.de> + * + * Work has started on 7th Sep 1998 on Northsea island Föhr. * - * Copyright 1985, Massachusetts Institute of Technology - * Copyright 1989, PCS Computer Systeme GmbH, West Germany - * Copyright 1994, Sterling Software @ NASA-Ames Research Center - * Copyright 1995, Regents of the University of California, - * Lars Köller <Lars.Koeller@Uni-Bielefeld.DE> + * $Id: freebsd_system.c,v 3.4 1998/11/15 16:50:04 lkoeller Exp lkoeller $ + */ + +/* + * Copyright (c) 1998 Lars Köller + * All rights reserved. * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of PCS and Sterling Software not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. PCS and Sterling Software makes no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. * - * PCS & STERLING SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL PCS & STERLING SOFTWARE - * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * - * Original Author: Emanuel Jay Berkenbilt, MIT Project Athena - * Author: Thomas A. Baghli, PCS Computer Systeme GmbH, West Germany - * tom@meepmeep.pcs.com - * 1994 Revision - * Author: Roger Smith, Sterling Software @ NASA-Ames Research Center - * Moffett Field, California, rsmith@proteus.arc.nasa.gov - * 1995, ... FreeBSD 2.x, 3.x Version - * Author: Lars Köller, Univerity of Bielefeld, Germany - * Lars.Koeller@Uni-Bielefeld.DE */ -/* This file contains only system functions - that is the functions that - * get the information the performance monitor is monitoring. No calls - * to any X routines should be made here. The reason for doing this is - * so that as the X toolkit becomes available and the X window system - * improves no changes will have to be made to this file, and as this - * program is made available for a new type of machine, only this file - * will need to be changed. +/* + * + * Parts of this program are derived from the iostat program: + * + * Copyright (c) 1997, 1998 Kenneth D. Merry. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * */ -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif +/* + * Parts of this program are derived from other original FreeBSD programs: + * + * Copyright (c) 1986, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ -#if (defined(BSD) && (BSD >= 199506)) -# include <osreldate.h> -#else -# error You have to use at least a FreeBSD 2.2.X system +#ifndef LINT +static char rcsid[] = "$Id: freebsd_system.c,v 3.4 1998/11/15 16:50:04 lkoeller Exp lkoeller $"; #endif +#include "fbsd_vers.h" + #include <X11/IntrinsicP.h> #include "system.h" - -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <unistd.h> -#include <paths.h> -#include <kvm.h> -#include <nlist.h> -#include <limits.h> -#include <errno.h> -#include <err.h> +#include "is.h" #include <sys/file.h> #include <sys/param.h> +#include <sys/types.h> #include <sys/socket.h> #include <sys/sysctl.h> #include <sys/dkstat.h> -#ifdef HAVE_DEVSTAT -#include <devstat.h> -#endif #include <sys/buf.h> -#include <sys/vmmeter.h> -#include <vm/vm.h> #include <sys/time.h> +#include <vm/vm.h> #include <net/if.h> -#if __FreeBSD_version >= 300000 #include <net/if_var.h> -#endif #include <netinet/in.h> #include <sys/stat.h> #include <sys/conf.h> #include <sys/rlist.h> #include <sys/mount.h> #include <nfs/rpcv2.h> -#include <nfs/nfsv2.h> +#include <nfs/nfsproto.h> #include <nfs/nfs.h> -#ifndef CTL_FS -#define CTL_FS CTL_VFS /* compatibility w/ Lite1 */ -#endif - -/* - * It's a mess with all these version numbers: - * - * 2.0-RELEASE: 199411 - * 2.1-current's: 199501, 199503 - * 2.0.5-RELEASE: 199504 - * 2.2-current before 2.1: 199508 - * 2.1.0-RELEASE: 199511 - * 2.2-current before 2.1.5: 199512 - * 2.1.5-RELEASE: 199607 - * 2.2-current before 2.1.6: 199608 - * 2.1.6-RELEASE: 199612 - * 2.1.7-RELEASE: 199612 - * 2.2-RELEASE: 220000 (ahhhhh) - * 3.0-current as of Feb 1997: 300000 (ohhhhh) - */ - -/* - * FreeBSD version 2.2 and greater have NFSv3 - */ -#if __FreeBSD_version >= 220000 -# define HAS_NFS_V3 -#endif /* FreeBSD_version */ - -#include "is.h" +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <unistd.h> +#include <ctype.h> +#include <paths.h> +#include <kvm.h> +#include <nlist.h> +#include <limits.h> +#include <errno.h> +#include <err.h> +#include <devstat.h> -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif -#define WANT_STAT(x) (poss_stats[(x)] != NO_STAT) +struct nlist namelist[] = { +#define X_HZ 0 + { "_hz" }, +#define X_STATHZ 1 + { "_stathz" }, +#define X_CP_TIME 2 + { "_cp_time" }, +#define X_TK_NIN 3 + { "_tk_nin" }, +#define X_TK_NOUT 4 + { "_tk_nout" }, +#define N_IFNET 5 + { "_ifnet" }, +#define X_INTRCNT 6 + { "_intrcnt" }, +#define X_EINTRCNT 7 + { "_eintrcnt" }, +#define X_BOOTTIME 8 + { "_boottime" }, +#if __FreeBSD_version < 400000 +#define VM_NSWAP 9 + { "_nswap" }, +#define VM_NSWDEV 10 + { "_nswdev" }, +#define VM_DMMAX 11 + { "_dmmax" }, +#define VM_SWAPLIST 12 + { "_swaplist" }, +#define VM_SWDEVT 13 + { "_swdevt" }, +#define X_END 13 + { NULL }, +#else +#define X_END 8 + { NULL }, +#endif /* __FreeBSD_version < 400000 */ -#ifdef HAVE_DEVSTAT -/* the old values */ -#define DK_NDRIVE 8 -#define DK_NAMELEN 8 -#endif +}; -/* - Function Prototypes -*/ -static int get_namelist(const char *kernel_name, const char *memory_name); -static void kread(int nlx, void *addr, size_t size); -static void collect_stats(void); -static int total_disk_transfers(void); -static int get_swapspace(void); -#ifdef HAVE_DEVSTAT -void init_devstat(void); -int get_devstat(void); -#endif /* HAVE_DEVSTAT */ +extern Widget perfmon[NUM_GRAPHS]; +extern char *info1; +double current_values[NUM_GRAPHS]; -/* - Variables & Structs -*/ -static unsigned long *intrcnt; -static int nintr, hz; static kvm_t *kd; static char errbuf[_POSIX2_LINE_MAX]; -static char dr_name[DK_NDRIVE][DK_NAMELEN]; -static double etime; -#ifdef HAVE_DEVSTAT -long generation; -devstat_select_mode select_mode; -struct devstat_match *matches; -int num_matches; -int num_selected, num_selections; -long select_generation; -static struct statinfo cur, last; -int num_devices; -struct device_selection *dev_select; -char nodisk; -#endif /* HAVE_DEVSTAT */ - - -#if __FreeBSD_version >= 220000 -float current_values[NUM_GRAPHS]; -#else -int current_values[NUM_GRAPHS]; -#endif -stat_type stats; - -extern Widget perfmon[NUM_GRAPHS]; - -static struct packet { - int input, output, collisions; -} packets, old_packets; +static int has_nfs; +static int hz, stathz; +static double etime, pct; +static long tmp; +struct vfsconf vfc; +/* + * Variables holding the statistic information + */ +static struct statinfo cur, last; static struct nfsstats nfsstats; static struct _nfsStats { - int nfsServer, nfsClient; + int ServerCalls, ServerCacheHit, ServerCacheMis; + int ClientCalls, ClientCacheHit, ClientCacheMis; } nfsStats, old_nfsStats; +static struct _packets { + int input, output, collisions; +} packets, old_packets; +static int interrupts, old_interrupts; -/* NB that we'll have to include machine/asname.h when the kernel goes ELF */ -struct nlist nl[] = { -#define X_CPTIME 0 - { "_cp_time" }, -#define X_SUM 1 - { "_cnt" }, -#define X_BOOTTIME 2 - { "_boottime" }, -#define X_DKXFER 3 -#ifdef HAVE_DEVSTAT - { "_hz" }, /* just a placeholder */ -#else - { "_dk_xfer" }, -#endif -#define X_HZ 4 - { "_hz" }, -#define N_IFNET 5 - { "_ifnet" }, -#define X_INTRCNT 6 - { "_intrcnt" }, -#define X_EINTRCNT 7 - { "_eintrcnt" }, -#if __FreeBSD_version < 400000 -#define VM_NSWAP 8 - { "_nswap" }, /* size of largest swap device */ -#define VM_NSWDEV 9 - { "_nswdev" }, /* number of swap devices */ -#define VM_DMMAX 10 - { "_dmmax" }, /* maximum size of a swap block */ -#define VM_SWAPLIST 11 - { "_swaplist" },/* list of free swap areas */ -#define VM_SWDEVT 12 - { "_swdevt" }, /* list of swap devices and sizes */ -#endif - { "" }, -}; - -struct { - long time[CPUSTATES]; -#ifndef HAVE_DEVSTAT - long xfer[DK_NDRIVE]; -#endif - struct vmmeter Sum; - struct vmmeter Rate; - int interrupts; -} s, s1; - -int first_time_getswap; +/* + * Variables need for devstat to get diskio statistics + */ +static struct statinfo cur, last; +static struct devstat_match *matches = NULL; +static struct device_selection *dev_select = NULL; +static devstat_select_mode select_mode; +static int num_matches = 0, num_devices = 0; +static int num_selected = 0, num_selections = 0; +static int num_devices_specified = 0, maxshowdevs; +static long generation, select_generation; +static char **specified_devices = NULL; +static struct _diskstat { + long double da_trsf, da_mb; + long double cd_trsf, cd_mb; + long double sa_trsf, sa_mb; +} diskstat; + +void sys_setup(void); +void update_stats(void); + +static void get_namelist(const char *kernel_name, const char *memory_name); +static void kread(int nlx, void *addr, size_t size); +static double get_load(void); +static void get_cpustat(void); +static void get_ttystat(void); +static void get_interrupts(void); +static void init_diskio(void); +static void get_diskio(void); +static double get_swapspace(void); +static void get_netstat(void); +static void get_nfsstat(void); -#define rate s.Rate -#define sum s.Sum -/* - This routine does all necessary setting up of structures - that will handle system calls. -*/ -void sys_setup() +void +sys_setup(void) { - get_namelist(getbootfile(), _PATH_KMEM); - collect_stats(); -#ifdef HAVE_DEVSTAT - init_devstat(); -#endif - /* hack to enforce a resize of the 'Free Swap' graph - without this the left border always displays the first drawn line - cause this field isn't resized very often due to slow change of - the free swapspace! */ - first_time_getswap = 1; - etime = 1.0; + get_namelist(getbootfile(), _PATH_MEM); + + get_cpustat(); + get_load(); + get_ttystat(); + get_interrupts(); + init_diskio(); + get_diskio(); + + /* + * To force first scale of 'free swapspace' to 100%, we need this hack! + * Wee use a value < 0 cause it's not a valid value! + */ + current_values[FREE_MEM] = -0.4 * SCALE_HACK; + + get_netstat(); + + /* + * Check if we have NFS in the kernel + */ + if (getvfsbyname("nfs", &vfc) < 0) { + fprintf(stderr, "xperfmon++: getvfsbyname: NFS not compiled into kernel\n"); + has_nfs = FALSE; + } else { + has_nfs = TRUE; + get_nfsstat(); + } } -/* - Update the data structures -*/ -void update_stats() +void +update_stats(void) { - int state; - double pct, tot, loadavg[3]; + static int firsttime = 1; + /* + * For any stat we need etime, so get it! + */ + get_cpustat(); + current_values[ USER_CPU_PERCENTAGE] = cur.cp_time[CP_USER] * pct * SCALE_HACK; + current_values[ NICE_CPU_PERCENTAGE] = cur.cp_time[CP_NICE] * pct * SCALE_HACK; + current_values[SYSTEM_CPU_PERCENTAGE] = cur.cp_time[CP_SYS] * pct * SCALE_HACK; + current_values[ INTER_CPU_PERCENTAGE] = cur.cp_time[CP_INTR] * pct * SCALE_HACK; + current_values[ IDLE_CPU_PERCENTAGE] = cur.cp_time[CP_IDLE] * pct * SCALE_HACK; + + if (perfmon[LOAD]) + current_values[LOAD] = get_load() * SCALE_HACK; + + if (perfmon[TTY_CHARS_IN] || perfmon[TTY_CHARS_OUT]) { + get_ttystat(); + current_values[TTY_IN] = cur.tk_nin/etime * SCALE_HACK; + current_values[TTY_OUT] = cur.tk_nout/etime * SCALE_HACK; + } - collect_stats(); + if (perfmon[INTERRUPTS]) { + get_interrupts(); + current_values[INTERRUPTS] = (interrupts - old_interrupts)/etime * SCALE_HACK; + } - tot = 0; - for (state = 0; state < CPUSTATES; ++state) - tot += s.time[state]; - if (tot) - pct = 100 / tot; + /* + * The first time called, we want to get 100% + * for the full scale of the graph! + */ + if (perfmon[FREE_MEM] && !firsttime) + current_values[FREE_MEM] = + (current_values[FREE_MEM] < 0 ? 100.0 * SCALE_HACK : get_swapspace() * SCALE_HACK); else - pct = 0; + --firsttime; + + if (perfmon[DISK_TRANSFERS] || perfmon[DISK_MB] || + perfmon[TAPE_TRANSFERS] || perfmon[TAPE_MB] || + perfmon[CDROM_TRANSFERS] || perfmon[CDROM_MB] ) { + get_diskio(); + current_values[DISK_TRANSFERS] = diskstat.da_trsf * SCALE_HACK; + current_values[DISK_MB] = diskstat.da_mb * SCALE_HACK; + current_values[TAPE_TRANSFERS] = diskstat.sa_trsf * SCALE_HACK; + current_values[TAPE_MB] = diskstat.sa_mb * SCALE_HACK; + current_values[CDROM_TRANSFERS] = diskstat.cd_trsf * SCALE_HACK; + current_values[CDROM_MB] = diskstat.cd_mb * SCALE_HACK; + } -#if __FreeBSD_version >= 220000 - if (getloadavg(loadavg, sizeof(loadavg) / sizeof(loadavg[0])) == -1 ) { - fprintf( stderr, "xperfmon++: getloadavg returned no values\n" ); - current_values[LOAD] = 0; - } else { - current_values[LOAD] = loadavg[0]*100; - /* fprintf( stderr, "loadavg: %f %f %f\n", loadavg[0], loadavg[1], loadavg[2] ); */ + if (perfmon[INPUT_PACKETS] || perfmon[OUTPUT_PACKETS] || + perfmon[COLLISION_PACKETS]){ + get_netstat(); + current_values[ INPUT_PACKETS] = + (packets.input - old_packets.input)/etime * SCALE_HACK; + current_values[ OUTPUT_PACKETS] = + (packets.output - old_packets.output)/etime * SCALE_HACK; + current_values[COLLISION_PACKETS] = + (packets.collisions - old_packets.collisions)/etime * SCALE_HACK; } -#endif -#if __FreeBSD_version >= 220000 - current_values[USER_CPU_PERCENTAGE] = s.time[CP_USER] * pct; - current_values[NICE_CPU_PERCENTAGE] = s.time[CP_NICE] * pct; - current_values[SYSTEM_CPU_PERCENTAGE] = s.time[CP_SYS] * pct; - current_values[INTER_CPU_PERCENTAGE] = s.time[CP_INTR] * pct; -#else - current_values[USER_CPU_PERCENTAGE] = (s.time[CP_USER] + s.time[CP_NICE]) * pct; - current_values[SYSTEM_CPU_PERCENTAGE] = (s.time[CP_SYS] + s.time[CP_INTR]) * pct;; -#endif - current_values[IDLE_CPU_PERCENTAGE] = s.time[CP_IDLE] * pct; - - if (perfmon[FREE_MEM]) { - if(!first_time_getswap) - current_values[FREE_MEM] = get_swapspace(); - else { - current_values[FREE_MEM] = 100; - first_time_getswap = 0; - } + if (has_nfs && (perfmon[NFS_CLIENT_CALLS] || + perfmon[NFS_CLIENT_HIT] || + perfmon[NFS_CLIENT_MIS] || + perfmon[NFS_SERVER_CALLS] || + perfmon[NFS_SERVER_HIT] || + perfmon[NFS_SERVER_MIS])) { + get_nfsstat(); + current_values[NFS_CLIENT_CALLS] = + (nfsStats.ClientCalls - old_nfsStats.ClientCalls)/etime * SCALE_HACK; + current_values[NFS_SERVER_CALLS] = + (nfsStats.ServerCalls - old_nfsStats.ServerCalls)/etime * SCALE_HACK; + current_values[NFS_CLIENT_HIT] = + (nfsStats.ClientCacheHit - old_nfsStats.ClientCacheHit)/etime * SCALE_HACK; + current_values[NFS_CLIENT_MIS] = + (nfsStats.ClientCacheMis - old_nfsStats.ClientCacheMis)/etime * SCALE_HACK; + current_values[NFS_SERVER_HIT] = + (nfsStats.ServerCacheHit - old_nfsStats.ServerCacheHit)/etime * SCALE_HACK; + current_values[NFS_SERVER_MIS] = + (nfsStats.ServerCacheMis - old_nfsStats.ServerCacheMis)/etime * SCALE_HACK; } - if (perfmon[DISK_TRANSFERS]) - current_values[DISK_TRANSFERS] = total_disk_transfers(); - if (perfmon[INTERRUPTS]) - current_values[INTERRUPTS] = (s.interrupts - s1.interrupts)/etime; - if (perfmon[INPUT_PACKETS]) - current_values[INPUT_PACKETS] = (packets.input - old_packets.input)/etime; - if (perfmon[OUTPUT_PACKETS]) - current_values[OUTPUT_PACKETS] = (packets.output - old_packets.output)/etime; - if (perfmon[COLLISION_PACKETS]) - current_values[COLLISION_PACKETS] = (packets.collisions - old_packets.collisions)/etime; - if (perfmon[NFS_CLIENT_CALLS]) - current_values[NFS_CLIENT_CALLS] = (nfsStats.nfsClient - old_nfsStats.nfsClient)/etime; - if (perfmon[NFS_SERVER_CALLS]) - current_values[NFS_SERVER_CALLS] = (nfsStats.nfsServer - old_nfsStats.nfsServer)/etime; } -/* - Collect the overall disk transfer rates -*/ -int -total_disk_transfers() +static void +get_namelist(kernel_name, memory_name) + const char *kernel_name, *memory_name; { - register int i, total_xfers = 0; + register int i, ret; + time_t now, boottime; + int nintv; -#ifdef HAVE_DEVSTAT - total_xfers = get_devstat(); -#else - for(i=0; i < DK_NDRIVE; i++) - total_xfers += s.xfer[i]; -#endif - return(total_xfers/etime); + kd = kvm_openfiles(kernel_name, memory_name, NULL, O_RDONLY, errbuf); + if (kd == 0) + errx(1, "xperfmon++: kvm_openfiles: %s", errbuf); + + if ((ret = kvm_nlist(kd, namelist)) != 0) { + if (ret > 0) { + (void)fprintf(stderr, "xperfmon++: undefined symbols:"); + for (i = 0; i < sizeof(namelist)/sizeof(namelist[0]); i++) + if (namelist[i].n_type == 0 || namelist[i].n_value == 0) + fprintf(stderr, "%s", namelist[i].n_name); + fprintf(stderr, "\n"); + } else + errx(1, "xperfmon++: kvm_nlist: %s", kvm_geterr(kd)); + exit(1); + } + + kread(X_HZ, &hz, sizeof(hz)); + kread(X_STATHZ, &stathz, sizeof(stathz)); + + if (stathz) + hz = stathz; + + kread(X_BOOTTIME, &boottime, sizeof(boottime)); + time(&now); + nintv = now - boottime; + if (nintv <= 0 || nintv > 60*60*24*365*10) + errx(1, "Time makes no sense ... namelist must be wrong", NULL); } -/* - Collect all the data -*/ -void -collect_stats() +static void +kread(nlx, addr, size) + int nlx; void *addr; size_t size; { - off_t ifnetaddr; - register int i, tmp; - int mib[3], size; -#if (__FreeBSD_version >= 300004) - struct vfsconf vfc; -#endif + char *sym; - kread(X_CPTIME, s.time, sizeof(s.time)); -#ifndef HAVE_DEVSTAT - kread(X_DKXFER, s.xfer, sizeof(s.xfer)); -#endif - kread(X_SUM, &sum, sizeof(sum) ); + if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) { + sym = namelist[nlx].n_name; + if (*sym == '_') + ++sym; + errx(1, "xperfmon++: %s: %s", sym, kvm_geterr(kd)); + } +} - nintr = nl[X_EINTRCNT].n_value - nl[X_INTRCNT].n_value; - if ((intrcnt = (unsigned long *) malloc((size_t) nintr)) == NULL) - err(1, "xperfmon++ malloc in collect_stats"); - nintr /= sizeof(long); - kread(X_INTRCNT, intrcnt, (size_t) nintr*sizeof(long)); - s1.interrupts = s.interrupts; - s.interrupts = 0; - for (i = 0; i < nintr; i++) - s.interrupts += *(intrcnt + i); - free(intrcnt); - etime = 0; -#ifndef HAVE_DEVSTAT - for (i=0; i < DK_NDRIVE; i++) { - tmp = s.xfer[i]; - s.xfer[i] -= s1.xfer[i]; - s1.xfer[i] = tmp; - } -#endif - for (i=0; i < CPUSTATES; i++) { - tmp = s.time[i]; - s.time[i] -= s1.time[i]; - s1.time[i] = tmp; - etime += s.time[i]; +static void +get_cpustat(void) +{ + register int i; + double tot; + + kread(X_CP_TIME, cur.cp_time, sizeof(cur.cp_time)); + + etime = 0.0; + for (i = 0; i < CPUSTATES; i++) { + tmp = cur.cp_time[i]; + cur.cp_time[i] -= last.cp_time[i]; + last.cp_time[i] = tmp; + etime += cur.cp_time[i]; } - if(etime == 0.) - etime = 1.; - etime /= hz; + tot = etime; -/* - Collect the Network-Traffic -*/ + if (etime == 0.0 ) + etime = 1.0; - if ((ifnetaddr = nl[N_IFNET].n_value) != 0) { -#if __FreeBSD_version < 300000 - struct ifnet ifnet; - kread(N_IFNET, &ifnetaddr, sizeof(ifnetaddr)); - old_packets = packets; - packets.input = packets.output = packets.collisions = 0; - while (ifnetaddr) { - kvm_read(kd, ifnetaddr, &ifnet, sizeof ifnet ); - packets.input += ifnet.if_ipackets; - packets.output += ifnet.if_opackets; - packets.collisions += ifnet.if_collisions; - ifnetaddr = (u_long) ifnet.if_next; - } -#else /* 3.0-current, Jan 1997 */ - /* Stolen from netstat/if.c */ - struct ifnet ifnet; - struct ifnethead ifnethead; - u_long ifaddraddr, ifnetfound; - struct ifaddr ifa; + etime /= (float)hz; - if(kvm_read(kd, ifnetaddr, (char *)&ifnethead, sizeof ifnethead) == -1) - return; - ifnetaddr = (u_long)ifnethead.tqh_first; - if(kvm_read(kd, ifnetaddr, (char *)&ifnet, sizeof ifnet) == -1) - return; + /* + * scale to percent + */ + if(tot) + pct = 100.0 / tot; + else + pct = 0; +} - old_packets = packets; - packets.input = packets.output = packets.collisions = 0; - ifaddraddr = 0; - while (ifnetaddr || ifaddraddr) { - if (ifaddraddr == 0) { - ifnetfound = ifnetaddr; - if(kvm_read(kd, ifnetaddr, (char *)&ifnet, sizeof ifnet) == -1) - return; - ifnetaddr = (u_long)ifnet.if_link.tqe_next; - ifaddraddr = (u_long)ifnet.if_addrhead.tqh_first; - } - if (kvm_read(kd, ifaddraddr, (char *)&ifa, sizeof ifa) == -1) { - ifaddraddr = 0; - continue; - } - ifaddraddr = (u_long)ifa.ifa_link.tqe_next; - packets.input += ifnet.if_ipackets; - packets.output += ifnet.if_opackets; - packets.collisions += ifnet.if_collisions; - } -#endif - } +static double +get_load(void) +{ + double loadavg[3]; -/* - Collect the NFS and RPC Calls -*/ - - size = sizeof(nfsstats); - mib[0] = CTL_FS; -#if (__FreeBSD_version >= 300004) - if (getvfsbyname("nfs", &vfc) < 0) - /* no NFS in the kernel */ + loadavg[0] = 0.0; + if (getloadavg(loadavg, sizeof(loadavg)/sizeof(loadavg[0])) == -1) { + fprintf(stderr, "xperfmon++: getloadavg() returned no values\n"); return; - mib[1] = vfc.vfc_typenum; -#else - mib[1] = MOUNT_NFS; -#endif - mib[2] = NFS_NFSSTATS; - - if (sysctl( mib, 3, &nfsstats, &size, NULL, 0) < 0) - return; - else { - old_nfsStats = nfsStats; - - nfsStats.nfsClient = nfsstats.rpccnt[NFSPROC_GETATTR] + - nfsstats.rpccnt[NFSPROC_SETATTR] + - nfsstats.rpccnt[NFSPROC_LOOKUP] + - nfsstats.rpccnt[NFSPROC_READLINK] + - nfsstats.rpccnt[NFSPROC_READ] + - nfsstats.rpccnt[NFSPROC_WRITE] + - nfsstats.rpccnt[NFSPROC_CREATE] + - nfsstats.rpccnt[NFSPROC_REMOVE] + - nfsstats.rpccnt[NFSPROC_RENAME] + - nfsstats.rpccnt[NFSPROC_LINK] + - nfsstats.rpccnt[NFSPROC_SYMLINK] + - nfsstats.rpccnt[NFSPROC_MKDIR] + - nfsstats.rpccnt[NFSPROC_RMDIR] + - nfsstats.rpccnt[NFSPROC_READDIR] + -#ifndef HAS_NFS_V3 - nfsstats.rpccnt[NFSPROC_STATFS] + - nfsstats.rpccnt[NQNFSPROC_READDIRLOOK] + -#else /* HAS_NFS_V3 */ - nfsstats.rpccnt[NFSPROC_READDIRPLUS] + - nfsstats.rpccnt[NFSPROC_FSSTAT] + - nfsstats.rpccnt[NFSPROC_FSINFO] + - nfsstats.rpccnt[NFSPROC_PATHCONF] + - nfsstats.rpccnt[NFSPROC_COMMIT] + -#endif /* HAS_NFS_V3 */ - nfsstats.rpccnt[NQNFSPROC_GETLEASE] + - nfsstats.rpccnt[NQNFSPROC_VACATED] + - nfsstats.rpccnt[NQNFSPROC_EVICTED]; - - nfsStats.nfsServer = nfsstats.srvrpccnt[NFSPROC_GETATTR] + - nfsstats.srvrpccnt[NFSPROC_SETATTR] + - nfsstats.srvrpccnt[NFSPROC_LOOKUP] + - nfsstats.srvrpccnt[NFSPROC_READLINK] + - nfsstats.srvrpccnt[NFSPROC_READ] + - nfsstats.srvrpccnt[NFSPROC_WRITE] + - nfsstats.srvrpccnt[NFSPROC_CREATE] + - nfsstats.srvrpccnt[NFSPROC_REMOVE] + - nfsstats.srvrpccnt[NFSPROC_RENAME] + - nfsstats.srvrpccnt[NFSPROC_LINK] + - nfsstats.srvrpccnt[NFSPROC_SYMLINK] + - nfsstats.srvrpccnt[NFSPROC_MKDIR] + - nfsstats.srvrpccnt[NFSPROC_RMDIR] + - nfsstats.srvrpccnt[NFSPROC_READDIR] + -#ifndef HAS_NFS_V3 - nfsstats.srvrpccnt[NFSPROC_STATFS] + - nfsstats.srvrpccnt[NQNFSPROC_READDIRLOOK] + -#else /* HAS_NFS_V3 */ - nfsstats.srvrpccnt[NFSPROC_READDIRPLUS] + - nfsstats.srvrpccnt[NFSPROC_FSSTAT] + - nfsstats.srvrpccnt[NFSPROC_FSINFO] + - nfsstats.srvrpccnt[NFSPROC_PATHCONF] + - nfsstats.srvrpccnt[NFSPROC_COMMIT] + -#endif /* HAS_NFS_V3 */ - nfsstats.srvrpccnt[NQNFSPROC_GETLEASE] + - nfsstats.srvrpccnt[NQNFSPROC_VACATED] + - nfsstats.srvrpccnt[NQNFSPROC_EVICTED]; } + return(loadavg[0]); } -/* - Reads the nlist from the kernel -*/ -int -get_namelist(kernel_name, memory_name) - const char *kernel_name, *memory_name; +static void +get_ttystat(void) { - time_t now; - time_t boottime; - register int i, c; - int nintv; + kread(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin)); + kread(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout)); - kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); - if (kd == 0) { - (void)fprintf(stderr, "xperfmon++: kvm_openfiles: %s\n", errbuf); - exit(1); - } + tmp = cur.tk_nin; + cur.tk_nin -= last.tk_nin; + last.tk_nin = tmp; - if ((c = kvm_nlist(kd, nl)) != 0) { - if (c > 0) { - (void)fprintf(stderr,"xperfmon++: undefined symbols:"); - for (c = 0; c < sizeof(nl)/sizeof(nl[0]); c++) - if (nl[c].n_type == 0) - fprintf(stderr, " %s", nl[c].n_name); - (void)fputc('\n', stderr); - } else - (void)fprintf(stderr, "xperfmon++: kvm_nlist: %s\n", kvm_geterr(kd)); exit(1); - } + tmp = cur.tk_nout; + cur.tk_nout -= last.tk_nout; + last.tk_nout = tmp; +} - kread(X_BOOTTIME, &boottime, sizeof(boottime)); - kread(X_HZ, &hz, sizeof(hz)); - for (i = 0; i < DK_NDRIVE; i++) { - strcpy(dr_name[i], "xx"); - } - time(&now); - nintv = now - boottime; - if (nintv <= 0 || nintv > 60*60*24*365*10) { - fprintf(stderr, - "Time makes no sense... namelist must be wrong.\n"); - exit(1); - } - return(nintv); + +static void +get_interrupts(void) +{ + register int i; + unsigned long *intrcnt; + int nintr; + + nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value; + if ((intrcnt = (unsigned long *)malloc((size_t) nintr)) == NULL) + err(1, "xperfmon++: malloc failed in get_interrupts()"); + nintr /= sizeof(long); + kread(X_INTRCNT, intrcnt, (size_t)nintr*sizeof(long)); + old_interrupts = interrupts; + for (i = 0, interrupts = 0; i < nintr; i++) + interrupts += *(intrcnt + i); + free(intrcnt); } /* - Kread reads something from the kernel, given its nlist index. -*/ + * Parts extracted from /usr/src/usr.bin/nfsstat/nfsstat.c + * pay attention Copyrights! + */ static void -kread(nlx, addr, size) - int nlx; - void *addr; - size_t size; +get_nfsstat(void) { - char *sym; - - if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) { - sym = nl[nlx].n_name; - if (*sym == '_') - ++sym; - (void)fprintf(stderr, - "xpermon++: symbol %s not defined\n", sym); - exit(1); - } - if (kvm_read(kd, nl[nlx].n_value, addr, size) != size) { - sym = nl[nlx].n_name; - if (*sym == '_') - ++sym; - (void)fprintf(stderr, "xperfmon++: %s: %s\n", sym, kvm_geterr(kd)); - exit(1); - } + int name[3]; + size_t size = sizeof(nfsstats); + + name[0] = CTL_VFS; + name[1] = vfc.vfc_typenum; + name[2] = NFS_NFSSTATS; + if (sysctl(name, 3, &nfsstats, &size, (void *)0, (size_t)0) < 0) { + fprintf(stderr, "xperfmon++: get_nfsstat(): Can?%t get NFS statistics with sysctl()\n"); + return; + } + + old_nfsStats = nfsStats; + + nfsStats.ClientCalls = nfsstats.rpccnt[NFSPROC_GETATTR] + + nfsstats.rpccnt[NFSPROC_SETATTR] + + nfsstats.rpccnt[NFSPROC_LOOKUP] + + nfsstats.rpccnt[NFSPROC_READLINK] + + nfsstats.rpccnt[NFSPROC_READ] + + nfsstats.rpccnt[NFSPROC_WRITE] + + nfsstats.rpccnt[NFSPROC_CREATE] + + nfsstats.rpccnt[NFSPROC_REMOVE] + + nfsstats.rpccnt[NFSPROC_RENAME] + + nfsstats.rpccnt[NFSPROC_LINK] + + nfsstats.rpccnt[NFSPROC_SYMLINK] + + nfsstats.rpccnt[NFSPROC_MKDIR] + + nfsstats.rpccnt[NFSPROC_RMDIR] + + nfsstats.rpccnt[NFSPROC_READDIR] + + nfsstats.rpccnt[NFSPROC_READDIRPLUS]+ + nfsstats.rpccnt[NFSPROC_ACCESS] + + nfsstats.rpccnt[NFSPROC_MKNOD] + + nfsstats.rpccnt[NFSPROC_FSSTAT] + + nfsstats.rpccnt[NFSPROC_FSINFO] + + nfsstats.rpccnt[NFSPROC_PATHCONF] + + nfsstats.rpccnt[NFSPROC_COMMIT] + + nfsstats.rpccnt[NQNFSPROC_GETLEASE] + + nfsstats.rpccnt[NQNFSPROC_VACATED] + + nfsstats.rpccnt[NQNFSPROC_EVICTED]; + + nfsStats.ClientCacheHit = nfsstats.attrcache_hits + + nfsstats.lookupcache_hits + + nfsstats.biocache_reads - + nfsstats.read_bios + + nfsstats.biocache_writes - + nfsstats.write_bios + + nfsstats.biocache_readlinks - + nfsstats.readlink_bios + + nfsstats.biocache_readdirs - + nfsstats.readdir_bios + + nfsstats.direofcache_hits; + + nfsStats.ClientCacheMis = nfsstats.attrcache_misses + + nfsstats.lookupcache_misses + + nfsstats.read_bios + + nfsstats.write_bios + + nfsstats.readlink_bios + + nfsstats.readdir_bios + + nfsstats.direofcache_misses; + + nfsStats.ServerCalls = nfsstats.srvrpccnt[NFSPROC_GETATTR] + + nfsstats.srvrpccnt[NFSPROC_SETATTR] + + nfsstats.srvrpccnt[NFSPROC_LOOKUP] + + nfsstats.srvrpccnt[NFSPROC_READLINK] + + nfsstats.srvrpccnt[NFSPROC_READ] + + nfsstats.srvrpccnt[NFSPROC_WRITE] + + nfsstats.srvrpccnt[NFSPROC_CREATE] + + nfsstats.srvrpccnt[NFSPROC_REMOVE] + + nfsstats.srvrpccnt[NFSPROC_RENAME] + + nfsstats.srvrpccnt[NFSPROC_LINK] + + nfsstats.srvrpccnt[NFSPROC_SYMLINK] + + nfsstats.srvrpccnt[NFSPROC_MKDIR] + + nfsstats.srvrpccnt[NFSPROC_RMDIR] + + nfsstats.srvrpccnt[NFSPROC_READDIR] + + nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]+ + nfsstats.srvrpccnt[NFSPROC_ACCESS] + + nfsstats.srvrpccnt[NFSPROC_MKNOD] + + nfsstats.srvrpccnt[NFSPROC_FSSTAT] + + nfsstats.srvrpccnt[NFSPROC_FSINFO] + + nfsstats.srvrpccnt[NFSPROC_PATHCONF] + + nfsstats.srvrpccnt[NFSPROC_COMMIT] + + nfsstats.srvrpccnt[NQNFSPROC_GETLEASE] + + nfsstats.srvrpccnt[NQNFSPROC_VACATED] + + nfsstats.srvrpccnt[NQNFSPROC_EVICTED]; + + nfsStats.ServerCacheHit = nfsstats.srvcache_inproghits + + nfsstats.srvcache_idemdonehits + + nfsstats.srvcache_nonidemdonehits; + + nfsStats.ServerCacheMis = nfsstats.srvcache_misses; } + /* - * get_swapspace is based on a program called swapinfo written - * by Kevin Lahey <kml@rokkaku.atl.ga.us>. + * Stolen from /usr/src/usr.sbin/pstat/pstat.c and + * /usr/src/usr.bin/top/machine.c (pay attention Copyrights!) */ -int -get_swapspace() +static double +get_swapspace(void) { #if __FreeBSD_version >= 400000 - /* based on swapmode from /usr/src/usr.bin/top/machine.c */ - int n; - int percentfree; - struct kvm_swap swapary[1]; - - n = kvm_getswapinfo(kd, swapary, 1, 0); - if (n < 0) - return(0); - - percentfree = (int)((((double)swapary[0].ksw_total - - (double)swapary[0].ksw_used) * 100.0) / - (double)swapary[0].ksw_total); - return(percentfree); -#else - char *header; - int hlen, nswap, nswdev, dmmax; - int i, div, avail, nfree, npfree, used; - struct swdevt *sw; - long blocksize, *perdev; - struct rlist head; -#if __FreeBSD_version >= 220000 - struct rlisthdr swaplist; - struct rlist *swapptr; -#else - struct rlist *swaplist; -#endif - u_long ptr; - kread(VM_NSWAP, &nswap, sizeof(nswap)); - kread(VM_NSWDEV, &nswdev, sizeof(nswdev)); - kread(VM_DMMAX, &dmmax, sizeof(dmmax)); - kread(VM_SWAPLIST, &swaplist, sizeof(swaplist)); - if ((sw = malloc(nswdev * sizeof(*sw))) == NULL || - (perdev = malloc(nswdev * sizeof(*perdev))) == NULL) - err(1, "xperfmon++ malloc in get_swapspace"); - kread(VM_SWDEVT, &ptr, sizeof(ptr)); - kvm_read(kd, ptr, sw, nswdev * sizeof(*sw)); - /* Count up swap space. */ - nfree = 0; - memset(perdev, 0, nswdev * sizeof(*perdev)); -#if __FreeBSD_version >= 220000 - swapptr = swaplist.rlh_list; - while (swapptr) { -#else - while (swaplist) { -#endif - int top, bottom, next_block; -#if __FreeBSD_version >= 220000 - kvm_read(kd, (u_long)swapptr, &head, sizeof(struct rlist)); -#else - kvm_read(kd, (u_long)swaplist, &head, sizeof(struct rlist)); -#endif - top = head.rl_end; - bottom = head.rl_start; - - nfree += top - bottom + 1; - - /* - * Swap space is split up among the configured disks. - * - * For interleaved swap devices, the first dmmax blocks - * of swap space some from the first disk, the next dmmax - * blocks from the next, and so on up to nswap blocks. - * - * The list of free space joins adjacent free blocks, - * ignoring device boundries. If we want to keep track - * of this information per device, we'll just have to - * extract it ourselves. - */ - while (top / dmmax != bottom / dmmax) { - next_block = ((bottom + dmmax) / dmmax); - perdev[(bottom / dmmax) % nswdev] += - next_block * dmmax - bottom; - bottom = next_block * dmmax; - } - perdev[(bottom / dmmax) % nswdev] += - top - bottom + 1; -#if __FreeBSD_version >= 220000 - swapptr = head.rl_next; + /* based on swapmode from /usr/src/usr.bin/top/machine.c */ + int n; + int percentfree; + struct kvm_swap swapary[1]; + + n = kvm_getswapinfo(kd, swapary, 1, 0); + if (n < 0) + return(0); + + percentfree = ((((double)swapary[0].ksw_total - + (double)swapary[0].ksw_used) * 100.0) / + (double)swapary[0].ksw_total); + return(percentfree); + #else - swaplist = head.rl_next; -#endif - } - - header = getbsize(&hlen, &blocksize); - div = blocksize / 512; - avail = npfree = 0; - for (i = 0; i < nswdev; i++) { - int xsize, xfree; - - /* - * Don't report statistics for partitions which have not - * yet been activated via swapon(8). - */ - if (!(sw[i].sw_flags & SW_FREED)) - continue; - - /* The first dmmax is never allocated to avoid trashing of - * disklabels - */ - xsize = sw[i].sw_nblks - dmmax; - xfree = perdev[i]; - used = xsize - xfree; - npfree++; - avail += xsize; + /* based on /usr/src/usr.sbin/pstat/pstat.c */ + char *header; + int hlen, nswap, nswdev, dmmax; + int i, div, avail, nfree, npfree, used; + struct swdevt *sw; + long blocksize, *perdev; + struct rlist head; + struct rlisthdr swaplist; + struct rlist *swapptr; + u_long ptr; + + kread(VM_NSWAP, &nswap, sizeof(nswap)); + kread(VM_NSWDEV, &nswdev, sizeof(nswdev)); + kread(VM_DMMAX, &dmmax, sizeof(dmmax)); + kread(VM_SWAPLIST, &swaplist, sizeof(swaplist)); + if ((sw = malloc(nswdev * sizeof(*sw))) == NULL || + (perdev = malloc(nswdev * sizeof(*perdev))) == NULL) + err(1, "xperfmon++ malloc in get_swapspace"); + kread(VM_SWDEVT, &ptr, sizeof(ptr)); + kvm_read(kd, ptr, sw, nswdev * sizeof(*sw)); + + /* Count up swap space. */ + nfree = 0; + memset(perdev, 0, nswdev * sizeof(*perdev)); + swapptr = swaplist.rlh_list; + while (swapptr) { + int top, bottom, next_block; + kvm_read(kd, (u_long)swapptr, &head, sizeof(struct rlist)); + top = head.rl_end; + bottom = head.rl_start; + + nfree += top - bottom + 1; + + /* + * Swap space is split up among the configured disks. + * + * For interleaved swap devices, the first dmmax blocks + * of swap space some from the first disk, the next dmmax + * blocks from the next, and so on up to nswap blocks. + * + * The list of free space joins adjacent free blocks, + * ignoring device boundries. If we want to keep track + * of this information per device, we'll just have to + * extract it ourselves. + */ + while (top / dmmax != bottom / dmmax) { + next_block = ((bottom + dmmax) / dmmax); + perdev[(bottom / dmmax) % nswdev] += + next_block * dmmax - bottom; + bottom = next_block * dmmax; } + perdev[(bottom / dmmax) % nswdev] += + top - bottom + 1; + swapptr = head.rl_next; + } + header = getbsize(&hlen, &blocksize); + div = blocksize / 512; + avail = npfree = 0; + for (i = 0; i < nswdev; i++) { + int xsize, xfree; /* - * If only one partition has been set up via swapon(8), we don't - * need to bother with totals. + * Don't report statistics for partitions which have not + * yet been activated via swapon(8). */ - used = avail - nfree; + if (!(sw[i].sw_flags & SW_FREED)) + continue; + + /* The first dmmax is never allocated to avoid trashing of + * disklabels + */ + xsize = sw[i].sw_nblks - dmmax; + xfree = perdev[i]; + used = xsize - xfree; + npfree++; + avail += xsize; + } + + /* + * If only one partition has been set up via swapon(8), we don't + * need to bother with totals. + */ + used = avail - nfree; + free(sw); + free(perdev); + + return((100.0*nfree)/avail); - free(perdev); - free(sw); - return((100*nfree)/avail); /* return free swap in percent */ #endif /* __FreeBSD_version >= 400000 */ } -#ifdef HAVE_DEVSTAT -/* routines which use libdevstat */ -/* this is partly taken from FreeBSD - /usr/src/usr.sbin/iostat */ -void -init_devstat(void) -{ - /* - * Make sure that the userland devstat version matches the kernel - * devstat version. - */ - if (checkversion() < 0) { - nodisk++; - return; - } - /* find out how many devices we have */ - if ((num_devices = getnumdevs()) < 0) { - nodisk++; - return; - } - cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); - last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); - bzero(cur.dinfo, sizeof(struct devinfo)); - bzero(last.dinfo, sizeof(struct devinfo)); +/* + * Stolen from /usr/src/usr.bin/netstat/if.c + * pay attention Copyrights! + */ +static void +get_netstat(void) +{ + off_t ifnetaddr; - /* - * Grab all the devices. We don't look to see if the list has - * changed here, since it almost certainly has. We only look for - * errors. - */ - if (getdevs(&cur) == -1) { - nodisk++; - return; - } + if ((ifnetaddr = namelist[N_IFNET].n_value) != 0) { + struct ifnet ifnet; + struct ifnethead ifnethead; + u_long ifaddraddr, ifnetfound; + struct ifaddr ifa; - num_devices = cur.dinfo->numdevs; - generation = cur.dinfo->generation; + if(kvm_read(kd, ifnetaddr, (char *)&ifnethead, sizeof(ifnethead)) == -1) + return; + ifnetaddr = (u_long)ifnethead.tqh_first; + if(kvm_read(kd, ifnetaddr, (char *)&ifnet, sizeof(ifnet)) == -1) + return; - dev_select = NULL; + old_packets = packets; + packets.input = packets.output = packets.collisions = 0; + ifaddraddr = 0; + while (ifnetaddr || ifaddraddr) { + if (ifaddraddr == 0) { + ifnetfound = ifnetaddr; + if(kvm_read(kd, ifnetaddr, (char *)&ifnet, sizeof ifnet) == -1) + return; + ifnetaddr = (u_long)ifnet.if_link.tqe_next; + ifaddraddr = (u_long)ifnet.if_addrhead.tqh_first; + } + if (kvm_read(kd, ifaddraddr, (char *)&ifa, sizeof ifa) == -1) { + ifaddraddr = 0; + continue; + } + ifaddraddr = (u_long)ifa.ifa_link.tqe_next; - /* only interested in disks */ - matches = NULL; - if (buildmatch("da", &matches, &num_matches) != 0) { - nodisk++; - return; + packets.input += ifnet.if_ipackets; + packets.output += ifnet.if_opackets; + packets.collisions += ifnet.if_collisions; } + } +} - if (num_matches == 0) - select_mode = DS_SELECT_ADD; - else - select_mode = DS_SELECT_ONLY; - - /* - * At this point, selectdevs will almost surely indicate that the - * device list has changed, so we don't look for return values of 0 - * or 1. If we get back -1, though, there is an error. - */ - if (selectdevs(&dev_select, &num_selected, - &num_selections, &select_generation, - generation, cur.dinfo->devices, num_devices, - matches, num_matches, - NULL, 0, - select_mode, DK_NDRIVE, 0) == -1) - nodisk++; +/* + * Many thanks to Kenneth Merry <ken@plutotech.com> who helped to code + * the initial disk statistic routines + */ +static void +init_diskio(void) +{ + int retval, i; + + cur.dinfo = (struct devinfo *) malloc(sizeof(struct devinfo)); + last.dinfo = (struct devinfo *) malloc(sizeof(struct devinfo)); + bzero(cur.dinfo, sizeof(struct devinfo)); + bzero(last.dinfo, sizeof(struct devinfo)); + + if (checkversion() < 0) + errx(1, "xperfmon++: %s", devstat_errbuf); + + /* + * man muß über specified devices gehen, um da1,... zu + * selektieren, siehe /usr/src/usr.sbin/iostat/iostat.c + */ + +/* printf("%s\n", info1); LK!!! */ + if (buildmatch("da", &matches, &num_matches) != 0) + errx(1, "xperfmon++: %s", devstat_errbuf); + if (buildmatch("sa", &matches, &num_matches) != 0) + errx(1, "xperfmon++: %s", devstat_errbuf); + if (buildmatch("cd", &matches, &num_matches) != 0) + errx(1, "xperfmon++: %s", devstat_errbuf); + + if (getdevs(&cur) == -1) + errx(1, "xperfmon++: %s", devstat_errbuf); + + maxshowdevs = 50; + + 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, + DS_SELECT_ONLY, maxshowdevs, 0); + switch (retval) { + case -1: + errx(1, "xperfmon++: %s", devstat_errbuf); + break; + default: + break; + } } -int -get_devstat(void) + +static void +get_diskio(void) { - register int dn; - long double busy_seconds; - u_int64_t total_transfers; - struct devinfo *tmp_dinfo; - int total_xfers = 0; - - if (nodisk == 0) { - /* - * 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)) { + register int i, dn; + long double busy_seconds; + long double transfers_per_second, mb_per_second; + struct devinfo *tmp_dinfo; + int retval; + + 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, "xperfmon++: %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, + DS_SELECT_ONLY, maxshowdevs, 0); + switch (retval) { case -1: - return (0); - 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, - NULL, 0, - select_mode, DK_NDRIVE, 0); - switch(retval) { - case -1: - return (0); - case 1: - break; - default: - break; - } + errx(1, "xperfmon++: %s", devstat_errbuf); break; - } default: break; } - - /* - * Calculate elapsed time up front, since it's the same for all - * devices. - */ - busy_seconds = compute_etime(cur.busy_time, last.busy_time); - - /* this is the first time thru so just copy cur to last */ - if (last.dinfo->numdevs == 0) { - tmp_dinfo = last.dinfo; - last.dinfo = cur.dinfo; - cur.dinfo = tmp_dinfo; - last.busy_time = cur.busy_time; - return (0); + break; } + default: + break; + } + /* + * Calculate elapsed time up front, since it's the same for all + * devices. + */ - for (dn = 0; dn < num_devices; dn++) { - int di; + diskstat.da_trsf = diskstat.da_mb = 0.0; + diskstat.sa_trsf = diskstat.sa_mb = 0.0; + diskstat.cd_trsf = diskstat.cd_mb = 0.0; - if ((dev_select[dn].selected == 0) - || (dev_select[dn].selected > DK_NDRIVE)) - continue; + busy_seconds = compute_etime(cur.busy_time, last.busy_time); - di = dev_select[dn].position; + for (dn = 0; dn < num_devices; dn++) { + int di; - if (compute_stats(&cur.dinfo->devices[di], - &last.dinfo->devices[di], busy_seconds, - NULL, &total_transfers, - NULL, NULL, - NULL, NULL, - NULL, NULL)!= 0) - break; - total_xfers += (int)total_transfers; - } + if (dev_select[dn].selected == 0) + continue; - tmp_dinfo = last.dinfo; - last.dinfo = cur.dinfo; - cur.dinfo = tmp_dinfo; + di = dev_select[dn].position; - last.busy_time = cur.busy_time; + if (compute_stats(&cur.dinfo->devices[di], + &last.dinfo->devices[di], busy_seconds, + NULL, NULL, + NULL, NULL, + &transfers_per_second, &mb_per_second, + NULL, NULL) != 0) + errx(1, "xperfmon++: %s", devstat_errbuf); - } else - /* no disks found ? */ - total_xfers = 0; + if (strcmp(cur.dinfo->devices[di].device_name, "da") == 0 || + strcmp(cur.dinfo->devices[di].device_name, "wd") == 0) { +#ifdef DEBUG + printf( "da%d: %Lf %Lf\n", cur.dinfo->devices[di].unit_number, transfers_per_second, mb_per_second); +#endif + diskstat.da_trsf += transfers_per_second; + diskstat.da_mb += mb_per_second; + } + if (strcmp(cur.dinfo->devices[di].device_name, "sa") == 0) { +#ifdef DEBUG + printf( "sa%d: %Lf %Lf\n", cur.dinfo->devices[di].unit_number, transfers_per_second, mb_per_second); +#endif + diskstat.sa_trsf += transfers_per_second; + diskstat.sa_mb += mb_per_second; + } + if (strcmp(cur.dinfo->devices[di].device_name, "cd") == 0 || + strcmp(cur.dinfo->devices[di].device_name, "acd") == 0) { +#ifdef DEBUG + printf( "cd%d: %Lf %Lf\n", cur.dinfo->devices[di].unit_number, transfers_per_second, mb_per_second); +#endif + diskstat.cd_trsf += transfers_per_second; + diskstat.cd_mb += mb_per_second; + } + + } - return (total_xfers); } -#endif /* HAVE_DEVSTAT */ |