scsi: ufs: add long random read/write unit tests
Generalize the long_sequential_test framework to execute long random read and long random write tests as well. The random tests submit a large number of 4KB requests to randomly chosen LBAs. Currently the tests are defined to read/write 64MB. Change-Id: I9d797c0d61d863b2a9fbcd593a1be9065202ef76 Signed-off-by: Lee Susman <lsusman@codeaurora.org> [merez@codeaurora.org: fix trivial conflicts] Signed-off-by: Maya Erez <merez@codeaurora.org>
This commit is contained in:
parent
580910dcef
commit
d4cf62968e
1 changed files with 124 additions and 27 deletions
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2 and
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
@ -32,6 +32,7 @@
|
||||||
#define TEST_MAX_SECTOR_RANGE (10*1024*1024) /* 5GB */
|
#define TEST_MAX_SECTOR_RANGE (10*1024*1024) /* 5GB */
|
||||||
#define LARGE_PRIME_1 1103515367
|
#define LARGE_PRIME_1 1103515367
|
||||||
#define LARGE_PRIME_2 35757
|
#define LARGE_PRIME_2 35757
|
||||||
|
#define MAGIC_SEED 7
|
||||||
#define DEFAULT_NUM_OF_BIOS 2
|
#define DEFAULT_NUM_OF_BIOS 2
|
||||||
#define LONG_SEQUENTIAL_MIXED_TIMOUT_MS 100000
|
#define LONG_SEQUENTIAL_MIXED_TIMOUT_MS 100000
|
||||||
#define THREADS_COMPLETION_TIMOUT msecs_to_jiffies(10000) /* 10 sec */
|
#define THREADS_COMPLETION_TIMOUT msecs_to_jiffies(10000) /* 10 sec */
|
||||||
|
@ -41,6 +42,8 @@
|
||||||
|
|
||||||
/* the amount of requests that will be inserted */
|
/* the amount of requests that will be inserted */
|
||||||
#define LONG_SEQ_TEST_NUM_REQS 256
|
#define LONG_SEQ_TEST_NUM_REQS 256
|
||||||
|
/* we issue 4KB requests, so 256 reqs = 1MB */
|
||||||
|
#define LONG_RAND_TEST_NUM_REQS (256 * 64)
|
||||||
/* request queue limitation is 128 requests, and we leave 10 spare requests */
|
/* request queue limitation is 128 requests, and we leave 10 spare requests */
|
||||||
#define QUEUE_MAX_REQUESTS 118
|
#define QUEUE_MAX_REQUESTS 118
|
||||||
#define MB_MSEC_RATIO_APPROXIMATION ((1024 * 1024) / 1000)
|
#define MB_MSEC_RATIO_APPROXIMATION ((1024 * 1024) / 1000)
|
||||||
|
@ -76,10 +79,6 @@ const struct file_operations ufs_test_ ## test_name ## _ops = { \
|
||||||
ufs_test_add_test(utd, UFS_TEST_ ## upper_case_name, "ufs_test_"#test_name,\
|
ufs_test_add_test(utd, UFS_TEST_ ## upper_case_name, "ufs_test_"#test_name,\
|
||||||
&(ufs_test_ ## test_name ## _ops)); \
|
&(ufs_test_ ## test_name ## _ops)); \
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum ufs_test_testcases {
|
enum ufs_test_testcases {
|
||||||
UFS_TEST_WRITE_READ_TEST,
|
UFS_TEST_WRITE_READ_TEST,
|
||||||
UFS_TEST_MULTI_QUERY,
|
UFS_TEST_MULTI_QUERY,
|
||||||
|
@ -88,6 +87,9 @@ enum ufs_test_testcases {
|
||||||
UFS_TEST_LONG_SEQUENTIAL_WRITE,
|
UFS_TEST_LONG_SEQUENTIAL_WRITE,
|
||||||
UFS_TEST_LONG_SEQUENTIAL_MIXED,
|
UFS_TEST_LONG_SEQUENTIAL_MIXED,
|
||||||
|
|
||||||
|
UFS_TEST_LONG_RANDOM_READ,
|
||||||
|
UFS_TEST_LONG_RANDOM_WRITE,
|
||||||
|
|
||||||
UFS_TEST_PARALLEL_READ_AND_WRITE,
|
UFS_TEST_PARALLEL_READ_AND_WRITE,
|
||||||
UFS_TEST_LUN_DEPTH,
|
UFS_TEST_LUN_DEPTH,
|
||||||
|
|
||||||
|
@ -328,6 +330,15 @@ static int ufs_test_show(struct seq_file *file, int test_case)
|
||||||
"throughput at the driver level by sequentially reading many "
|
"throughput at the driver level by sequentially reading many "
|
||||||
"large requests.\n";
|
"large requests.\n";
|
||||||
break;
|
break;
|
||||||
|
case UFS_TEST_LONG_RANDOM_READ:
|
||||||
|
test_description = "\nufs_long_random_read_test\n"
|
||||||
|
"=========\n"
|
||||||
|
"Description:\n"
|
||||||
|
"This test runs the following scenarios\n"
|
||||||
|
"- Long Random Read Test: this test measures read "
|
||||||
|
"IOPS at the driver level by reading many 4KB requests"
|
||||||
|
"with random LBAs\n";
|
||||||
|
break;
|
||||||
case UFS_TEST_LONG_SEQUENTIAL_WRITE:
|
case UFS_TEST_LONG_SEQUENTIAL_WRITE:
|
||||||
test_description = "\nufs_long_sequential_write_test\n"
|
test_description = "\nufs_long_sequential_write_test\n"
|
||||||
"=========\n"
|
"=========\n"
|
||||||
|
@ -337,6 +348,15 @@ static int ufs_test_show(struct seq_file *file, int test_case)
|
||||||
"throughput at the driver level by sequentially writing many "
|
"throughput at the driver level by sequentially writing many "
|
||||||
"large requests\n";
|
"large requests\n";
|
||||||
break;
|
break;
|
||||||
|
case UFS_TEST_LONG_RANDOM_WRITE:
|
||||||
|
test_description = "\nufs_long_random_write_test\n"
|
||||||
|
"=========\n"
|
||||||
|
"Description:\n"
|
||||||
|
"This test runs the following scenarios\n"
|
||||||
|
"- Long Random Write Test: this test measures write "
|
||||||
|
"IOPS at the driver level by writing many 4KB requests"
|
||||||
|
"with random LBAs\n";
|
||||||
|
break;
|
||||||
case UFS_TEST_LONG_SEQUENTIAL_MIXED:
|
case UFS_TEST_LONG_SEQUENTIAL_MIXED:
|
||||||
test_description = "\nufs_long_sequential_mixed_test_read\n"
|
test_description = "\nufs_long_sequential_mixed_test_read\n"
|
||||||
"=========\n"
|
"=========\n"
|
||||||
|
@ -601,6 +621,16 @@ static bool ufs_test_multi_thread_completion(void)
|
||||||
utd->test_stage != UFS_TEST_LUN_DEPTH_TEST_RUNNING;
|
utd->test_stage != UFS_TEST_LUN_DEPTH_TEST_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool long_rand_test_check_completion(void)
|
||||||
|
{
|
||||||
|
if (utd->completed_req_count > LONG_RAND_TEST_NUM_REQS) {
|
||||||
|
pr_err("%s: Error: Completed more requests than total test requests.\nTerminating test."
|
||||||
|
, __func__);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (utd->completed_req_count == LONG_RAND_TEST_NUM_REQS);
|
||||||
|
}
|
||||||
|
|
||||||
static bool long_seq_test_check_completion(void)
|
static bool long_seq_test_check_completion(void)
|
||||||
{
|
{
|
||||||
if (utd->completed_req_count > LONG_SEQ_TEST_NUM_REQS) {
|
if (utd->completed_req_count > LONG_SEQ_TEST_NUM_REQS) {
|
||||||
|
@ -821,7 +851,7 @@ static int ufs_test_run_lun_depth_test(struct test_data *td)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void long_seq_test_free_end_io_fn(struct request *rq, int err)
|
static void long_test_free_end_io_fn(struct request *rq, int err)
|
||||||
{
|
{
|
||||||
struct test_request *test_rq;
|
struct test_request *test_rq;
|
||||||
struct test_data *ptd = test_get_test_data();
|
struct test_data *ptd = test_get_test_data();
|
||||||
|
@ -863,7 +893,7 @@ static void long_seq_test_free_end_io_fn(struct request *rq, int err)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* run_long_seq_test - main function for long sequential test
|
* run_long_test - main function for long sequential test
|
||||||
* @td - test specific data
|
* @td - test specific data
|
||||||
*
|
*
|
||||||
* This function is used to fill up (and keep full) the test queue with
|
* This function is used to fill up (and keep full) the test queue with
|
||||||
|
@ -871,12 +901,12 @@ static void long_seq_test_free_end_io_fn(struct request *rq, int err)
|
||||||
* 1. Only read/write (STAGE_1 or no stage)
|
* 1. Only read/write (STAGE_1 or no stage)
|
||||||
* 2. Simultaneous read and write to the same LBAs (STAGE_2)
|
* 2. Simultaneous read and write to the same LBAs (STAGE_2)
|
||||||
*/
|
*/
|
||||||
static int run_long_seq_test(struct test_data *td)
|
static int run_long_test(struct test_data *td)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int direction;
|
int direction, long_test_num_requests, num_bios_per_request;
|
||||||
static unsigned int inserted_requests;
|
static unsigned int inserted_requests;
|
||||||
u32 sector;
|
u32 sector, seed, num_bios, seq_sector_delta;
|
||||||
|
|
||||||
BUG_ON(!td);
|
BUG_ON(!td);
|
||||||
sector = td->start_sector;
|
sector = td->start_sector;
|
||||||
|
@ -886,18 +916,41 @@ static int run_long_seq_test(struct test_data *td)
|
||||||
inserted_requests = 0;
|
inserted_requests = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the direction */
|
/* Set test parameters */
|
||||||
switch (td->test_info.testcase) {
|
switch (td->test_info.testcase) {
|
||||||
|
case UFS_TEST_LONG_RANDOM_READ:
|
||||||
|
num_bios_per_request = 1;
|
||||||
|
long_test_num_requests = LONG_RAND_TEST_NUM_REQS;
|
||||||
|
direction = READ;
|
||||||
|
break;
|
||||||
|
case UFS_TEST_LONG_RANDOM_WRITE:
|
||||||
|
num_bios_per_request = 1;
|
||||||
|
long_test_num_requests = LONG_RAND_TEST_NUM_REQS;
|
||||||
|
direction = WRITE;
|
||||||
|
break;
|
||||||
case UFS_TEST_LONG_SEQUENTIAL_READ:
|
case UFS_TEST_LONG_SEQUENTIAL_READ:
|
||||||
|
num_bios_per_request = TEST_MAX_BIOS_PER_REQ;
|
||||||
|
long_test_num_requests = LONG_SEQ_TEST_NUM_REQS;
|
||||||
direction = READ;
|
direction = READ;
|
||||||
break;
|
break;
|
||||||
case UFS_TEST_LONG_SEQUENTIAL_WRITE:
|
case UFS_TEST_LONG_SEQUENTIAL_WRITE:
|
||||||
|
num_bios_per_request = TEST_MAX_BIOS_PER_REQ;
|
||||||
|
long_test_num_requests = LONG_SEQ_TEST_NUM_REQS;
|
||||||
case UFS_TEST_LONG_SEQUENTIAL_MIXED:
|
case UFS_TEST_LONG_SEQUENTIAL_MIXED:
|
||||||
default:
|
default:
|
||||||
direction = WRITE;
|
direction = WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* NUM_OF_BLOCK * (BLOCK_SIZE / SECTOR_SIZE) */
|
||||||
|
seq_sector_delta = num_bios_per_request * (PAGE_SIZE /
|
||||||
|
td->req_q->limits.logical_block_size);
|
||||||
|
/* just for the first iteration */
|
||||||
|
sector -= seq_sector_delta;
|
||||||
|
|
||||||
|
seed = utd->random_test_seed ? utd->random_test_seed : MAGIC_SEED;
|
||||||
|
|
||||||
pr_info("%s: Adding %d requests, first req_id=%d", __func__,
|
pr_info("%s: Adding %d requests, first req_id=%d", __func__,
|
||||||
LONG_SEQ_TEST_NUM_REQS, td->wr_rd_next_req_id);
|
long_test_num_requests, td->wr_rd_next_req_id);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/*
|
/*
|
||||||
|
@ -912,9 +965,23 @@ static int run_long_seq_test(struct test_data *td)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (td->test_info.testcase) {
|
||||||
|
case UFS_TEST_LONG_SEQUENTIAL_READ:
|
||||||
|
case UFS_TEST_LONG_SEQUENTIAL_WRITE:
|
||||||
|
case UFS_TEST_LONG_SEQUENTIAL_MIXED:
|
||||||
|
sector += seq_sector_delta;
|
||||||
|
break;
|
||||||
|
case UFS_TEST_LONG_RANDOM_READ:
|
||||||
|
case UFS_TEST_LONG_RANDOM_WRITE:
|
||||||
|
pseudo_rnd_sector_and_size(&seed, td->start_sector,
|
||||||
|
§or, &num_bios);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ret = test_iosched_add_wr_rd_test_req(0, direction, sector,
|
ret = test_iosched_add_wr_rd_test_req(0, direction, sector,
|
||||||
TEST_MAX_BIOS_PER_REQ, TEST_PATTERN_5A,
|
num_bios_per_request, TEST_PATTERN_5A,
|
||||||
long_seq_test_free_end_io_fn);
|
long_test_free_end_io_fn);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("%s: failed to create request" , __func__);
|
pr_err("%s: failed to create request" , __func__);
|
||||||
break;
|
break;
|
||||||
|
@ -922,8 +989,8 @@ static int run_long_seq_test(struct test_data *td)
|
||||||
inserted_requests++;
|
inserted_requests++;
|
||||||
if (utd->test_stage == UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE2) {
|
if (utd->test_stage == UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE2) {
|
||||||
ret = test_iosched_add_wr_rd_test_req(0, READ, sector,
|
ret = test_iosched_add_wr_rd_test_req(0, READ, sector,
|
||||||
TEST_MAX_BIOS_PER_REQ, TEST_PATTERN_5A,
|
num_bios_per_request, TEST_PATTERN_5A,
|
||||||
long_seq_test_free_end_io_fn);
|
long_test_free_end_io_fn);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("%s: failed to create request" ,
|
pr_err("%s: failed to create request" ,
|
||||||
__func__);
|
__func__);
|
||||||
|
@ -931,17 +998,11 @@ static int run_long_seq_test(struct test_data *td)
|
||||||
}
|
}
|
||||||
inserted_requests++;
|
inserted_requests++;
|
||||||
}
|
}
|
||||||
/* NUM_OF_BLOCK * (BLOCK_SIZE / SECTOR_SIZE) */
|
|
||||||
sector += TEST_MAX_BIOS_PER_REQ * (PAGE_SIZE /
|
|
||||||
td->req_q->limits.logical_block_size);
|
|
||||||
td->test_info.test_byte_count +=
|
|
||||||
(TEST_MAX_BIOS_PER_REQ * sizeof(unsigned int) *
|
|
||||||
BIO_U32_SIZE);
|
|
||||||
|
|
||||||
} while (inserted_requests < LONG_SEQ_TEST_NUM_REQS);
|
} while (inserted_requests < long_test_num_requests);
|
||||||
|
|
||||||
/* in this case the queue will not run in the above loop */
|
/* in this case the queue will not run in the above loop */
|
||||||
if (LONG_SEQ_TEST_NUM_REQS < QUEUE_MAX_REQUESTS)
|
if (long_test_num_requests < QUEUE_MAX_REQUESTS)
|
||||||
blk_run_queue(td->req_q);
|
blk_run_queue(td->req_q);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -952,18 +1013,38 @@ static int run_mixed_long_seq_test(struct test_data *td)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
utd->test_stage = UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE1;
|
utd->test_stage = UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE1;
|
||||||
ret = run_long_seq_test(td);
|
ret = run_long_test(td);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
pr_info("%s: First write iteration completed.", __func__);
|
pr_info("%s: First write iteration completed.", __func__);
|
||||||
pr_info("%s: Starting mixed write and reads sequence.", __func__);
|
pr_info("%s: Starting mixed write and reads sequence.", __func__);
|
||||||
utd->test_stage = UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE2;
|
utd->test_stage = UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE2;
|
||||||
ret = run_long_seq_test(td);
|
ret = run_long_test(td);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int long_rand_test_calc_iops(struct test_data *td)
|
||||||
|
{
|
||||||
|
unsigned long mtime, num_ios, iops;
|
||||||
|
|
||||||
|
mtime = ktime_to_ms(utd->test_info.test_duration);
|
||||||
|
num_ios = utd->completed_req_count;
|
||||||
|
|
||||||
|
pr_info("%s: time is %lu msec, IOS count is %lu", __func__, mtime,
|
||||||
|
num_ios);
|
||||||
|
|
||||||
|
/* preserve some precision */
|
||||||
|
num_ios *= 1000;
|
||||||
|
/* calculate those iops */
|
||||||
|
iops = num_ios / mtime;
|
||||||
|
|
||||||
|
pr_info("%s: IOPS: %lu IOP/sec\n", __func__, iops);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int long_seq_test_calc_throughput(struct test_data *td)
|
static int long_seq_test_calc_throughput(struct test_data *td)
|
||||||
{
|
{
|
||||||
unsigned long fraction, integer;
|
unsigned long fraction, integer;
|
||||||
|
@ -1030,9 +1111,17 @@ static ssize_t ufs_test_write(struct file *file, const char __user *buf,
|
||||||
utd->test_info.run_test_fn = ufs_test_run_multi_query_test;
|
utd->test_info.run_test_fn = ufs_test_run_multi_query_test;
|
||||||
utd->test_info.check_test_result_fn = ufs_test_check_result;
|
utd->test_info.check_test_result_fn = ufs_test_check_result;
|
||||||
break;
|
break;
|
||||||
|
case UFS_TEST_LONG_RANDOM_READ:
|
||||||
|
case UFS_TEST_LONG_RANDOM_WRITE:
|
||||||
|
utd->test_info.run_test_fn = run_long_test;
|
||||||
|
utd->test_info.post_test_fn = long_rand_test_calc_iops;
|
||||||
|
utd->test_info.check_test_result_fn = ufs_test_check_result;
|
||||||
|
utd->test_info.check_test_completion_fn =
|
||||||
|
long_rand_test_check_completion;
|
||||||
|
break;
|
||||||
case UFS_TEST_LONG_SEQUENTIAL_READ:
|
case UFS_TEST_LONG_SEQUENTIAL_READ:
|
||||||
case UFS_TEST_LONG_SEQUENTIAL_WRITE:
|
case UFS_TEST_LONG_SEQUENTIAL_WRITE:
|
||||||
utd->test_info.run_test_fn = run_long_seq_test;
|
utd->test_info.run_test_fn = run_long_test;
|
||||||
utd->test_info.post_test_fn = long_seq_test_calc_throughput;
|
utd->test_info.post_test_fn = long_seq_test_calc_throughput;
|
||||||
utd->test_info.check_test_result_fn = ufs_test_check_result;
|
utd->test_info.check_test_result_fn = ufs_test_check_result;
|
||||||
utd->test_info.check_test_completion_fn =
|
utd->test_info.check_test_completion_fn =
|
||||||
|
@ -1081,6 +1170,8 @@ static ssize_t ufs_test_write(struct file *file, const char __user *buf,
|
||||||
|
|
||||||
TEST_OPS(write_read_test, WRITE_READ_TEST);
|
TEST_OPS(write_read_test, WRITE_READ_TEST);
|
||||||
TEST_OPS(multi_query, MULTI_QUERY);
|
TEST_OPS(multi_query, MULTI_QUERY);
|
||||||
|
TEST_OPS(long_random_read, LONG_RANDOM_READ);
|
||||||
|
TEST_OPS(long_random_write, LONG_RANDOM_WRITE);
|
||||||
TEST_OPS(long_sequential_read, LONG_SEQUENTIAL_READ);
|
TEST_OPS(long_sequential_read, LONG_SEQUENTIAL_READ);
|
||||||
TEST_OPS(long_sequential_write, LONG_SEQUENTIAL_WRITE);
|
TEST_OPS(long_sequential_write, LONG_SEQUENTIAL_WRITE);
|
||||||
TEST_OPS(long_sequential_mixed, LONG_SEQUENTIAL_MIXED);
|
TEST_OPS(long_sequential_mixed, LONG_SEQUENTIAL_MIXED);
|
||||||
|
@ -1125,6 +1216,12 @@ static int ufs_test_debugfs_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = add_test(utd, write_read_test, WRITE_READ_TEST);
|
ret = add_test(utd, write_read_test, WRITE_READ_TEST);
|
||||||
|
if (ret)
|
||||||
|
goto exit_err;
|
||||||
|
ret = add_test(utd, long_random_read, LONG_RANDOM_READ);
|
||||||
|
if (ret)
|
||||||
|
goto exit_err;
|
||||||
|
ret = add_test(utd, long_random_write, LONG_RANDOM_WRITE);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto exit_err;
|
goto exit_err;
|
||||||
ret = add_test(utd, long_sequential_read, LONG_SEQUENTIAL_READ);
|
ret = add_test(utd, long_sequential_read, LONG_SEQUENTIAL_READ);
|
||||||
|
|
Loading…
Add table
Reference in a new issue