svn commit: trunk/busybox/miscutils

vda at busybox.net vda at busybox.net
Fri Sep 28 10:28:03 UTC 2007


Author: vda
Date: 2007-09-28 03:28:03 -0700 (Fri, 28 Sep 2007)
New Revision: 20079

Log:
hdparm: simplify timing measurement (it wa the last last user
of setitimer in the tree).

static.thousand                                       16       -     -16
read_big_block                                        81      46     -35
getitimer                                             41       -     -41
setitimer                                             47       -     -47
__GI_setitimer                                        47       -     -47
do_time                                              480     386     -94
------------------------------------------------------------------------------
(add/remove: 0/4 grow/shrink: 0/2 up/down: 0/-280)           Total: -280 bytes

M    miscutils/hdparm.c


Modified:
   trunk/busybox/miscutils/hdparm.c


Changeset:
Modified: trunk/busybox/miscutils/hdparm.c
===================================================================
--- trunk/busybox/miscutils/hdparm.c	2007-09-28 10:25:32 UTC (rev 20078)
+++ trunk/busybox/miscutils/hdparm.c	2007-09-28 10:28:03 UTC (rev 20079)
@@ -429,10 +429,8 @@
 #define SIG                     0x00ff  /* signature location */
 #define SIG_VAL                 0x00a5  /* signature value */
 
-#define TIMING_MB               64
 #define TIMING_BUF_MB           1
 #define TIMING_BUF_BYTES        (TIMING_BUF_MB * 1024 * 1024)
-#define BUFCACHE_FACTOR         2
 
 #undef DO_FLUSHCACHE            /* under construction: force cache flush on -W0 */
 
@@ -505,6 +503,9 @@
 	unsigned long hwif_ctrl;
 	unsigned long hwif_irq;
 #endif
+#ifdef DO_FLUSHCACHE
+	unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
+#endif
 };
 #define G (*(struct globals*)&bb_common_bufsiz1)
 struct BUG_G_too_big {
@@ -1342,22 +1343,17 @@
 	xlseek(fd, (off_t) 0, SEEK_SET);
 }
 
-static int read_big_block(/*int fd,*/ char *buf)
+static void read_big_block(/*int fd,*/ char *buf)
 {
 	int i;
 
-	i = read(fd, buf, TIMING_BUF_BYTES);
-	if (i != TIMING_BUF_BYTES) {
-		bb_error_msg("read(%d bytes) failed (rc=%d)", TIMING_BUF_BYTES, i);
-		return 1;
-	}
+	xread(fd, buf, TIMING_BUF_BYTES);
 	/* access all sectors of buf to ensure the read fully completed */
 	for (i = 0; i < TIMING_BUF_BYTES; i += 512)
 		buf[i] &= 1;
-	return 0;
 }
 
-static unsigned long long do_blkgetsize(/*int fd*/ void)
+static unsigned long long dev_size_mb(/*int fd*/ void)
 {
 	union {
 		unsigned long long blksize64;
@@ -1365,85 +1361,88 @@
 	} u;
 
 	if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // returns bytes
-		return u.blksize64 / 512;
+		return u.blksize64 / (1024 * 1024);
 	}
 	xioctl(fd, BLKGETSIZE, &u.blksize32); // returns sectors
-	return u.blksize32;
+	return u.blksize32 / (2 * 1024);
 }
 
-static void print_timing(unsigned t, double e)
+static void print_timing(unsigned long m, unsigned elapsed_us)
 {
-	if (t >= e)  /* more than 1MB/s */
-		printf("%4d MB in %.2f seconds = %.2f %cB/sec\n", t, e, t / e, 'M');
-	else
-		printf("%4d MB in %.2f seconds = %.2f %cB/sec\n", t, e, t / e * 1024, 'k');
+	unsigned sec = elapsed_us / 1000000;
+	unsigned hs = (elapsed_us % 1000000) / 10000;
+
+	printf("%5lu MB in %u.%02u seconds = %lu kB/s\n",
+		m, sec, hs,
+		/* Trying to not overflow 32-bit arith in m * CONST
+		 * by keeping CONST not so big. + 1 prevents div-by-0. */
+		(m * (1024 * 1000000 / (64*1024))) / (elapsed_us / (64*1024) + 1)
+		// ~= (m * 1024 * 1000000) / elapsed_ms
+		// = (m * 1024) / (elapsed_ms / 1000000)
+		// = kb / elapsed_sec
+	);
 }
 
-static void do_time(int flag /*,int fd*/)
-/* flag = 0 time_cache, 1 time_device */
+static void do_time(int cache /*,int fd*/)
+/* cache=1: time cache: repeatedly read N MB at offset 0
+ * cache=0: time device: linear read, starting at offset 0
+ */
 {
-	static const struct itimerval thousand = {{1000, 0}, {1000, 0}};
-
-	struct itimerval itv;
+	unsigned max_iterations, iterations;
+	unsigned start; /* don't need to be long long */
 	unsigned elapsed, elapsed2;
-	unsigned max_iterations, total_MB, iterations;
+	unsigned long total_MB;
 	char *buf = xmalloc(TIMING_BUF_BYTES);
 
-	if (mlock(buf, TIMING_BUF_BYTES)) {
-		bb_perror_msg("mlock");
-		goto quit2;
-	}
+	if (mlock(buf, TIMING_BUF_BYTES))
+		bb_perror_msg_and_die("mlock");
 
-	max_iterations = do_blkgetsize() / (2 * 1024) / TIMING_BUF_MB;
+	/* Don't want to read past the end! */
+	max_iterations = UINT_MAX;
+	if (!cache)
+		max_iterations = dev_size_mb() / TIMING_BUF_MB;
 
-	/* Clear out the device request queues & give them time to complete */
+	/* Clear out the device request queues & give them time to complete.
+	 * NB: *small* delay. User is expected to have a clue and to not run
+	 * heavy io in parallel with measurements. */
 	sync();
-	sleep(2);
-	if (flag == 0) { /* Time cache */
+	sleep(1);
+	if (cache) { /* Time cache */
 		seek_to_zero();
-		if (read_big_block(buf))
-			goto quit;
-		printf(" Timing buffer-cache reads:  ");
+		read_big_block(buf);
+		printf("Timing buffer-cache reads: ");
 	} else { /* Time device */
-		printf(" Timing buffered disk reads: ");
+		printf("Timing buffered disk reads:");
 	}
 	fflush(stdout);
-	iterations = 0;
-	/*
-	 * getitimer() is used rather than gettimeofday() because
-	 * it is much more consistent (on my machine, at least).
-	 */
-//TODO: get rid of
-	setitimer(ITIMER_REAL, &thousand, NULL);
+
 	/* Now do the timing */
+	iterations = 0;
+	start = monotonic_us();
 	do {
-		++iterations;
-		if (flag == 0)
+		if (cache)
 			seek_to_zero();
-		if (read_big_block(buf))
-			goto quit;
-		getitimer(ITIMER_REAL, &itv);
-		elapsed = (1000 - itv.it_value.tv_sec) * 1000000
-				- itv.it_value.tv_usec;
+		read_big_block(buf);
+		elapsed = (unsigned)monotonic_us() - start;
+		++iterations;
 	} while (elapsed < 3000000 && iterations < max_iterations);
-	total_MB = iterations * TIMING_BUF_MB;
-	if (flag == 0) {
-		/* Now remove the lseek() and getitimer() overheads from the elapsed time */
-		setitimer(ITIMER_REAL, &thousand, NULL);
+	total_MB = (unsigned long)iterations * TIMING_BUF_MB;
+	//printf(" elapsed:%u iterations:%u ", elapsed, iterations);
+	if (cache) {
+		/* Now remove the lseek() and monotonic_us() overheads
+		 * from elapsed */
+		start = monotonic_us();
 		do {
 			seek_to_zero();
-			getitimer(ITIMER_REAL, &itv);
-			elapsed2 = (1000 - itv.it_value.tv_sec) * 1000000
-					- itv.it_value.tv_usec;
+			elapsed2 = (unsigned)monotonic_us() - start;
 		} while (--iterations);
+		//printf(" elapsed2:%u ", elapsed2);
 		elapsed -= elapsed2;
-		total_MB *= BUFCACHE_FACTOR;
+		total_MB *= 2; // BUFCACHE_FACTOR (why?)
 		flush_buffer_cache();
 	}
-	print_timing(total_MB, elapsed / 1000000.0);
- quit:
+	print_timing(total_MB, elapsed);
 	munlock(buf, TIMING_BUF_BYTES);
- quit2:
 	free(buf);
 }
 
@@ -1688,7 +1687,6 @@
 #ifndef WIN_FLUSHCACHE
 #define WIN_FLUSHCACHE 0xe7
 #endif
-		static unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
 #endif /* DO_FLUSHCACHE */
 		args[2] = wcache ? 0x02 : 0x82;
 		print_flag_on_off(get_wcache, "drive write-caching", wcache);
@@ -1749,7 +1747,7 @@
 		char buf[512];
 		flush_buffer_cache();
 		if (-1 == read(fd, buf, sizeof(buf)))
-			bb_perror_msg("read(%d bytes) failed (rc=%d)", sizeof(buf), -1);
+			bb_perror_msg("read(%d bytes) failed (rc=-1)", sizeof(buf));
 	}
 #endif	/* HDIO_DRIVE_CMD */
 
@@ -1912,9 +1910,9 @@
 		ioctl_or_warn(fd, BLKRRPART, NULL);
 
 	if (do_ctimings)
-		do_time(0 /*,fd*/); /* time cache */
+		do_time(1 /*,fd*/); /* time cache */
 	if (do_timings)
-		do_time(1 /*,fd*/); /* time device */
+		do_time(0 /*,fd*/); /* time device */
 	if (do_flush)
 		flush_buffer_cache();
 	close(fd);




More information about the busybox-cvs mailing list