4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
31 * sar generates a report either from an input data file or by invoking sadc to
32 * read system activity counters at the specified intervals.
34 * usage: sar [-ubdycwaqvmpgrkA] [-o file] t [n]
35 * sar [-ubdycwaqvmpgrkA][-s hh:mm][-e hh:mm][-i ss][-f file]
38 #include <sys/param.h>
40 #include <sys/sysinfo.h>
42 #include <sys/types.h>
43 #include <sys/utsname.h>
60 #define PGTOBLK(x) ((x) * (pagesize >> 9))
61 #define BLKTOPG(x) ((x) / (pagesize >> 9))
62 #define BLKS(x) ((x) >> 9)
64 static void prpass(int);
65 static void prtopt(void);
66 static void prtavg(void);
67 static void prttim(void);
68 static void prtmachid(void);
69 static void prthdg(void);
70 static void tsttab(void);
71 static void update_counters(void);
72 static void usage(void);
73 static void fail(int, char *, ...);
74 static void safe_zalloc(void **, int, int);
75 static int safe_read(int, void *, size_t);
76 static void safe_write(int, void *, size_t);
77 static int safe_strtoi(char const *, char *);
78 static void ulong_delta(uint64_t *, uint64_t *, uint64_t *, uint64_t *,
80 static float denom(float);
81 static float freq(float, float);
83 static struct sa64 nx
, ox
, ax
, dx
;
84 static iodevinfo_t
*nxio
, *oxio
, *axio
, *dxio
;
85 static struct tm
*curt
, args
, arge
;
87 static int sflg
, eflg
, iflg
, oflg
, fflg
;
88 static int realtime
, passno
= 0, do_disk
;
89 static int t
= 0, n
= 0, lines
= 0;
93 static char options
[30], fopt
[30];
94 static float tdiff
, sec_diff
, totsec_diff
= 0.0, percent
;
95 static float start_time
, end_time
, isec
;
98 static int pipedes
[2];
99 static char arg1
[10], arg2
[10];
103 * To avoid overflow in the kmem allocation data, declare a copy of the
104 * main kmeminfo_t type with larger data types. Use this for storing
105 * the data held to display average values
107 static struct kmeminfo_l
109 u_longlong_t km_mem
[KMEM_NCLASS
];
110 u_longlong_t km_alloc
[KMEM_NCLASS
];
111 u_longlong_t km_fail
[KMEM_NCLASS
];
115 main(int argc
, char **argv
)
117 char flnm
[PATH_MAX
], ofile
[PATH_MAX
];
122 pagesize
= sysconf(_SC_PAGESIZE
);
125 * Process options with arguments and pack options
128 while ((i
= getopt(argc
, argv
, "ubdycwaqvmpgrkAo:s:e:i:f:")) != EOF
)
129 switch (ccc
= (char)i
) {
132 if (strlcpy(ofile
, optarg
, sizeof (ofile
)) >=
134 fail(2, "-o filename is too long: %s", optarg
);
138 if (sscanf(optarg
, "%d:%d:%d",
139 &args
.tm_hour
, &args
.tm_min
, &args
.tm_sec
) < 1)
140 fail(0, "-%c %s -- illegal option argument",
144 start_time
= args
.tm_hour
*3600.0 +
150 if (sscanf(optarg
, "%d:%d:%d",
151 &arge
.tm_hour
, &arge
.tm_min
, &arge
.tm_sec
) < 1)
152 fail(0, "-%c %s -- illegal option argument",
156 end_time
= arge
.tm_hour
*3600.0 +
162 if (sscanf(optarg
, "%f", &isec
) < 1)
163 fail(0, "-%c %s -- illegal option argument",
172 if (strlcpy(flnm
, optarg
, sizeof (flnm
)) >=
174 fail(2, "-f filename is too long: %s", optarg
);
184 * Check for repeated options. To make sure
185 * that options[30] does not overflow.
187 if (strchr(options
, ccc
) == NULL
)
188 (void) strncat(options
, &ccc
, 1);
193 * Are starting and ending times consistent?
195 if ((sflg
) && (eflg
) && (end_time
<= start_time
))
196 fail(0, "ending time <= starting time");
199 * Determine if t and n arguments are given, and whether to run in real
200 * time or from a file.
202 switch (argc
- optind
) {
203 case 0: /* Get input data from file */
206 curt
= localtime(&temp
);
207 (void) snprintf(flnm
, PATH_MAX
, "/var/log/sa/sa%.2d",
210 if ((fin
= open(flnm
, O_RDONLY
)) == -1)
211 fail(1, "can't open %s", flnm
);
213 case 1: /* Real time data; one cycle */
215 t
= safe_strtoi(argv
[optind
], "invalid sampling interval");
218 case 2: /* Real time data; specified cycles */
221 t
= safe_strtoi(argv
[optind
], "invalid sampling interval");
222 n
= 1 + safe_strtoi(argv
[optind
+1], "invalid sample count");
227 * "u" is the default option, which displays CPU utilization.
229 if (strlen(options
) == 0)
230 (void) strcpy(options
, "u");
233 * "A" means all data options.
235 if (strchr(options
, 'A') != NULL
)
236 (void) strcpy(options
, "udqbwcayvmpgrk");
240 * Get input data from sadc via pipe.
243 fail(0, "sampling interval t <= 0 sec");
245 fail(0, "number of sample intervals n <= 0");
246 (void) sprintf(arg1
, "%d", t
);
247 (void) sprintf(arg2
, "%d", n
);
248 if (pipe(pipedes
) == -1)
249 fail(1, "pipe failed");
250 if ((childid
= fork()) == 0) {
252 * Child: shift pipedes[write] to stdout,
253 * and close the pipe entries.
255 (void) dup2(pipedes
[1], 1);
257 (void) close(pipedes
[0]);
259 (void) close(pipedes
[1]);
261 if (execlp("/usr/lib/sa/sadc",
262 "/usr/lib/sa/sadc", arg1
, arg2
, 0) == -1)
263 fail(1, "exec of /usr/lib/sa/sadc failed");
264 } else if (childid
== -1) {
265 fail(1, "Could not fork to exec sadc");
268 * Parent: close unused output.
271 (void) close(pipedes
[1]);
275 if (strcmp(ofile
, flnm
) == 0)
276 fail(0, "output file name same as input file name");
277 fout
= creat(ofile
, 00644);
280 hz
= sysconf(_SC_CLK_TCK
);
282 nxio
= oxio
= dxio
= axio
= NULL
;
286 * Make single pass, processing all options.
288 (void) strcpy(fopt
, options
);
291 (void) kill(childid
, SIGINT
);
295 * Make multiple passes, one for each option.
297 while (strlen(strncpy(fopt
, &options
[jj
++], 1))) {
298 if (lseek(fin
, 0, SEEK_SET
) == (off_t
)-1)
299 fail(0, "lseek failed");
309 * Convert array of 32-bit uints to 64-bit uints
312 convert_32to64(uint64_t *dst
, uint_t
*src
, int size
)
314 for (; size
> 0; size
--)
315 *dst
++ = (uint64_t)(*src
++);
319 * Convert array of 64-bit uints to 32-bit uints
322 convert_64to32(uint_t
*dst
, uint64_t *src
, int size
)
324 for (; size
> 0; size
--)
325 *dst
++ = (uint32_t)(*src
++);
329 * Read records from input, classify, and decide on printing.
332 prpass(int input_pipe
)
335 int i
, j
, state_change
, recno
= 0;
337 float trec
, tnext
= 0;
338 ulong_t old_niodevs
= 0, prev_niodevs
= 0;
339 iodevinfo_t
*aio
, *dio
, *oio
;
342 uint64_t ts
, te
; /* time interval start and end */
344 do_disk
= (strchr(fopt
, 'd') != NULL
);
345 if (!input_pipe
&& fstat(fin
, &in_stat
) == -1)
346 fail(1, "unable to stat data file");
351 while (safe_read(fin
, &tx
, sizeof (struct sa
))) {
353 * First, we convert 32-bit tx to 64-bit nx structure
354 * which is used later. Conversion could be done
355 * after initial operations, right before calculations,
356 * but it would introduce additional juggling with vars.
357 * Thus, we convert all data now, and don't care about
362 convert_32to64((uint64_t *)&nx
.csi
, (uint_t
*)&tx
.csi
,
363 sizeof (tx
.csi
) / sizeof (uint_t
));
364 convert_32to64((uint64_t *)&nx
.cvmi
, (uint_t
*)&tx
.cvmi
,
365 sizeof (tx
.cvmi
) / sizeof (uint_t
));
366 convert_32to64((uint64_t *)&nx
.si
, (uint_t
*)&tx
.si
,
367 sizeof (tx
.si
) / sizeof (uint_t
));
368 (void) memcpy(&nx
.vmi
, &tx
.vmi
,
369 sizeof (tx
) - (((char *)&tx
.vmi
) - ((char *)&tx
)));
371 * sadc is the only utility used to generate sar data
372 * and it uses the valid field as follows:
375 * We can use this fact to improve sar's ability to detect
376 * bad data, since any value apart from 0 or 1 can be
377 * interpreted as invalid data.
379 if (nx
.valid
!= 0 && nx
.valid
!= 1)
380 fail(2, "data file not in sar format");
382 niodevs
= nx
.niodevs
;
384 * niodevs has the value of current number of devices
387 * The following 'if' condition is to decide whether memory
388 * has to be allocated or not if already allocated memory is
389 * bigger or smaller than memory needed to store the current
390 * niodevs details in memory.
392 * when first while loop starts, pre_niodevs has 0 and then
393 * always get initialized to the current number of devices
394 * from nx.niodevs if it is different from previously read
397 * if the current niodevs has the same value of previously
398 * allocated memory i.e, for prev_niodevs, it skips the
399 * following 'if' loop or otherwise it allocates memory for
400 * current devises (niodevs) and stores that value in
401 * prev_niodevs for next time when loop continues to read
404 if (niodevs
!= prev_niodevs
) {
407 * The required buffer size must fit in a size_t.
409 if (SIZE_MAX
/ sizeof (iodevinfo_t
) < niodevs
)
410 fail(2, "insufficient address space to hold "
411 "%lu device records", niodevs
);
412 size
= niodevs
* sizeof (iodevinfo_t
);
413 prev_niodevs
= niodevs
;
415 * The data file must exceed this size to be valid.
418 if ((curr_pos
= lseek(fin
, 0, SEEK_CUR
)) ==
420 fail(1, "lseek failed");
421 if (in_stat
.st_size
< curr_pos
||
422 size
> in_stat
.st_size
- curr_pos
)
423 fail(2, "data file corrupt;"
424 " specified size exceeds actual");
427 safe_zalloc((void **)&nxio
, size
, 1);
429 if (niodevs
!= old_niodevs
)
431 for (i
= 0; i
< niodevs
; i
++) {
432 if (safe_read(fin
, &nxio
[i
], sizeof (iodevinfo_t
)) == 0)
433 fail(1, "premature end-of-file seen");
434 if (i
< old_niodevs
&&
435 nxio
[i
].ks
.ks_kid
!= oxio
[i
].ks
.ks_kid
)
438 curt
= localtime(&nx
.ts
);
439 trec
= curt
->tm_hour
* 3600.0 +
440 curt
->tm_min
* 60.0 +
442 if ((recno
== 0) && (trec
< start_time
))
444 if ((eflg
) && (trec
> end_time
))
446 if ((oflg
) && (passno
== 1)) {
448 * The calculated values are stroed in nx strcuture.
449 * Convert 64-bit nx to 32-bit tx structure.
453 convert_64to32((uint_t
*)&tx
.csi
, (uint64_t *)&nx
.csi
,
454 sizeof (nx
.csi
) / sizeof (uint64_t));
455 convert_64to32((uint_t
*)&tx
.cvmi
, (uint64_t *)&nx
.cvmi
,
456 sizeof (nx
.cvmi
) / sizeof (uint64_t));
457 convert_64to32((uint_t
*)&tx
.si
, (uint64_t *)&nx
.si
,
458 sizeof (nx
.si
) / sizeof (uint64_t));
459 (void) memcpy(&tx
.vmi
, &nx
.vmi
,
460 sizeof (nx
) - (((char *)&nx
.vmi
) - ((char *)&nx
)));
461 if (tx
.valid
!= 0 && tx
.valid
!= 1)
462 fail(2, "data file not in sar format");
464 safe_write(fout
, &tx
, sizeof (struct sa
));
465 for (i
= 0; i
< niodevs
; i
++)
466 safe_write(fout
, &nxio
[i
],
467 sizeof (iodevinfo_t
));
476 if ((iflg
) && (tnext
== 0))
482 * This dummy record signifies system restart
483 * New initial values of counters follow in next
488 (void) printf("\tunix restarts\n");
493 if ((iflg
) && (trec
< tnext
))
498 * Either the number of devices or the ordering of
499 * the kstats has changed. We need to re-organise
500 * the layout of our avg/delta arrays so that we
501 * can cope with this in update_counters().
503 size
= niodevs
* sizeof (iodevinfo_t
);
504 safe_zalloc((void *)&aio
, size
, 0);
505 safe_zalloc((void *)&dio
, size
, 0);
506 safe_zalloc((void *)&oio
, size
, 0);
509 * Loop through all the newly read iodev's, locate
510 * the corresponding entry in the old arrays and
511 * copy the entries into the same bucket of the
514 for (i
= 0; i
< niodevs
; i
++) {
515 kid
= nxio
[i
].ks
.ks_kid
;
516 for (j
= 0; j
< old_niodevs
; j
++) {
517 if (oxio
[j
].ks
.ks_kid
== kid
) {
533 old_niodevs
= niodevs
;
537 ts
= ox
.csi
.cpu
[0] + ox
.csi
.cpu
[1] +
538 ox
.csi
.cpu
[2] + ox
.csi
.cpu
[3];
539 te
= nx
.csi
.cpu
[0] + nx
.csi
.cpu
[1] +
540 nx
.csi
.cpu
[2] + nx
.csi
.cpu
[3];
541 tdiff
= (float)(te
- ts
);
542 sec_diff
= tdiff
/ hz
;
543 percent
= 100.0 / tdiff
;
546 * If the CPU stat counters have rolled
547 * backward, this is our best indication that
548 * a CPU has been offlined. We don't have
549 * enough data to compute a sensible delta, so
550 * toss out this interval, but compute the next
551 * interval's delta from these values.
561 totsec_diff
+= sec_diff
;
563 ox
= nx
; /* Age the data */
564 (void) memcpy(oxio
, nxio
, niodevs
* sizeof (iodevinfo_t
));
566 while (tnext
<= trec
)
570 * After this place, all functions are using niodevs to access the
571 * memory for device details. Here, old_niodevs has the correct value
572 * of memory allocated for storing device information. Since niodevs
573 * doesn't have correct value, sometimes, it was corrupting memory.
575 niodevs
= old_niodevs
;
578 (void) memset(&ax
, 0, sizeof (ax
)); /* Zero out the accumulators. */
579 (void) memset(&kmi
, 0, sizeof (kmi
));
582 * axio will not be allocated if the user specified -e or -s, and
583 * no records in the file fell inside the specified time range.
586 (void) memset(axio
, 0, niodevs
* sizeof (iodevinfo_t
));
591 * Print time label routine.
596 curt
= localtime(&nx
.ts
);
597 (void) printf("%.2d:%.2d:%.2d", curt
->tm_hour
, curt
->tm_min
,
603 * Test if 8-spaces to be added routine.
615 * Print machine identification.
623 (void) printf("\n%s %s %s %s %s %.2d/%.2d/%.4d\n",
624 name
.sysname
, name
.nodename
, name
.release
, name
.version
,
625 name
.machine
, curt
->tm_mon
+ 1, curt
->tm_mday
,
626 curt
->tm_year
+ 1900);
630 * Print report heading routine.
640 while ((ccc
= fopt
[jj
++]) != '\0') {
644 (void) printf(" %7s %7s %7s %7s\n",
651 (void) printf(" %7s %7s %7s %7s %7s %7s %7s %7s\n",
662 (void) printf(" %-8.8s %7s %7s %7s %7s %7s %7s\n",
672 (void) printf(" %7s %7s %7s %7s %7s %7s\n",
681 (void) printf(" %7s %7s %7s %7s %7s %7s %7s\n",
691 (void) printf(" %7s %7s %7s %7s %7s\n",
699 (void) printf(" %7s %7s %7s\n",
705 (void) printf(" %7s %7s %7s %7s\n",
712 (void) printf(" %s %s %s %s\n",
719 (void) printf(" %7s %7s\n",
724 (void) printf(" %7s %7s %7s %7s %7s %7s\n",
733 (void) printf(" %8s %8s %8s %8s %8s\n",
741 (void) printf(" %7s %8s\n",
746 (void) printf(" %7s %7s %5s %7s %7s %5s %11s %5s\n",
758 if (jj
> 2 || do_disk
)
763 * compute deltas and update accumulators
766 update_counters(void)
769 iodevinfo_t
*nio
, *oio
, *aio
, *dio
;
771 ulong_delta((uint64_t *)&nx
.csi
, (uint64_t *)&ox
.csi
,
772 (uint64_t *)&dx
.csi
, (uint64_t *)&ax
.csi
, 0, sizeof (ax
.csi
));
773 ulong_delta((uint64_t *)&nx
.si
, (uint64_t *)&ox
.si
,
774 (uint64_t *)&dx
.si
, (uint64_t *)&ax
.si
, 0, sizeof (ax
.si
));
775 ulong_delta((uint64_t *)&nx
.cvmi
, (uint64_t *)&ox
.cvmi
,
776 (uint64_t *)&dx
.cvmi
, (uint64_t *)&ax
.cvmi
, 0,
779 ax
.vmi
.freemem
+= dx
.vmi
.freemem
= nx
.vmi
.freemem
- ox
.vmi
.freemem
;
780 ax
.vmi
.swap_avail
+= dx
.vmi
.swap_avail
=
781 nx
.vmi
.swap_avail
- ox
.vmi
.swap_avail
;
787 for (i
= 0; i
< niodevs
; i
++) {
788 aio
->kios
.wlastupdate
+= dio
->kios
.wlastupdate
789 = nio
->kios
.wlastupdate
- oio
->kios
.wlastupdate
;
790 aio
->kios
.reads
+= dio
->kios
.reads
791 = nio
->kios
.reads
- oio
->kios
.reads
;
792 aio
->kios
.writes
+= dio
->kios
.writes
793 = nio
->kios
.writes
- oio
->kios
.writes
;
794 aio
->kios
.nread
+= dio
->kios
.nread
795 = nio
->kios
.nread
- oio
->kios
.nread
;
796 aio
->kios
.nwritten
+= dio
->kios
.nwritten
797 = nio
->kios
.nwritten
- oio
->kios
.nwritten
;
798 aio
->kios
.wlentime
+= dio
->kios
.wlentime
799 = nio
->kios
.wlentime
- oio
->kios
.wlentime
;
800 aio
->kios
.rlentime
+= dio
->kios
.rlentime
801 = nio
->kios
.rlentime
- oio
->kios
.rlentime
;
802 aio
->kios
.wtime
+= dio
->kios
.wtime
803 = nio
->kios
.wtime
- oio
->kios
.wtime
;
804 aio
->kios
.rtime
+= dio
->kios
.rtime
805 = nio
->kios
.rtime
- oio
->kios
.rtime
;
806 aio
->ks
.ks_snaptime
+= dio
->ks
.ks_snaptime
807 = nio
->ks
.ks_snaptime
- oio
->ks
.ks_snaptime
;
816 prt_u_opt(struct sa64
*xx
)
818 (void) printf(" %7.0f %7.0f %7.0f %7.0f\n",
819 (float)xx
->csi
.cpu
[1] * percent
,
820 (float)xx
->csi
.cpu
[2] * percent
,
821 (float)xx
->csi
.cpu
[3] * percent
,
822 (float)xx
->csi
.cpu
[0] * percent
);
826 prt_b_opt(struct sa64
*xx
)
828 (void) printf(" %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f\n",
829 (float)xx
->csi
.bread
/ sec_diff
,
830 (float)xx
->csi
.lread
/ sec_diff
,
831 freq((float)xx
->csi
.lread
, (float)xx
->csi
.bread
),
832 (float)xx
->csi
.bwrite
/ sec_diff
,
833 (float)xx
->csi
.lwrite
/ sec_diff
,
834 freq((float)xx
->csi
.lwrite
, (float)xx
->csi
.bwrite
),
835 (float)xx
->csi
.phread
/ sec_diff
,
836 (float)xx
->csi
.phwrite
/ sec_diff
);
840 prt_d_opt(int ii
, iodevinfo_t
*xio
)
842 double etime
, hr_etime
, tps
, avq
, avs
, pbusy
;
846 hr_etime
= (double)xio
[ii
].ks
.ks_snaptime
;
848 hr_etime
= (double)NANOSEC
;
849 pbusy
= (double)xio
[ii
].kios
.rtime
* 100.0 / hr_etime
;
852 etime
= hr_etime
/ (double)NANOSEC
;
853 tps
= (double)(xio
[ii
].kios
.reads
+ xio
[ii
].kios
.writes
) / etime
;
854 avq
= (double)xio
[ii
].kios
.wlentime
/ hr_etime
;
855 avs
= (double)xio
[ii
].kios
.rlentime
/ hr_etime
;
857 (void) printf(" %-8.8s ", nxio
[ii
].ks
.ks_name
);
858 (void) printf("%7.0f %7.1f %7.0f %7.0f %7.1f %7.1f\n",
862 BLKS(xio
[ii
].kios
.nread
+ xio
[ii
].kios
.nwritten
) / etime
,
863 (tps
> 0 ? avq
/ tps
* 1000.0 : 0.0),
864 (tps
> 0 ? avs
/ tps
* 1000.0 : 0.0));
868 prt_y_opt(struct sa64
*xx
)
870 (void) printf(" %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f\n",
871 (float)xx
->csi
.rawch
/ sec_diff
,
872 (float)xx
->csi
.canch
/ sec_diff
,
873 (float)xx
->csi
.outch
/ sec_diff
,
874 (float)xx
->csi
.rcvint
/ sec_diff
,
875 (float)xx
->csi
.xmtint
/ sec_diff
,
876 (float)xx
->csi
.mdmint
/ sec_diff
);
880 prt_c_opt(struct sa64
*xx
)
882 (void) printf(" %7.0f %7.0f %7.0f %7.2f %7.2f %7.0f %7.0f\n",
883 (float)xx
->csi
.syscall
/ sec_diff
,
884 (float)xx
->csi
.sysread
/ sec_diff
,
885 (float)xx
->csi
.syswrite
/ sec_diff
,
886 (float)(xx
->csi
.sysfork
+ xx
->csi
.sysvfork
) / sec_diff
,
887 (float)xx
->csi
.sysexec
/ sec_diff
,
888 (float)xx
->csi
.readch
/ sec_diff
,
889 (float)xx
->csi
.writech
/ sec_diff
);
893 prt_w_opt(struct sa64
*xx
)
895 (void) printf(" %7.2f %7.1f %7.2f %7.1f %7.0f\n",
896 (float)xx
->cvmi
.swapin
/ sec_diff
,
897 (float)PGTOBLK(xx
->cvmi
.pgswapin
) / sec_diff
,
898 (float)xx
->cvmi
.swapout
/ sec_diff
,
899 (float)PGTOBLK(xx
->cvmi
.pgswapout
) / sec_diff
,
900 (float)xx
->csi
.pswitch
/ sec_diff
);
904 prt_a_opt(struct sa64
*xx
)
906 (void) printf(" %7.0f %7.0f %7.0f\n",
907 (float)xx
->csi
.ufsiget
/ sec_diff
,
908 (float)xx
->csi
.namei
/ sec_diff
,
909 (float)xx
->csi
.ufsdirblk
/ sec_diff
);
913 prt_q_opt(struct sa64
*xx
)
915 if (xx
->si
.runocc
== 0 || xx
->si
.updates
== 0)
916 (void) printf(" %7.1f %7.0f", 0., 0.);
918 (void) printf(" %7.1f %7.0f",
919 (float)xx
->si
.runque
/ (float)xx
->si
.runocc
,
920 (float)xx
->si
.runocc
/ (float)xx
->si
.updates
* 100.0);
922 if (xx
->si
.swpocc
== 0 || xx
->si
.updates
== 0)
923 (void) printf(" %7.1f %7.0f\n", 0., 0.);
925 (void) printf(" %7.1f %7.0f\n",
926 (float)xx
->si
.swpque
/ (float)xx
->si
.swpocc
,
927 (float)xx
->si
.swpocc
/ (float)xx
->si
.updates
* 100.0);
932 prt_v_opt(struct sa64
*xx
)
934 (void) printf(" %4lu/%-4lu %4llu %4lu/%-4lu %4llu %4lu/%-4lu "
935 "%4llu %4lu/%-4lu\n",
936 nx
.szproc
, nx
.mszproc
, xx
->csi
.procovf
,
937 nx
.szinode
, nx
.mszinode
, xx
->csi
.inodeovf
,
938 nx
.szfile
, nx
.mszfile
, xx
->csi
.fileovf
,
939 nx
.szlckr
, nx
.mszlckr
);
943 prt_m_opt(struct sa64
*xx
)
945 (void) printf(" %7.2f %7.2f\n",
946 (float)xx
->csi
.msg
/ sec_diff
,
947 (float)xx
->csi
.sema
/ sec_diff
);
951 prt_p_opt(struct sa64
*xx
)
953 (void) printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
954 (float)xx
->cvmi
.pgfrec
/ sec_diff
,
955 (float)xx
->cvmi
.pgin
/ sec_diff
,
956 (float)xx
->cvmi
.pgpgin
/ sec_diff
,
957 (float)(xx
->cvmi
.prot_fault
+ xx
->cvmi
.cow_fault
) / sec_diff
,
958 (float)(xx
->cvmi
.hat_fault
+ xx
->cvmi
.as_fault
) / sec_diff
,
959 (float)xx
->cvmi
.softlock
/ sec_diff
);
963 prt_g_opt(struct sa64
*xx
)
965 (void) printf(" %8.2f %8.2f %8.2f %8.2f %8.2f\n",
966 (float)xx
->cvmi
.pgout
/ sec_diff
,
967 (float)xx
->cvmi
.pgpgout
/ sec_diff
,
968 (float)xx
->cvmi
.dfree
/ sec_diff
,
969 (float)xx
->cvmi
.scan
/ sec_diff
,
970 (float)xx
->csi
.ufsipage
* 100.0 /
971 denom((float)xx
->csi
.ufsipage
+
972 (float)xx
->csi
.ufsinopage
));
976 prt_r_opt(struct sa64
*xx
)
978 /* Avoid divide by Zero - Should never happen */
979 if (xx
->si
.updates
== 0)
980 (void) printf(" %7.0f %8.0f\n", 0., 0.);
982 (void) printf(" %7.0f %8.0f\n",
983 (double)xx
->vmi
.freemem
/ (float)xx
->si
.updates
,
984 (double)PGTOBLK(xx
->vmi
.swap_avail
) /
985 (float)xx
->si
.updates
);
990 prt_k_opt(struct sa64
*xx
, int n
)
993 (void) printf(" %7.0f %7.0f %5.0f %7.0f %7.0f %5.0f %11.0f"
995 (float)kmi
.km_mem
[KMEM_SMALL
] / n
,
996 (float)kmi
.km_alloc
[KMEM_SMALL
] / n
,
997 (float)kmi
.km_fail
[KMEM_SMALL
] / n
,
998 (float)kmi
.km_mem
[KMEM_LARGE
] / n
,
999 (float)kmi
.km_alloc
[KMEM_LARGE
] / n
,
1000 (float)kmi
.km_fail
[KMEM_LARGE
] / n
,
1001 (float)kmi
.km_alloc
[KMEM_OSIZE
] / n
,
1002 (float)kmi
.km_fail
[KMEM_OSIZE
] / n
);
1005 * If we are not reporting averages, use the read values
1008 (void) printf(" %7.0f %7.0f %5.0f %7.0f %7.0f %5.0f %11.0f"
1010 (float)xx
->kmi
.km_mem
[KMEM_SMALL
],
1011 (float)xx
->kmi
.km_alloc
[KMEM_SMALL
],
1012 (float)xx
->kmi
.km_fail
[KMEM_SMALL
],
1013 (float)xx
->kmi
.km_mem
[KMEM_LARGE
],
1014 (float)xx
->kmi
.km_alloc
[KMEM_LARGE
],
1015 (float)xx
->kmi
.km_fail
[KMEM_LARGE
],
1016 (float)xx
->kmi
.km_alloc
[KMEM_OSIZE
],
1017 (float)xx
->kmi
.km_fail
[KMEM_OSIZE
]);
1022 * Print options routine.
1032 while ((ccc
= fopt
[jj
++]) != '\0') {
1043 for (ii
= 0; ii
< niodevs
; ii
++)
1044 prt_d_opt(ii
, dxio
);
1079 * To avoid overflow, copy the data from the sa record
1080 * into a struct kmeminfo_l which has members with
1081 * larger data types.
1083 kmi
.km_mem
[KMEM_SMALL
] += nx
.kmi
.km_mem
[KMEM_SMALL
];
1084 kmi
.km_alloc
[KMEM_SMALL
] += nx
.kmi
.km_alloc
[KMEM_SMALL
];
1085 kmi
.km_fail
[KMEM_SMALL
] += nx
.kmi
.km_fail
[KMEM_SMALL
];
1086 kmi
.km_mem
[KMEM_LARGE
] += nx
.kmi
.km_mem
[KMEM_LARGE
];
1087 kmi
.km_alloc
[KMEM_LARGE
] += nx
.kmi
.km_alloc
[KMEM_LARGE
];
1088 kmi
.km_fail
[KMEM_LARGE
] += nx
.kmi
.km_fail
[KMEM_LARGE
];
1089 kmi
.km_alloc
[KMEM_OSIZE
] += nx
.kmi
.km_alloc
[KMEM_OSIZE
];
1090 kmi
.km_fail
[KMEM_OSIZE
] += nx
.kmi
.km_fail
[KMEM_OSIZE
];
1094 if (jj
> 2 || do_disk
)
1095 (void) printf("\n");
1097 (void) fflush(stdout
);
1101 * Print average routine.
1109 tdiff
= ax
.csi
.cpu
[0] + ax
.csi
.cpu
[1] + ax
.csi
.cpu
[2] + ax
.csi
.cpu
[3];
1113 sec_diff
= tdiff
/ hz
;
1114 percent
= 100.0 / tdiff
;
1115 (void) printf("\n");
1117 while ((ccc
= fopt
[jj
++]) != '\0') {
1119 (void) printf("Average ");
1129 for (ii
= 0; ii
< niodevs
; ii
++)
1130 prt_d_opt(ii
, axio
);
1162 prt_k_opt(&ax
, lines
);
1169 ulong_delta(uint64_t *new, uint64_t *old
, uint64_t *delta
, uint64_t *accum
,
1175 for (i
= begin
; i
< end
; i
+= sizeof (uint64_t)) {
1179 d
= n
+ 0x100000000LL
- o
;
1183 *accum
++ += *delta
++ = d
;
1188 * used to prevent zero denominators
1193 return ((x
> 0.5) ? x
: 1.0);
1197 * a little calculation that comes up often when computing frequency
1198 * of one operation relative to another
1201 freq(float x
, float y
)
1203 return ((x
< 0.5) ? 100.0 : (x
- y
) / x
* 100.0);
1209 (void) fprintf(stderr
,
1210 "usage: sar [-ubdycwaqvmpgrkA][-o file] t [n]\n"
1211 "\tsar [-ubdycwaqvmpgrkA] [-s hh:mm][-e hh:mm][-i ss][-f file]\n");
1215 fail(int do_perror
, char *message
, ...)
1219 va_start(args
, message
);
1220 (void) fprintf(stderr
, "sar: ");
1221 (void) vfprintf(stderr
, message
, args
);
1223 (void) fprintf(stderr
, "\n");
1224 switch (do_perror
) {
1225 case 0: /* usage message */
1228 case 1: /* perror output */
1231 case 2: /* no further output */
1233 default: /* error */
1234 (void) fprintf(stderr
, "unsupported failure mode\n");
1241 safe_strtoi(char const *val
, char *errmsg
)
1247 tmp
= strtol(val
, &end
, 10);
1248 if (*end
!= '\0' || errno
)
1249 fail(0, "%s %s", errmsg
, val
);
1254 safe_zalloc(void **ptr
, int size
, int free_first
)
1258 if ((*ptr
= malloc(size
)) == NULL
)
1259 fail(1, "malloc failed");
1260 (void) memset(*ptr
, 0, size
);
1264 safe_read(int fd
, void *buf
, size_t size
)
1266 size_t rsize
= read(fd
, buf
, size
);
1272 fail(1, "read failed");
1278 safe_write(int fd
, void *buf
, size_t size
)
1280 if (write(fd
, buf
, size
) != size
)
1281 fail(1, "write failed");