pdb.c revision 3125
11592Srgrimes/* 21592Srgrimes * Copyright (c) 1994 Christopher G. Demetriou 31592Srgrimes * All rights reserved. 41592Srgrimes * 51592Srgrimes * Redistribution and use in source and binary forms, with or without 61592Srgrimes * modification, are permitted provided that the following conditions 71592Srgrimes * are met: 81592Srgrimes * 1. Redistributions of source code must retain the above copyright 91592Srgrimes * notice, this list of conditions and the following disclaimer. 101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111592Srgrimes * notice, this list of conditions and the following disclaimer in the 121592Srgrimes * documentation and/or other materials provided with the distribution. 131592Srgrimes * 3. All advertising materials mentioning features or use of this software 141592Srgrimes * must display the following acknowledgement: 151592Srgrimes * This product includes software developed by Christopher G. Demetriou. 161592Srgrimes * 4. The name of the author may not be used to endorse or promote products 171592Srgrimes * derived from this software without specific prior written permission 181592Srgrimes * 191592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 201592Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 211592Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 221592Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 231592Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 241592Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 251592Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 261592Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 271592Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 281592Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 291592Srgrimes */ 301592Srgrimes 311592Srgrimes#ifndef LINT 321592Srgrimesstatic char rcsid[] = "$Id: pdb.c,v 1.1 1994/03/24 18:41:54 cgd Exp $"; 331592Srgrimes#endif 341592Srgrimes 351592Srgrimes#include <sys/types.h> 361592Srgrimes#include <sys/acct.h> 371592Srgrimes#include <err.h> 381592Srgrimes#include <errno.h> 391592Srgrimes#include <fcntl.h> 401592Srgrimes#include <stdio.h> 411592Srgrimes#include "extern.h" 421592Srgrimes#include "pathnames.h" 431592Srgrimes 441592Srgrimesstatic int check_junk __P((struct cmdinfo *)); 451592Srgrimesstatic void add_ci __P((const struct cmdinfo *, struct cmdinfo *)); 461592Srgrimesstatic void print_ci __P((const struct cmdinfo *, const struct cmdinfo *)); 471592Srgrimes 481592Srgrimesstatic DB *pacct_db; 491592Srgrimes 501592Srgrimesint 511592Srgrimespacct_init() 521592Srgrimes{ 531592Srgrimes DB *saved_pacct_db; 541592Srgrimes int error; 551592Srgrimes 561592Srgrimes pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL); 571592Srgrimes if (pacct_db == NULL) 581592Srgrimes return (-1); 591592Srgrimes 601592Srgrimes error = 0; 611592Srgrimes if (!iflag) { 621592Srgrimes DBT key, data; 631592Srgrimes int serr, nerr; 641592Srgrimes 651592Srgrimes saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDONLY, 0, DB_BTREE, 661592Srgrimes NULL); 671592Srgrimes if (saved_pacct_db == NULL) { 681592Srgrimes error = errno == ENOENT ? 0 : -1; 691592Srgrimes if (error) 701592Srgrimes warn("retrieving process accounting summary"); 711592Srgrimes goto out; 721592Srgrimes } 731592Srgrimes 741592Srgrimes serr = DB_SEQ(saved_pacct_db, &key, &data, R_FIRST); 751592Srgrimes if (serr < 0) { 761592Srgrimes warn("retrieving process accounting summary"); 771592Srgrimes error = -1; 781592Srgrimes goto closeout; 791592Srgrimes } 801592Srgrimes while (serr == 0) { 811592Srgrimes nerr = DB_PUT(pacct_db, &key, &data, 0); 821592Srgrimes if (nerr < 0) { 831592Srgrimes warn("initializing process accounting stats"); 841592Srgrimes error = -1; 851592Srgrimes break; 861592Srgrimes } 871592Srgrimes 881592Srgrimes serr = DB_SEQ(saved_pacct_db, &key, &data, R_NEXT); 891592Srgrimes if (serr < 0) { 901592Srgrimes warn("retrieving process accounting summary"); 911592Srgrimes error = -1; 921592Srgrimes break; 931592Srgrimes } 941592Srgrimes } 951592Srgrimes 961592Srgrimescloseout: if (DB_CLOSE(saved_pacct_db) < 0) { 971592Srgrimes warn("closing process accounting summary"); 981592Srgrimes error = -1; 991592Srgrimes } 1001592Srgrimes } 1011592Srgrimes 1021592Srgrimesout: if (error != 0) 1031592Srgrimes pacct_destroy(); 1041592Srgrimes return (error); 1051592Srgrimes} 1061592Srgrimes 1071592Srgrimesvoid 1081592Srgrimespacct_destroy() 1091592Srgrimes{ 1101592Srgrimes if (DB_CLOSE(pacct_db) < 0) 1111592Srgrimes warn("destroying process accounting stats"); 1121592Srgrimes} 1131592Srgrimes 1141592Srgrimesint 1151592Srgrimespacct_add(ci) 1161592Srgrimes const struct cmdinfo *ci; 1171592Srgrimes{ 1181592Srgrimes DBT key, data; 1191592Srgrimes struct cmdinfo newci; 1201592Srgrimes char keydata[sizeof ci->ci_comm]; 1211592Srgrimes int rv; 1221592Srgrimes 1231592Srgrimes bcopy(ci->ci_comm, &keydata, sizeof keydata); 1241592Srgrimes key.data = &keydata; 1251592Srgrimes key.size = strlen(keydata); 1261592Srgrimes 1271592Srgrimes rv = DB_GET(pacct_db, &key, &data, 0); 1281592Srgrimes if (rv < 0) { 1291592Srgrimes warn("get key %s from process accounting stats", ci->ci_comm); 1301592Srgrimes return (-1); 1311592Srgrimes } else if (rv == 0) { /* it's there; copy whole thing */ 1321592Srgrimes /* XXX compare size if paranoid */ 1331592Srgrimes /* add the old data to the new data */ 1341592Srgrimes bcopy(data.data, &newci, data.size); 1351592Srgrimes } else { /* it's not there; zero it and copy the key */ 1361592Srgrimes bzero(&newci, sizeof newci); 1371592Srgrimes bcopy(key.data, newci.ci_comm, key.size); 1381592Srgrimes } 1391592Srgrimes 1401592Srgrimes add_ci(ci, &newci); 1411592Srgrimes 1421592Srgrimes data.data = &newci; 1431592Srgrimes data.size = sizeof newci; 1441592Srgrimes rv = DB_PUT(pacct_db, &key, &data, 0); 1451592Srgrimes if (rv < 0) { 1461592Srgrimes warn("add key %s to process accounting stats", ci->ci_comm); 1471592Srgrimes return (-1); 1481592Srgrimes } else if (rv == 1) { 1491592Srgrimes warnx("duplicate key %s in process accounting stats", 1501592Srgrimes ci->ci_comm); 1511592Srgrimes return (-1); 1521592Srgrimes } 1531592Srgrimes 1541592Srgrimes return (0); 1551592Srgrimes} 1561592Srgrimes 1571592Srgrimesint 1581592Srgrimespacct_update() 1591592Srgrimes{ 1601592Srgrimes DB *saved_pacct_db; 1611592Srgrimes DBT key, data; 1621592Srgrimes int error, serr, nerr; 1631592Srgrimes 1641592Srgrimes saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, 1651592Srgrimes DB_BTREE, NULL); 1661592Srgrimes if (saved_pacct_db == NULL) { 1671592Srgrimes warn("creating process accounting summary"); 1681592Srgrimes return (-1); 1691592Srgrimes } 1701592Srgrimes 1711592Srgrimes error = 0; 1721592Srgrimes 1731592Srgrimes serr = DB_SEQ(pacct_db, &key, &data, R_FIRST); 1741592Srgrimes if (serr < 0) { 1751592Srgrimes warn("retrieving process accounting stats"); 1761592Srgrimes error = -1; 1771592Srgrimes } 1781592Srgrimes while (serr == 0) { 1791592Srgrimes nerr = DB_PUT(saved_pacct_db, &key, &data, 0); 1801592Srgrimes if (nerr < 0) { 1811592Srgrimes warn("saving process accounting summary"); 1821592Srgrimes error = -1; 1831592Srgrimes break; 1841592Srgrimes } 1851592Srgrimes 1861592Srgrimes serr = DB_SEQ(pacct_db, &key, &data, R_NEXT); 1871592Srgrimes if (serr < 0) { 1881592Srgrimes warn("retrieving process accounting stats"); 1891592Srgrimes error = -1; 1901592Srgrimes break; 1911592Srgrimes } 1921592Srgrimes } 1931592Srgrimes 1941592Srgrimes if (DB_SYNC(saved_pacct_db, 0) < 0) { 1951592Srgrimes warn("syncing process accounting summary"); 1961592Srgrimes error = -1; 1971592Srgrimes } 1981592Srgrimes if (DB_CLOSE(saved_pacct_db) < 0) { 1991592Srgrimes warn("closing process accounting summary"); 2001592Srgrimes error = -1; 2011592Srgrimes } 2021592Srgrimes return error; 2031592Srgrimes} 2041592Srgrimes 2051592Srgrimesvoid 2061592Srgrimespacct_print() 2071592Srgrimes{ 2081592Srgrimes BTREEINFO bti; 2091592Srgrimes DBT key, data, ndata; 2101592Srgrimes DB *output_pacct_db; 2111592Srgrimes struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk; 2121592Srgrimes int rv; 2131592Srgrimes 2141592Srgrimes bzero(&ci_total, sizeof ci_total); 2151592Srgrimes strcpy(ci_total.ci_comm, ""); 2161592Srgrimes bzero(&ci_other, sizeof ci_other); 2171592Srgrimes strcpy(ci_other.ci_comm, "***other"); 2181592Srgrimes bzero(&ci_junk, sizeof ci_junk); 2191592Srgrimes strcpy(ci_junk.ci_comm, "**junk**"); 2201592Srgrimes 2211592Srgrimes /* 2221592Srgrimes * Retrieve them into new DB, sorted by appropriate key. 2231592Srgrimes * At the same time, cull 'other' and 'junk' 2241592Srgrimes */ 2251592Srgrimes bzero(&bti, sizeof bti); 2261592Srgrimes bti.compare = sa_cmp; 2271592Srgrimes output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti); 2281592Srgrimes if (output_pacct_db == NULL) { 2291592Srgrimes warn("couldn't sort process accounting stats"); 2301592Srgrimes return; 2311592Srgrimes } 2321592Srgrimes 2331592Srgrimes ndata.data = NULL; 2341592Srgrimes ndata.size = 0; 2351592Srgrimes rv = DB_SEQ(pacct_db, &key, &data, R_FIRST); 2361592Srgrimes if (rv < 0) 2371592Srgrimes warn("retrieving process accounting stats"); 2381592Srgrimes while (rv == 0) { 2391592Srgrimes cip = (struct cmdinfo *) data.data; 2401592Srgrimes bcopy(cip, &ci, sizeof ci); 2411592Srgrimes 2421592Srgrimes /* add to total */ 2431592Srgrimes add_ci(&ci, &ci_total); 2441592Srgrimes 2451592Srgrimes if (vflag && ci.ci_calls <= cutoff && 2461592Srgrimes (fflag || check_junk(&ci))) { 2471592Srgrimes /* put it into **junk** */ 2481592Srgrimes add_ci(&ci, &ci_junk); 2491592Srgrimes goto next; 2501592Srgrimes } 2511592Srgrimes if (!aflag && 2521592Srgrimes ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) { 2531592Srgrimes /* put into ***other */ 2541592Srgrimes add_ci(&ci, &ci_other); 2551592Srgrimes goto next; 2561592Srgrimes } 2571592Srgrimes rv = DB_PUT(output_pacct_db, &data, &ndata, 0); 2581592Srgrimes if (rv < 0) 2591592Srgrimes warn("sorting process accounting stats"); 2601592Srgrimes 2611592Srgrimesnext: rv = DB_SEQ(pacct_db, &key, &data, R_NEXT); 2621592Srgrimes if (rv < 0) 2631592Srgrimes warn("retrieving process accounting stats"); 2641592Srgrimes } 2651592Srgrimes 2661592Srgrimes /* insert **junk** and ***other */ 2671592Srgrimes if (ci_junk.ci_calls != 0) { 2681592Srgrimes data.data = &ci_junk; 2691592Srgrimes data.size = sizeof ci_junk; 2701592Srgrimes rv = DB_PUT(output_pacct_db, &data, &ndata, 0); 2711592Srgrimes if (rv < 0) 2721592Srgrimes warn("sorting process accounting stats"); 2731592Srgrimes } 2741592Srgrimes if (ci_other.ci_calls != 0) { 2751592Srgrimes data.data = &ci_other; 2761592Srgrimes data.size = sizeof ci_other; 2771592Srgrimes rv = DB_PUT(output_pacct_db, &data, &ndata, 0); 2781592Srgrimes if (rv < 0) 2791592Srgrimes warn("sorting process accounting stats"); 2801592Srgrimes } 2811592Srgrimes 2821592Srgrimes /* print out the total */ 2831592Srgrimes print_ci(&ci_total, &ci_total); 2841592Srgrimes 2851592Srgrimes /* print out; if reversed, print first (smallest) first */ 2861592Srgrimes rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST); 2871592Srgrimes if (rv < 0) 2881592Srgrimes warn("retrieving process accounting report"); 2891592Srgrimes while (rv == 0) { 2901592Srgrimes cip = (struct cmdinfo *) data.data; 2911592Srgrimes bcopy(cip, &ci, sizeof ci); 2921592Srgrimes 2931592Srgrimes print_ci(&ci, &ci_total); 2941592Srgrimes 2951592Srgrimes rv = DB_SEQ(output_pacct_db, &data, &ndata, 2961592Srgrimes rflag ? R_NEXT : R_PREV); 2971592Srgrimes if (rv < 0) 2981592Srgrimes warn("retrieving process accounting report"); 2991592Srgrimes } 3001592Srgrimes DB_CLOSE(output_pacct_db); 3011592Srgrimes} 3021592Srgrimes 3031592Srgrimesstatic int 3041592Srgrimescheck_junk(cip) 3051592Srgrimes struct cmdinfo *cip; 3061592Srgrimes{ 3071592Srgrimes char *cp; 3081592Srgrimes size_t len; 3091592Srgrimes 3101592Srgrimes fprintf(stderr, "%s (%qu) -- ", cip->ci_comm, cip->ci_calls); 3111592Srgrimes cp = fgetln(stdin, &len); 3121592Srgrimes 3131592Srgrimes return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0; 3141592Srgrimes} 3151592Srgrimes 3161592Srgrimesstatic void 3171592Srgrimesadd_ci(fromcip, tocip) 3181592Srgrimes const struct cmdinfo *fromcip; 3191592Srgrimes struct cmdinfo *tocip; 3201592Srgrimes{ 3211592Srgrimes tocip->ci_calls += fromcip->ci_calls; 3221592Srgrimes tocip->ci_etime += fromcip->ci_etime; 3231592Srgrimes tocip->ci_utime += fromcip->ci_utime; 3241592Srgrimes tocip->ci_stime += fromcip->ci_stime; 3251592Srgrimes tocip->ci_mem += fromcip->ci_mem; 3261592Srgrimes tocip->ci_io += fromcip->ci_io; 3271592Srgrimes} 3281592Srgrimes 3291592Srgrimesstatic void 3301592Srgrimesprint_ci(cip, totalcip) 3311592Srgrimes const struct cmdinfo *cip, *totalcip; 3321592Srgrimes{ 3331592Srgrimes double t, c; 3341592Srgrimes int uflow; 3351592Srgrimes 3361592Srgrimes c = cip->ci_calls ? cip->ci_calls : 1; 3371592Srgrimes t = (cip->ci_utime + cip->ci_stime) / (double) AHZ; 3381592Srgrimes if (t < 0.01) { 3391592Srgrimes t = 0.01; 3401592Srgrimes uflow = 1; 3411592Srgrimes } else 3421592Srgrimes uflow = 0; 3431592Srgrimes 3441592Srgrimes printf("%8qu ", cip->ci_calls); 3451592Srgrimes if (cflag) { 3461592Srgrimes if (cip != totalcip) 3471592Srgrimes printf(" %4.2f%% ", 3481592Srgrimes cip->ci_calls / (double) totalcip->ci_calls); 3491592Srgrimes else 3501592Srgrimes printf(" %4s ", ""); 3511592Srgrimes } 3521592Srgrimes 3531592Srgrimes if (jflag) 3541592Srgrimes printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c)); 3551592Srgrimes else 3561592Srgrimes printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ)); 3571592Srgrimes if (cflag) { 3581592Srgrimes if (cip != totalcip) 3591592Srgrimes printf(" %4.2f%% ", 3601592Srgrimes cip->ci_etime / (double) totalcip->ci_etime); 3611592Srgrimes else 3621592Srgrimes printf(" %4s ", ""); 3631592Srgrimes } 3641592Srgrimes 3651592Srgrimes if (!lflag) { 3661592Srgrimes if (jflag) 3671592Srgrimes printf("%11.2fcp ", t / (double) cip->ci_calls); 3681592Srgrimes else 3691592Srgrimes printf("%11.2fcp ", t / 60.0); 3701592Srgrimes if (cflag) { 3711592Srgrimes if (cip != totalcip) 3721592Srgrimes printf(" %4.2f%% ", 3731592Srgrimes (cip->ci_utime + cip->ci_stime) / (double) 3741592Srgrimes (totalcip->ci_utime + totalcip->ci_stime)); 3751592Srgrimes else 3761592Srgrimes printf(" %4s ", ""); 3771592Srgrimes } 3781592Srgrimes } else { 3791592Srgrimes if (jflag) 3801592Srgrimes printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c)); 3811592Srgrimes else 3821592Srgrimes printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ)); 3831592Srgrimes if (cflag) { 3841592Srgrimes if (cip != totalcip) 3851592Srgrimes printf(" %4.2f%% ", cip->ci_utime / (double) totalcip->ci_utime); 3861592Srgrimes else 3871592Srgrimes printf(" %4s ", ""); 3881592Srgrimes } 3891592Srgrimes if (jflag) 3901592Srgrimes printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c)); 3911592Srgrimes else 3921592Srgrimes printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ)); 3931592Srgrimes if (cflag) { 3941592Srgrimes if (cip != totalcip) 3951592Srgrimes printf(" %4.2f%% ", cip->ci_stime / (double) totalcip->ci_stime); 3961592Srgrimes else 3971592Srgrimes printf(" %4s ", ""); 3981592Srgrimes } 3991592Srgrimes } 4001592Srgrimes 4011592Srgrimes if (tflag) 4021592Srgrimes if (!uflow) 4031592Srgrimes printf("%8.2fre/cp ", cip->ci_etime / (double) (cip->ci_utime + cip->ci_stime)); 4041592Srgrimes else 4051592Srgrimes printf("%8 ", "*ignore*"); 4061592Srgrimes 4071592Srgrimes if (Dflag) 4081592Srgrimes printf("%10qutio ", cip->ci_io); 4091592Srgrimes else 4101592Srgrimes printf("%8.0favio ", cip->ci_io / c); 4111592Srgrimes 4121592Srgrimes if (Kflag) 4131592Srgrimes printf("%10quk*sec ", cip->ci_mem); 4141592Srgrimes else 4151592Srgrimes printf("%8.0fk ", cip->ci_mem / t); 4161592Srgrimes 4171592Srgrimes printf(" %s\n", cip->ci_comm); 4181592Srgrimes} 4191592Srgrimes