# HG changeset patch # User js198686 # Date 1178100301 25200 # Node ID ec477fe2405a2c2a8bfe6cd84994c6d82725c87e # Parent b39c1d0a6cde13014d120e4c516bfa80fc4dc852 6521106 sar -c incorrectly reports averages due to 32bit truncation diff -r b39c1d0a6cde -r ec477fe2405a usr/src/cmd/sa/sa.h --- a/usr/src/cmd/sa/sa.h Wed May 02 01:39:51 2007 -0700 +++ b/usr/src/cmd/sa/sa.h Wed May 02 03:05:01 2007 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -24,7 +23,7 @@ /* - * Copyright 1992-1994, 2000, 2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -93,6 +92,129 @@ /* An array of iodevinfo structs come next in the sadc files */ }; +typedef struct cpu64_sysinfo { + uint64_t cpu[CPU_STATES]; + uint64_t wait[W_STATES]; + uint64_t bread; + uint64_t bwrite; + uint64_t lread; + uint64_t lwrite; + uint64_t phread; + uint64_t phwrite; + uint64_t pswitch; + uint64_t trap; + uint64_t intr; + uint64_t syscall; + uint64_t sysread; + uint64_t syswrite; + uint64_t sysfork; + uint64_t sysvfork; + uint64_t sysexec; + uint64_t readch; + uint64_t writech; + uint64_t rcvint; + uint64_t xmtint; + uint64_t mdmint; + uint64_t rawch; + uint64_t canch; + uint64_t outch; + uint64_t msg; + uint64_t sema; + uint64_t namei; + uint64_t ufsiget; + uint64_t ufsdirblk; + uint64_t ufsipage; + uint64_t ufsinopage; + uint64_t inodeovf; + uint64_t fileovf; + uint64_t procovf; + uint64_t intrthread; + uint64_t intrblk; + uint64_t idlethread; + uint64_t inv_swtch; + uint64_t nthreads; + uint64_t cpumigrate; + uint64_t xcalls; + uint64_t mutex_adenters; + uint64_t rw_rdfails; + uint64_t rw_wrfails; + uint64_t modload; + uint64_t modunload; + uint64_t bawrite; + uint64_t rw_enters; + uint64_t win_uo_cnt; + uint64_t win_uu_cnt; + uint64_t win_so_cnt; + uint64_t win_su_cnt; + uint64_t win_suo_cnt; +} cpu64_sysinfo_t; + +typedef struct cpu64_vminfo { + uint64_t pgrec; + uint64_t pgfrec; + uint64_t pgin; + uint64_t pgpgin; + uint64_t pgout; + uint64_t pgpgout; + uint64_t swapin; + uint64_t pgswapin; + uint64_t swapout; + uint64_t pgswapout; + uint64_t zfod; + uint64_t dfree; + uint64_t scan; + uint64_t rev; + uint64_t hat_fault; + uint64_t as_fault; + uint64_t maj_fault; + uint64_t cow_fault; + uint64_t prot_fault; + uint64_t softlock; + uint64_t kernel_asflt; + uint64_t pgrrun; + uint64_t execpgin; + uint64_t execpgout; + uint64_t execfree; + uint64_t anonpgin; + uint64_t anonpgout; + uint64_t anonfree; + uint64_t fspgin; + uint64_t fspgout; + uint64_t fsfree; +} cpu64_vminfo_t; + +typedef struct sysinfo64 { + uint64_t updates; + uint64_t runque; + uint64_t runocc; + uint64_t swpque; + uint64_t swpocc; + uint64_t waiting; +} sysinfo64_t; + +struct sa64 { + int valid; + time_t ts; + + cpu64_sysinfo_t csi; + cpu64_vminfo_t cvmi; + sysinfo64_t si; + vminfo_t vmi; + kmeminfo_t kmi; + + ulong_t szinode; + ulong_t szfile; + ulong_t szproc; + ulong_t szlckr; + + ulong_t mszinode; + ulong_t mszfile; + ulong_t mszproc; + ulong_t mszlckr; + + ulong_t niodevs; +}; + extern struct sa sa; #ifdef __cplusplus diff -r b39c1d0a6cde -r ec477fe2405a usr/src/cmd/sa/sar.c --- a/usr/src/cmd/sa/sar.c Wed May 02 01:39:51 2007 -0700 +++ b/usr/src/cmd/sa/sar.c Wed May 02 03:05:01 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -77,12 +77,12 @@ static int safe_read(int, void *, size_t); static void safe_write(int, void *, size_t); static int safe_strtoi(char const *, char *); -static void ulong_delta(ulong_t *, ulong_t *, ulong_t *, ulong_t *, +static void ulong_delta(uint64_t *, uint64_t *, uint64_t *, uint64_t *, int, int); static float denom(float); static float freq(float, float); -static struct sa nx, ox, ax, dx; +static struct sa64 nx, ox, ax, dx; static iodevinfo_t *nxio, *oxio, *axio, *dxio; static struct tm *curt, args, arge; @@ -94,7 +94,6 @@ static int tabflg; static char options[30], fopt[30]; static float tdiff, sec_diff, totsec_diff = 0.0, percent; -static time_t ts, te; /* time interval start and end */ static float start_time, end_time, isec; static int fin, fout; static pid_t childid; @@ -309,6 +308,16 @@ } /* + * Convert array of 32-bit uints to 64-bit uints + */ +static void +convert_32to64(uint64_t *dst, uint_t *src, int size) +{ + for (; size > 0; size--) + *dst++ = (uint64_t)(*src++); +} + +/* * Read records from input, classify, and decide on printing. */ static void @@ -321,6 +330,8 @@ ulong_t old_niodevs = 0, prev_niodevs = 0; iodevinfo_t *aio, *dio, *oio; struct stat in_stat; + struct sa tx; + uint64_t ts, te; /* time interval start and end */ do_disk = (strchr(fopt, 'd') != NULL); if (!input_pipe && fstat(fin, &in_stat) == -1) @@ -329,7 +340,25 @@ if (sflg) tnext = start_time; - while (safe_read(fin, &nx, sizeof (struct sa))) { + while (safe_read(fin, &tx, sizeof (struct sa))) { + /* + * First, we convert 32bit tx to 64bit nx structure + * which is used later. Conversion could be done + * after initial operations, right before calculations, + * but it would introduce additional juggling with vars. + * Thus, we convert all data now, and don't care about + * tx any further. + */ + nx.valid = tx.valid; + nx.ts = tx.ts; + convert_32to64((uint64_t *)&nx.csi, (uint_t *)&tx.csi, + sizeof (tx.csi) / sizeof (uint_t)); + convert_32to64((uint64_t *)&nx.cvmi, (uint_t *)&tx.cvmi, + sizeof (tx.cvmi) / sizeof (uint_t)); + convert_32to64((uint64_t *)&nx.si, (uint_t *)&tx.si, + sizeof (tx.si) / sizeof (uint_t)); + (void) memcpy(&nx.vmi, &tx.vmi, + sizeof (tx) - (((char *)&tx.vmi) - ((char *)&tx))); /* * sadc is the only utility used to generate sar data * and it uses the valid field as follows: @@ -714,12 +743,12 @@ int i; iodevinfo_t *nio, *oio, *aio, *dio; - ulong_delta((ulong_t *)&nx.csi, (ulong_t *)&ox.csi, - (ulong_t *)&dx.csi, (ulong_t *)&ax.csi, 0, sizeof (ax.csi)); - ulong_delta((ulong_t *)&nx.si, (ulong_t *)&ox.si, - (ulong_t *)&dx.si, (ulong_t *)&ax.si, 0, sizeof (ax.si)); - ulong_delta((ulong_t *)&nx.cvmi, (ulong_t *)&ox.cvmi, - (ulong_t *)&dx.cvmi, (ulong_t *)&ax.cvmi, 0, + ulong_delta((uint64_t *)&nx.csi, (uint64_t *)&ox.csi, + (uint64_t *)&dx.csi, (uint64_t *)&ax.csi, 0, sizeof (ax.csi)); + ulong_delta((uint64_t *)&nx.si, (uint64_t *)&ox.si, + (uint64_t *)&dx.si, (uint64_t *)&ax.si, 0, sizeof (ax.si)); + ulong_delta((uint64_t *)&nx.cvmi, (uint64_t *)&ox.cvmi, + (uint64_t *)&dx.cvmi, (uint64_t *)&ax.cvmi, 0, sizeof (ax.cvmi)); ax.vmi.freemem += dx.vmi.freemem = nx.vmi.freemem - ox.vmi.freemem; @@ -757,7 +786,7 @@ } static void -prt_u_opt(struct sa *xx) +prt_u_opt(struct sa64 *xx) { (void) printf(" %7.0f %7.0f %7.0f %7.0f\n", (float)xx->csi.cpu[1] * percent, @@ -767,7 +796,7 @@ } static void -prt_b_opt(struct sa *xx) +prt_b_opt(struct sa64 *xx) { (void) printf(" %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f\n", (float)xx->csi.bread / sec_diff, @@ -806,7 +835,7 @@ } static void -prt_y_opt(struct sa *xx) +prt_y_opt(struct sa64 *xx) { (void) printf(" %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f\n", (float)xx->csi.rawch / sec_diff, @@ -818,7 +847,7 @@ } static void -prt_c_opt(struct sa *xx) +prt_c_opt(struct sa64 *xx) { (void) printf(" %7.0f %7.0f %7.0f %7.2f %7.2f %7.0f %7.0f\n", (float)xx->csi.syscall / sec_diff, @@ -831,7 +860,7 @@ } static void -prt_w_opt(struct sa *xx) +prt_w_opt(struct sa64 *xx) { (void) printf(" %7.2f %7.1f %7.2f %7.1f %7.0f\n", (float)xx->cvmi.swapin / sec_diff, @@ -842,7 +871,7 @@ } static void -prt_a_opt(struct sa *xx) +prt_a_opt(struct sa64 *xx) { (void) printf(" %7.0f %7.0f %7.0f\n", (float)xx->csi.ufsiget / sec_diff, @@ -851,7 +880,7 @@ } static void -prt_q_opt(struct sa *xx) +prt_q_opt(struct sa64 *xx) { if (xx->si.runocc == 0 || xx->si.updates == 0) (void) printf(" %7.1f %7.0f", 0., 0.); @@ -870,10 +899,10 @@ } static void -prt_v_opt(struct sa *xx) +prt_v_opt(struct sa64 *xx) { - (void) printf(" %4lu/%-4lu %4u %4lu/%-4lu %4u %4lu/%-4lu " - "%4u %4lu/%-4lu\n", + (void) printf(" %4lu/%-4lu %4llu %4lu/%-4lu %4llu %4lu/%-4lu " + "%4llu %4lu/%-4lu\n", nx.szproc, nx.mszproc, xx->csi.procovf, nx.szinode, nx.mszinode, xx->csi.inodeovf, nx.szfile, nx.mszfile, xx->csi.fileovf, @@ -881,7 +910,7 @@ } static void -prt_m_opt(struct sa *xx) +prt_m_opt(struct sa64 *xx) { (void) printf(" %7.2f %7.2f\n", (float)xx->csi.msg / sec_diff, @@ -889,7 +918,7 @@ } static void -prt_p_opt(struct sa *xx) +prt_p_opt(struct sa64 *xx) { (void) printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n", (float)xx->cvmi.pgfrec / sec_diff, @@ -901,7 +930,7 @@ } static void -prt_g_opt(struct sa *xx) +prt_g_opt(struct sa64 *xx) { (void) printf(" %8.2f %8.2f %8.2f %8.2f %8.2f\n", (float)xx->cvmi.pgout / sec_diff, @@ -914,7 +943,7 @@ } static void -prt_r_opt(struct sa *xx) +prt_r_opt(struct sa64 *xx) { /* Avoid divide by Zero - Should never happen */ if (xx->si.updates == 0) @@ -928,7 +957,7 @@ } static void -prt_k_opt(struct sa *xx, int n) +prt_k_opt(struct sa64 *xx, int n) { if (n != 1) { (void) printf(" %7.0f %7.0f %5.0f %7.0f %7.0f %5.0f %11.0f" @@ -1107,18 +1136,22 @@ } static void -ulong_delta(ulong_t *new, ulong_t *old, ulong_t *delta, ulong_t *accum, +ulong_delta(uint64_t *new, uint64_t *old, uint64_t *delta, uint64_t *accum, int begin, int end) { int i; - ulong_t *np, *op, *dp, *ap; + uint64_t n, o, d; - np = new; - op = old; - dp = delta; - ap = accum; - for (i = begin; i < end; i += sizeof (ulong_t)) - *ap++ += *dp++ = *np++ - *op++; + for (i = begin; i < end; i += sizeof (uint64_t)) { + n = *new++; + o = *old++; + if (o > n) { + d = n + 0x100000000LL - o; + } else { + d = n - o; + } + *accum++ += *delta++ = d; + } } /*