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