diff options
author | Per Forlin <per.forlin@linaro.org> | 2011-07-01 12:55:27 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-07-20 17:21:12 -0400 |
commit | bf043330362b1ccb0c0611b8fc394e06ba8498b0 (patch) | |
tree | 487ce7a117c16e63d6d49cb74df21d7fdf3ce03f /drivers/mmc/card | |
parent | 9f9c4180f88d127e2bb83913d80750a8fbdb8f3e (diff) |
mmc: mmc_test: test to measure how sg_len affect performance
Add a test that measures how the mmc bandwidth depends on the numbers of
sg elements in the sg list. The transfer size if fixed and sg length goes
from a few up to 512. The purpose is to measure overhead caused by
multiple sg elements.
Signed-off-by: Per Forlin <per.forlin@linaro.org>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Venkatraman S <svenkatr@ti.com>
Tested-by: Sourav Poddar <sourav.poddar@ti.com>
Tested-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/card')
-rw-r--r-- | drivers/mmc/card/mmc_test.c | 151 |
1 files changed, 139 insertions, 12 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 51031a54470..006a5e9f8ab 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c | |||
@@ -155,6 +155,7 @@ enum mmc_test_prep_media { | |||
155 | }; | 155 | }; |
156 | 156 | ||
157 | struct mmc_test_multiple_rw { | 157 | struct mmc_test_multiple_rw { |
158 | unsigned int *sg_len; | ||
158 | unsigned int *bs; | 159 | unsigned int *bs; |
159 | unsigned int len; | 160 | unsigned int len; |
160 | unsigned int size; | 161 | unsigned int size; |
@@ -387,21 +388,26 @@ out_free: | |||
387 | * Map memory into a scatterlist. Optionally allow the same memory to be | 388 | * Map memory into a scatterlist. Optionally allow the same memory to be |
388 | * mapped more than once. | 389 | * mapped more than once. |
389 | */ | 390 | */ |
390 | static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz, | 391 | static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long size, |
391 | struct scatterlist *sglist, int repeat, | 392 | struct scatterlist *sglist, int repeat, |
392 | unsigned int max_segs, unsigned int max_seg_sz, | 393 | unsigned int max_segs, unsigned int max_seg_sz, |
393 | unsigned int *sg_len) | 394 | unsigned int *sg_len, int min_sg_len) |
394 | { | 395 | { |
395 | struct scatterlist *sg = NULL; | 396 | struct scatterlist *sg = NULL; |
396 | unsigned int i; | 397 | unsigned int i; |
398 | unsigned long sz = size; | ||
397 | 399 | ||
398 | sg_init_table(sglist, max_segs); | 400 | sg_init_table(sglist, max_segs); |
401 | if (min_sg_len > max_segs) | ||
402 | min_sg_len = max_segs; | ||
399 | 403 | ||
400 | *sg_len = 0; | 404 | *sg_len = 0; |
401 | do { | 405 | do { |
402 | for (i = 0; i < mem->cnt; i++) { | 406 | for (i = 0; i < mem->cnt; i++) { |
403 | unsigned long len = PAGE_SIZE << mem->arr[i].order; | 407 | unsigned long len = PAGE_SIZE << mem->arr[i].order; |
404 | 408 | ||
409 | if (min_sg_len && (size / min_sg_len < len)) | ||
410 | len = ALIGN(size / min_sg_len, 512); | ||
405 | if (len > sz) | 411 | if (len > sz) |
406 | len = sz; | 412 | len = sz; |
407 | if (len > max_seg_sz) | 413 | if (len > max_seg_sz) |
@@ -574,11 +580,12 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes, | |||
574 | 580 | ||
575 | printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " | 581 | printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " |
576 | "%lu.%09lu seconds (%u kB/s, %u KiB/s, " | 582 | "%lu.%09lu seconds (%u kB/s, %u KiB/s, " |
577 | "%u.%02u IOPS)\n", | 583 | "%u.%02u IOPS, sg_len %d)\n", |
578 | mmc_hostname(test->card->host), count, sectors, count, | 584 | mmc_hostname(test->card->host), count, sectors, count, |
579 | sectors >> 1, (sectors & 1 ? ".5" : ""), | 585 | sectors >> 1, (sectors & 1 ? ".5" : ""), |
580 | (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec, | 586 | (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec, |
581 | rate / 1000, rate / 1024, iops / 100, iops % 100); | 587 | rate / 1000, rate / 1024, iops / 100, iops % 100, |
588 | test->area.sg_len); | ||
582 | 589 | ||
583 | mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops); | 590 | mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops); |
584 | } | 591 | } |
@@ -1412,7 +1419,7 @@ static int mmc_test_no_highmem(struct mmc_test_card *test) | |||
1412 | * Map sz bytes so that it can be transferred. | 1419 | * Map sz bytes so that it can be transferred. |
1413 | */ | 1420 | */ |
1414 | static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz, | 1421 | static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz, |
1415 | int max_scatter) | 1422 | int max_scatter, int min_sg_len) |
1416 | { | 1423 | { |
1417 | struct mmc_test_area *t = &test->area; | 1424 | struct mmc_test_area *t = &test->area; |
1418 | int err; | 1425 | int err; |
@@ -1425,7 +1432,7 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz, | |||
1425 | &t->sg_len); | 1432 | &t->sg_len); |
1426 | } else { | 1433 | } else { |
1427 | err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs, | 1434 | err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs, |
1428 | t->max_seg_sz, &t->sg_len); | 1435 | t->max_seg_sz, &t->sg_len, min_sg_len); |
1429 | } | 1436 | } |
1430 | if (err) | 1437 | if (err) |
1431 | printk(KERN_INFO "%s: Failed to map sg list\n", | 1438 | printk(KERN_INFO "%s: Failed to map sg list\n", |
@@ -1451,7 +1458,7 @@ static int mmc_test_area_transfer(struct mmc_test_card *test, | |||
1451 | static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz, | 1458 | static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz, |
1452 | unsigned int dev_addr, int write, | 1459 | unsigned int dev_addr, int write, |
1453 | int max_scatter, int timed, int count, | 1460 | int max_scatter, int timed, int count, |
1454 | bool nonblock) | 1461 | bool nonblock, int min_sg_len) |
1455 | { | 1462 | { |
1456 | struct timespec ts1, ts2; | 1463 | struct timespec ts1, ts2; |
1457 | int ret = 0; | 1464 | int ret = 0; |
@@ -1474,7 +1481,7 @@ static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz, | |||
1474 | sz = max_tfr; | 1481 | sz = max_tfr; |
1475 | } | 1482 | } |
1476 | 1483 | ||
1477 | ret = mmc_test_area_map(test, sz, max_scatter); | 1484 | ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len); |
1478 | if (ret) | 1485 | if (ret) |
1479 | return ret; | 1486 | return ret; |
1480 | 1487 | ||
@@ -1506,7 +1513,7 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz, | |||
1506 | int timed) | 1513 | int timed) |
1507 | { | 1514 | { |
1508 | return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter, | 1515 | return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter, |
1509 | timed, 1, false); | 1516 | timed, 1, false, 0); |
1510 | } | 1517 | } |
1511 | 1518 | ||
1512 | /* | 1519 | /* |
@@ -2084,7 +2091,8 @@ static int mmc_test_large_seq_write_perf(struct mmc_test_card *test) | |||
2084 | 2091 | ||
2085 | static int mmc_test_rw_multiple(struct mmc_test_card *test, | 2092 | static int mmc_test_rw_multiple(struct mmc_test_card *test, |
2086 | struct mmc_test_multiple_rw *tdata, | 2093 | struct mmc_test_multiple_rw *tdata, |
2087 | unsigned int reqsize, unsigned int size) | 2094 | unsigned int reqsize, unsigned int size, |
2095 | int min_sg_len) | ||
2088 | { | 2096 | { |
2089 | unsigned int dev_addr; | 2097 | unsigned int dev_addr; |
2090 | struct mmc_test_area *t = &test->area; | 2098 | struct mmc_test_area *t = &test->area; |
@@ -2121,7 +2129,7 @@ static int mmc_test_rw_multiple(struct mmc_test_card *test, | |||
2121 | /* Run test */ | 2129 | /* Run test */ |
2122 | ret = mmc_test_area_io_seq(test, reqsize, dev_addr, | 2130 | ret = mmc_test_area_io_seq(test, reqsize, dev_addr, |
2123 | tdata->do_write, 0, 1, size / reqsize, | 2131 | tdata->do_write, 0, 1, size / reqsize, |
2124 | tdata->do_nonblock_req); | 2132 | tdata->do_nonblock_req, min_sg_len); |
2125 | if (ret) | 2133 | if (ret) |
2126 | goto err; | 2134 | goto err; |
2127 | 2135 | ||
@@ -2146,7 +2154,22 @@ static int mmc_test_rw_multiple_size(struct mmc_test_card *test, | |||
2146 | } | 2154 | } |
2147 | 2155 | ||
2148 | for (i = 0 ; i < rw->len && ret == 0; i++) { | 2156 | for (i = 0 ; i < rw->len && ret == 0; i++) { |
2149 | ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size); | 2157 | ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size, 0); |
2158 | if (ret) | ||
2159 | break; | ||
2160 | } | ||
2161 | return ret; | ||
2162 | } | ||
2163 | |||
2164 | static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test, | ||
2165 | struct mmc_test_multiple_rw *rw) | ||
2166 | { | ||
2167 | int ret = 0; | ||
2168 | int i; | ||
2169 | |||
2170 | for (i = 0 ; i < rw->len && ret == 0; i++) { | ||
2171 | ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size, | ||
2172 | rw->sg_len[i]); | ||
2150 | if (ret) | 2173 | if (ret) |
2151 | break; | 2174 | break; |
2152 | } | 2175 | } |
@@ -2229,6 +2252,82 @@ static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test) | |||
2229 | return mmc_test_rw_multiple_size(test, &test_data); | 2252 | return mmc_test_rw_multiple_size(test, &test_data); |
2230 | } | 2253 | } |
2231 | 2254 | ||
2255 | /* | ||
2256 | * Multiple blocking write 1 to 512 sg elements | ||
2257 | */ | ||
2258 | static int mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card *test) | ||
2259 | { | ||
2260 | unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6, | ||
2261 | 1 << 7, 1 << 8, 1 << 9}; | ||
2262 | struct mmc_test_multiple_rw test_data = { | ||
2263 | .sg_len = sg_len, | ||
2264 | .size = TEST_AREA_MAX_SIZE, | ||
2265 | .len = ARRAY_SIZE(sg_len), | ||
2266 | .do_write = true, | ||
2267 | .do_nonblock_req = false, | ||
2268 | .prepare = MMC_TEST_PREP_ERASE, | ||
2269 | }; | ||
2270 | |||
2271 | return mmc_test_rw_multiple_sg_len(test, &test_data); | ||
2272 | }; | ||
2273 | |||
2274 | /* | ||
2275 | * Multiple non-blocking write 1 to 512 sg elements | ||
2276 | */ | ||
2277 | static int mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card *test) | ||
2278 | { | ||
2279 | unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6, | ||
2280 | 1 << 7, 1 << 8, 1 << 9}; | ||
2281 | struct mmc_test_multiple_rw test_data = { | ||
2282 | .sg_len = sg_len, | ||
2283 | .size = TEST_AREA_MAX_SIZE, | ||
2284 | .len = ARRAY_SIZE(sg_len), | ||
2285 | .do_write = true, | ||
2286 | .do_nonblock_req = true, | ||
2287 | .prepare = MMC_TEST_PREP_ERASE, | ||
2288 | }; | ||
2289 | |||
2290 | return mmc_test_rw_multiple_sg_len(test, &test_data); | ||
2291 | } | ||
2292 | |||
2293 | /* | ||
2294 | * Multiple blocking read 1 to 512 sg elements | ||
2295 | */ | ||
2296 | static int mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card *test) | ||
2297 | { | ||
2298 | unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6, | ||
2299 | 1 << 7, 1 << 8, 1 << 9}; | ||
2300 | struct mmc_test_multiple_rw test_data = { | ||
2301 | .sg_len = sg_len, | ||
2302 | .size = TEST_AREA_MAX_SIZE, | ||
2303 | .len = ARRAY_SIZE(sg_len), | ||
2304 | .do_write = false, | ||
2305 | .do_nonblock_req = false, | ||
2306 | .prepare = MMC_TEST_PREP_NONE, | ||
2307 | }; | ||
2308 | |||
2309 | return mmc_test_rw_multiple_sg_len(test, &test_data); | ||
2310 | } | ||
2311 | |||
2312 | /* | ||
2313 | * Multiple non-blocking read 1 to 512 sg elements | ||
2314 | */ | ||
2315 | static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test) | ||
2316 | { | ||
2317 | unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6, | ||
2318 | 1 << 7, 1 << 8, 1 << 9}; | ||
2319 | struct mmc_test_multiple_rw test_data = { | ||
2320 | .sg_len = sg_len, | ||
2321 | .size = TEST_AREA_MAX_SIZE, | ||
2322 | .len = ARRAY_SIZE(sg_len), | ||
2323 | .do_write = false, | ||
2324 | .do_nonblock_req = true, | ||
2325 | .prepare = MMC_TEST_PREP_NONE, | ||
2326 | }; | ||
2327 | |||
2328 | return mmc_test_rw_multiple_sg_len(test, &test_data); | ||
2329 | } | ||
2330 | |||
2232 | static const struct mmc_test_case mmc_test_cases[] = { | 2331 | static const struct mmc_test_case mmc_test_cases[] = { |
2233 | { | 2332 | { |
2234 | .name = "Basic write (no data verification)", | 2333 | .name = "Basic write (no data verification)", |
@@ -2523,6 +2622,34 @@ static const struct mmc_test_case mmc_test_cases[] = { | |||
2523 | .run = mmc_test_profile_mult_read_nonblock_perf, | 2622 | .run = mmc_test_profile_mult_read_nonblock_perf, |
2524 | .cleanup = mmc_test_area_cleanup, | 2623 | .cleanup = mmc_test_area_cleanup, |
2525 | }, | 2624 | }, |
2625 | |||
2626 | { | ||
2627 | .name = "Write performance blocking req 1 to 512 sg elems", | ||
2628 | .prepare = mmc_test_area_prepare, | ||
2629 | .run = mmc_test_profile_sglen_wr_blocking_perf, | ||
2630 | .cleanup = mmc_test_area_cleanup, | ||
2631 | }, | ||
2632 | |||
2633 | { | ||
2634 | .name = "Write performance non-blocking req 1 to 512 sg elems", | ||
2635 | .prepare = mmc_test_area_prepare, | ||
2636 | .run = mmc_test_profile_sglen_wr_nonblock_perf, | ||
2637 | .cleanup = mmc_test_area_cleanup, | ||
2638 | }, | ||
2639 | |||
2640 | { | ||
2641 | .name = "Read performance blocking req 1 to 512 sg elems", | ||
2642 | .prepare = mmc_test_area_prepare, | ||
2643 | .run = mmc_test_profile_sglen_r_blocking_perf, | ||
2644 | .cleanup = mmc_test_area_cleanup, | ||
2645 | }, | ||
2646 | |||
2647 | { | ||
2648 | .name = "Read performance non-blocking req 1 to 512 sg elems", | ||
2649 | .prepare = mmc_test_area_prepare, | ||
2650 | .run = mmc_test_profile_sglen_r_nonblock_perf, | ||
2651 | .cleanup = mmc_test_area_cleanup, | ||
2652 | }, | ||
2526 | }; | 2653 | }; |
2527 | 2654 | ||
2528 | static DEFINE_MUTEX(mmc_test_lock); | 2655 | static DEFINE_MUTEX(mmc_test_lock); |