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:
parent
0d3c6afc93
commit
c3122bca53
@ -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 {
|
||||||
++iterations;
|
if (cache)
|
||||||
if (flag == 0)
|
|
||||||
seek_to_zero();
|
seek_to_zero();
|
||||||
if (read_big_block(buf))
|
read_big_block(buf);
|
||||||
goto quit;
|
elapsed = (unsigned)monotonic_us() - start;
|
||||||
getitimer(ITIMER_REAL, &itv);
|
++iterations;
|
||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user