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_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);