From owner-freebsd-ports Fri Mar 8 04:26:55 1996 Return-Path: owner-ports Received: (from root@localhost) by freefall.freebsd.org (8.7.3/8.7.3) id DAA01553 for ports-outgoing; Fri, 8 Mar 1996 03:19:05 -0800 (PST) Received: from who.cdrom.com (who.cdrom.com [192.216.222.3]) by freefall.freebsd.org (8.7.3/8.7.3) with SMTP id DAA01505 for ; Fri, 8 Mar 1996 03:18:55 -0800 (PST) Received: from lirmm.lirmm.fr (lirmm.lirmm.fr [193.49.104.10]) by who.cdrom.com (8.6.12/8.6.11) with ESMTP id XAA21998 for ; Thu, 7 Mar 1996 23:09:52 -0800 Received: from lirmm.fr (baobab.lirmm.fr [193.49.106.14]) by lirmm.lirmm.fr (8.7.1/8.6.4) with ESMTP id IAA19184 for ; Fri, 8 Mar 1996 08:09:23 +0100 (MET) Message-Id: <199603080709.IAA19184@lirmm.lirmm.fr> To: ports@FreeBSD.ORG Subject: xperfmon++ Date: Fri, 08 Mar 1996 08:09:21 +0100 From: "Philippe Charnier" Sender: owner-ports@FreeBSD.ORG X-Loop: owner-ports@FreeBSD.ORG Precedence: bulk Hi, Here is a new patch-aa for xperfmon++ (in sysutils) that take into account the recent changes in pstat (-s), and make the swap information working again. -------- -------- Philippe Charnier charnier@lirmm.fr LIRMM, 161 rue Ada, 34392 Montpellier cedex 5 -- France ------------------------------------------------------------------------ *** bsd_system.c.orig Thu Mar 7 21:12:50 1996 --- bsd_system.c Thu Mar 7 21:31:28 1996 *************** *** 0 **** --- 1,567 ---- + /* + * Perfmon Performance Monitor + * + * 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 + + #include "system.h" + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + + #if __FreeBSD__ > 1 + #include + /* + * XXX temporary hack: FreeBSD-2.2-current has been floating around + * with 199508 for some time; FreeBSD-2.1 will be 199511 however (so + * 2.2-current has been bumped to 199512 recently). Recognize the old + * 2.2-current as NFSv3 for a grace period. + * FreeBSD 2.0.5 was 199504, btw. Both, 2.0.5 and 2.1 don't have + * NFSv3. + */ + # if __FreeBSD_version > 199511 || __FreeBSD_version == 199508 + # define HAS_NFS_V3 + # endif /* FreeBSD_version */ + #endif /* FreeBSD */ + + #include "is.h" + + #ifndef TRUE + #define TRUE 1 + #define FALSE 0 + #endif + + #define WANT_STAT(x) (poss_stats[(x)] != NO_STAT) + + /* + 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); + + /* + 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; + + int current_values[NUM_GRAPHS]; + stat_type stats; + + extern Widget perfmon[NUM_GRAPHS]; + + static struct packet { + int input, output, collisions; + } packets, old_packets; + + static struct nfsstats nfsstats; + static struct _nfsStats { + int nfsServer, nfsClient; + } nfsStats, old_nfsStats; + + struct nlist nl[] = { + #define X_CPTIME 0 + { "_cp_time" }, + #define X_SUM 1 + { "_cnt" }, + #define X_BOOTTIME 2 + { "_boottime" }, + #define X_DKXFER 3 + { "_dk_xfer" }, + #define X_HZ 4 + { "_hz" }, + #define N_IFNET 5 + { "_ifnet" }, + #define X_INTRCNT 6 + { "_intrcnt" }, + #define X_EINTRCNT 7 + { "_eintrcnt" }, + #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 */ + { "" }, + }; + + struct { + long time[CPUSTATES]; + long xfer[DK_NDRIVE]; + struct vmmeter Sum; + struct vmmeter Rate; + int interrupts; + } s, s1; + + int off; + + #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() + { + get_namelist(getbootfile(), _PATH_KMEM); + collect_stats(); + /* 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! */ + off = 100 - get_swapspace(); + etime = 1.0; + } + + + /* + Update the data structures + */ + void update_stats() + { + int state; + double pct, tot;; + + collect_stats(); + + tot = 0; + for (state = 0; state < CPUSTATES; ++state) + tot += s.time[state]; + if (tot) + pct = 100 / tot; + else + pct = 0; + 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;; + current_values[IDLE_CPU_PERCENTAGE] = s.time[CP_IDLE] * pct; + + if (perfmon[FREE_MEM]) { + current_values[FREE_MEM] = get_swapspace() + off; + off = 0; + } + 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() + { + register int i, total_xfers = 0; + + for(i=0; i < DK_NDRIVE; i++) + total_xfers += s.xfer[i]; + return(total_xfers/etime); + } + + + /* + Collect all the data + */ + void + collect_stats() + { + off_t ifnetaddr; + register int i, tmp; + int mib[3], size; + + kread(X_CPTIME, s.time, sizeof(s.time)); + kread(X_DKXFER, s.xfer, sizeof(s.xfer)); + kread(X_SUM, &sum, sizeof(sum) ); + + 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; + for (i=0; i < DK_NDRIVE; i++) { + tmp = s.xfer[i]; + s.xfer[i] -= s1.xfer[i]; + s1.xfer[i] = tmp; + } + for (i=0; i < CPUSTATES; i++) { + tmp = s.time[i]; + s.time[i] -= s1.time[i]; + s1.time[i] = tmp; + etime += s.time[i]; + } + if(etime == 0.) + etime = 1.; + etime /= hz; + + /* + Collect the Network-Traffic + */ + + if (nl[N_IFNET].n_value != 0) { + 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; + } + } + + /* + Collect the NFS and RPC Calls + */ + + size = sizeof(nfsstats); + mib[0] = CTL_FS; + mib[1] = MOUNT_NFS; + 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]; + } + } + + + /* + Reads the nlist from the kernel + */ + int + get_namelist(kernel_name, memory_name) + const char *kernel_name, *memory_name; + { + time_t now; + time_t boottime; + register int i, c; + int nintv; + + kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); + if (kd == 0) { + (void)fprintf(stderr, "xperfmon++: kvm_openfiles: %s\n", errbuf); + exit(1); + } + + 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); + } + + 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); + } + + + /* + Kread reads something from the kernel, given its nlist index. + */ + static void + kread(nlx, addr, size) + int nlx; + void *addr; + size_t size; + { + 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); + } + } + + #define SVAR(var) __STRING(var) /* to force expansion */ + #define KGET(idx, var) \ + KGET1(idx, &var, sizeof(var), SVAR(var)) + #define KGET1(idx, p, s, msg) \ + KGET2(nl[idx].n_value, p, s, msg) + #define KGET2(addr, p, s, msg) \ + if (kvm_read(kd, (u_long)(addr), p, s) != s) \ + warnx("cannot read %s: %s", msg, kvm_geterr(kd)) + #define KGETRET(addr, p, s, msg) \ + if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ + warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ + return (0); \ + } + + + /* + * get_swapspace is based on a program called swapinfo written + * by Kevin Lahey . + */ + int + get_swapspace() + { + 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; + KGET(VM_NSWAP, nswap); + KGET(VM_NSWDEV, nswdev); + KGET(VM_DMMAX, dmmax); + KGET1(VM_SWAPLIST, &swaplist, sizeof swaplist, "swaplist"); + if ((sw = malloc(nswdev * sizeof(*sw))) == NULL || + (perdev = malloc(nswdev * sizeof(*perdev))) == NULL) + err(1, "xperfmon++ malloc in get_swapspace"); + KGET1(VM_SWDEVT, &ptr, sizeof ptr, "swdevt"); + KGET2(ptr, sw, nswdev * sizeof(*sw), "*swdevt"); + /* Count up swap space. */ + nfree = 0; + memset(perdev, 0, nswdev * sizeof(*perdev)); + swapptr = swaplist.rlh_list; + while (swapptr) { + int top, bottom, next_block; + + KGET2(swapptr, &head, sizeof(struct rlist), "swapptr"); + + 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; + + /* + * 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; + } + + /* + * If only one partition has been set up via swapon(8), we don't + * need to bother with totals. + */ + used = avail - nfree; + + free(perdev); + free(sw); + return((100*nfree)/avail); /* return free swap in percent */ + }