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
This commit is contained in:
Denis Vlasenko 2007-09-28 10:28:03 +00:00
parent 0d3c6afc93
commit c3122bca53

View File

@ -429,10 +429,8 @@ static const char *const secu_str[] = {
#define SIG 0x00ff /* signature location */ #define SIG 0x00ff /* signature location */
#define SIG_VAL 0x00a5 /* signature value */ #define SIG_VAL 0x00a5 /* signature value */
#define TIMING_MB 64
#define TIMING_BUF_MB 1 #define TIMING_BUF_MB 1
#define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024) #define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024)
#define BUFCACHE_FACTOR 2
#undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */ #undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */
@ -505,6 +503,9 @@ struct globals {
unsigned long hwif_ctrl; unsigned long hwif_ctrl;
unsigned long hwif_irq; unsigned long hwif_irq;
#endif #endif
#ifdef DO_FLUSHCACHE
unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
#endif
}; };
#define G (*(struct globals*)&bb_common_bufsiz1) #define G (*(struct globals*)&bb_common_bufsiz1)
struct BUG_G_too_big { struct BUG_G_too_big {
@ -1342,22 +1343,17 @@ static void seek_to_zero(/*int fd*/ void)
xlseek(fd, (off_t) 0, SEEK_SET); 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; int i;
i = read(fd, buf, TIMING_BUF_BYTES); xread(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;
}
/* access all sectors of buf to ensure the read fully completed */ /* access all sectors of buf to ensure the read fully completed */
for (i = 0; i < TIMING_BUF_BYTES; i += 512) for (i = 0; i < TIMING_BUF_BYTES; i += 512)
buf[i] &= 1; 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 { union {
unsigned long long blksize64; unsigned long long blksize64;
@ -1365,85 +1361,88 @@ static unsigned long long do_blkgetsize(/*int fd*/ void)
} u; } u;
if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // returns bytes 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 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 */ unsigned sec = elapsed_us / 1000000;
printf("%4d MB in %.2f seconds = %.2f %cB/sec\n", t, e, t / e, 'M'); unsigned hs = (elapsed_us % 1000000) / 10000;
else
printf("%4d MB in %.2f seconds = %.2f %cB/sec\n", t, e, t / e * 1024, 'k'); 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*/) static void do_time(int cache /*,int fd*/)
/* flag = 0 time_cache, 1 time_device */ /* 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}}; unsigned max_iterations, iterations;
unsigned start; /* don't need to be long long */
struct itimerval itv;
unsigned elapsed, elapsed2; unsigned elapsed, elapsed2;
unsigned max_iterations, total_MB, iterations; unsigned long total_MB;
char *buf = xmalloc(TIMING_BUF_BYTES); char *buf = xmalloc(TIMING_BUF_BYTES);
if (mlock(buf, TIMING_BUF_BYTES)) { if (mlock(buf, TIMING_BUF_BYTES))
bb_perror_msg("mlock"); bb_perror_msg_and_die("mlock");
goto quit2;
}
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(); sync();
sleep(2); sleep(1);
if (flag == 0) { /* Time cache */ if (cache) { /* Time cache */
seek_to_zero(); seek_to_zero();
if (read_big_block(buf)) read_big_block(buf);
goto quit;
printf("Timing buffer-cache reads: "); printf("Timing buffer-cache reads: ");
} else { /* Time device */ } else { /* Time device */
printf("Timing buffered disk reads:"); printf("Timing buffered disk reads:");
} }
fflush(stdout); 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 */ /* Now do the timing */
iterations = 0;
start = monotonic_us();
do { do {
if (cache)
seek_to_zero();
read_big_block(buf);
elapsed = (unsigned)monotonic_us() - start;
++iterations; ++iterations;
if (flag == 0)
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;
} while (elapsed < 3000000 && iterations < max_iterations); } while (elapsed < 3000000 && iterations < max_iterations);
total_MB = iterations * TIMING_BUF_MB; total_MB = (unsigned long)iterations * TIMING_BUF_MB;
if (flag == 0) { //printf(" elapsed:%u iterations:%u ", elapsed, iterations);
/* Now remove the lseek() and getitimer() overheads from the elapsed time */ if (cache) {
setitimer(ITIMER_REAL, &thousand, NULL); /* Now remove the lseek() and monotonic_us() overheads
* from elapsed */
start = monotonic_us();
do { do {
seek_to_zero(); seek_to_zero();
getitimer(ITIMER_REAL, &itv); elapsed2 = (unsigned)monotonic_us() - start;
elapsed2 = (1000 - itv.it_value.tv_sec) * 1000000
- itv.it_value.tv_usec;
} while (--iterations); } while (--iterations);
//printf(" elapsed2:%u ", elapsed2);
elapsed -= elapsed2; elapsed -= elapsed2;
total_MB *= BUFCACHE_FACTOR; total_MB *= 2; // BUFCACHE_FACTOR (why?)
flush_buffer_cache(); flush_buffer_cache();
} }
print_timing(total_MB, elapsed / 1000000.0); print_timing(total_MB, elapsed);
quit:
munlock(buf, TIMING_BUF_BYTES); munlock(buf, TIMING_BUF_BYTES);
quit2:
free(buf); free(buf);
} }
@ -1688,7 +1687,6 @@ static void process_dev(char *devname)
#ifndef WIN_FLUSHCACHE #ifndef WIN_FLUSHCACHE
#define WIN_FLUSHCACHE 0xe7 #define WIN_FLUSHCACHE 0xe7
#endif #endif
static unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
#endif /* DO_FLUSHCACHE */ #endif /* DO_FLUSHCACHE */
args[2] = wcache ? 0x02 : 0x82; args[2] = wcache ? 0x02 : 0x82;
print_flag_on_off(get_wcache, "drive write-caching", wcache); print_flag_on_off(get_wcache, "drive write-caching", wcache);
@ -1749,7 +1747,7 @@ static void process_dev(char *devname)
char buf[512]; char buf[512];
flush_buffer_cache(); flush_buffer_cache();
if (-1 == read(fd, buf, sizeof(buf))) 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 */ #endif /* HDIO_DRIVE_CMD */
@ -1912,9 +1910,9 @@ static void process_dev(char *devname)
ioctl_or_warn(fd, BLKRRPART, NULL); ioctl_or_warn(fd, BLKRRPART, NULL);
if (do_ctimings) if (do_ctimings)
do_time(0 /*,fd*/); /* time cache */ do_time(1 /*,fd*/); /* time cache */
if (do_timings) if (do_timings)
do_time(1 /*,fd*/); /* time device */ do_time(0 /*,fd*/); /* time device */
if (do_flush) if (do_flush)
flush_buffer_cache(); flush_buffer_cache();
close(fd); close(fd);