From c3122bca53255799f052fcc0e911b68237faa12d Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Fri, 28 Sep 2007 10:28:03 +0000 Subject: [PATCH] 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 --- miscutils/hdparm.c | 126 ++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 64 deletions(-) diff --git a/miscutils/hdparm.c b/miscutils/hdparm.c index a3a5a7336..8a7204f29 100644 --- a/miscutils/hdparm.c +++ b/miscutils/hdparm.c @@ -429,10 +429,8 @@ static const char *const secu_str[] = { #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 @@ struct globals { 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 @@ static void seek_to_zero(/*int fd*/ void) 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 @@ static unsigned long long do_blkgetsize(/*int fd*/ void) } 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 @@ static void process_dev(char *devname) #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 @@ static void process_dev(char *devname) 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 @@ static void process_dev(char *devname) 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);