diff options
author | Adrian Hunter <adrian.hunter@nokia.com> | 2011-02-08 06:41:02 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-03-15 13:48:42 -0400 |
commit | b6056d12342f936256cbf64c86459af06f11cd5e (patch) | |
tree | ab033f6d6d53f29a5f5953cb77de333bf229ea24 /drivers/mmc/card | |
parent | 0532ff6358ae00615cfba7212f5075356b437c66 (diff) |
mmc: mmc_test: add tests to measure random I/O operations per second
Existing performance tests measure single or sequential I/O speed.
Add two random I/O tests:
33. Random read performance by transfer size
34. Random write performance by transfer size
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/card')
-rw-r--r-- | drivers/mmc/card/mmc_test.c | 139 |
1 files changed, 128 insertions, 11 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index ec6060c06ce8..d1aa57a4d058 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c | |||
@@ -88,6 +88,7 @@ struct mmc_test_area { | |||
88 | * @sectors: amount of sectors to check in one group | 88 | * @sectors: amount of sectors to check in one group |
89 | * @ts: time values of transfer | 89 | * @ts: time values of transfer |
90 | * @rate: calculated transfer rate | 90 | * @rate: calculated transfer rate |
91 | * @iops: I/O operations per second (times 100) | ||
91 | */ | 92 | */ |
92 | struct mmc_test_transfer_result { | 93 | struct mmc_test_transfer_result { |
93 | struct list_head link; | 94 | struct list_head link; |
@@ -95,6 +96,7 @@ struct mmc_test_transfer_result { | |||
95 | unsigned int sectors; | 96 | unsigned int sectors; |
96 | struct timespec ts; | 97 | struct timespec ts; |
97 | unsigned int rate; | 98 | unsigned int rate; |
99 | unsigned int iops; | ||
98 | }; | 100 | }; |
99 | 101 | ||
100 | /** | 102 | /** |
@@ -495,7 +497,7 @@ static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts) | |||
495 | */ | 497 | */ |
496 | static void mmc_test_save_transfer_result(struct mmc_test_card *test, | 498 | static void mmc_test_save_transfer_result(struct mmc_test_card *test, |
497 | unsigned int count, unsigned int sectors, struct timespec ts, | 499 | unsigned int count, unsigned int sectors, struct timespec ts, |
498 | unsigned int rate) | 500 | unsigned int rate, unsigned int iops) |
499 | { | 501 | { |
500 | struct mmc_test_transfer_result *tr; | 502 | struct mmc_test_transfer_result *tr; |
501 | 503 | ||
@@ -510,6 +512,7 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test, | |||
510 | tr->sectors = sectors; | 512 | tr->sectors = sectors; |
511 | tr->ts = ts; | 513 | tr->ts = ts; |
512 | tr->rate = rate; | 514 | tr->rate = rate; |
515 | tr->iops = iops; | ||
513 | 516 | ||
514 | list_add_tail(&tr->link, &test->gr->tr_lst); | 517 | list_add_tail(&tr->link, &test->gr->tr_lst); |
515 | } | 518 | } |
@@ -520,20 +523,22 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test, | |||
520 | static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes, | 523 | static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes, |
521 | struct timespec *ts1, struct timespec *ts2) | 524 | struct timespec *ts1, struct timespec *ts2) |
522 | { | 525 | { |
523 | unsigned int rate, sectors = bytes >> 9; | 526 | unsigned int rate, iops, sectors = bytes >> 9; |
524 | struct timespec ts; | 527 | struct timespec ts; |
525 | 528 | ||
526 | ts = timespec_sub(*ts2, *ts1); | 529 | ts = timespec_sub(*ts2, *ts1); |
527 | 530 | ||
528 | rate = mmc_test_rate(bytes, &ts); | 531 | rate = mmc_test_rate(bytes, &ts); |
532 | iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */ | ||
529 | 533 | ||
530 | printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " | 534 | printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " |
531 | "seconds (%u kB/s, %u KiB/s)\n", | 535 | "seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n", |
532 | mmc_hostname(test->card->host), sectors, sectors >> 1, | 536 | mmc_hostname(test->card->host), sectors, sectors >> 1, |
533 | (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec, | 537 | (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec, |
534 | (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024); | 538 | (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024, |
539 | iops / 100, iops % 100); | ||
535 | 540 | ||
536 | mmc_test_save_transfer_result(test, 1, sectors, ts, rate); | 541 | mmc_test_save_transfer_result(test, 1, sectors, ts, rate, iops); |
537 | } | 542 | } |
538 | 543 | ||
539 | /* | 544 | /* |
@@ -543,22 +548,24 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes, | |||
543 | unsigned int count, struct timespec *ts1, | 548 | unsigned int count, struct timespec *ts1, |
544 | struct timespec *ts2) | 549 | struct timespec *ts2) |
545 | { | 550 | { |
546 | unsigned int rate, sectors = bytes >> 9; | 551 | unsigned int rate, iops, sectors = bytes >> 9; |
547 | uint64_t tot = bytes * count; | 552 | uint64_t tot = bytes * count; |
548 | struct timespec ts; | 553 | struct timespec ts; |
549 | 554 | ||
550 | ts = timespec_sub(*ts2, *ts1); | 555 | ts = timespec_sub(*ts2, *ts1); |
551 | 556 | ||
552 | rate = mmc_test_rate(tot, &ts); | 557 | rate = mmc_test_rate(tot, &ts); |
558 | iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */ | ||
553 | 559 | ||
554 | printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " | 560 | printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " |
555 | "%lu.%09lu seconds (%u kB/s, %u KiB/s)\n", | 561 | "%lu.%09lu seconds (%u kB/s, %u KiB/s, " |
562 | "%u.%02u IOPS)\n", | ||
556 | mmc_hostname(test->card->host), count, sectors, count, | 563 | mmc_hostname(test->card->host), count, sectors, count, |
557 | sectors >> 1, (sectors & 1 ? ".5" : ""), | 564 | sectors >> 1, (sectors & 1 ? ".5" : ""), |
558 | (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec, | 565 | (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec, |
559 | rate / 1000, rate / 1024); | 566 | rate / 1000, rate / 1024, iops / 100, iops % 100); |
560 | 567 | ||
561 | mmc_test_save_transfer_result(test, count, sectors, ts, rate); | 568 | mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops); |
562 | } | 569 | } |
563 | 570 | ||
564 | /* | 571 | /* |
@@ -1768,6 +1775,102 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test) | |||
1768 | return 0; | 1775 | return 0; |
1769 | } | 1776 | } |
1770 | 1777 | ||
1778 | static unsigned int rnd_next = 1; | ||
1779 | |||
1780 | static unsigned int mmc_test_rnd_num(unsigned int rnd_cnt) | ||
1781 | { | ||
1782 | uint64_t r; | ||
1783 | |||
1784 | rnd_next = rnd_next * 1103515245 + 12345; | ||
1785 | r = (rnd_next >> 16) & 0x7fff; | ||
1786 | return (r * rnd_cnt) >> 15; | ||
1787 | } | ||
1788 | |||
1789 | static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print, | ||
1790 | unsigned long sz) | ||
1791 | { | ||
1792 | unsigned int dev_addr, cnt, rnd_addr, range1, range2, last_ea = 0, ea; | ||
1793 | unsigned int ssz; | ||
1794 | struct timespec ts1, ts2, ts; | ||
1795 | int ret; | ||
1796 | |||
1797 | ssz = sz >> 9; | ||
1798 | |||
1799 | rnd_addr = mmc_test_capacity(test->card) / 4; | ||
1800 | range1 = rnd_addr / test->card->pref_erase; | ||
1801 | range2 = range1 / ssz; | ||
1802 | |||
1803 | getnstimeofday(&ts1); | ||
1804 | for (cnt = 0; cnt < UINT_MAX; cnt++) { | ||
1805 | getnstimeofday(&ts2); | ||
1806 | ts = timespec_sub(ts2, ts1); | ||
1807 | if (ts.tv_sec >= 10) | ||
1808 | break; | ||
1809 | ea = mmc_test_rnd_num(range1); | ||
1810 | if (ea == last_ea) | ||
1811 | ea -= 1; | ||
1812 | last_ea = ea; | ||
1813 | dev_addr = rnd_addr + test->card->pref_erase * ea + | ||
1814 | ssz * mmc_test_rnd_num(range2); | ||
1815 | ret = mmc_test_area_io(test, sz, dev_addr, write, 0, 0); | ||
1816 | if (ret) | ||
1817 | return ret; | ||
1818 | } | ||
1819 | if (print) | ||
1820 | mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); | ||
1821 | return 0; | ||
1822 | } | ||
1823 | |||
1824 | static int mmc_test_random_perf(struct mmc_test_card *test, int write) | ||
1825 | { | ||
1826 | unsigned int next; | ||
1827 | unsigned long sz; | ||
1828 | int ret; | ||
1829 | |||
1830 | for (sz = 512; sz < test->area.max_tfr; sz <<= 1) { | ||
1831 | /* | ||
1832 | * When writing, try to get more consistent results by running | ||
1833 | * the test twice with exactly the same I/O but outputting the | ||
1834 | * results only for the 2nd run. | ||
1835 | */ | ||
1836 | if (write) { | ||
1837 | next = rnd_next; | ||
1838 | ret = mmc_test_rnd_perf(test, write, 0, sz); | ||
1839 | if (ret) | ||
1840 | return ret; | ||
1841 | rnd_next = next; | ||
1842 | } | ||
1843 | ret = mmc_test_rnd_perf(test, write, 1, sz); | ||
1844 | if (ret) | ||
1845 | return ret; | ||
1846 | } | ||
1847 | sz = test->area.max_tfr; | ||
1848 | if (write) { | ||
1849 | next = rnd_next; | ||
1850 | ret = mmc_test_rnd_perf(test, write, 0, sz); | ||
1851 | if (ret) | ||
1852 | return ret; | ||
1853 | rnd_next = next; | ||
1854 | } | ||
1855 | return mmc_test_rnd_perf(test, write, 1, sz); | ||
1856 | } | ||
1857 | |||
1858 | /* | ||
1859 | * Random read performance by transfer size. | ||
1860 | */ | ||
1861 | static int mmc_test_random_read_perf(struct mmc_test_card *test) | ||
1862 | { | ||
1863 | return mmc_test_random_perf(test, 0); | ||
1864 | } | ||
1865 | |||
1866 | /* | ||
1867 | * Random write performance by transfer size. | ||
1868 | */ | ||
1869 | static int mmc_test_random_write_perf(struct mmc_test_card *test) | ||
1870 | { | ||
1871 | return mmc_test_random_perf(test, 1); | ||
1872 | } | ||
1873 | |||
1771 | static const struct mmc_test_case mmc_test_cases[] = { | 1874 | static const struct mmc_test_case mmc_test_cases[] = { |
1772 | { | 1875 | { |
1773 | .name = "Basic write (no data verification)", | 1876 | .name = "Basic write (no data verification)", |
@@ -2007,6 +2110,20 @@ static const struct mmc_test_case mmc_test_cases[] = { | |||
2007 | .cleanup = mmc_test_area_cleanup, | 2110 | .cleanup = mmc_test_area_cleanup, |
2008 | }, | 2111 | }, |
2009 | 2112 | ||
2113 | { | ||
2114 | .name = "Random read performance by transfer size", | ||
2115 | .prepare = mmc_test_area_prepare, | ||
2116 | .run = mmc_test_random_read_perf, | ||
2117 | .cleanup = mmc_test_area_cleanup, | ||
2118 | }, | ||
2119 | |||
2120 | { | ||
2121 | .name = "Random write performance by transfer size", | ||
2122 | .prepare = mmc_test_area_prepare, | ||
2123 | .run = mmc_test_random_write_perf, | ||
2124 | .cleanup = mmc_test_area_cleanup, | ||
2125 | }, | ||
2126 | |||
2010 | }; | 2127 | }; |
2011 | 2128 | ||
2012 | static DEFINE_MUTEX(mmc_test_lock); | 2129 | static DEFINE_MUTEX(mmc_test_lock); |
@@ -2150,11 +2267,11 @@ static int mtf_test_show(struct seq_file *sf, void *data) | |||
2150 | seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result); | 2267 | seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result); |
2151 | 2268 | ||
2152 | list_for_each_entry(tr, &gr->tr_lst, link) { | 2269 | list_for_each_entry(tr, &gr->tr_lst, link) { |
2153 | seq_printf(sf, "%u %d %lu.%09lu %u\n", | 2270 | seq_printf(sf, "%u %d %lu.%09lu %u %u.%02u\n", |
2154 | tr->count, tr->sectors, | 2271 | tr->count, tr->sectors, |
2155 | (unsigned long)tr->ts.tv_sec, | 2272 | (unsigned long)tr->ts.tv_sec, |
2156 | (unsigned long)tr->ts.tv_nsec, | 2273 | (unsigned long)tr->ts.tv_nsec, |
2157 | tr->rate); | 2274 | tr->rate, tr->iops / 100, tr->iops % 100); |
2158 | } | 2275 | } |
2159 | } | 2276 | } |
2160 | 2277 | ||