1*3e9fa0fcSdholland /* $NetBSD: main.c,v 1.28 2010/06/10 06:28:33 dholland Exp $ */
2d220ca5bScgd
30b6d07ecScgd /*
40b6d07ecScgd * Copyright (c) 1994 Christopher G. Demetriou
50b6d07ecScgd * All rights reserved.
60b6d07ecScgd *
70b6d07ecScgd * Redistribution and use in source and binary forms, with or without
80b6d07ecScgd * modification, are permitted provided that the following conditions
90b6d07ecScgd * are met:
100b6d07ecScgd * 1. Redistributions of source code must retain the above copyright
110b6d07ecScgd * notice, this list of conditions and the following disclaimer.
120b6d07ecScgd * 2. Redistributions in binary form must reproduce the above copyright
130b6d07ecScgd * notice, this list of conditions and the following disclaimer in the
140b6d07ecScgd * documentation and/or other materials provided with the distribution.
150b6d07ecScgd * 3. All advertising materials mentioning features or use of this software
160b6d07ecScgd * must display the following acknowledgement:
17db755e7cScgd * This product includes software developed for the
18cacf2d0fSgrant * NetBSD Project. See http://www.NetBSD.org/ for
19db755e7cScgd * information about NetBSD.
200b6d07ecScgd * 4. The name of the author may not be used to endorse or promote products
21db755e7cScgd * derived from this software without specific prior written permission.
220b6d07ecScgd *
230b6d07ecScgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
240b6d07ecScgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
250b6d07ecScgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
260b6d07ecScgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
270b6d07ecScgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
280b6d07ecScgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
290b6d07ecScgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
300b6d07ecScgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
310b6d07ecScgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
320b6d07ecScgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33db755e7cScgd *
34db755e7cScgd * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
350b6d07ecScgd */
360b6d07ecScgd
37dc0e957aSlukem #include <sys/cdefs.h>
38dc0e957aSlukem #ifndef lint
399c194566Slukem __COPYRIGHT("@(#) Copyright (c) 1994\
409c194566Slukem Christopher G. Demetriou. All rights reserved.");
410b6d07ecScgd
42*3e9fa0fcSdholland __RCSID("$NetBSD: main.c,v 1.28 2010/06/10 06:28:33 dholland Exp $");
430b6d07ecScgd #endif
440b6d07ecScgd
450b6d07ecScgd /*
460b6d07ecScgd * sa: system accounting
470b6d07ecScgd */
480b6d07ecScgd
490b6d07ecScgd #include <sys/types.h>
500b6d07ecScgd #include <sys/acct.h>
510b6d07ecScgd #include <ctype.h>
520b6d07ecScgd #include <err.h>
53b834536aSchristos #include <vis.h>
540b6d07ecScgd #include <fcntl.h>
550b6d07ecScgd #include <signal.h>
560b6d07ecScgd #include <stdio.h>
570b6d07ecScgd #include <stdlib.h>
5806b20ecaScgd #include <string.h>
590b6d07ecScgd #include <unistd.h>
600b6d07ecScgd #include "extern.h"
610b6d07ecScgd #include "pathnames.h"
620b6d07ecScgd
63*3e9fa0fcSdholland static int acct_load(const char *, int);
6408571458Sdholland static u_quad_t decode_comp_t(comp_t);
6508571458Sdholland static int cmp_comm(const char *, const char *);
6608571458Sdholland static int cmp_usrsys(const DBT *, const DBT *);
6708571458Sdholland static int cmp_avgusrsys(const DBT *, const DBT *);
6808571458Sdholland static int cmp_dkio(const DBT *, const DBT *);
6908571458Sdholland static int cmp_avgdkio(const DBT *, const DBT *);
7008571458Sdholland static int cmp_cpumem(const DBT *, const DBT *);
7108571458Sdholland static int cmp_avgcpumem(const DBT *, const DBT *);
7208571458Sdholland static int cmp_calls(const DBT *, const DBT *);
7308571458Sdholland static void usage(void) __dead;
740b6d07ecScgd
750b6d07ecScgd int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
760b6d07ecScgd int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
770b6d07ecScgd int cutoff = 1;
780b6d07ecScgd
79103ca7bcSlukem static const char *dfltargv[] = { _PATH_ACCT };
80103ca7bcSlukem static const int dfltargc = (sizeof(dfltargv)/sizeof(char *));
810b6d07ecScgd
820b6d07ecScgd /* default to comparing by sum of user + system time */
830b6d07ecScgd cmpf_t sa_cmp = cmp_usrsys;
840b6d07ecScgd
850b6d07ecScgd int
main(int argc,char ** argv)86109bd3a9Sdholland main(int argc, char **argv)
870b6d07ecScgd {
883e43cc03Smark int ch;
890b6d07ecScgd int error;
900b6d07ecScgd
91dc0e957aSlukem error = 0;
920b6d07ecScgd while ((ch = getopt(argc, argv, "abcdDfijkKlmnqrstuv:")) != -1)
930b6d07ecScgd switch (ch) {
940b6d07ecScgd case 'a':
950b6d07ecScgd /* print all commands */
960b6d07ecScgd aflag = 1;
970b6d07ecScgd break;
980b6d07ecScgd case 'b':
990b6d07ecScgd /* sort by per-call user/system time average */
1000b6d07ecScgd bflag = 1;
1010b6d07ecScgd sa_cmp = cmp_avgusrsys;
1020b6d07ecScgd break;
1030b6d07ecScgd case 'c':
1040b6d07ecScgd /* print percentage total time */
1050b6d07ecScgd cflag = 1;
1060b6d07ecScgd break;
1070b6d07ecScgd case 'd':
1080b6d07ecScgd /* sort by averge number of disk I/O ops */
1090b6d07ecScgd dflag = 1;
1100b6d07ecScgd sa_cmp = cmp_avgdkio;
1110b6d07ecScgd break;
1120b6d07ecScgd case 'D':
1130b6d07ecScgd /* print and sort by total disk I/O ops */
1140b6d07ecScgd Dflag = 1;
1150b6d07ecScgd sa_cmp = cmp_dkio;
1160b6d07ecScgd break;
1170b6d07ecScgd case 'f':
1180b6d07ecScgd /* force no interactive threshold comprison */
1190b6d07ecScgd fflag = 1;
1200b6d07ecScgd break;
1210b6d07ecScgd case 'i':
1220b6d07ecScgd /* do not read in summary file */
1230b6d07ecScgd iflag = 1;
1240b6d07ecScgd break;
1250b6d07ecScgd case 'j':
1260b6d07ecScgd /* instead of total minutes, give sec/call */
1270b6d07ecScgd jflag = 1;
1280b6d07ecScgd break;
1290b6d07ecScgd case 'k':
130d20841bbSwiz /* sort by CPU-time average memory usage */
1310b6d07ecScgd kflag = 1;
1320b6d07ecScgd sa_cmp = cmp_avgcpumem;
1330b6d07ecScgd break;
1340b6d07ecScgd case 'K':
135d20841bbSwiz /* print and sort by CPU-storage integral */
1360b6d07ecScgd sa_cmp = cmp_cpumem;
1370b6d07ecScgd Kflag = 1;
1380b6d07ecScgd break;
1390b6d07ecScgd case 'l':
140a9356936Swiz /* separate system and user time */
1410b6d07ecScgd lflag = 1;
1420b6d07ecScgd break;
1430b6d07ecScgd case 'm':
1440b6d07ecScgd /* print procs and time per-user */
1450b6d07ecScgd mflag = 1;
1460b6d07ecScgd break;
1470b6d07ecScgd case 'n':
1480b6d07ecScgd /* sort by number of calls */
1490b6d07ecScgd sa_cmp = cmp_calls;
1500b6d07ecScgd break;
1510b6d07ecScgd case 'q':
1520b6d07ecScgd /* quiet; error messages only */
1530b6d07ecScgd qflag = 1;
1540b6d07ecScgd break;
1550b6d07ecScgd case 'r':
1560b6d07ecScgd /* reverse order of sort */
1570b6d07ecScgd rflag = 1;
1580b6d07ecScgd break;
1590b6d07ecScgd case 's':
1600b6d07ecScgd /* merge accounting file into summaries */
1610b6d07ecScgd sflag = 1;
1620b6d07ecScgd break;
1630b6d07ecScgd case 't':
1640b6d07ecScgd /* report ratio of user and system times */
1650b6d07ecScgd tflag = 1;
1660b6d07ecScgd break;
1670b6d07ecScgd case 'u':
1680b6d07ecScgd /* first, print uid and command name */
1690b6d07ecScgd uflag = 1;
1700b6d07ecScgd break;
1710b6d07ecScgd case 'v':
1720b6d07ecScgd /* cull junk */
1730b6d07ecScgd vflag = 1;
1740b6d07ecScgd cutoff = atoi(optarg);
1750b6d07ecScgd break;
1760b6d07ecScgd case '?':
1770b6d07ecScgd default:
178b834536aSchristos usage();
179b834536aSchristos /*NOTREACHED*/
1800b6d07ecScgd }
1810b6d07ecScgd
1820b6d07ecScgd argc -= optind;
1830b6d07ecScgd argv += optind;
1840b6d07ecScgd
1850b6d07ecScgd /* various argument checking */
1860b6d07ecScgd if (fflag && !vflag)
1870b6d07ecScgd errx(1, "only one of -f requires -v");
1880b6d07ecScgd if (fflag && aflag)
1890b6d07ecScgd errx(1, "only one of -a and -v may be specified");
1900b6d07ecScgd /* XXX need more argument checking */
1910b6d07ecScgd
1920b6d07ecScgd if (!uflag) {
1930b6d07ecScgd /* initialize tables */
1940b6d07ecScgd if ((sflag || (!mflag && !qflag)) && pacct_init() != 0)
1950b6d07ecScgd errx(1, "process accounting initialization failed");
1960b6d07ecScgd if ((sflag || (mflag && !qflag)) && usracct_init() != 0)
1970b6d07ecScgd errx(1, "user accounting initialization failed");
1980b6d07ecScgd }
1990b6d07ecScgd
2000b6d07ecScgd if (argc == 0) {
2010b6d07ecScgd argc = dfltargc;
202103ca7bcSlukem argv = __UNCONST(dfltargv);
2030b6d07ecScgd }
2040b6d07ecScgd
2050b6d07ecScgd /* for each file specified */
2060b6d07ecScgd for (; argc > 0; argc--, argv++) {
2070b6d07ecScgd int fd;
2080b6d07ecScgd
2090b6d07ecScgd /*
2100b6d07ecScgd * load the accounting data from the file.
2110b6d07ecScgd * if it fails, go on to the next file.
2120b6d07ecScgd */
2130b6d07ecScgd fd = acct_load(argv[0], sflag);
2140b6d07ecScgd if (fd < 0)
2150b6d07ecScgd continue;
2160b6d07ecScgd
2170b6d07ecScgd if (!uflag && sflag) {
2180b6d07ecScgd #ifndef DEBUG
2190b6d07ecScgd sigset_t nmask, omask;
2200b6d07ecScgd int unmask = 1;
2210b6d07ecScgd
2220b6d07ecScgd /*
2230b6d07ecScgd * block most signals so we aren't interrupted during
2240b6d07ecScgd * the update.
2250b6d07ecScgd */
2260b6d07ecScgd if (sigfillset(&nmask) == -1) {
2270b6d07ecScgd warn("sigfillset");
2280b6d07ecScgd unmask = 0;
2290b6d07ecScgd error = 1;
2300b6d07ecScgd }
2310b6d07ecScgd if (unmask &&
2320b6d07ecScgd (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)) {
2330b6d07ecScgd warn("couldn't set signal mask ");
2340b6d07ecScgd unmask = 0;
2350b6d07ecScgd error = 1;
2360b6d07ecScgd }
2370b6d07ecScgd #endif /* DEBUG */
2380b6d07ecScgd
2390b6d07ecScgd /*
2400b6d07ecScgd * truncate the accounting data file ASAP, to avoid
2410b6d07ecScgd * losing data. don't worry about errors in updating
2420b6d07ecScgd * the saved stats; better to underbill than overbill,
2430b6d07ecScgd * but we want every accounting record intact.
2440b6d07ecScgd */
2450b6d07ecScgd if (ftruncate(fd, 0) == -1) {
246dc0e957aSlukem warn("couldn't truncate %s", *argv);
2470b6d07ecScgd error = 1;
2480b6d07ecScgd }
2490b6d07ecScgd
2500b6d07ecScgd /*
2510b6d07ecScgd * update saved user and process accounting data.
2520b6d07ecScgd * note errors for later.
2530b6d07ecScgd */
2540b6d07ecScgd if (pacct_update() != 0 || usracct_update() != 0)
2550b6d07ecScgd error = 1;
2560b6d07ecScgd
2570b6d07ecScgd #ifndef DEBUG
2580b6d07ecScgd /*
2590b6d07ecScgd * restore signals
2600b6d07ecScgd */
2610b6d07ecScgd if (unmask &&
2620b6d07ecScgd (sigprocmask(SIG_SETMASK, &omask, NULL) == -1)) {
2630b6d07ecScgd warn("couldn't restore signal mask");
2640b6d07ecScgd error = 1;
2650b6d07ecScgd }
2660b6d07ecScgd #endif /* DEBUG */
2670b6d07ecScgd }
2680b6d07ecScgd
2690b6d07ecScgd /*
2700b6d07ecScgd * close the opened accounting file
2710b6d07ecScgd */
2720b6d07ecScgd if (close(fd) == -1) {
273dc0e957aSlukem warn("close %s", *argv);
2740b6d07ecScgd error = 1;
2750b6d07ecScgd }
2760b6d07ecScgd }
2770b6d07ecScgd
2780b6d07ecScgd if (!uflag && !qflag) {
2790b6d07ecScgd /* print any results we may have obtained. */
2800b6d07ecScgd if (!mflag)
2810b6d07ecScgd pacct_print();
2820b6d07ecScgd else
2830b6d07ecScgd usracct_print();
2840b6d07ecScgd }
2850b6d07ecScgd
2860b6d07ecScgd if (!uflag) {
2870b6d07ecScgd /* finally, deallocate databases */
2880b6d07ecScgd if (sflag || (!mflag && !qflag))
2890b6d07ecScgd pacct_destroy();
2900b6d07ecScgd if (sflag || (mflag && !qflag))
2910b6d07ecScgd usracct_destroy();
2920b6d07ecScgd }
2930b6d07ecScgd
2940b6d07ecScgd exit(error);
2950b6d07ecScgd }
2960b6d07ecScgd
2970b6d07ecScgd static int
acct_load(const char * pn,int wr)298*3e9fa0fcSdholland acct_load(const char *pn, int wr)
2990b6d07ecScgd {
3000b6d07ecScgd struct acct ac;
3010b6d07ecScgd struct cmdinfo ci;
30246a41907Slukem size_t i;
303b834536aSchristos FILE *fp;
3040b6d07ecScgd
3050b6d07ecScgd /*
3060b6d07ecScgd * open the file
3070b6d07ecScgd */
308b834536aSchristos fp = fopen(pn, wr ? "r+" : "r");
309b834536aSchristos if (fp == NULL) {
3100b6d07ecScgd warn("open %s %s", pn, wr ? "for read/write" : "read-only");
3110b6d07ecScgd return (-1);
3120b6d07ecScgd }
3130b6d07ecScgd
3140b6d07ecScgd /*
3150b6d07ecScgd * read all we can; don't stat and open because more processes
3160b6d07ecScgd * could exit, and we'd miss them
3170b6d07ecScgd */
318d04a0515Schristos for (;;) {
3190b6d07ecScgd /* get one accounting entry and punt if there's an error */
320b834536aSchristos if (fread(&ac, sizeof(struct acct), 1, fp) != 1) {
321b834536aSchristos if (feof(fp))
3220b6d07ecScgd break;
323b834536aSchristos if (ferror(fp))
324b834536aSchristos warn("error reading %s", pn);
325b834536aSchristos else
326b834536aSchristos warnx("short read of accounting data in %s",
327b834536aSchristos pn);
328b834536aSchristos break;
329b834536aSchristos }
3300b6d07ecScgd
3310b6d07ecScgd /* decode it */
3320b6d07ecScgd ci.ci_calls = 1;
333dd94184aSmycroft for (i = 0; i < sizeof(ac.ac_comm) && ac.ac_comm[i] != '\0';
3340b6d07ecScgd i++) {
3350b6d07ecScgd char c = ac.ac_comm[i];
3360b6d07ecScgd
3379122339bSdsl if (!isascii(c) || iscntrl((unsigned char)c)) {
3380b6d07ecScgd ci.ci_comm[i] = '?';
3390b6d07ecScgd ci.ci_flags |= CI_UNPRINTABLE;
3400b6d07ecScgd } else
3410b6d07ecScgd ci.ci_comm[i] = c;
3420b6d07ecScgd }
3430b6d07ecScgd if (ac.ac_flag & AFORK)
3440b6d07ecScgd ci.ci_comm[i++] = '*';
3450b6d07ecScgd ci.ci_comm[i++] = '\0';
3460b6d07ecScgd ci.ci_etime = decode_comp_t(ac.ac_etime);
3470b6d07ecScgd ci.ci_utime = decode_comp_t(ac.ac_utime);
3480b6d07ecScgd ci.ci_stime = decode_comp_t(ac.ac_stime);
3490b6d07ecScgd ci.ci_uid = ac.ac_uid;
3500b6d07ecScgd ci.ci_mem = ac.ac_mem;
3510b6d07ecScgd ci.ci_io = decode_comp_t(ac.ac_io) / AHZ;
3520b6d07ecScgd
3530b6d07ecScgd if (!uflag) {
3540b6d07ecScgd /* and enter it into the usracct and pacct databases */
3550b6d07ecScgd if (sflag || (!mflag && !qflag))
3560b6d07ecScgd pacct_add(&ci);
3570b6d07ecScgd if (sflag || (mflag && !qflag))
3580b6d07ecScgd usracct_add(&ci);
3590b6d07ecScgd } else if (!qflag)
360d20841bbSwiz printf("%6u %12.2f CPU %12lluk mem %12llu io %s\n",
3610b6d07ecScgd ci.ci_uid,
3620b6d07ecScgd (ci.ci_utime + ci.ci_stime) / (double) AHZ,
363a62207feSmrg (unsigned long long)ci.ci_mem,
364a62207feSmrg (unsigned long long)ci.ci_io, ci.ci_comm);
3650b6d07ecScgd }
3660b6d07ecScgd
3670b6d07ecScgd /* finally, return the file descriptor for possible truncation */
368b834536aSchristos return (fileno(fp));
3690b6d07ecScgd }
3700b6d07ecScgd
3710b6d07ecScgd static u_quad_t
decode_comp_t(comp_t comp)3725fbc0033Sdrochner decode_comp_t(comp_t comp)
3730b6d07ecScgd {
3740b6d07ecScgd u_quad_t rv;
3750b6d07ecScgd
3760b6d07ecScgd /*
3770b6d07ecScgd * for more info on the comp_t format, see:
3780b6d07ecScgd * /usr/src/sys/kern/kern_acct.c
3790b6d07ecScgd * /usr/src/sys/sys/acct.h
3800b6d07ecScgd * /usr/src/usr.bin/lastcomm/lastcomm.c
3810b6d07ecScgd */
3820b6d07ecScgd rv = comp & 0x1fff; /* 13 bit fraction */
3830b6d07ecScgd comp >>= 13; /* 3 bit base-8 exponent */
3840b6d07ecScgd while (comp--)
3850b6d07ecScgd rv <<= 3;
3860b6d07ecScgd
3870b6d07ecScgd return (rv);
3880b6d07ecScgd }
3890b6d07ecScgd
3900b6d07ecScgd /* sort commands, doing the right thing in terms of reversals */
3910b6d07ecScgd static int
cmp_comm(const char * s1,const char * s2)392109bd3a9Sdholland cmp_comm(const char *s1, const char *s2)
3930b6d07ecScgd {
3940b6d07ecScgd int rv;
3950b6d07ecScgd
3960b6d07ecScgd rv = strcmp(s1, s2);
3970b6d07ecScgd if (rv == 0)
3980b6d07ecScgd rv = -1;
3990b6d07ecScgd return (rflag ? rv : -rv);
4000b6d07ecScgd }
4010b6d07ecScgd
4020b6d07ecScgd /* sort by total user and system time */
4030b6d07ecScgd static int
cmp_usrsys(const DBT * d1,const DBT * d2)404109bd3a9Sdholland cmp_usrsys(const DBT *d1, const DBT *d2)
4050b6d07ecScgd {
4067f3235feSmycroft struct cmdinfo c1, c2;
4070b6d07ecScgd u_quad_t t1, t2;
4080b6d07ecScgd
4097f3235feSmycroft memcpy(&c1, d1->data, sizeof(c1));
4107f3235feSmycroft memcpy(&c2, d2->data, sizeof(c2));
4110b6d07ecScgd
4127f3235feSmycroft t1 = c1.ci_utime + c1.ci_stime;
4137f3235feSmycroft t2 = c2.ci_utime + c2.ci_stime;
4140b6d07ecScgd
4150b6d07ecScgd if (t1 < t2)
4160b6d07ecScgd return -1;
4170b6d07ecScgd else if (t1 == t2)
4187f3235feSmycroft return (cmp_comm(c1.ci_comm, c2.ci_comm));
4190b6d07ecScgd else
4200b6d07ecScgd return 1;
4210b6d07ecScgd }
4220b6d07ecScgd
4230b6d07ecScgd /* sort by average user and system time */
4240b6d07ecScgd static int
cmp_avgusrsys(const DBT * d1,const DBT * d2)425109bd3a9Sdholland cmp_avgusrsys(const DBT *d1, const DBT *d2)
4260b6d07ecScgd {
4277f3235feSmycroft struct cmdinfo c1, c2;
4280b6d07ecScgd double t1, t2;
4290b6d07ecScgd
4307f3235feSmycroft memcpy(&c1, d1->data, sizeof(c1));
4317f3235feSmycroft memcpy(&c2, d2->data, sizeof(c2));
4320b6d07ecScgd
4337f3235feSmycroft t1 = c1.ci_utime + c1.ci_stime;
4347f3235feSmycroft t1 /= (double) (c1.ci_calls ? c1.ci_calls : 1);
4350b6d07ecScgd
4367f3235feSmycroft t2 = c2.ci_utime + c2.ci_stime;
4377f3235feSmycroft t2 /= (double) (c2.ci_calls ? c2.ci_calls : 1);
4380b6d07ecScgd
4390b6d07ecScgd if (t1 < t2)
4400b6d07ecScgd return -1;
4410b6d07ecScgd else if (t1 == t2)
4427f3235feSmycroft return (cmp_comm(c1.ci_comm, c2.ci_comm));
4430b6d07ecScgd else
4440b6d07ecScgd return 1;
4450b6d07ecScgd }
4460b6d07ecScgd
4470b6d07ecScgd /* sort by total number of disk I/O operations */
4480b6d07ecScgd static int
cmp_dkio(const DBT * d1,const DBT * d2)449109bd3a9Sdholland cmp_dkio(const DBT *d1, const DBT *d2)
4500b6d07ecScgd {
4517f3235feSmycroft struct cmdinfo c1, c2;
4520b6d07ecScgd
4537f3235feSmycroft memcpy(&c1, d1->data, sizeof(c1));
4547f3235feSmycroft memcpy(&c2, d2->data, sizeof(c2));
4550b6d07ecScgd
4567f3235feSmycroft if (c1.ci_io < c2.ci_io)
4570b6d07ecScgd return -1;
4587f3235feSmycroft else if (c1.ci_io == c2.ci_io)
4597f3235feSmycroft return (cmp_comm(c1.ci_comm, c2.ci_comm));
4600b6d07ecScgd else
4610b6d07ecScgd return 1;
4620b6d07ecScgd }
4630b6d07ecScgd
4640b6d07ecScgd /* sort by average number of disk I/O operations */
4650b6d07ecScgd static int
cmp_avgdkio(const DBT * d1,const DBT * d2)466109bd3a9Sdholland cmp_avgdkio(const DBT *d1, const DBT *d2)
4670b6d07ecScgd {
4687f3235feSmycroft struct cmdinfo c1, c2;
4690b6d07ecScgd double n1, n2;
4700b6d07ecScgd
4717f3235feSmycroft memcpy(&c1, d1->data, sizeof(c1));
4727f3235feSmycroft memcpy(&c2, d2->data, sizeof(c2));
4730b6d07ecScgd
4747f3235feSmycroft n1 = (double) c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
4757f3235feSmycroft n2 = (double) c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
4760b6d07ecScgd
4770b6d07ecScgd if (n1 < n2)
4780b6d07ecScgd return -1;
4790b6d07ecScgd else if (n1 == n2)
4807f3235feSmycroft return (cmp_comm(c1.ci_comm, c2.ci_comm));
4810b6d07ecScgd else
4820b6d07ecScgd return 1;
4830b6d07ecScgd }
4840b6d07ecScgd
485d20841bbSwiz /* sort by the CPU-storage integral */
4860b6d07ecScgd static int
cmp_cpumem(const DBT * d1,const DBT * d2)487109bd3a9Sdholland cmp_cpumem(const DBT *d1, const DBT *d2)
4880b6d07ecScgd {
4897f3235feSmycroft struct cmdinfo c1, c2;
4900b6d07ecScgd
4917f3235feSmycroft memcpy(&c1, d1->data, sizeof(c1));
4927f3235feSmycroft memcpy(&c2, d2->data, sizeof(c2));
4930b6d07ecScgd
4947f3235feSmycroft if (c1.ci_mem < c2.ci_mem)
4950b6d07ecScgd return -1;
4967f3235feSmycroft else if (c1.ci_mem == c2.ci_mem)
4977f3235feSmycroft return (cmp_comm(c1.ci_comm, c2.ci_comm));
4980b6d07ecScgd else
4990b6d07ecScgd return 1;
5000b6d07ecScgd }
5010b6d07ecScgd
502d20841bbSwiz /* sort by the CPU-time average memory usage */
5030b6d07ecScgd static int
cmp_avgcpumem(const DBT * d1,const DBT * d2)504109bd3a9Sdholland cmp_avgcpumem(const DBT *d1, const DBT *d2)
5050b6d07ecScgd {
5067f3235feSmycroft struct cmdinfo c1, c2;
5070b6d07ecScgd u_quad_t t1, t2;
5080b6d07ecScgd double n1, n2;
5090b6d07ecScgd
5107f3235feSmycroft memcpy(&c1, d1->data, sizeof(c1));
5117f3235feSmycroft memcpy(&c2, d2->data, sizeof(c2));
5120b6d07ecScgd
5137f3235feSmycroft t1 = c1.ci_utime + c1.ci_stime;
5147f3235feSmycroft t2 = c2.ci_utime + c2.ci_stime;
5150b6d07ecScgd
5167f3235feSmycroft n1 = (double) c1.ci_mem / (double) (t1 ? t1 : 1);
5177f3235feSmycroft n2 = (double) c2.ci_mem / (double) (t2 ? t2 : 1);
5180b6d07ecScgd
5190b6d07ecScgd if (n1 < n2)
5200b6d07ecScgd return -1;
5210b6d07ecScgd else if (n1 == n2)
5227f3235feSmycroft return (cmp_comm(c1.ci_comm, c2.ci_comm));
5230b6d07ecScgd else
5240b6d07ecScgd return 1;
5250b6d07ecScgd }
5260b6d07ecScgd
5270b6d07ecScgd /* sort by the number of invocations */
5280b6d07ecScgd static int
cmp_calls(const DBT * d1,const DBT * d2)529109bd3a9Sdholland cmp_calls(const DBT *d1, const DBT *d2)
5300b6d07ecScgd {
5317f3235feSmycroft struct cmdinfo c1, c2;
5320b6d07ecScgd
5337f3235feSmycroft memcpy(&c1, d1->data, sizeof(c1));
5347f3235feSmycroft memcpy(&c2, d2->data, sizeof(c2));
5350b6d07ecScgd
5367f3235feSmycroft if (c1.ci_calls < c2.ci_calls)
5370b6d07ecScgd return -1;
5387f3235feSmycroft else if (c1.ci_calls == c2.ci_calls)
5397f3235feSmycroft return (cmp_comm(c1.ci_comm, c2.ci_comm));
5400b6d07ecScgd else
5410b6d07ecScgd return 1;
5420b6d07ecScgd }
543b834536aSchristos
544b834536aSchristos static void
usage(void)545109bd3a9Sdholland usage(void)
546b834536aSchristos {
547c2bdafabScgd
548b834536aSchristos (void)fprintf(stderr,
549b635f565Sjmmv "usage: %s [-abcdDfijkKlmnqrstu] [-v cutoff] [file ...]\n",
550c2bdafabScgd getprogname());
551b834536aSchristos exit(0);
552b834536aSchristos }
553b834536aSchristos
554b834536aSchristos const char *
fmt(const DBT * key)555109bd3a9Sdholland fmt(const DBT *key)
556b834536aSchristos {
557b834536aSchristos static char *buf = NULL;
558b834536aSchristos static size_t len = 0;
559a82a0d12Sitojun char *nbuf;
560a82a0d12Sitojun
561a82a0d12Sitojun if (len < key->size * 4 + 1) {
562a82a0d12Sitojun nbuf = realloc(buf, key->size * 4 + 1);
563a82a0d12Sitojun if (!nbuf)
564a82a0d12Sitojun err(1, "realloc");
565a82a0d12Sitojun buf = nbuf;
566a82a0d12Sitojun len = key->size * 4 + 1;
567a82a0d12Sitojun }
568b834536aSchristos (void)strvisx(buf, key->data, key->size, 0);
569b834536aSchristos return buf;
570b834536aSchristos }
571