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>
This commit is contained in:
@@ -155,6 +155,7 @@ enum mmc_test_prep_media {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct mmc_test_multiple_rw {
|
struct mmc_test_multiple_rw {
|
||||||
|
unsigned int *sg_len;
|
||||||
unsigned int *bs;
|
unsigned int *bs;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
@@ -387,21 +388,26 @@ out_free:
|
|||||||
* Map memory into a scatterlist. Optionally allow the same memory to be
|
* Map memory into a scatterlist. Optionally allow the same memory to be
|
||||||
* mapped more than once.
|
* mapped more than once.
|
||||||
*/
|
*/
|
||||||
static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
|
static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long size,
|
||||||
struct scatterlist *sglist, int repeat,
|
struct scatterlist *sglist, int repeat,
|
||||||
unsigned int max_segs, unsigned int max_seg_sz,
|
unsigned int max_segs, unsigned int max_seg_sz,
|
||||||
unsigned int *sg_len)
|
unsigned int *sg_len, int min_sg_len)
|
||||||
{
|
{
|
||||||
struct scatterlist *sg = NULL;
|
struct scatterlist *sg = NULL;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
unsigned long sz = size;
|
||||||
|
|
||||||
sg_init_table(sglist, max_segs);
|
sg_init_table(sglist, max_segs);
|
||||||
|
if (min_sg_len > max_segs)
|
||||||
|
min_sg_len = max_segs;
|
||||||
|
|
||||||
*sg_len = 0;
|
*sg_len = 0;
|
||||||
do {
|
do {
|
||||||
for (i = 0; i < mem->cnt; i++) {
|
for (i = 0; i < mem->cnt; i++) {
|
||||||
unsigned long len = PAGE_SIZE << mem->arr[i].order;
|
unsigned long len = PAGE_SIZE << mem->arr[i].order;
|
||||||
|
|
||||||
|
if (min_sg_len && (size / min_sg_len < len))
|
||||||
|
len = ALIGN(size / min_sg_len, 512);
|
||||||
if (len > sz)
|
if (len > sz)
|
||||||
len = sz;
|
len = sz;
|
||||||
if (len > max_seg_sz)
|
if (len > max_seg_sz)
|
||||||
@@ -574,11 +580,12 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
|
|||||||
|
|
||||||
printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
|
printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
|
||||||
"%lu.%09lu seconds (%u kB/s, %u KiB/s, "
|
"%lu.%09lu seconds (%u kB/s, %u KiB/s, "
|
||||||
"%u.%02u IOPS)\n",
|
"%u.%02u IOPS, sg_len %d)\n",
|
||||||
mmc_hostname(test->card->host), count, sectors, count,
|
mmc_hostname(test->card->host), count, sectors, count,
|
||||||
sectors >> 1, (sectors & 1 ? ".5" : ""),
|
sectors >> 1, (sectors & 1 ? ".5" : ""),
|
||||||
(unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
|
(unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
|
||||||
rate / 1000, rate / 1024, iops / 100, iops % 100);
|
rate / 1000, rate / 1024, iops / 100, iops % 100,
|
||||||
|
test->area.sg_len);
|
||||||
|
|
||||||
mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops);
|
mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops);
|
||||||
}
|
}
|
||||||
@@ -1412,7 +1419,7 @@ static int mmc_test_no_highmem(struct mmc_test_card *test)
|
|||||||
* Map sz bytes so that it can be transferred.
|
* Map sz bytes so that it can be transferred.
|
||||||
*/
|
*/
|
||||||
static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
|
static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
|
||||||
int max_scatter)
|
int max_scatter, int min_sg_len)
|
||||||
{
|
{
|
||||||
struct mmc_test_area *t = &test->area;
|
struct mmc_test_area *t = &test->area;
|
||||||
int err;
|
int err;
|
||||||
@@ -1425,7 +1432,7 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
|
|||||||
&t->sg_len);
|
&t->sg_len);
|
||||||
} else {
|
} else {
|
||||||
err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
|
err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
|
||||||
t->max_seg_sz, &t->sg_len);
|
t->max_seg_sz, &t->sg_len, min_sg_len);
|
||||||
}
|
}
|
||||||
if (err)
|
if (err)
|
||||||
printk(KERN_INFO "%s: Failed to map sg list\n",
|
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,
|
|||||||
static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
|
static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
|
||||||
unsigned int dev_addr, int write,
|
unsigned int dev_addr, int write,
|
||||||
int max_scatter, int timed, int count,
|
int max_scatter, int timed, int count,
|
||||||
bool nonblock)
|
bool nonblock, int min_sg_len)
|
||||||
{
|
{
|
||||||
struct timespec ts1, ts2;
|
struct timespec ts1, ts2;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -1474,7 +1481,7 @@ static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
|
|||||||
sz = max_tfr;
|
sz = max_tfr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mmc_test_area_map(test, sz, max_scatter);
|
ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -1506,7 +1513,7 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
|
|||||||
int timed)
|
int timed)
|
||||||
{
|
{
|
||||||
return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter,
|
return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter,
|
||||||
timed, 1, false);
|
timed, 1, false, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2084,7 +2091,8 @@ static int mmc_test_large_seq_write_perf(struct mmc_test_card *test)
|
|||||||
|
|
||||||
static int mmc_test_rw_multiple(struct mmc_test_card *test,
|
static int mmc_test_rw_multiple(struct mmc_test_card *test,
|
||||||
struct mmc_test_multiple_rw *tdata,
|
struct mmc_test_multiple_rw *tdata,
|
||||||
unsigned int reqsize, unsigned int size)
|
unsigned int reqsize, unsigned int size,
|
||||||
|
int min_sg_len)
|
||||||
{
|
{
|
||||||
unsigned int dev_addr;
|
unsigned int dev_addr;
|
||||||
struct mmc_test_area *t = &test->area;
|
struct mmc_test_area *t = &test->area;
|
||||||
@@ -2121,7 +2129,7 @@ static int mmc_test_rw_multiple(struct mmc_test_card *test,
|
|||||||
/* Run test */
|
/* Run test */
|
||||||
ret = mmc_test_area_io_seq(test, reqsize, dev_addr,
|
ret = mmc_test_area_io_seq(test, reqsize, dev_addr,
|
||||||
tdata->do_write, 0, 1, size / reqsize,
|
tdata->do_write, 0, 1, size / reqsize,
|
||||||
tdata->do_nonblock_req);
|
tdata->do_nonblock_req, min_sg_len);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@@ -2146,7 +2154,22 @@ static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0 ; i < rw->len && ret == 0; i++) {
|
for (i = 0 ; i < rw->len && ret == 0; i++) {
|
||||||
ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size);
|
ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size, 0);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test,
|
||||||
|
struct mmc_test_multiple_rw *rw)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0 ; i < rw->len && ret == 0; i++) {
|
||||||
|
ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size,
|
||||||
|
rw->sg_len[i]);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2229,6 +2252,82 @@ static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test)
|
|||||||
return mmc_test_rw_multiple_size(test, &test_data);
|
return mmc_test_rw_multiple_size(test, &test_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Multiple blocking write 1 to 512 sg elements
|
||||||
|
*/
|
||||||
|
static int mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card *test)
|
||||||
|
{
|
||||||
|
unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
|
||||||
|
1 << 7, 1 << 8, 1 << 9};
|
||||||
|
struct mmc_test_multiple_rw test_data = {
|
||||||
|
.sg_len = sg_len,
|
||||||
|
.size = TEST_AREA_MAX_SIZE,
|
||||||
|
.len = ARRAY_SIZE(sg_len),
|
||||||
|
.do_write = true,
|
||||||
|
.do_nonblock_req = false,
|
||||||
|
.prepare = MMC_TEST_PREP_ERASE,
|
||||||
|
};
|
||||||
|
|
||||||
|
return mmc_test_rw_multiple_sg_len(test, &test_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Multiple non-blocking write 1 to 512 sg elements
|
||||||
|
*/
|
||||||
|
static int mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card *test)
|
||||||
|
{
|
||||||
|
unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
|
||||||
|
1 << 7, 1 << 8, 1 << 9};
|
||||||
|
struct mmc_test_multiple_rw test_data = {
|
||||||
|
.sg_len = sg_len,
|
||||||
|
.size = TEST_AREA_MAX_SIZE,
|
||||||
|
.len = ARRAY_SIZE(sg_len),
|
||||||
|
.do_write = true,
|
||||||
|
.do_nonblock_req = true,
|
||||||
|
.prepare = MMC_TEST_PREP_ERASE,
|
||||||
|
};
|
||||||
|
|
||||||
|
return mmc_test_rw_multiple_sg_len(test, &test_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Multiple blocking read 1 to 512 sg elements
|
||||||
|
*/
|
||||||
|
static int mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card *test)
|
||||||
|
{
|
||||||
|
unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
|
||||||
|
1 << 7, 1 << 8, 1 << 9};
|
||||||
|
struct mmc_test_multiple_rw test_data = {
|
||||||
|
.sg_len = sg_len,
|
||||||
|
.size = TEST_AREA_MAX_SIZE,
|
||||||
|
.len = ARRAY_SIZE(sg_len),
|
||||||
|
.do_write = false,
|
||||||
|
.do_nonblock_req = false,
|
||||||
|
.prepare = MMC_TEST_PREP_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
return mmc_test_rw_multiple_sg_len(test, &test_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Multiple non-blocking read 1 to 512 sg elements
|
||||||
|
*/
|
||||||
|
static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
|
||||||
|
{
|
||||||
|
unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
|
||||||
|
1 << 7, 1 << 8, 1 << 9};
|
||||||
|
struct mmc_test_multiple_rw test_data = {
|
||||||
|
.sg_len = sg_len,
|
||||||
|
.size = TEST_AREA_MAX_SIZE,
|
||||||
|
.len = ARRAY_SIZE(sg_len),
|
||||||
|
.do_write = false,
|
||||||
|
.do_nonblock_req = true,
|
||||||
|
.prepare = MMC_TEST_PREP_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
return mmc_test_rw_multiple_sg_len(test, &test_data);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct mmc_test_case mmc_test_cases[] = {
|
static const struct mmc_test_case mmc_test_cases[] = {
|
||||||
{
|
{
|
||||||
.name = "Basic write (no data verification)",
|
.name = "Basic write (no data verification)",
|
||||||
@@ -2523,6 +2622,34 @@ static const struct mmc_test_case mmc_test_cases[] = {
|
|||||||
.run = mmc_test_profile_mult_read_nonblock_perf,
|
.run = mmc_test_profile_mult_read_nonblock_perf,
|
||||||
.cleanup = mmc_test_area_cleanup,
|
.cleanup = mmc_test_area_cleanup,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = "Write performance blocking req 1 to 512 sg elems",
|
||||||
|
.prepare = mmc_test_area_prepare,
|
||||||
|
.run = mmc_test_profile_sglen_wr_blocking_perf,
|
||||||
|
.cleanup = mmc_test_area_cleanup,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = "Write performance non-blocking req 1 to 512 sg elems",
|
||||||
|
.prepare = mmc_test_area_prepare,
|
||||||
|
.run = mmc_test_profile_sglen_wr_nonblock_perf,
|
||||||
|
.cleanup = mmc_test_area_cleanup,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = "Read performance blocking req 1 to 512 sg elems",
|
||||||
|
.prepare = mmc_test_area_prepare,
|
||||||
|
.run = mmc_test_profile_sglen_r_blocking_perf,
|
||||||
|
.cleanup = mmc_test_area_cleanup,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = "Read performance non-blocking req 1 to 512 sg elems",
|
||||||
|
.prepare = mmc_test_area_prepare,
|
||||||
|
.run = mmc_test_profile_sglen_r_nonblock_perf,
|
||||||
|
.cleanup = mmc_test_area_cleanup,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_MUTEX(mmc_test_lock);
|
static DEFINE_MUTEX(mmc_test_lock);
|
||||||
|
Reference in New Issue
Block a user