pdb.c revision 99829
13125Sdg/* 23125Sdg * Copyright (c) 1994 Christopher G. Demetriou 33125Sdg * All rights reserved. 43125Sdg * 53125Sdg * Redistribution and use in source and binary forms, with or without 63125Sdg * modification, are permitted provided that the following conditions 73125Sdg * are met: 83125Sdg * 1. Redistributions of source code must retain the above copyright 93125Sdg * notice, this list of conditions and the following disclaimer. 103125Sdg * 2. Redistributions in binary form must reproduce the above copyright 113125Sdg * notice, this list of conditions and the following disclaimer in the 123125Sdg * documentation and/or other materials provided with the distribution. 133125Sdg * 3. All advertising materials mentioning features or use of this software 143125Sdg * must display the following acknowledgement: 153125Sdg * This product includes software developed by Christopher G. Demetriou. 163125Sdg * 4. The name of the author may not be used to endorse or promote products 173125Sdg * derived from this software without specific prior written permission 183125Sdg * 193125Sdg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 203125Sdg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 213125Sdg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 223125Sdg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 233125Sdg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 243125Sdg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 253125Sdg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 263125Sdg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 273125Sdg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 283125Sdg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 293125Sdg */ 303125Sdg 3130425Scharnier#ifndef lint 3230425Scharnierstatic const char rcsid[] = 3350479Speter "$FreeBSD: head/usr.sbin/sa/pdb.c 99829 2002-07-11 22:11:20Z alfred $"; 3430425Scharnier#endif /* not lint */ 353125Sdg 363125Sdg#include <sys/types.h> 373125Sdg#include <sys/acct.h> 383125Sdg#include <err.h> 393125Sdg#include <errno.h> 403125Sdg#include <fcntl.h> 413125Sdg#include <stdio.h> 4213558Smpp#include <string.h> 433125Sdg#include "extern.h" 443125Sdg#include "pathnames.h" 453125Sdg 463125Sdgstatic int check_junk __P((struct cmdinfo *)); 473125Sdgstatic void add_ci __P((const struct cmdinfo *, struct cmdinfo *)); 483125Sdgstatic void print_ci __P((const struct cmdinfo *, const struct cmdinfo *)); 493125Sdg 503125Sdgstatic DB *pacct_db; 513125Sdg 523125Sdgint 533125Sdgpacct_init() 543125Sdg{ 553125Sdg DB *saved_pacct_db; 563125Sdg int error; 573125Sdg 583125Sdg pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL); 593125Sdg if (pacct_db == NULL) 603125Sdg return (-1); 613125Sdg 623125Sdg error = 0; 633125Sdg if (!iflag) { 643125Sdg DBT key, data; 653125Sdg int serr, nerr; 663125Sdg 673125Sdg saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDONLY, 0, DB_BTREE, 683125Sdg NULL); 693125Sdg if (saved_pacct_db == NULL) { 703125Sdg error = errno == ENOENT ? 0 : -1; 713125Sdg if (error) 723125Sdg warn("retrieving process accounting summary"); 733125Sdg goto out; 743125Sdg } 753125Sdg 763125Sdg serr = DB_SEQ(saved_pacct_db, &key, &data, R_FIRST); 773125Sdg if (serr < 0) { 783125Sdg warn("retrieving process accounting summary"); 793125Sdg error = -1; 803125Sdg goto closeout; 813125Sdg } 823125Sdg while (serr == 0) { 833125Sdg nerr = DB_PUT(pacct_db, &key, &data, 0); 843125Sdg if (nerr < 0) { 853125Sdg warn("initializing process accounting stats"); 863125Sdg error = -1; 873125Sdg break; 883125Sdg } 893125Sdg 903125Sdg serr = DB_SEQ(saved_pacct_db, &key, &data, R_NEXT); 913125Sdg if (serr < 0) { 923125Sdg warn("retrieving process accounting summary"); 933125Sdg error = -1; 943125Sdg break; 953125Sdg } 963125Sdg } 973125Sdg 983125Sdgcloseout: if (DB_CLOSE(saved_pacct_db) < 0) { 993125Sdg warn("closing process accounting summary"); 1003125Sdg error = -1; 1013125Sdg } 1023125Sdg } 1033125Sdg 1043125Sdgout: if (error != 0) 1053125Sdg pacct_destroy(); 1063125Sdg return (error); 1073125Sdg} 1083125Sdg 1093125Sdgvoid 1103125Sdgpacct_destroy() 1113125Sdg{ 1123125Sdg if (DB_CLOSE(pacct_db) < 0) 1133125Sdg warn("destroying process accounting stats"); 1143125Sdg} 1153125Sdg 1163125Sdgint 1173125Sdgpacct_add(ci) 1183125Sdg const struct cmdinfo *ci; 1193125Sdg{ 1203125Sdg DBT key, data; 1213125Sdg struct cmdinfo newci; 1223125Sdg char keydata[sizeof ci->ci_comm]; 1233125Sdg int rv; 1243125Sdg 1253125Sdg bcopy(ci->ci_comm, &keydata, sizeof keydata); 1263125Sdg key.data = &keydata; 1273125Sdg key.size = strlen(keydata); 1283125Sdg 1293125Sdg rv = DB_GET(pacct_db, &key, &data, 0); 1303125Sdg if (rv < 0) { 1313125Sdg warn("get key %s from process accounting stats", ci->ci_comm); 1323125Sdg return (-1); 1333125Sdg } else if (rv == 0) { /* it's there; copy whole thing */ 1343125Sdg /* XXX compare size if paranoid */ 1353125Sdg /* add the old data to the new data */ 1363125Sdg bcopy(data.data, &newci, data.size); 1373125Sdg } else { /* it's not there; zero it and copy the key */ 1383125Sdg bzero(&newci, sizeof newci); 1393125Sdg bcopy(key.data, newci.ci_comm, key.size); 1403125Sdg } 1418857Srgrimes 1423125Sdg add_ci(ci, &newci); 1433125Sdg 1448857Srgrimes data.data = &newci; 1453125Sdg data.size = sizeof newci; 1463125Sdg rv = DB_PUT(pacct_db, &key, &data, 0); 1473125Sdg if (rv < 0) { 1483125Sdg warn("add key %s to process accounting stats", ci->ci_comm); 1493125Sdg return (-1); 1503125Sdg } else if (rv == 1) { 1513125Sdg warnx("duplicate key %s in process accounting stats", 1523125Sdg ci->ci_comm); 1533125Sdg return (-1); 1543125Sdg } 1553125Sdg 1563125Sdg return (0); 1573125Sdg} 1583125Sdg 1593125Sdgint 1603125Sdgpacct_update() 1613125Sdg{ 1623125Sdg DB *saved_pacct_db; 1633125Sdg DBT key, data; 1643125Sdg int error, serr, nerr; 1653125Sdg 1663125Sdg saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, 1673125Sdg DB_BTREE, NULL); 1683125Sdg if (saved_pacct_db == NULL) { 1693125Sdg warn("creating process accounting summary"); 1703125Sdg return (-1); 1713125Sdg } 1723125Sdg 1733125Sdg error = 0; 1743125Sdg 1753125Sdg serr = DB_SEQ(pacct_db, &key, &data, R_FIRST); 1763125Sdg if (serr < 0) { 1773125Sdg warn("retrieving process accounting stats"); 1783125Sdg error = -1; 1793125Sdg } 1803125Sdg while (serr == 0) { 1813125Sdg nerr = DB_PUT(saved_pacct_db, &key, &data, 0); 1823125Sdg if (nerr < 0) { 1833125Sdg warn("saving process accounting summary"); 1843125Sdg error = -1; 1853125Sdg break; 1863125Sdg } 1873125Sdg 1883125Sdg serr = DB_SEQ(pacct_db, &key, &data, R_NEXT); 1893125Sdg if (serr < 0) { 1903125Sdg warn("retrieving process accounting stats"); 1913125Sdg error = -1; 1923125Sdg break; 1933125Sdg } 1943125Sdg } 1953125Sdg 1963125Sdg if (DB_SYNC(saved_pacct_db, 0) < 0) { 1973125Sdg warn("syncing process accounting summary"); 1983125Sdg error = -1; 1993125Sdg } 2003125Sdg if (DB_CLOSE(saved_pacct_db) < 0) { 2013125Sdg warn("closing process accounting summary"); 2023125Sdg error = -1; 2033125Sdg } 2043125Sdg return error; 2053125Sdg} 2063125Sdg 2073125Sdgvoid 2083125Sdgpacct_print() 2093125Sdg{ 2103125Sdg BTREEINFO bti; 2113125Sdg DBT key, data, ndata; 2123125Sdg DB *output_pacct_db; 2133125Sdg struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk; 2143125Sdg int rv; 2153125Sdg 2163125Sdg bzero(&ci_total, sizeof ci_total); 2173125Sdg strcpy(ci_total.ci_comm, ""); 2183125Sdg bzero(&ci_other, sizeof ci_other); 2193125Sdg strcpy(ci_other.ci_comm, "***other"); 2203125Sdg bzero(&ci_junk, sizeof ci_junk); 2213125Sdg strcpy(ci_junk.ci_comm, "**junk**"); 2223125Sdg 2233125Sdg /* 2243125Sdg * Retrieve them into new DB, sorted by appropriate key. 2253125Sdg * At the same time, cull 'other' and 'junk' 2263125Sdg */ 2273125Sdg bzero(&bti, sizeof bti); 2283125Sdg bti.compare = sa_cmp; 2293125Sdg output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti); 2303125Sdg if (output_pacct_db == NULL) { 2313125Sdg warn("couldn't sort process accounting stats"); 2323125Sdg return; 2333125Sdg } 2343125Sdg 2353125Sdg ndata.data = NULL; 2363125Sdg ndata.size = 0; 2373125Sdg rv = DB_SEQ(pacct_db, &key, &data, R_FIRST); 2383125Sdg if (rv < 0) 2393125Sdg warn("retrieving process accounting stats"); 2403125Sdg while (rv == 0) { 2413125Sdg cip = (struct cmdinfo *) data.data; 2423125Sdg bcopy(cip, &ci, sizeof ci); 2433125Sdg 2443125Sdg /* add to total */ 2453125Sdg add_ci(&ci, &ci_total); 2463125Sdg 2473125Sdg if (vflag && ci.ci_calls <= cutoff && 2483125Sdg (fflag || check_junk(&ci))) { 2493125Sdg /* put it into **junk** */ 2503125Sdg add_ci(&ci, &ci_junk); 2513125Sdg goto next; 2523125Sdg } 2533125Sdg if (!aflag && 2543125Sdg ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) { 2553125Sdg /* put into ***other */ 2563125Sdg add_ci(&ci, &ci_other); 2573125Sdg goto next; 2583125Sdg } 2593125Sdg rv = DB_PUT(output_pacct_db, &data, &ndata, 0); 2603125Sdg if (rv < 0) 2613125Sdg warn("sorting process accounting stats"); 2623125Sdg 2633125Sdgnext: rv = DB_SEQ(pacct_db, &key, &data, R_NEXT); 2643125Sdg if (rv < 0) 2653125Sdg warn("retrieving process accounting stats"); 2663125Sdg } 2673125Sdg 2683125Sdg /* insert **junk** and ***other */ 2693125Sdg if (ci_junk.ci_calls != 0) { 2703125Sdg data.data = &ci_junk; 2713125Sdg data.size = sizeof ci_junk; 2723125Sdg rv = DB_PUT(output_pacct_db, &data, &ndata, 0); 2733125Sdg if (rv < 0) 2743125Sdg warn("sorting process accounting stats"); 2753125Sdg } 2763125Sdg if (ci_other.ci_calls != 0) { 2773125Sdg data.data = &ci_other; 2783125Sdg data.size = sizeof ci_other; 2793125Sdg rv = DB_PUT(output_pacct_db, &data, &ndata, 0); 2803125Sdg if (rv < 0) 2813125Sdg warn("sorting process accounting stats"); 2823125Sdg } 2833125Sdg 2843125Sdg /* print out the total */ 2853125Sdg print_ci(&ci_total, &ci_total); 2863125Sdg 2873125Sdg /* print out; if reversed, print first (smallest) first */ 2883125Sdg rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST); 2893125Sdg if (rv < 0) 2903125Sdg warn("retrieving process accounting report"); 2913125Sdg while (rv == 0) { 2923125Sdg cip = (struct cmdinfo *) data.data; 2933125Sdg bcopy(cip, &ci, sizeof ci); 2943125Sdg 2953125Sdg print_ci(&ci, &ci_total); 2963125Sdg 2973125Sdg rv = DB_SEQ(output_pacct_db, &data, &ndata, 2983125Sdg rflag ? R_NEXT : R_PREV); 2993125Sdg if (rv < 0) 3003125Sdg warn("retrieving process accounting report"); 3013125Sdg } 3023125Sdg DB_CLOSE(output_pacct_db); 3033125Sdg} 3043125Sdg 3053125Sdgstatic int 3063125Sdgcheck_junk(cip) 3073125Sdg struct cmdinfo *cip; 3083125Sdg{ 3093125Sdg char *cp; 3103125Sdg size_t len; 3113125Sdg 3123125Sdg fprintf(stderr, "%s (%qu) -- ", cip->ci_comm, cip->ci_calls); 3133125Sdg cp = fgetln(stdin, &len); 3143125Sdg 3153125Sdg return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0; 3163125Sdg} 3173125Sdg 3183125Sdgstatic void 3193125Sdgadd_ci(fromcip, tocip) 3203125Sdg const struct cmdinfo *fromcip; 3213125Sdg struct cmdinfo *tocip; 3223125Sdg{ 3233125Sdg tocip->ci_calls += fromcip->ci_calls; 3243125Sdg tocip->ci_etime += fromcip->ci_etime; 3253125Sdg tocip->ci_utime += fromcip->ci_utime; 3263125Sdg tocip->ci_stime += fromcip->ci_stime; 3273125Sdg tocip->ci_mem += fromcip->ci_mem; 3283125Sdg tocip->ci_io += fromcip->ci_io; 3293125Sdg} 3303125Sdg 3313125Sdgstatic void 3323125Sdgprint_ci(cip, totalcip) 3333125Sdg const struct cmdinfo *cip, *totalcip; 3343125Sdg{ 3353125Sdg double t, c; 3363125Sdg int uflow; 3373125Sdg 3383125Sdg c = cip->ci_calls ? cip->ci_calls : 1; 3393125Sdg t = (cip->ci_utime + cip->ci_stime) / (double) AHZ; 3403125Sdg if (t < 0.01) { 3413125Sdg t = 0.01; 3423125Sdg uflow = 1; 3433125Sdg } else 3443125Sdg uflow = 0; 3453125Sdg 3463125Sdg printf("%8qu ", cip->ci_calls); 3473125Sdg if (cflag) { 3483125Sdg if (cip != totalcip) 3493125Sdg printf(" %4.2f%% ", 3503125Sdg cip->ci_calls / (double) totalcip->ci_calls); 3513125Sdg else 3523125Sdg printf(" %4s ", ""); 3533125Sdg } 3543125Sdg 3553125Sdg if (jflag) 3563125Sdg printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c)); 3573125Sdg else 3583125Sdg printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ)); 3593125Sdg if (cflag) { 3603125Sdg if (cip != totalcip) 3613125Sdg printf(" %4.2f%% ", 3623125Sdg cip->ci_etime / (double) totalcip->ci_etime); 3633125Sdg else 3643125Sdg printf(" %4s ", ""); 3653125Sdg } 3663125Sdg 3673125Sdg if (!lflag) { 3683125Sdg if (jflag) 3693125Sdg printf("%11.2fcp ", t / (double) cip->ci_calls); 3703125Sdg else 3713125Sdg printf("%11.2fcp ", t / 60.0); 3723125Sdg if (cflag) { 3733125Sdg if (cip != totalcip) 3743125Sdg printf(" %4.2f%% ", 3753125Sdg (cip->ci_utime + cip->ci_stime) / (double) 3763125Sdg (totalcip->ci_utime + totalcip->ci_stime)); 3773125Sdg else 3783125Sdg printf(" %4s ", ""); 3793125Sdg } 3803125Sdg } else { 3813125Sdg if (jflag) 3823125Sdg printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c)); 3833125Sdg else 3843125Sdg printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ)); 3853125Sdg if (cflag) { 3863125Sdg if (cip != totalcip) 3873125Sdg printf(" %4.2f%% ", cip->ci_utime / (double) totalcip->ci_utime); 3883125Sdg else 3893125Sdg printf(" %4s ", ""); 3903125Sdg } 3913125Sdg if (jflag) 3923125Sdg printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c)); 3933125Sdg else 3943125Sdg printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ)); 3953125Sdg if (cflag) { 3963125Sdg if (cip != totalcip) 3973125Sdg printf(" %4.2f%% ", cip->ci_stime / (double) totalcip->ci_stime); 3983125Sdg else 3993125Sdg printf(" %4s ", ""); 4003125Sdg } 4013125Sdg } 4023125Sdg 40399829Salfred if (tflag) { 4043125Sdg if (!uflow) 40599829Salfred printf("%8.2fre/cp ", 40699829Salfred cip->ci_etime / 40799829Salfred (double) (cip->ci_utime + cip->ci_stime)); 4083125Sdg else 40913558Smpp printf("*ignore* "); 41099829Salfred } 4113125Sdg 4123125Sdg if (Dflag) 4133125Sdg printf("%10qutio ", cip->ci_io); 4143125Sdg else 4153125Sdg printf("%8.0favio ", cip->ci_io / c); 4163125Sdg 4173125Sdg if (Kflag) 4183125Sdg printf("%10quk*sec ", cip->ci_mem); 4193125Sdg else 4203125Sdg printf("%8.0fk ", cip->ci_mem / t); 4213125Sdg 4223125Sdg printf(" %s\n", cip->ci_comm); 4233125Sdg} 424