Home | History | Annotate | Line # | Download | only in sa
main.c revision 1.10
      1  1.10      cgd /* $NetBSD: main.c,v 1.10 2000/06/14 17:26:23 cgd Exp $ */
      2   1.9      cgd 
      3   1.1      cgd /*
      4   1.1      cgd  * Copyright (c) 1994 Christopher G. Demetriou
      5   1.1      cgd  * All rights reserved.
      6  1.10      cgd  *
      7   1.1      cgd  * Redistribution and use in source and binary forms, with or without
      8   1.1      cgd  * modification, are permitted provided that the following conditions
      9   1.1      cgd  * are met:
     10   1.1      cgd  * 1. Redistributions of source code must retain the above copyright
     11   1.1      cgd  *    notice, this list of conditions and the following disclaimer.
     12   1.1      cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1      cgd  *    notice, this list of conditions and the following disclaimer in the
     14   1.1      cgd  *    documentation and/or other materials provided with the distribution.
     15   1.1      cgd  * 3. All advertising materials mentioning features or use of this software
     16   1.1      cgd  *    must display the following acknowledgement:
     17  1.10      cgd  *          This product includes software developed for the
     18  1.10      cgd  *          NetBSD Project.  See http://www.netbsd.org/ for
     19  1.10      cgd  *          information about NetBSD.
     20   1.1      cgd  * 4. The name of the author may not be used to endorse or promote products
     21  1.10      cgd  *    derived from this software without specific prior written permission.
     22  1.10      cgd  *
     23   1.1      cgd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     24   1.1      cgd  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     25   1.1      cgd  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     26   1.1      cgd  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     27   1.1      cgd  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     28   1.1      cgd  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     29   1.1      cgd  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     30   1.1      cgd  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     31   1.1      cgd  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     32   1.1      cgd  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33  1.10      cgd  *
     34  1.10      cgd  * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
     35   1.1      cgd  */
     36   1.1      cgd 
     37   1.7    lukem #include <sys/cdefs.h>
     38   1.7    lukem #ifndef lint
     39   1.7    lukem __COPYRIGHT("@(#) Copyright (c) 1994 Christopher G. Demetriou\n\
     40   1.7    lukem  All rights reserved.\n");
     41   1.1      cgd 
     42  1.10      cgd __RCSID("$NetBSD: main.c,v 1.10 2000/06/14 17:26:23 cgd Exp $");
     43   1.1      cgd #endif
     44   1.1      cgd 
     45   1.1      cgd /*
     46   1.1      cgd  * sa:	system accounting
     47   1.1      cgd  */
     48   1.1      cgd 
     49   1.1      cgd #include <sys/types.h>
     50   1.1      cgd #include <sys/acct.h>
     51   1.1      cgd #include <ctype.h>
     52   1.1      cgd #include <err.h>
     53   1.1      cgd #include <fcntl.h>
     54   1.1      cgd #include <signal.h>
     55   1.1      cgd #include <stdio.h>
     56   1.1      cgd #include <stdlib.h>
     57   1.5      cgd #include <string.h>
     58   1.1      cgd #include <unistd.h>
     59   1.1      cgd #include "extern.h"
     60   1.1      cgd #include "pathnames.h"
     61   1.1      cgd 
     62   1.1      cgd static int	acct_load	__P((char *, int));
     63   1.1      cgd static u_quad_t	decode_comp_t	__P((comp_t));
     64   1.1      cgd static int	cmp_comm	__P((const char *, const char *));
     65   1.1      cgd static int	cmp_usrsys	__P((const DBT *, const DBT *));
     66   1.1      cgd static int	cmp_avgusrsys	__P((const DBT *, const DBT *));
     67   1.1      cgd static int	cmp_dkio	__P((const DBT *, const DBT *));
     68   1.1      cgd static int	cmp_avgdkio	__P((const DBT *, const DBT *));
     69   1.1      cgd static int	cmp_cpumem	__P((const DBT *, const DBT *));
     70   1.1      cgd static int	cmp_avgcpumem	__P((const DBT *, const DBT *));
     71   1.1      cgd static int	cmp_calls	__P((const DBT *, const DBT *));
     72   1.1      cgd 
     73   1.1      cgd int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
     74   1.1      cgd int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
     75   1.1      cgd int cutoff = 1;
     76   1.1      cgd 
     77   1.1      cgd static char	*dfltargv[] = { _PATH_ACCT };
     78   1.4  mycroft static int	dfltargc = (sizeof(dfltargv)/sizeof(char *));
     79   1.1      cgd 
     80   1.1      cgd /* default to comparing by sum of user + system time */
     81   1.1      cgd cmpf_t   sa_cmp = cmp_usrsys;
     82   1.1      cgd 
     83   1.1      cgd int
     84   1.1      cgd main(argc, argv)
     85   1.1      cgd 	int argc;
     86   1.1      cgd 	char **argv;
     87   1.1      cgd {
     88   1.6     mark 	int ch;
     89   1.1      cgd 	int error;
     90   1.1      cgd 
     91   1.7    lukem 	error = 0;
     92   1.1      cgd 	while ((ch = getopt(argc, argv, "abcdDfijkKlmnqrstuv:")) != -1)
     93   1.1      cgd 		switch (ch) {
     94   1.1      cgd 			case 'a':
     95   1.1      cgd 				/* print all commands */
     96   1.1      cgd 				aflag = 1;
     97   1.1      cgd 				break;
     98   1.1      cgd 			case 'b':
     99   1.1      cgd 				/* sort by per-call user/system time average */
    100   1.1      cgd 				bflag = 1;
    101   1.1      cgd 				sa_cmp = cmp_avgusrsys;
    102   1.1      cgd 				break;
    103   1.1      cgd 			case 'c':
    104   1.1      cgd 				/* print percentage total time */
    105   1.1      cgd 				cflag = 1;
    106   1.1      cgd 				break;
    107   1.1      cgd 			case 'd':
    108   1.1      cgd 				/* sort by averge number of disk I/O ops */
    109   1.1      cgd 				dflag = 1;
    110   1.1      cgd 				sa_cmp = cmp_avgdkio;
    111   1.1      cgd 				break;
    112   1.1      cgd 			case 'D':
    113   1.1      cgd 				/* print and sort by total disk I/O ops */
    114   1.1      cgd 				Dflag = 1;
    115   1.1      cgd 				sa_cmp = cmp_dkio;
    116   1.1      cgd 				break;
    117   1.1      cgd 			case 'f':
    118   1.1      cgd 				/* force no interactive threshold comprison */
    119   1.1      cgd 				fflag = 1;
    120   1.1      cgd 				break;
    121   1.1      cgd 			case 'i':
    122   1.1      cgd 				/* do not read in summary file */
    123   1.1      cgd 				iflag = 1;
    124   1.1      cgd 				break;
    125   1.1      cgd 			case 'j':
    126   1.1      cgd 				/* instead of total minutes, give sec/call */
    127   1.1      cgd 				jflag = 1;
    128   1.1      cgd 				break;
    129   1.1      cgd 			case 'k':
    130   1.1      cgd 				/* sort by cpu-time average memory usage */
    131   1.1      cgd 				kflag = 1;
    132   1.1      cgd 				sa_cmp = cmp_avgcpumem;
    133   1.1      cgd 				break;
    134   1.1      cgd 			case 'K':
    135   1.1      cgd 				/* print and sort by cpu-storage integral */
    136   1.1      cgd 				sa_cmp = cmp_cpumem;
    137   1.1      cgd 				Kflag = 1;
    138   1.1      cgd 				break;
    139   1.1      cgd 			case 'l':
    140   1.1      cgd 				/* seperate system and user time */
    141   1.1      cgd 				lflag = 1;
    142   1.1      cgd 				break;
    143   1.1      cgd 			case 'm':
    144   1.1      cgd 				/* print procs and time per-user */
    145   1.1      cgd 				mflag = 1;
    146   1.1      cgd 				break;
    147   1.1      cgd 			case 'n':
    148   1.1      cgd 				/* sort by number of calls */
    149   1.1      cgd 				sa_cmp = cmp_calls;
    150   1.1      cgd 				break;
    151   1.1      cgd 			case 'q':
    152   1.1      cgd 				/* quiet; error messages only */
    153   1.1      cgd 				qflag = 1;
    154   1.1      cgd 				break;
    155   1.1      cgd 			case 'r':
    156   1.1      cgd 				/* reverse order of sort */
    157   1.1      cgd 				rflag = 1;
    158   1.1      cgd 				break;
    159   1.1      cgd 			case 's':
    160   1.1      cgd 				/* merge accounting file into summaries */
    161   1.1      cgd 				sflag = 1;
    162   1.1      cgd 				break;
    163   1.1      cgd 			case 't':
    164   1.1      cgd 				/* report ratio of user and system times */
    165   1.1      cgd 				tflag = 1;
    166   1.1      cgd 				break;
    167   1.1      cgd 			case 'u':
    168   1.1      cgd 				/* first, print uid and command name */
    169   1.1      cgd 				uflag = 1;
    170   1.1      cgd 				break;
    171   1.1      cgd 			case 'v':
    172   1.1      cgd 				/* cull junk */
    173   1.1      cgd 				vflag = 1;
    174   1.1      cgd 				cutoff = atoi(optarg);
    175   1.1      cgd 				break;
    176   1.1      cgd 			case '?':
    177   1.1      cgd 	                default:
    178   1.1      cgd 				(void)fprintf(stderr,
    179   1.1      cgd 				    "usage: sa [-abcdDfijkKlmnqrstu] [-v cutoff] [file ...]\n");
    180   1.1      cgd 				exit(1);
    181   1.1      cgd 		}
    182   1.1      cgd 
    183   1.1      cgd 	argc -= optind;
    184   1.1      cgd 	argv += optind;
    185   1.1      cgd 
    186   1.1      cgd 	/* various argument checking */
    187   1.1      cgd 	if (fflag && !vflag)
    188   1.1      cgd 		errx(1, "only one of -f requires -v");
    189   1.1      cgd 	if (fflag && aflag)
    190   1.1      cgd 		errx(1, "only one of -a and -v may be specified");
    191   1.1      cgd 	/* XXX need more argument checking */
    192   1.1      cgd 
    193   1.1      cgd 	if (!uflag) {
    194   1.1      cgd 		/* initialize tables */
    195   1.1      cgd 		if ((sflag || (!mflag && !qflag)) && pacct_init() != 0)
    196   1.1      cgd 			errx(1, "process accounting initialization failed");
    197   1.1      cgd 		if ((sflag || (mflag && !qflag)) && usracct_init() != 0)
    198   1.1      cgd 			errx(1, "user accounting initialization failed");
    199   1.1      cgd 	}
    200   1.1      cgd 
    201   1.1      cgd 	if (argc == 0) {
    202   1.1      cgd 		argc = dfltargc;
    203   1.1      cgd 		argv = dfltargv;
    204   1.1      cgd 	}
    205   1.1      cgd 
    206   1.1      cgd 	/* for each file specified */
    207   1.1      cgd 	for (; argc > 0; argc--, argv++) {
    208   1.1      cgd 		int	fd;
    209   1.1      cgd 
    210   1.1      cgd 		/*
    211   1.1      cgd 		 * load the accounting data from the file.
    212   1.1      cgd 		 * if it fails, go on to the next file.
    213   1.1      cgd 		 */
    214   1.1      cgd 		fd = acct_load(argv[0], sflag);
    215   1.1      cgd 		if (fd < 0)
    216   1.1      cgd 			continue;
    217   1.1      cgd 
    218   1.1      cgd 		if (!uflag && sflag) {
    219   1.1      cgd #ifndef DEBUG
    220   1.1      cgd 			sigset_t nmask, omask;
    221   1.1      cgd 			int unmask = 1;
    222   1.1      cgd 
    223   1.1      cgd 			/*
    224   1.1      cgd 			 * block most signals so we aren't interrupted during
    225   1.1      cgd 			 * the update.
    226   1.1      cgd 			 */
    227   1.1      cgd 			if (sigfillset(&nmask) == -1) {
    228   1.1      cgd 				warn("sigfillset");
    229   1.1      cgd 				unmask = 0;
    230   1.1      cgd 				error = 1;
    231   1.1      cgd 			}
    232   1.1      cgd 			if (unmask &&
    233   1.1      cgd 			    (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)) {
    234   1.1      cgd 				warn("couldn't set signal mask ");
    235   1.1      cgd 				unmask = 0;
    236   1.1      cgd 				error = 1;
    237   1.1      cgd 			}
    238   1.1      cgd #endif /* DEBUG */
    239   1.1      cgd 
    240   1.1      cgd 			/*
    241   1.1      cgd 			 * truncate the accounting data file ASAP, to avoid
    242   1.1      cgd 			 * losing data.  don't worry about errors in updating
    243   1.1      cgd 			 * the saved stats; better to underbill than overbill,
    244   1.1      cgd 			 * but we want every accounting record intact.
    245   1.1      cgd 			 */
    246   1.1      cgd 			if (ftruncate(fd, 0) == -1) {
    247   1.7    lukem 				warn("couldn't truncate %s", *argv);
    248   1.1      cgd 				error = 1;
    249   1.1      cgd 			}
    250   1.1      cgd 
    251   1.1      cgd 			/*
    252   1.1      cgd 			 * update saved user and process accounting data.
    253   1.1      cgd 			 * note errors for later.
    254   1.1      cgd 			 */
    255   1.1      cgd 			if (pacct_update() != 0 || usracct_update() != 0)
    256   1.1      cgd 				error = 1;
    257   1.1      cgd 
    258   1.1      cgd #ifndef DEBUG
    259   1.1      cgd 			/*
    260   1.1      cgd 			 * restore signals
    261   1.1      cgd 			 */
    262   1.1      cgd 			if (unmask &&
    263   1.1      cgd 			    (sigprocmask(SIG_SETMASK, &omask, NULL) == -1)) {
    264   1.1      cgd 				warn("couldn't restore signal mask");
    265   1.1      cgd 				error = 1;
    266   1.1      cgd 			}
    267   1.1      cgd #endif /* DEBUG */
    268   1.1      cgd 		}
    269   1.1      cgd 
    270   1.1      cgd 		/*
    271   1.1      cgd 		 * close the opened accounting file
    272   1.1      cgd 		 */
    273   1.1      cgd 		if (close(fd) == -1) {
    274   1.7    lukem 			warn("close %s", *argv);
    275   1.1      cgd 			error = 1;
    276   1.1      cgd 		}
    277   1.1      cgd 	}
    278   1.1      cgd 
    279   1.1      cgd 	if (!uflag && !qflag) {
    280   1.1      cgd 		/* print any results we may have obtained. */
    281   1.1      cgd 		if (!mflag)
    282   1.1      cgd 			pacct_print();
    283   1.1      cgd 		else
    284   1.1      cgd 			usracct_print();
    285   1.1      cgd 	}
    286   1.1      cgd 
    287   1.1      cgd 	if (!uflag) {
    288   1.1      cgd 		/* finally, deallocate databases */
    289   1.1      cgd 		if (sflag || (!mflag && !qflag))
    290   1.1      cgd 			pacct_destroy();
    291   1.1      cgd 		if (sflag || (mflag && !qflag))
    292   1.1      cgd 			usracct_destroy();
    293   1.1      cgd 	}
    294   1.1      cgd 
    295   1.1      cgd 	exit(error);
    296   1.1      cgd }
    297   1.1      cgd 
    298   1.1      cgd static int
    299   1.1      cgd acct_load(pn, wr)
    300   1.1      cgd 	char *pn;
    301   1.1      cgd 	int wr;
    302   1.1      cgd {
    303   1.1      cgd 	struct acct ac;
    304   1.1      cgd 	struct cmdinfo ci;
    305   1.1      cgd 	ssize_t rv;
    306   1.1      cgd 	int fd, i;
    307   1.1      cgd 
    308   1.1      cgd 	/*
    309   1.1      cgd 	 * open the file
    310   1.1      cgd 	 */
    311   1.1      cgd 	fd = open(pn, wr ? O_RDWR : O_RDONLY, 0);
    312   1.1      cgd 	if (fd == -1) {
    313   1.1      cgd 		warn("open %s %s", pn, wr ? "for read/write" : "read-only");
    314   1.1      cgd 		return (-1);
    315   1.1      cgd 	}
    316   1.1      cgd 
    317   1.1      cgd 	/*
    318   1.1      cgd 	 * read all we can; don't stat and open because more processes
    319   1.1      cgd 	 * could exit, and we'd miss them
    320   1.1      cgd 	 */
    321   1.1      cgd 	while (1) {
    322   1.1      cgd 		/* get one accounting entry and punt if there's an error */
    323   1.1      cgd 		rv = read(fd, &ac, sizeof(struct acct));
    324   1.1      cgd 		if (rv == -1)
    325   1.1      cgd 			warn("error reading %s", pn);
    326   1.1      cgd 		else if (rv > 0 && rv < sizeof(struct acct))
    327   1.1      cgd 			warnx("short read of accounting data in %s", pn);
    328   1.1      cgd 		if (rv != sizeof(struct acct))
    329   1.1      cgd 			break;
    330   1.1      cgd 
    331   1.1      cgd 		/* decode it */
    332   1.1      cgd 		ci.ci_calls = 1;
    333   1.4  mycroft 		for (i = 0; i < sizeof(ac.ac_comm) && ac.ac_comm[i] != '\0';
    334   1.1      cgd 		    i++) {
    335   1.1      cgd 			char c = ac.ac_comm[i];
    336   1.1      cgd 
    337   1.1      cgd 			if (!isascii(c) || iscntrl(c)) {
    338   1.1      cgd 				ci.ci_comm[i] = '?';
    339   1.1      cgd 				ci.ci_flags |= CI_UNPRINTABLE;
    340   1.1      cgd 			} else
    341   1.1      cgd 				ci.ci_comm[i] = c;
    342   1.1      cgd 		}
    343   1.1      cgd 		if (ac.ac_flag & AFORK)
    344   1.1      cgd 			ci.ci_comm[i++] = '*';
    345   1.1      cgd 		ci.ci_comm[i++] = '\0';
    346   1.1      cgd 		ci.ci_etime = decode_comp_t(ac.ac_etime);
    347   1.1      cgd 		ci.ci_utime = decode_comp_t(ac.ac_utime);
    348   1.1      cgd 		ci.ci_stime = decode_comp_t(ac.ac_stime);
    349   1.1      cgd 		ci.ci_uid = ac.ac_uid;
    350   1.1      cgd 		ci.ci_mem = ac.ac_mem;
    351   1.1      cgd 		ci.ci_io = decode_comp_t(ac.ac_io) / AHZ;
    352   1.1      cgd 
    353   1.1      cgd 		if (!uflag) {
    354   1.1      cgd 			/* and enter it into the usracct and pacct databases */
    355   1.1      cgd 			if (sflag || (!mflag && !qflag))
    356   1.1      cgd 				pacct_add(&ci);
    357   1.1      cgd 			if (sflag || (mflag && !qflag))
    358   1.1      cgd 				usracct_add(&ci);
    359   1.1      cgd 		} else if (!qflag)
    360   1.7    lukem 			printf("%6u %12.2f cpu %12quk mem %12qu io %s\n",
    361   1.1      cgd 			    ci.ci_uid,
    362   1.1      cgd 			    (ci.ci_utime + ci.ci_stime) / (double) AHZ,
    363   1.8      mrg 			    (unsigned long long)ci.ci_mem,
    364   1.8      mrg 			    (unsigned long long)ci.ci_io, ci.ci_comm);
    365   1.1      cgd 	}
    366   1.1      cgd 
    367   1.1      cgd 	/* finally, return the file descriptor for possible truncation */
    368   1.1      cgd 	return (fd);
    369   1.1      cgd }
    370   1.1      cgd 
    371   1.1      cgd static u_quad_t
    372   1.1      cgd decode_comp_t(comp)
    373   1.1      cgd 	comp_t comp;
    374   1.1      cgd {
    375   1.1      cgd 	u_quad_t rv;
    376   1.1      cgd 
    377   1.1      cgd 	/*
    378   1.1      cgd 	 * for more info on the comp_t format, see:
    379   1.1      cgd 	 *	/usr/src/sys/kern/kern_acct.c
    380   1.1      cgd 	 *	/usr/src/sys/sys/acct.h
    381   1.1      cgd 	 *	/usr/src/usr.bin/lastcomm/lastcomm.c
    382   1.1      cgd 	 */
    383   1.1      cgd 	rv = comp & 0x1fff;	/* 13 bit fraction */
    384   1.1      cgd 	comp >>= 13;		/* 3 bit base-8 exponent */
    385   1.1      cgd 	while (comp--)
    386   1.1      cgd 		rv <<= 3;
    387   1.1      cgd 
    388   1.1      cgd 	return (rv);
    389   1.1      cgd }
    390   1.1      cgd 
    391   1.1      cgd /* sort commands, doing the right thing in terms of reversals */
    392   1.1      cgd static int
    393   1.1      cgd cmp_comm(s1, s2)
    394   1.1      cgd 	const char *s1, *s2;
    395   1.1      cgd {
    396   1.1      cgd 	int rv;
    397   1.1      cgd 
    398   1.1      cgd 	rv = strcmp(s1, s2);
    399   1.1      cgd 	if (rv == 0)
    400   1.1      cgd 		rv = -1;
    401   1.1      cgd 	return (rflag ? rv : -rv);
    402   1.1      cgd }
    403   1.1      cgd 
    404   1.1      cgd /* sort by total user and system time */
    405   1.1      cgd static int
    406   1.1      cgd cmp_usrsys(d1, d2)
    407   1.1      cgd 	const DBT *d1, *d2;
    408   1.1      cgd {
    409   1.3  mycroft 	struct cmdinfo c1, c2;
    410   1.1      cgd 	u_quad_t t1, t2;
    411   1.1      cgd 
    412   1.3  mycroft 	memcpy(&c1, d1->data, sizeof(c1));
    413   1.3  mycroft 	memcpy(&c2, d2->data, sizeof(c2));
    414   1.1      cgd 
    415   1.3  mycroft 	t1 = c1.ci_utime + c1.ci_stime;
    416   1.3  mycroft 	t2 = c2.ci_utime + c2.ci_stime;
    417   1.1      cgd 
    418   1.1      cgd 	if (t1 < t2)
    419   1.1      cgd 		return -1;
    420   1.1      cgd 	else if (t1 == t2)
    421   1.3  mycroft 		return (cmp_comm(c1.ci_comm, c2.ci_comm));
    422   1.1      cgd 	else
    423   1.1      cgd 		return 1;
    424   1.1      cgd }
    425   1.1      cgd 
    426   1.1      cgd /* sort by average user and system time */
    427   1.1      cgd static int
    428   1.1      cgd cmp_avgusrsys(d1, d2)
    429   1.1      cgd 	const DBT *d1, *d2;
    430   1.1      cgd {
    431   1.3  mycroft 	struct cmdinfo c1, c2;
    432   1.1      cgd 	double t1, t2;
    433   1.1      cgd 
    434   1.3  mycroft 	memcpy(&c1, d1->data, sizeof(c1));
    435   1.3  mycroft 	memcpy(&c2, d2->data, sizeof(c2));
    436   1.1      cgd 
    437   1.3  mycroft 	t1 = c1.ci_utime + c1.ci_stime;
    438   1.3  mycroft 	t1 /= (double) (c1.ci_calls ? c1.ci_calls : 1);
    439   1.1      cgd 
    440   1.3  mycroft 	t2 = c2.ci_utime + c2.ci_stime;
    441   1.3  mycroft 	t2 /= (double) (c2.ci_calls ? c2.ci_calls : 1);
    442   1.1      cgd 
    443   1.1      cgd 	if (t1 < t2)
    444   1.1      cgd 		return -1;
    445   1.1      cgd 	else if (t1 == t2)
    446   1.3  mycroft 		return (cmp_comm(c1.ci_comm, c2.ci_comm));
    447   1.1      cgd 	else
    448   1.1      cgd 		return 1;
    449   1.1      cgd }
    450   1.1      cgd 
    451   1.1      cgd /* sort by total number of disk I/O operations */
    452   1.1      cgd static int
    453   1.1      cgd cmp_dkio(d1, d2)
    454   1.1      cgd 	const DBT *d1, *d2;
    455   1.1      cgd {
    456   1.3  mycroft 	struct cmdinfo c1, c2;
    457   1.1      cgd 
    458   1.3  mycroft 	memcpy(&c1, d1->data, sizeof(c1));
    459   1.3  mycroft 	memcpy(&c2, d2->data, sizeof(c2));
    460   1.1      cgd 
    461   1.3  mycroft 	if (c1.ci_io < c2.ci_io)
    462   1.1      cgd 		return -1;
    463   1.3  mycroft 	else if (c1.ci_io == c2.ci_io)
    464   1.3  mycroft 		return (cmp_comm(c1.ci_comm, c2.ci_comm));
    465   1.1      cgd 	else
    466   1.1      cgd 		return 1;
    467   1.1      cgd }
    468   1.1      cgd 
    469   1.1      cgd /* sort by average number of disk I/O operations */
    470   1.1      cgd static int
    471   1.1      cgd cmp_avgdkio(d1, d2)
    472   1.1      cgd 	const DBT *d1, *d2;
    473   1.1      cgd {
    474   1.3  mycroft 	struct cmdinfo c1, c2;
    475   1.1      cgd 	double n1, n2;
    476   1.1      cgd 
    477   1.3  mycroft 	memcpy(&c1, d1->data, sizeof(c1));
    478   1.3  mycroft 	memcpy(&c2, d2->data, sizeof(c2));
    479   1.1      cgd 
    480   1.3  mycroft 	n1 = (double) c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
    481   1.3  mycroft 	n2 = (double) c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
    482   1.1      cgd 
    483   1.1      cgd 	if (n1 < n2)
    484   1.1      cgd 		return -1;
    485   1.1      cgd 	else if (n1 == n2)
    486   1.3  mycroft 		return (cmp_comm(c1.ci_comm, c2.ci_comm));
    487   1.1      cgd 	else
    488   1.1      cgd 		return 1;
    489   1.1      cgd }
    490   1.1      cgd 
    491   1.1      cgd /* sort by the cpu-storage integral */
    492   1.1      cgd static int
    493   1.1      cgd cmp_cpumem(d1, d2)
    494   1.1      cgd 	const DBT *d1, *d2;
    495   1.1      cgd {
    496   1.3  mycroft 	struct cmdinfo c1, c2;
    497   1.1      cgd 
    498   1.3  mycroft 	memcpy(&c1, d1->data, sizeof(c1));
    499   1.3  mycroft 	memcpy(&c2, d2->data, sizeof(c2));
    500   1.1      cgd 
    501   1.3  mycroft 	if (c1.ci_mem < c2.ci_mem)
    502   1.1      cgd 		return -1;
    503   1.3  mycroft 	else if (c1.ci_mem == c2.ci_mem)
    504   1.3  mycroft 		return (cmp_comm(c1.ci_comm, c2.ci_comm));
    505   1.1      cgd 	else
    506   1.1      cgd 		return 1;
    507   1.1      cgd }
    508   1.1      cgd 
    509   1.1      cgd /* sort by the cpu-time average memory usage */
    510   1.1      cgd static int
    511   1.1      cgd cmp_avgcpumem(d1, d2)
    512   1.1      cgd 	const DBT *d1, *d2;
    513   1.1      cgd {
    514   1.3  mycroft 	struct cmdinfo c1, c2;
    515   1.1      cgd 	u_quad_t t1, t2;
    516   1.1      cgd 	double n1, n2;
    517   1.1      cgd 
    518   1.3  mycroft 	memcpy(&c1, d1->data, sizeof(c1));
    519   1.3  mycroft 	memcpy(&c2, d2->data, sizeof(c2));
    520   1.1      cgd 
    521   1.3  mycroft 	t1 = c1.ci_utime + c1.ci_stime;
    522   1.3  mycroft 	t2 = c2.ci_utime + c2.ci_stime;
    523   1.1      cgd 
    524   1.3  mycroft 	n1 = (double) c1.ci_mem / (double) (t1 ? t1 : 1);
    525   1.3  mycroft 	n2 = (double) c2.ci_mem / (double) (t2 ? t2 : 1);
    526   1.1      cgd 
    527   1.1      cgd 	if (n1 < n2)
    528   1.1      cgd 		return -1;
    529   1.1      cgd 	else if (n1 == n2)
    530   1.3  mycroft 		return (cmp_comm(c1.ci_comm, c2.ci_comm));
    531   1.1      cgd 	else
    532   1.1      cgd 		return 1;
    533   1.1      cgd }
    534   1.1      cgd 
    535   1.1      cgd /* sort by the number of invocations */
    536   1.1      cgd static int
    537   1.1      cgd cmp_calls(d1, d2)
    538   1.1      cgd 	const DBT *d1, *d2;
    539   1.1      cgd {
    540   1.3  mycroft 	struct cmdinfo c1, c2;
    541   1.1      cgd 
    542   1.3  mycroft 	memcpy(&c1, d1->data, sizeof(c1));
    543   1.3  mycroft 	memcpy(&c2, d2->data, sizeof(c2));
    544   1.1      cgd 
    545   1.3  mycroft 	if (c1.ci_calls < c2.ci_calls)
    546   1.1      cgd 		return -1;
    547   1.3  mycroft 	else if (c1.ci_calls == c2.ci_calls)
    548   1.3  mycroft 		return (cmp_comm(c1.ci_comm, c2.ci_comm));
    549   1.1      cgd 	else
    550   1.1      cgd 		return 1;
    551   1.1      cgd }
    552