1 /* $NetBSD: pdb.c,v 1.12 2003/11/12 13:31:08 grant Exp $ */
4 * Copyright (c) 1994 Christopher G. Demetriou
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the
18 * NetBSD Project. See http://www.NetBSD.org/ for
19 * information about NetBSD.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
37 #include <sys/cdefs.h>
39 __RCSID("$NetBSD: pdb.c,v 1.12 2003/11/12 13:31:08 grant Exp $");
42 #include <sys/types.h>
50 #include "pathnames.h"
52 static int check_junk
__P((struct cmdinfo
*));
53 static void add_ci
__P((const struct cmdinfo
*, struct cmdinfo
*));
54 static void print_ci
__P((const struct cmdinfo
*, const struct cmdinfo
*));
65 pacct_db
= dbopen(NULL
, O_RDWR
|O_CREAT
|O_TRUNC
, 0644, DB_BTREE
, NULL
);
74 saved_pacct_db
= dbopen(_PATH_SAVACCT
, O_RDONLY
, 0, DB_BTREE
,
76 if (saved_pacct_db
== NULL
) {
77 error
= errno
== ENOENT
? 0 : -1;
79 warn("retrieving process accounting summary");
83 serr
= DB_SEQ(saved_pacct_db
, &key
, &data
, R_FIRST
);
85 warn("retrieving process accounting summary");
90 nerr
= DB_PUT(pacct_db
, &key
, &data
, R_NOOVERWRITE
);
92 warn("initializing process accounting stats");
97 warnx("duplicate key in `%s': %s",
98 _PATH_SAVACCT
, fmt(&key
));
100 warnx("too many duplicate keys;"
101 " `%s' possibly corrupted.",
108 serr
= DB_SEQ(saved_pacct_db
, &key
, &data
, R_NEXT
);
110 warn("retrieving process accounting summary");
116 closeout
: if (DB_CLOSE(saved_pacct_db
) < 0) {
117 warn("closing process accounting summary");
130 if (DB_CLOSE(pacct_db
) < 0)
131 warn("destroying process accounting stats");
136 const struct cmdinfo
*ci
;
139 struct cmdinfo newci
;
140 char keydata
[sizeof(ci
->ci_comm
)];
143 memcpy(&keydata
, ci
->ci_comm
, sizeof(keydata
));
145 key
.size
= strlen(keydata
);
147 rv
= DB_GET(pacct_db
, &key
, &data
, 0);
149 warn("get key %s from process accounting stats", ci
->ci_comm
);
151 } else if (rv
== 0) { /* it's there; copy whole thing */
152 /* XXX compare size if paranoid */
153 /* add the old data to the new data */
154 memcpy(&newci
, data
.data
, data
.size
);
155 } else { /* it's not there; zero it and copy the key */
156 memset(&newci
, 0, sizeof(newci
));
157 memcpy(newci
.ci_comm
, key
.data
, key
.size
);
163 data
.size
= sizeof(newci
);
164 rv
= DB_PUT(pacct_db
, &key
, &data
, 0);
166 warn("add key %s to process accounting stats", ci
->ci_comm
);
168 } else if (rv
== 1) {
169 warnx("duplicate key %s in process accounting stats",
182 int error
, serr
, nerr
;
184 saved_pacct_db
= dbopen(_PATH_SAVACCT
, O_RDWR
|O_CREAT
|O_TRUNC
, 0644,
186 if (saved_pacct_db
== NULL
) {
187 warn("creating process accounting summary");
193 serr
= DB_SEQ(pacct_db
, &key
, &data
, R_FIRST
);
195 warn("retrieving process accounting stats");
199 nerr
= DB_PUT(saved_pacct_db
, &key
, &data
, 0);
201 warn("saving process accounting summary");
206 serr
= DB_SEQ(pacct_db
, &key
, &data
, R_NEXT
);
208 warn("retrieving process accounting stats");
214 if (DB_SYNC(saved_pacct_db
, 0) < 0) {
215 warn("syncing process accounting summary");
218 if (DB_CLOSE(saved_pacct_db
) < 0) {
219 warn("closing process accounting summary");
229 DBT key
, data
, ndata
;
231 struct cmdinfo ci
, ci_total
, ci_other
, ci_junk
;
234 memset(&ci_total
, 0, sizeof(ci_total
));
235 strcpy(ci_total
.ci_comm
, "");
236 memset(&ci_other
, 0, sizeof(ci_other
));
237 strcpy(ci_other
.ci_comm
, "***other");
238 memset(&ci_junk
, 0, sizeof(ci_junk
));
239 strcpy(ci_junk
.ci_comm
, "**junk**");
242 * Retrieve them into new DB, sorted by appropriate key.
243 * At the same time, cull 'other' and 'junk'
245 memset(&bti
, 0, sizeof(bti
));
246 bti
.compare
= sa_cmp
;
247 output_pacct_db
= dbopen(NULL
, O_RDWR
, 0, DB_BTREE
, &bti
);
248 if (output_pacct_db
== NULL
) {
249 warn("couldn't sort process accounting stats");
255 rv
= DB_SEQ(pacct_db
, &key
, &data
, R_FIRST
);
257 warn("retrieving process accounting stats");
259 memcpy(&ci
, data
.data
, sizeof(ci
));
262 add_ci(&ci
, &ci_total
);
264 if (vflag
&& ci
.ci_calls
<= (unsigned)cutoff
&&
265 (fflag
|| check_junk(&ci
))) {
266 /* put it into **junk** */
267 add_ci(&ci
, &ci_junk
);
271 ((ci
.ci_flags
& CI_UNPRINTABLE
) != 0 || ci
.ci_calls
<= 1)) {
272 /* put into ***other */
273 add_ci(&ci
, &ci_other
);
276 rv
= DB_PUT(output_pacct_db
, &data
, &ndata
, 0);
278 warn("sorting process accounting stats");
280 next
: rv
= DB_SEQ(pacct_db
, &key
, &data
, R_NEXT
);
282 warn("retrieving process accounting stats");
285 /* insert **junk** and ***other */
286 if (ci_junk
.ci_calls
!= 0) {
287 data
.data
= &ci_junk
;
288 data
.size
= sizeof(ci_junk
);
289 rv
= DB_PUT(output_pacct_db
, &data
, &ndata
, 0);
291 warn("sorting process accounting stats");
293 if (ci_other
.ci_calls
!= 0) {
294 data
.data
= &ci_other
;
295 data
.size
= sizeof(ci_other
);
296 rv
= DB_PUT(output_pacct_db
, &data
, &ndata
, 0);
298 warn("sorting process accounting stats");
301 /* print out the total */
302 print_ci(&ci_total
, &ci_total
);
304 /* print out; if reversed, print first (smallest) first */
305 rv
= DB_SEQ(output_pacct_db
, &data
, &ndata
, rflag
? R_FIRST
: R_LAST
);
307 warn("retrieving process accounting report");
309 memcpy(&ci
, data
.data
, sizeof(ci
));
311 print_ci(&ci
, &ci_total
);
313 rv
= DB_SEQ(output_pacct_db
, &data
, &ndata
,
314 rflag
? R_NEXT
: R_PREV
);
316 warn("retrieving process accounting report");
318 DB_CLOSE(output_pacct_db
);
328 fprintf(stderr
, "%s (%llu) -- ", cip
->ci_comm
,
329 (unsigned long long)cip
->ci_calls
);
330 cp
= fgetln(stdin
, &len
);
332 return (cp
&& (cp
[0] == 'y' || cp
[0] == 'Y')) ? 1 : 0;
336 add_ci(fromcip
, tocip
)
337 const struct cmdinfo
*fromcip
;
338 struct cmdinfo
*tocip
;
340 tocip
->ci_calls
+= fromcip
->ci_calls
;
341 tocip
->ci_etime
+= fromcip
->ci_etime
;
342 tocip
->ci_utime
+= fromcip
->ci_utime
;
343 tocip
->ci_stime
+= fromcip
->ci_stime
;
344 tocip
->ci_mem
+= fromcip
->ci_mem
;
345 tocip
->ci_io
+= fromcip
->ci_io
;
349 print_ci(cip
, totalcip
)
350 const struct cmdinfo
*cip
, *totalcip
;
355 c
= cip
->ci_calls
? cip
->ci_calls
: 1;
356 t
= (cip
->ci_utime
+ cip
->ci_stime
) / (double) AHZ
;
363 printf("%8llu ", (unsigned long long)cip
->ci_calls
);
367 cip
->ci_calls
/ (double) totalcip
->ci_calls
);
373 printf("%11.2fre ", cip
->ci_etime
/ (double) (AHZ
* c
));
375 printf("%11.2fre ", cip
->ci_etime
/ (60.0 * AHZ
));
379 cip
->ci_etime
/ (double) totalcip
->ci_etime
);
386 printf("%11.2fcp ", t
/ (double) cip
->ci_calls
);
388 printf("%11.2fcp ", t
/ 60.0);
392 (cip
->ci_utime
+ cip
->ci_stime
) / (double)
393 (totalcip
->ci_utime
+ totalcip
->ci_stime
));
399 printf("%11.2fu ", cip
->ci_utime
/ (double) (AHZ
* c
));
401 printf("%11.2fu ", cip
->ci_utime
/ (60.0 * AHZ
));
404 printf(" %4.2f%% ", cip
->ci_utime
/ (double) totalcip
->ci_utime
);
409 printf("%11.2fs ", cip
->ci_stime
/ (double) (AHZ
* c
));
411 printf("%11.2fs ", cip
->ci_stime
/ (60.0 * AHZ
));
414 printf(" %4.2f%% ", cip
->ci_stime
/ (double) totalcip
->ci_stime
);
422 printf("%8.2fre/cp ", cip
->ci_etime
/ (double) (cip
->ci_utime
+ cip
->ci_stime
));
424 printf("%8s ", "*ignore*");
428 printf("%10llutio ", (unsigned long long)cip
->ci_io
);
430 printf("%8.0favio ", cip
->ci_io
/ c
);
433 printf("%10lluk*sec ", (unsigned long long)cip
->ci_mem
);
435 printf("%8.0fk ", cip
->ci_mem
/ t
);
437 printf(" %s\n", cip
->ci_comm
);