changeset 4151:ec477fe2405a

6521106 sar -c incorrectly reports averages due to 32bit truncation
author js198686
date Wed, 02 May 2007 03:05:01 -0700
parents b39c1d0a6cde
children b15a6321ae17
files usr/src/cmd/sa/sa.h usr/src/cmd/sa/sar.c
diffstat 2 files changed, 193 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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;
+	}
 }
 
 /*