diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-09-28 10:28:03 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-09-28 10:28:03 +0000 |
| commit | c3122bca53255799f052fcc0e911b68237faa12d (patch) | |
| tree | 853664b39497f379970bf5b45b1986ae58de13f2 /miscutils | |
| parent | 0d3c6afc93c8a6216fee9d60ecaa6a9d52687a65 (diff) | |
| download | busybox-w32-c3122bca53255799f052fcc0e911b68237faa12d.tar.gz busybox-w32-c3122bca53255799f052fcc0e911b68237faa12d.tar.bz2 busybox-w32-c3122bca53255799f052fcc0e911b68237faa12d.zip | |
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
Diffstat (limited to 'miscutils')
| -rw-r--r-- | miscutils/hdparm.c | 126 |
1 files 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[] = { | |||
| 429 | #define SIG 0x00ff /* signature location */ | 429 | #define SIG 0x00ff /* signature location */ |
| 430 | #define SIG_VAL 0x00a5 /* signature value */ | 430 | #define SIG_VAL 0x00a5 /* signature value */ |
| 431 | 431 | ||
| 432 | #define TIMING_MB 64 | ||
| 433 | #define TIMING_BUF_MB 1 | 432 | #define TIMING_BUF_MB 1 |
| 434 | #define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024) | 433 | #define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024) |
| 435 | #define BUFCACHE_FACTOR 2 | ||
| 436 | 434 | ||
| 437 | #undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */ | 435 | #undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */ |
| 438 | 436 | ||
| @@ -505,6 +503,9 @@ struct globals { | |||
| 505 | unsigned long hwif_ctrl; | 503 | unsigned long hwif_ctrl; |
| 506 | unsigned long hwif_irq; | 504 | unsigned long hwif_irq; |
| 507 | #endif | 505 | #endif |
| 506 | #ifdef DO_FLUSHCACHE | ||
| 507 | unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 }; | ||
| 508 | #endif | ||
| 508 | }; | 509 | }; |
| 509 | #define G (*(struct globals*)&bb_common_bufsiz1) | 510 | #define G (*(struct globals*)&bb_common_bufsiz1) |
| 510 | struct BUG_G_too_big { | 511 | struct BUG_G_too_big { |
| @@ -1342,22 +1343,17 @@ static void seek_to_zero(/*int fd*/ void) | |||
| 1342 | xlseek(fd, (off_t) 0, SEEK_SET); | 1343 | xlseek(fd, (off_t) 0, SEEK_SET); |
| 1343 | } | 1344 | } |
| 1344 | 1345 | ||
| 1345 | static int read_big_block(/*int fd,*/ char *buf) | 1346 | static void read_big_block(/*int fd,*/ char *buf) |
| 1346 | { | 1347 | { |
| 1347 | int i; | 1348 | int i; |
| 1348 | 1349 | ||
| 1349 | i = read(fd, buf, TIMING_BUF_BYTES); | 1350 | xread(fd, buf, TIMING_BUF_BYTES); |
| 1350 | if (i != TIMING_BUF_BYTES) { | ||
| 1351 | bb_error_msg("read(%d bytes) failed (rc=%d)", TIMING_BUF_BYTES, i); | ||
| 1352 | return 1; | ||
| 1353 | } | ||
| 1354 | /* access all sectors of buf to ensure the read fully completed */ | 1351 | /* access all sectors of buf to ensure the read fully completed */ |
| 1355 | for (i = 0; i < TIMING_BUF_BYTES; i += 512) | 1352 | for (i = 0; i < TIMING_BUF_BYTES; i += 512) |
| 1356 | buf[i] &= 1; | 1353 | buf[i] &= 1; |
| 1357 | return 0; | ||
| 1358 | } | 1354 | } |
| 1359 | 1355 | ||
| 1360 | static unsigned long long do_blkgetsize(/*int fd*/ void) | 1356 | static unsigned long long dev_size_mb(/*int fd*/ void) |
| 1361 | { | 1357 | { |
| 1362 | union { | 1358 | union { |
| 1363 | unsigned long long blksize64; | 1359 | unsigned long long blksize64; |
| @@ -1365,85 +1361,88 @@ static unsigned long long do_blkgetsize(/*int fd*/ void) | |||
| 1365 | } u; | 1361 | } u; |
| 1366 | 1362 | ||
| 1367 | if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // returns bytes | 1363 | if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // returns bytes |
| 1368 | return u.blksize64 / 512; | 1364 | return u.blksize64 / (1024 * 1024); |
| 1369 | } | 1365 | } |
| 1370 | xioctl(fd, BLKGETSIZE, &u.blksize32); // returns sectors | 1366 | xioctl(fd, BLKGETSIZE, &u.blksize32); // returns sectors |
| 1371 | return u.blksize32; | 1367 | return u.blksize32 / (2 * 1024); |
| 1372 | } | 1368 | } |
| 1373 | 1369 | ||
| 1374 | static void print_timing(unsigned t, double e) | 1370 | static void print_timing(unsigned long m, unsigned elapsed_us) |
| 1375 | { | 1371 | { |
| 1376 | if (t >= e) /* more than 1MB/s */ | 1372 | unsigned sec = elapsed_us / 1000000; |
| 1377 | printf("%4d MB in %.2f seconds = %.2f %cB/sec\n", t, e, t / e, 'M'); | 1373 | unsigned hs = (elapsed_us % 1000000) / 10000; |
| 1378 | else | 1374 | |
| 1379 | printf("%4d MB in %.2f seconds = %.2f %cB/sec\n", t, e, t / e * 1024, 'k'); | 1375 | printf("%5lu MB in %u.%02u seconds = %lu kB/s\n", |
| 1376 | m, sec, hs, | ||
| 1377 | /* Trying to not overflow 32-bit arith in m * CONST | ||
| 1378 | * by keeping CONST not so big. + 1 prevents div-by-0. */ | ||
| 1379 | (m * (1024 * 1000000 / (64*1024))) / (elapsed_us / (64*1024) + 1) | ||
| 1380 | // ~= (m * 1024 * 1000000) / elapsed_ms | ||
| 1381 | // = (m * 1024) / (elapsed_ms / 1000000) | ||
| 1382 | // = kb / elapsed_sec | ||
| 1383 | ); | ||
| 1380 | } | 1384 | } |
| 1381 | 1385 | ||
| 1382 | static void do_time(int flag /*,int fd*/) | 1386 | static void do_time(int cache /*,int fd*/) |
| 1383 | /* flag = 0 time_cache, 1 time_device */ | 1387 | /* cache=1: time cache: repeatedly read N MB at offset 0 |
| 1388 | * cache=0: time device: linear read, starting at offset 0 | ||
| 1389 | */ | ||
| 1384 | { | 1390 | { |
| 1385 | static const struct itimerval thousand = {{1000, 0}, {1000, 0}}; | 1391 | unsigned max_iterations, iterations; |
| 1386 | 1392 | unsigned start; /* don't need to be long long */ | |
| 1387 | struct itimerval itv; | ||
| 1388 | unsigned elapsed, elapsed2; | 1393 | unsigned elapsed, elapsed2; |
| 1389 | unsigned max_iterations, total_MB, iterations; | 1394 | unsigned long total_MB; |
| 1390 | char *buf = xmalloc(TIMING_BUF_BYTES); | 1395 | char *buf = xmalloc(TIMING_BUF_BYTES); |
| 1391 | 1396 | ||
| 1392 | if (mlock(buf, TIMING_BUF_BYTES)) { | 1397 | if (mlock(buf, TIMING_BUF_BYTES)) |
| 1393 | bb_perror_msg("mlock"); | 1398 | bb_perror_msg_and_die("mlock"); |
| 1394 | goto quit2; | ||
| 1395 | } | ||
| 1396 | 1399 | ||
| 1397 | max_iterations = do_blkgetsize() / (2 * 1024) / TIMING_BUF_MB; | 1400 | /* Don't want to read past the end! */ |
| 1401 | max_iterations = UINT_MAX; | ||
| 1402 | if (!cache) | ||
| 1403 | max_iterations = dev_size_mb() / TIMING_BUF_MB; | ||
| 1398 | 1404 | ||
| 1399 | /* Clear out the device request queues & give them time to complete */ | 1405 | /* Clear out the device request queues & give them time to complete. |
| 1406 | * NB: *small* delay. User is expected to have a clue and to not run | ||
| 1407 | * heavy io in parallel with measurements. */ | ||
| 1400 | sync(); | 1408 | sync(); |
| 1401 | sleep(2); | 1409 | sleep(1); |
| 1402 | if (flag == 0) { /* Time cache */ | 1410 | if (cache) { /* Time cache */ |
| 1403 | seek_to_zero(); | 1411 | seek_to_zero(); |
| 1404 | if (read_big_block(buf)) | 1412 | read_big_block(buf); |
| 1405 | goto quit; | 1413 | printf("Timing buffer-cache reads: "); |
| 1406 | printf(" Timing buffer-cache reads: "); | ||
| 1407 | } else { /* Time device */ | 1414 | } else { /* Time device */ |
| 1408 | printf(" Timing buffered disk reads: "); | 1415 | printf("Timing buffered disk reads:"); |
| 1409 | } | 1416 | } |
| 1410 | fflush(stdout); | 1417 | fflush(stdout); |
| 1411 | iterations = 0; | 1418 | |
| 1412 | /* | ||
| 1413 | * getitimer() is used rather than gettimeofday() because | ||
| 1414 | * it is much more consistent (on my machine, at least). | ||
| 1415 | */ | ||
| 1416 | //TODO: get rid of | ||
| 1417 | setitimer(ITIMER_REAL, &thousand, NULL); | ||
| 1418 | /* Now do the timing */ | 1419 | /* Now do the timing */ |
| 1420 | iterations = 0; | ||
| 1421 | start = monotonic_us(); | ||
| 1419 | do { | 1422 | do { |
| 1420 | ++iterations; | 1423 | if (cache) |
| 1421 | if (flag == 0) | ||
| 1422 | seek_to_zero(); | 1424 | seek_to_zero(); |
| 1423 | if (read_big_block(buf)) | 1425 | read_big_block(buf); |
| 1424 | goto quit; | 1426 | elapsed = (unsigned)monotonic_us() - start; |
| 1425 | getitimer(ITIMER_REAL, &itv); | 1427 | ++iterations; |
| 1426 | elapsed = (1000 - itv.it_value.tv_sec) * 1000000 | ||
| 1427 | - itv.it_value.tv_usec; | ||
| 1428 | } while (elapsed < 3000000 && iterations < max_iterations); | 1428 | } while (elapsed < 3000000 && iterations < max_iterations); |
| 1429 | total_MB = iterations * TIMING_BUF_MB; | 1429 | total_MB = (unsigned long)iterations * TIMING_BUF_MB; |
| 1430 | if (flag == 0) { | 1430 | //printf(" elapsed:%u iterations:%u ", elapsed, iterations); |
| 1431 | /* Now remove the lseek() and getitimer() overheads from the elapsed time */ | 1431 | if (cache) { |
| 1432 | setitimer(ITIMER_REAL, &thousand, NULL); | 1432 | /* Now remove the lseek() and monotonic_us() overheads |
| 1433 | * from elapsed */ | ||
| 1434 | start = monotonic_us(); | ||
| 1433 | do { | 1435 | do { |
| 1434 | seek_to_zero(); | 1436 | seek_to_zero(); |
| 1435 | getitimer(ITIMER_REAL, &itv); | 1437 | elapsed2 = (unsigned)monotonic_us() - start; |
| 1436 | elapsed2 = (1000 - itv.it_value.tv_sec) * 1000000 | ||
| 1437 | - itv.it_value.tv_usec; | ||
| 1438 | } while (--iterations); | 1438 | } while (--iterations); |
| 1439 | //printf(" elapsed2:%u ", elapsed2); | ||
| 1439 | elapsed -= elapsed2; | 1440 | elapsed -= elapsed2; |
| 1440 | total_MB *= BUFCACHE_FACTOR; | 1441 | total_MB *= 2; // BUFCACHE_FACTOR (why?) |
| 1441 | flush_buffer_cache(); | 1442 | flush_buffer_cache(); |
| 1442 | } | 1443 | } |
| 1443 | print_timing(total_MB, elapsed / 1000000.0); | 1444 | print_timing(total_MB, elapsed); |
| 1444 | quit: | ||
| 1445 | munlock(buf, TIMING_BUF_BYTES); | 1445 | munlock(buf, TIMING_BUF_BYTES); |
| 1446 | quit2: | ||
| 1447 | free(buf); | 1446 | free(buf); |
| 1448 | } | 1447 | } |
| 1449 | 1448 | ||
| @@ -1688,7 +1687,6 @@ static void process_dev(char *devname) | |||
| 1688 | #ifndef WIN_FLUSHCACHE | 1687 | #ifndef WIN_FLUSHCACHE |
| 1689 | #define WIN_FLUSHCACHE 0xe7 | 1688 | #define WIN_FLUSHCACHE 0xe7 |
| 1690 | #endif | 1689 | #endif |
| 1691 | static unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 }; | ||
| 1692 | #endif /* DO_FLUSHCACHE */ | 1690 | #endif /* DO_FLUSHCACHE */ |
| 1693 | args[2] = wcache ? 0x02 : 0x82; | 1691 | args[2] = wcache ? 0x02 : 0x82; |
| 1694 | print_flag_on_off(get_wcache, "drive write-caching", wcache); | 1692 | print_flag_on_off(get_wcache, "drive write-caching", wcache); |
| @@ -1749,7 +1747,7 @@ static void process_dev(char *devname) | |||
| 1749 | char buf[512]; | 1747 | char buf[512]; |
| 1750 | flush_buffer_cache(); | 1748 | flush_buffer_cache(); |
| 1751 | if (-1 == read(fd, buf, sizeof(buf))) | 1749 | if (-1 == read(fd, buf, sizeof(buf))) |
| 1752 | bb_perror_msg("read(%d bytes) failed (rc=%d)", sizeof(buf), -1); | 1750 | bb_perror_msg("read(%d bytes) failed (rc=-1)", sizeof(buf)); |
| 1753 | } | 1751 | } |
| 1754 | #endif /* HDIO_DRIVE_CMD */ | 1752 | #endif /* HDIO_DRIVE_CMD */ |
| 1755 | 1753 | ||
| @@ -1912,9 +1910,9 @@ static void process_dev(char *devname) | |||
| 1912 | ioctl_or_warn(fd, BLKRRPART, NULL); | 1910 | ioctl_or_warn(fd, BLKRRPART, NULL); |
| 1913 | 1911 | ||
| 1914 | if (do_ctimings) | 1912 | if (do_ctimings) |
| 1915 | do_time(0 /*,fd*/); /* time cache */ | 1913 | do_time(1 /*,fd*/); /* time cache */ |
| 1916 | if (do_timings) | 1914 | if (do_timings) |
| 1917 | do_time(1 /*,fd*/); /* time device */ | 1915 | do_time(0 /*,fd*/); /* time device */ |
| 1918 | if (do_flush) | 1916 | if (do_flush) |
| 1919 | flush_buffer_cache(); | 1917 | flush_buffer_cache(); |
| 1920 | close(fd); | 1918 | close(fd); |
