xref: /illumos-gate/usr/src/cmd/acct/acctcms.c (revision 4f364e7c95ee7fd9d5bbeddc1940e92405bb0e72)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /*
34  *	acctcms [-a] [-c] [-j] [-n] [-s] [-p] [-o] [-t] [file...]
35  *	summarize per-process accounting
36  *	-a	output in ascii, rather than [pt]cms.h format
37  *	-c	sort by total cpu, rather than total kcore-minutes
38  *	-j	anything used only once -> ***other
39  *	-n	sort by number of processes
40  *	-s	any following files already in pcms.h format
41  *      -p      output prime time command summary (only with -a)
42  *      -o      output non-prime time (offshift) command summary (only
43  *		with -a option)
44  *	-t	process records in total (old) style (tcms.h) format
45  *	file	file in [pt]cms.h (if -s seen already) or acct.h (if not)
46  *	expected use:
47  *	acctcms /var/adm/pacct? > today; acctcms -s old today >new
48  *	cp new old; rm new
49  *	acctcms -a today; acctcms -a old
50  */
51 #include <stdio.h>
52 #include <sys/types.h>
53 #include <sys/param.h>
54 #include "acctdef.h"
55 #include <ctype.h>
56 #include <string.h>
57 #include <sys/acct.h>
58 #include <stdlib.h>
59 
60 int	csize = CSIZE;
61 
62 /*
63  *  Total cms records format
64  */
65 struct tcms {
66 	char	tcm_comm[8];	/* command name */
67 	long	tcm_pc;		/* number of processes */
68 	float	tcm_cpu;	/* cpu time(min) */
69 	float	tcm_real;	/* real time(min) */
70 	float	tcm_kcore;	/* kcore-minutes */
71 	ulong_t	tcm_io;		/* chars transferred */
72 	ulong_t	tcm_rw;		/* blocks read */
73 } ;
74 struct tcms	*tcm;
75 /*
76  * prime/nonprime CMS record format
77  */
78 struct pcms {
79 	char	pcm_comm[8];	/* command name */
80 	long	pcm_pc[2];	/* number of processes */
81 	float	pcm_cpu[2];	/* cpu time(min) */
82 	float	pcm_real[2];	/* real time(min) */
83 	float	pcm_kcore[2];	/* kcore-minutes */
84 	float	pcm_io[2];	/* chars transferred */
85 	float	pcm_rw[2];	/* blocks read */
86 } ;
87 struct pcms	*pcm;
88 struct  tcms    tcmtmp  = {{'*','*','*','o','t','h','e','r'}};
89 struct  pcms    pcmtmp  = {{'*','*','*','o','t','h','e','r'}};
90 int	aflg;
91 int	cflg;
92 int	jflg;
93 int	nflg;
94 int	sflg;
95 int	pflg;
96 int	oflg;
97 int	tflg;
98 int	errflg;
99 
100 #ifdef uts
101 float   expand();
102 #else
103 ulong_t	expand();
104 #endif
105 
106 void outputc(void);
107 void totprnt(struct pcms *);
108 void pprint(struct pcms *);
109 void prnt(struct pcms *, int);
110 void print(struct pcms *);
111 void outputa(void);
112 void toutptc(void);
113 void tprint(struct tcms *);
114 void toutpta(void);
115 int ncmp(struct pcms *, struct pcms *);
116 int tncmp(struct tcms *, struct tcms *);
117 int tccmp(struct tcms *, struct tcms *);
118 int tkcmp(struct tcms *, struct tcms *);
119 int ccmp(struct pcms *, struct pcms *);
120 int kcmp(struct pcms *, struct pcms *);
121 void tdofile(char *);
122 void dofile(char *);
123 void tfixjunk(void);
124 void fixjunk(void);
125 void tcmadd(struct tcms *, struct tcms *);
126 void pcmadd(struct pcms *, struct pcms *);
127 void tsqueeze(void);
128 void squeeze(void);
129 
130 /*  Format specification for ASCII printing */
131 
132 char	*fmtcmd =	"%-8.8s",
133 	*fmtcnt =	"%8ld",
134 	*fmtkcore =	" %11.2f",
135 	*fmtcpu =	" %9.2f",
136 	*fmtreal =	" %12.2f",
137 	*fmtmsz =	" %7.2f",
138 	*fmtmcpu =	" %6.2f",
139 	*fmthog =	" %5.2f",
140 	*fmtcharx =	" %12.0f",
141 	*fmtblkx =	" %10.0f" ;
142 
143 int
144 main(int argc, char **argv)
145 {
146 	int	c;
147 
148 	while((c = getopt(argc, argv, "acjnspot")) != EOF)
149 	switch(c) {
150 		case 'a':
151 			aflg++;
152 			continue;
153 		case 'c':
154 			cflg++;
155 			continue;
156 		case 'j':
157 			jflg++;
158 			continue;
159 		case 'n':
160 			nflg++;
161 			continue;
162 		case 's':
163 			sflg++;
164 			continue;
165 		case 'p':
166 			pflg++;
167 			continue;
168 		case 'o':
169 			oflg++;
170 			continue;
171 		case 't':
172 			tflg++;
173 			continue;
174 		default:
175 			errflg++;
176 			continue;
177 	}
178 	if(errflg){
179 		fprintf(stderr, "Usage: %s [-acjnspot] [file ...]\n", argv[0]);
180 		exit(1);
181 	}
182 	if(tflg) {
183 		if( (tcm = (struct tcms *)calloc(CSIZE, sizeof(struct tcms))) == NULL) {
184 			fprintf(stderr, "%s: Cannot allocate memory\n", argv[0]);
185 			exit(5);
186 		}
187 		for(; optind < argc; optind++)
188 			tdofile(argv[optind]);
189 		if (jflg)
190 			tfixjunk();
191 		tsqueeze();
192 		qsort(tcm, csize, sizeof(tcm[0]),
193 		    (int (*)(const void *, const void *))
194 		     ( nflg ? tncmp: (cflg? tccmp: tkcmp)));
195 		if (aflg)
196 			toutpta();
197 		else
198 			toutptc();
199 	} else {
200 		if( (pcm = (struct pcms *)calloc(CSIZE, sizeof(struct pcms))) == NULL) {
201 			fprintf(stderr, "%s: Cannot allocate memory\n", argv[0]);
202 			exit(6);
203 		}
204 		for(; optind < argc; optind++)
205 			dofile(argv[optind]);
206 		if (jflg)
207 			fixjunk();
208 		squeeze();
209 		qsort(pcm, csize, sizeof(pcm[0]),
210 		    (int (*)(const void *, const void *))
211 		    (nflg? ncmp: (cflg? ccmp: kcmp)));
212 		if (aflg)
213 			outputa();
214 		else
215 			outputc();
216 	}
217 	exit(0);
218 
219 }
220 
221 void
222 tdofile(char *fname)
223 {
224 	struct tcms cmt;
225 	union {
226 		struct acct ab;		/* SVR4 acct structure */
227 		struct o_acct oab;	/* SVR3 acct structure */
228 	} acct;
229 	int ver = 0;
230 	ulong_t	mem;
231 	ulong_t	cpu;
232 	ulong_t	real;
233 
234 	if (freopen(fname, "r", stdin) == NULL) {
235 		fprintf(stderr,  "acctcms: cannot open %s\n", fname);
236 		return;
237 	}
238 
239 	if (sflg)
240 		while (fread(&cmt, sizeof(cmt), 1, stdin) == 1)
241 			tenter(&cmt);
242 	else {
243 		if (fread(&acct.ab, sizeof(acct.ab), 1, stdin) == 1)
244 			/* check for expanded account structure flag */
245 			if (acct.ab.ac_flag & AEXPND)
246 				ver = 2;		/* 4.0 acct file */
247 			else
248 				ver = 1;		/* SVR3.x acct file */
249 
250 		rewind(stdin);	/* reset file pointer */
251 
252  		switch(ver) {
253 
254 		default:
255 				/* this can't happen */
256 			fprintf(stderr, "acctcms: encountered bad version number\n");
257 			return;
258 		case 1 :
259 			while (fread(&acct.oab, sizeof(acct.oab), 1, stdin) == 1) {
260 				CPYN(cmt.tcm_comm, acct.oab.ac_comm);
261 				cmt.tcm_pc = 1;
262 				cpu = expand(acct.oab.ac_stime)+
263 					expand(acct.oab.ac_utime);
264 				cmt.tcm_cpu = MINT(cpu);
265 				real = expand(acct.oab.ac_etime);
266 				cmt.tcm_real = MINT(real);
267 				mem = expand(acct.oab.ac_mem);
268 				cmt.tcm_kcore = MINT(KCORE(mem));
269 				cmt.tcm_io = expand(acct.oab.ac_io);
270 				cmt.tcm_rw = expand(acct.oab.ac_rw);
271 				tenter(&cmt);
272 			}
273 			break;
274 		case 2 :
275 
276 			while (fread(&acct.ab, sizeof(acct.ab), 1, stdin) == 1) {
277 				CPYN(cmt.tcm_comm, acct.ab.ac_comm);
278 				cmt.tcm_pc = 1;
279 				cpu = expand(acct.oab.ac_stime)+
280 					expand(acct.oab.ac_utime);
281 				cmt.tcm_cpu = MINT(cpu);
282 				real = expand(acct.ab.ac_etime);
283 				cmt.tcm_real = MINT(real);
284 				mem = expand(acct.ab.ac_mem);
285 				cmt.tcm_kcore = MINT(KCORE(mem));
286 				cmt.tcm_io = expand(acct.ab.ac_io);
287 				cmt.tcm_rw = expand(acct.ab.ac_rw);
288 				tenter(&cmt);
289 			}
290 			break;
291 		}
292 	}
293 }
294 
295 void
296 dofile(char *fname)
297 {
298 	union {
299 		struct acct ab;
300 		struct o_acct oab;
301 	} acct;
302 	struct pcms 	pcmt;
303 	double		ratio;
304 	long		elaps[2];
305 	ulong_t		etime;
306 	double	dtmp;
307 	unsigned long	ltmp;
308 	ulong_t	mem;
309 	ulong_t	cpu;
310 	ulong_t	real;
311 
312 	if (freopen(fname, "r", stdin) == NULL) {
313 		fprintf(stderr,  "acctcms: cannot open %s\n", fname);
314 		return;
315 	}
316 
317 	if (sflg)
318 		while (fread(&pcmt, sizeof(pcmt), 1, stdin) == 1)
319 			enter(&pcmt);
320 	else {
321 		int ver = 0;
322 
323 		if (fread(&acct.ab, sizeof(acct.ab), 1, stdin) == 1)
324 			/* check for expanded account structure flag */
325 			if (acct.ab.ac_flag & AEXPND)
326 				ver = 2;		/* 4.0 acct file */
327 			else
328 				ver = 1;		/* SVR3.x acct file */
329 
330 		rewind(stdin);	/* reset file pointer */
331 
332 		switch(ver) {
333 
334 		default :
335  				/* this can't happen */
336 			fprintf(stderr, "acctcms: encountered bad version number\n");
337 			return;
338 		case 1 :
339 
340 			while (fread(&acct.oab, sizeof(acct.oab), 1, stdin) == 1) {
341 				CPYN(pcmt.pcm_comm, acct.oab.ac_comm);
342 			/*
343 			** Approximate P/NP split as same as elapsed time
344 		 	*/
345 				if((etime = SECS(expand(acct.oab.ac_etime))) == 0)
346 					etime = 1;
347 				if (pnpsplit(acct.oab.ac_btime, etime, elaps)
348 				    == 0) {
349 					(void) fprintf(stderr, "acctcms: could "
350 					    "not calculate prime/non-prime "
351 					    "hours\n");
352 					exit(1);
353 				}
354 				ratio = (double)elaps[PRIME]/(double)etime;
355 				if(elaps[PRIME] > elaps[NONPRIME]) {
356 					pcmt.pcm_pc[PRIME] = 1;
357 					pcmt.pcm_pc[NONPRIME] = 0;
358 				} else {
359 					pcmt.pcm_pc[PRIME] = 0;
360 					pcmt.pcm_pc[NONPRIME] = 1;
361 				}
362 				cpu = expand(acct.oab.ac_stime)+
363 					expand(acct.oab.ac_utime);
364 				dtmp = MINT(cpu);
365 				pcmt.pcm_cpu[PRIME] = dtmp * ratio;
366 				pcmt.pcm_cpu[NONPRIME] = (ratio == 1.0) ? 0.0 :
367 					(dtmp - pcmt.pcm_cpu[PRIME]);
368 				real = expand(acct.oab.ac_etime);
369 				dtmp = MINT(real);
370 				pcmt.pcm_real[PRIME] = dtmp * ratio;
371 				pcmt.pcm_real[NONPRIME] = (ratio == 1.0) ? 0.0 :
372 					(dtmp - pcmt.pcm_real[PRIME]);
373 				mem = expand(acct.oab.ac_mem);
374 				dtmp = MINT(KCORE(mem));
375 				pcmt.pcm_kcore[PRIME] = dtmp * ratio;
376 				pcmt.pcm_kcore[NONPRIME] = (ratio == 1.0) ? 0.0 :
377 					(dtmp - pcmt.pcm_kcore[PRIME]);
378 				ltmp = expand(acct.oab.ac_io);
379 				pcmt.pcm_io[PRIME] = (double)ltmp * ratio;
380 				pcmt.pcm_io[NONPRIME] = (ratio == 1.0) ? 0.0 :
381 					((double)ltmp - pcmt.pcm_io[PRIME]);
382 				ltmp = expand(acct.oab.ac_rw);
383 				pcmt.pcm_rw[PRIME] = (double)ltmp * ratio;
384 				pcmt.pcm_rw[NONPRIME] = (ratio == 1.0) ? 0.0 :
385 					((double)ltmp - pcmt.pcm_rw[PRIME]);
386 				enter(&pcmt);
387 			}
388 
389 			break;
390 		case 2 :
391 			while (fread(&acct.ab, sizeof(acct.ab), 1, stdin) == 1) {
392 				CPYN(pcmt.pcm_comm, acct.ab.ac_comm);
393 				/*
394 				** Approximate P/NP split as same as elapsed time
395 		 		*/
396 				if((etime = SECS(expand(acct.ab.ac_etime))) == 0)
397 					etime = 1;
398 				if(pnpsplit(acct.ab.ac_btime, etime, elaps) == 0) {
399 					fprintf(stderr, "acctcms: could not calculate prime/non-prime hours\n");
400 					exit(1);
401 				}
402 				ratio = (double)elaps[PRIME]/(double)etime;
403 				if(elaps[PRIME] > elaps[NONPRIME]) {
404 					pcmt.pcm_pc[PRIME] = 1;
405 					pcmt.pcm_pc[NONPRIME] = 0;
406 				} else {
407 					pcmt.pcm_pc[PRIME] = 0;
408 					pcmt.pcm_pc[NONPRIME] = 1;
409 				}
410 				cpu = expand(acct.ab.ac_stime)+
411 					expand(acct.ab.ac_utime);
412 				dtmp = MINT(cpu);
413 				pcmt.pcm_cpu[PRIME] = dtmp * ratio;
414 				pcmt.pcm_cpu[NONPRIME] = (ratio == 1.0) ? 0.0 :
415 					(dtmp - pcmt.pcm_cpu[PRIME]);
416 				real = expand(acct.ab.ac_etime);
417 				dtmp = MINT(real);
418 				pcmt.pcm_real[PRIME] = dtmp * ratio;
419 				pcmt.pcm_real[NONPRIME] = (ratio == 1.0) ? 0.0 :
420 					(dtmp - pcmt.pcm_real[PRIME]);
421 				mem = expand(acct.ab.ac_mem);
422 				dtmp = MINT(KCORE(mem));
423 				pcmt.pcm_kcore[PRIME] = dtmp * ratio;
424 				pcmt.pcm_kcore[NONPRIME] = (ratio == 1.0) ? 0.0 :
425 					(dtmp - pcmt.pcm_kcore[PRIME]);
426 				ltmp = expand(acct.ab.ac_io);
427 				pcmt.pcm_io[PRIME] = (double)ltmp * ratio;
428 				pcmt.pcm_io[NONPRIME] = (ratio == 1.0) ? 0.0 :
429 					((double)ltmp - pcmt.pcm_io[PRIME]);
430 				ltmp = expand(acct.ab.ac_rw);
431 				pcmt.pcm_rw[PRIME] = (double)ltmp * ratio;
432 				pcmt.pcm_rw[NONPRIME] = (ratio == 1.0) ? 0.0 :
433 					((double)ltmp - pcmt.pcm_rw[PRIME]);
434 				enter(&pcmt);
435 			}
436 
437 			break;
438 		}
439 	}
440 }
441 
442 int
443 tenter(struct tcms *p)
444 {
445 	int i;
446 	int j;
447 	struct tcms *ntcm;
448 	for (i = j = 0; j < sizeof(p->tcm_comm); j++) {
449 		if (p->tcm_comm[j] && p->tcm_comm[j] <= 037)
450 			p->tcm_comm[j] = '?';
451 		i = i*7 + p->tcm_comm[j];	/* hash function */
452 	}
453 	if (i < 0)
454 		i = -i;
455 	for (i %= csize, j = 0; tcm[i].tcm_comm[0] && j != csize; i = (i+1)%csize, j++)
456 		if (EQN(p->tcm_comm, tcm[i].tcm_comm))
457 			break;
458 	if(j == csize) {
459 		if ((ntcm = (struct tcms *) realloc(tcm,
460 			(csize + CSIZE - 1) * sizeof (struct tcms))) == NULL) {
461 			fprintf(stderr,
462 				"acctcms: Cannot reallocate memory (tcm)\n");
463 			return(-1);
464 		} else {
465 			memset(&ntcm[csize], 0, CSIZE - 1);
466 			tcm = ntcm;
467 			if (!EQN(p->tcm_comm, tcm[i].tcm_comm))
468 				i = csize;
469 			csize = csize + CSIZE - 1;
470 		}
471 	}
472 	if (tcm[i].tcm_comm[0] == 0)
473 		CPYN(tcm[i].tcm_comm, p->tcm_comm);
474 	tcmadd(&tcm[i], p);
475 	return(i);
476 }
477 
478 int
479 enter(struct pcms *p)
480 {
481 	int i;
482 	int j;
483 	struct pcms *npcm;
484 	for (i = j = 0; j < sizeof(p->pcm_comm); j++) {
485 		if (p->pcm_comm[j] && p->pcm_comm[j] <= 037)
486 			p->pcm_comm[j] = '?';
487 		i = i*7 + p->pcm_comm[j];	/* hash function */
488 	}
489 	if (i < 0)
490 		i = -i;
491 	for (i %= csize, j = 0; pcm[i].pcm_comm[0] && j != csize; i = (i+1)%csize, j++)
492 		if (EQN(p->pcm_comm, pcm[i].pcm_comm))
493 			break;
494 	if(j == csize) {
495 		if ((npcm = (struct pcms *) realloc(pcm,
496 			(csize + CSIZE - 1) * sizeof (struct pcms))) == NULL) {
497 			fprintf(stderr,
498 				"acctcms: Cannot reallocate memory (pcm)\n");
499 			return(-1);
500 		} else {
501 			memset(&npcm[csize], 0, CSIZE - 1);
502 			pcm = npcm;
503 			if (!EQN(p->pcm_comm, pcm[i].pcm_comm))
504 				i = csize;
505 			csize = csize + CSIZE - 1;
506 		}
507 	}
508 	if (pcm[i].pcm_comm[0] == 0)
509 		CPYN(pcm[i].pcm_comm, p->pcm_comm);
510 	pcmadd(&pcm[i], p);
511 	return(i);
512 }
513 
514 void
515 tfixjunk(void)	/* combine commands used only once */
516 {
517 	int i, j;
518 	j = tenter(&tcmtmp);
519 	for (i = 0; i < csize; i++)
520 		if (i != j && tcm[i].tcm_comm[0] && tcm[i].tcm_pc <= 1) {
521 			tcmadd(&tcm[j], &tcm[i]);
522 			tcm[i].tcm_comm[0] = 0;
523 		}
524 }
525 
526 void
527 fixjunk(void)	/* combine commands used only once */
528 {
529 	int i, j;
530 	j = enter(&pcmtmp);
531 	for (i = 0; i < csize; i++)
532 		if (i != j && pcm[i].pcm_comm[0] && (pcm[i].pcm_pc[PRIME] + pcm[i].pcm_pc[NONPRIME]) <= 1) {
533 			pcmadd(&pcm[j], &pcm[i]);
534 			pcm[i].pcm_comm[0] = 0;
535 		}
536 }
537 
538 void
539 tcmadd(struct tcms *p1, struct tcms *p2)
540 {
541 	p1->tcm_pc += p2->tcm_pc;
542 	p1->tcm_cpu = p1->tcm_cpu + p2->tcm_cpu;
543 	p1->tcm_real = p1->tcm_real + p2->tcm_real;
544 	p1->tcm_kcore = p1->tcm_kcore + p2->tcm_kcore;
545 	p1->tcm_io += p2->tcm_io;
546 	p1->tcm_rw += p2->tcm_rw;
547 }
548 
549 void
550 pcmadd(struct pcms *p1, struct pcms *p2)
551 {
552 	p1->pcm_pc[PRIME] += p2->pcm_pc[PRIME];
553 	p1->pcm_pc[NONPRIME] += p2->pcm_pc[NONPRIME];
554 	p1->pcm_cpu[PRIME] += p2->pcm_cpu[PRIME];
555 	p1->pcm_cpu[NONPRIME] += p2->pcm_cpu[NONPRIME];
556 	p1->pcm_real[PRIME] += p2->pcm_real[PRIME];
557 	p1->pcm_real[NONPRIME] += p2->pcm_real[NONPRIME];
558 	p1->pcm_kcore[PRIME] += p2->pcm_kcore[PRIME];
559 	p1->pcm_kcore[NONPRIME] += p2->pcm_kcore[NONPRIME];
560 	p1->pcm_io[PRIME] += p2->pcm_io[PRIME];
561 	p1->pcm_io[NONPRIME] += p2->pcm_io[NONPRIME];
562 	p1->pcm_rw[PRIME] += p2->pcm_rw[PRIME];
563 	p1->pcm_rw[NONPRIME] += p2->pcm_rw[NONPRIME];
564 }
565 
566 void
567 tsqueeze(void)	/* get rid of holes in hash table */
568 {
569 	int i, k;
570 
571 	for (i = k = 0; i < csize; i++)
572 		if (tcm[i].tcm_comm[0]) {
573 			CPYN(tcm[k].tcm_comm, tcm[i].tcm_comm);
574 			tcm[k].tcm_pc = tcm[i].tcm_pc;
575 			tcm[k].tcm_cpu = tcm[i].tcm_cpu;
576 			tcm[k].tcm_real = tcm[i].tcm_real;
577 			tcm[k].tcm_kcore = tcm[i].tcm_kcore;
578 			tcm[k].tcm_io = tcm[i].tcm_io;
579 			tcm[k].tcm_rw = tcm[i].tcm_rw;
580 			k++;
581 		}
582 	csize = k;
583 }
584 
585 void
586 squeeze(void)	/* get rid of holes in hash table */
587 {
588 	int i, k;
589 
590 	for (i = k = 0; i < csize; i++)
591 		if (pcm[i].pcm_comm[0]) {
592 			CPYN(pcm[k].pcm_comm, pcm[i].pcm_comm);
593 			pcm[k].pcm_pc[PRIME] = pcm[i].pcm_pc[PRIME];
594 			pcm[k].pcm_pc[NONPRIME] = pcm[i].pcm_pc[NONPRIME];
595 			pcm[k].pcm_cpu[PRIME] = pcm[i].pcm_cpu[PRIME];
596 			pcm[k].pcm_cpu[NONPRIME] = pcm[i].pcm_cpu[NONPRIME];
597 			pcm[k].pcm_real[PRIME] = pcm[i].pcm_real[PRIME];
598 			pcm[k].pcm_real[NONPRIME] = pcm[i].pcm_real[NONPRIME];
599 			pcm[k].pcm_kcore[PRIME] = pcm[i].pcm_kcore[PRIME];
600 			pcm[k].pcm_kcore[NONPRIME] = pcm[i].pcm_kcore[NONPRIME];
601 			pcm[k].pcm_io[PRIME] = pcm[i].pcm_io[PRIME];
602 			pcm[k].pcm_io[NONPRIME] = pcm[i].pcm_io[NONPRIME];
603 			pcm[k].pcm_rw[PRIME] = pcm[i].pcm_rw[PRIME];
604 			pcm[k].pcm_rw[NONPRIME] = pcm[i].pcm_rw[NONPRIME];
605 			k++;
606 		}
607 	csize = k;
608 }
609 
610 int
611 tccmp(struct tcms *p1, struct tcms *p2)
612 {
613 	if (p1->tcm_cpu == p2->tcm_cpu)
614 		return(0);
615 	return ((p2->tcm_cpu > p1->tcm_cpu)? 1 : -1);
616 }
617 
618 int
619 ccmp(struct pcms *p1, struct pcms *p2)
620 {
621 	int	index;
622 
623 	if( (pflg && oflg) || (!pflg && !oflg) ) {
624 		if (p1->pcm_cpu[PRIME] + p1->pcm_cpu[NONPRIME] == p2->pcm_cpu[PRIME] + p2->pcm_cpu[NONPRIME])
625 			return(0);
626 		return ((p2->pcm_cpu[PRIME] + p2->pcm_cpu[NONPRIME] > p1->pcm_cpu[PRIME] + p1->pcm_cpu[NONPRIME])? 1 : -1);
627 	}
628 	index = pflg ? PRIME : NONPRIME;
629 	if (p1->pcm_cpu[index] == p2->pcm_cpu[index])
630 		return(0);
631 	return ((p2->pcm_cpu[index] > p1->pcm_cpu[index])? 1 : -1);
632 }
633 
634 int
635 tkcmp(struct tcms *p1, struct tcms *p2)
636 {
637 	if (p1->tcm_kcore == p2->tcm_kcore)
638 		return(0);
639 	return ((p2->tcm_kcore > p1->tcm_kcore)? 1 : -1);
640 }
641 
642 int
643 kcmp(struct pcms *p1, struct pcms *p2)
644 {
645 	int	index;
646 
647 	if( (pflg && oflg) || (!pflg && !pflg) ){
648 		if (p1->pcm_kcore[PRIME] + p1->pcm_kcore[NONPRIME] == p2->pcm_kcore[PRIME] + p2->pcm_kcore[NONPRIME])
649 			return(0);
650 		return ((p2->pcm_kcore[PRIME] + p2->pcm_kcore[NONPRIME] > p1->pcm_kcore[PRIME] + p1->pcm_kcore[NONPRIME])? 1 : -1);
651 	}
652 	index = pflg ? PRIME : NONPRIME;
653 	if (p1->pcm_kcore[index] == p2->pcm_kcore[index])
654 		return(0);
655 	return ((p2->pcm_kcore[index] > p1->pcm_kcore[index])? 1 : -1);
656 }
657 
658 int
659 tncmp(struct tcms *p1, struct tcms *p2)
660 {
661 	if (p1->tcm_pc == p2->tcm_pc)
662 		return(0);
663 	return ((p2->tcm_pc > p1->tcm_pc)? 1 : -1);
664 }
665 
666 int
667 ncmp(struct pcms *p1, struct pcms *p2)
668 {
669 	int	index;
670 
671 	if( (pflg && oflg) || (!pflg && !oflg) ) {
672 		if (p1->pcm_pc[PRIME] + p1->pcm_pc[NONPRIME] == p2->pcm_pc[PRIME] + p2->pcm_pc[NONPRIME])
673 			return(0);
674 		return ((p2->pcm_pc[PRIME] + p2->pcm_pc[NONPRIME] > p1->pcm_pc[PRIME] + p1->pcm_pc[NONPRIME])? 1 : -1);
675 	}
676 	index =  pflg ? PRIME : NONPRIME;
677 	if (p1->pcm_pc[index] == p2->pcm_pc[index])
678 		return(0);
679 	return ((p2->pcm_pc[index] > p1->pcm_pc[index])? 1 : -1);
680 }
681 
682 char	thd1[] =
683 "COMMAND   NUMBER      TOTAL       TOTAL       TOTAL   MEAN     MEAN     HOG      CHARS        BLOCKS\n";
684 char	thd2[] =
685 "NAME        CMDS    KCOREMIN     CPU-MIN     REAL-MIN SIZE-K  CPU-MIN  FACTOR   TRNSFD         READ\n";
686 
687 void
688 toutpta(void)
689 {
690 	int i;
691 
692 	printf(thd1);
693 	printf(thd2);
694 	printf("\n");
695 	for (i = 0; i < csize; i++)
696 		tcmadd(&tcmtmp, &tcm[i]);
697 	CPYN(tcmtmp.tcm_comm, "TOTALS");
698 	tprint(&tcmtmp);
699 	printf("\n");
700 	for (i = 0; i < csize; i++)
701 		tprint(&tcm[i]);
702 }
703 
704 void
705 tprint(struct tcms *p)
706 {
707 	printf("%-8.8s", p->tcm_comm);
708 	printf(" %7ld", p->tcm_pc);
709 	printf(" %11.2f", p->tcm_kcore);
710 	printf(" %10.2f", p->tcm_cpu);
711 	printf(" %12.2f", p->tcm_real);
712 	if(p->tcm_cpu == 0)  p->tcm_cpu = 1;
713 	printf(" %6.2f", p->tcm_kcore/p->tcm_cpu);
714 	if(p->tcm_pc == 0)  p->tcm_pc = 1;
715 	printf(" %7.2f", p->tcm_cpu/p->tcm_pc);
716 	if (p->tcm_real == 0)
717 		p->tcm_real = 1;
718 	printf(" %8.2f", p->tcm_cpu/p->tcm_real);
719 	printf(" %11lu", p->tcm_io);
720 	printf(" %11lu\n", p->tcm_rw);
721 }
722 
723 void
724 toutptc(void)
725 {
726 	int i;
727 
728 	for (i = 0; i < csize; i++)
729 		fwrite(&tcm[i], sizeof(tcm[i]), 1, stdout);
730 }
731 
732 char	hd1[] =
733 "COMMAND   NUMBER      TOTAL       TOTAL       TOTAL   MEAN    MEAN     HOG         CHARS     BLOCKS\n";
734 char	hd2[] =
735 "NAME        CMDS    KCOREMIN     CPU-MIN   REAL-MIN  SIZE-K  CPU-MIN  FACTOR      TRNSFD      READ\n";
736 char	hd3[] =
737 "COMMAND        NUMBER         TOTAL          CPU-MIN                 REAL-MIN        MEAN    MEAN      HOG       CHARS       BLOCKS\n";
738 char	hd4[] =
739 "NAME         (P)    (NP)   KCOREMIN       (P)      (NP)          (P)         (NP)  SIZE-K  CPU-MIN   FACTOR     TRNSFD        READ\n";
740 char	hdprime[] =
741 "                                   PRIME TIME COMMAND SUMMARY\n";
742 char	hdnonprime[] =
743 "                                  NON-PRIME TIME COMMAND SUMMARY\n";
744 char	hdtot[] =
745 "                                     TOTAL COMMAND SUMMARY\n";
746 char	hdp[] =
747 "                                PRIME/NON-PRIME TIME COMMAND SUMMARY\n";
748 
749 void
750 outputa(void)
751 {
752 	int i;
753 
754 	if( pflg && oflg ) printf(hdp);
755 	else if(pflg) printf(hdprime);
756 	else if(oflg) printf(hdnonprime);
757 	else printf(hdtot);
758 	if( (!pflg && !oflg) || (pflg ^ oflg)) {
759 		printf(hd1);
760 		printf(hd2);
761 	}
762 	else {
763 		printf(hd3);
764 		printf(hd4);
765 	}
766 	printf("\n");
767 	for (i = 0; i < csize; i++)
768 		pcmadd(&pcmtmp, &pcm[i]);
769 	CPYN(pcmtmp.pcm_comm, "TOTALS");
770 	print(&pcmtmp);
771 	printf("\n");
772 	for (i = 0; i < csize; i++)
773 		print(&pcm[i]);
774 }
775 
776 void
777 print(struct pcms *p)
778 {
779 	if(pflg && oflg) pprint(p);
780 	else if(pflg || oflg) prnt(p, pflg ? PRIME : NONPRIME);
781 	else totprnt(p);
782 }
783 
784 void
785 prnt(struct pcms *p, int hr)
786 {
787 	if(p->pcm_pc[hr] == 0) return;
788 	printf(fmtcmd, p->pcm_comm);
789 	printf(fmtcnt, p->pcm_pc[hr]);
790 	printf(fmtkcore, p->pcm_kcore[hr]);
791 	printf(fmtcpu, p->pcm_cpu[hr]);
792 	printf(fmtreal, p->pcm_real[hr]);
793 	if(p->pcm_cpu[hr] == 0)  p->pcm_cpu[hr] = 1;
794 	printf(fmtmsz, p->pcm_kcore[hr]/p->pcm_cpu[hr]);
795 	if(p->pcm_pc[hr] == 0)  p->pcm_pc[hr] = 1;
796 	printf(fmtmcpu, p->pcm_cpu[hr]/p->pcm_pc[hr]);
797 	if (p->pcm_real[hr] == 0)
798 		p->pcm_real[hr] = 1;
799 	printf(fmthog, p->pcm_cpu[hr]/p->pcm_real[hr]);
800 	printf(fmtcharx,p->pcm_io[hr]);
801 	printf(fmtblkx,p->pcm_rw[hr]);
802 	printf("\n");
803 }
804 
805 void
806 pprint(struct pcms *p)
807 {
808 	printf(fmtcmd, p->pcm_comm);
809 	printf(fmtcnt, p->pcm_pc[PRIME]);
810 	printf(fmtcnt, p->pcm_pc[NONPRIME]);
811 	printf(fmtkcore, TOTAL(p->pcm_kcore));
812 	printf(fmtcpu, p->pcm_cpu[PRIME]);
813 	printf(fmtcpu, p->pcm_cpu[NONPRIME]);
814 	printf(fmtreal, p->pcm_real[PRIME]);
815 	printf(fmtreal, p->pcm_real[NONPRIME]);
816 	if(TOTAL(p->pcm_cpu) == 0)  p->pcm_cpu[PRIME] = 1;
817 	printf(fmtmsz, TOTAL(p->pcm_kcore)/TOTAL(p->pcm_cpu));
818 	if(TOTAL(p->pcm_pc) == 0)  p->pcm_pc[PRIME] = 1;
819 	printf(fmtmcpu, TOTAL(p->pcm_cpu)/TOTAL(p->pcm_pc));
820 	if ( TOTAL(p->pcm_real) == 0)
821 		p->pcm_real[PRIME] = 1;
822 	printf(fmthog, TOTAL(p->pcm_cpu)/TOTAL(p->pcm_real));
823 	printf(fmtcharx,TOTAL(p->pcm_io));
824 	printf(fmtblkx, TOTAL(p->pcm_rw));
825 	printf("\n");
826 }
827 
828 void
829 totprnt(struct pcms *p)
830 {
831 	printf(fmtcmd, p->pcm_comm);
832 	printf(fmtcnt, TOTAL(p->pcm_pc));
833 	printf(fmtkcore, TOTAL(p->pcm_kcore));
834 	printf(fmtcpu, TOTAL(p->pcm_cpu));
835 	printf(fmtreal, TOTAL(p->pcm_real));
836 	if(TOTAL(p->pcm_cpu) == 0)  p->pcm_cpu[PRIME] = 1;
837 	printf(fmtmsz, TOTAL(p->pcm_kcore)/TOTAL(p->pcm_cpu));
838 	if(TOTAL(p->pcm_pc) == 0)  p->pcm_pc[PRIME] = 1;
839 	printf(fmtmcpu, TOTAL(p->pcm_cpu)/TOTAL(p->pcm_pc));
840 	if (TOTAL(p->pcm_real) == 0)
841 		p->pcm_real[PRIME] = 1;
842 	printf(fmthog, TOTAL(p->pcm_cpu)/TOTAL(p->pcm_real));
843 	printf(fmtcharx,TOTAL(p->pcm_io));
844 	printf(fmtblkx,TOTAL(p->pcm_rw));
845 	printf("\n");
846 }
847 
848 void
849 outputc(void)
850 {
851 	int i;
852 
853 	for (i = 0; i < csize; i++)
854 		fwrite(&pcm[i], sizeof(pcm[i]), 1, stdout);
855 }
856