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:
Lee Susman 2015-01-19 21:38:26 +02:00 committed by David Keitel
parent 580910dcef
commit d4cf62968e

View file

@ -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
* 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 LARGE_PRIME_1 1103515367
#define LARGE_PRIME_2 35757
#define MAGIC_SEED 7
#define DEFAULT_NUM_OF_BIOS 2
#define LONG_SEQUENTIAL_MIXED_TIMOUT_MS 100000
#define THREADS_COMPLETION_TIMOUT msecs_to_jiffies(10000) /* 10 sec */
@ -41,6 +42,8 @@
/* the amount of requests that will be inserted */
#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 */
#define QUEUE_MAX_REQUESTS 118
#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_ ## test_name ## _ops)); \
enum ufs_test_testcases {
UFS_TEST_WRITE_READ_TEST,
UFS_TEST_MULTI_QUERY,
@ -88,6 +87,9 @@ enum ufs_test_testcases {
UFS_TEST_LONG_SEQUENTIAL_WRITE,
UFS_TEST_LONG_SEQUENTIAL_MIXED,
UFS_TEST_LONG_RANDOM_READ,
UFS_TEST_LONG_RANDOM_WRITE,
UFS_TEST_PARALLEL_READ_AND_WRITE,
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 "
"large requests.\n";
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:
test_description = "\nufs_long_sequential_write_test\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 "
"large requests\n";
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:
test_description = "\nufs_long_sequential_mixed_test_read\n"
"=========\n"
@ -601,6 +621,16 @@ static bool ufs_test_multi_thread_completion(void)
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)
{
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;
}
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_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
*
* 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)
* 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 direction;
int direction, long_test_num_requests, num_bios_per_request;
static unsigned int inserted_requests;
u32 sector;
u32 sector, seed, num_bios, seq_sector_delta;
BUG_ON(!td);
sector = td->start_sector;
@ -886,18 +916,41 @@ static int run_long_seq_test(struct test_data *td)
inserted_requests = 0;
}
/* Set the direction */
/* Set test parameters */
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:
num_bios_per_request = TEST_MAX_BIOS_PER_REQ;
long_test_num_requests = LONG_SEQ_TEST_NUM_REQS;
direction = READ;
break;
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:
default:
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__,
LONG_SEQ_TEST_NUM_REQS, td->wr_rd_next_req_id);
long_test_num_requests, td->wr_rd_next_req_id);
do {
/*
@ -912,9 +965,23 @@ static int run_long_seq_test(struct test_data *td)
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,
&sector, &num_bios);
default:
break;
}
ret = test_iosched_add_wr_rd_test_req(0, direction, sector,
TEST_MAX_BIOS_PER_REQ, TEST_PATTERN_5A,
long_seq_test_free_end_io_fn);
num_bios_per_request, TEST_PATTERN_5A,
long_test_free_end_io_fn);
if (ret) {
pr_err("%s: failed to create request" , __func__);
break;
@ -922,8 +989,8 @@ static int run_long_seq_test(struct test_data *td)
inserted_requests++;
if (utd->test_stage == UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE2) {
ret = test_iosched_add_wr_rd_test_req(0, READ, sector,
TEST_MAX_BIOS_PER_REQ, TEST_PATTERN_5A,
long_seq_test_free_end_io_fn);
num_bios_per_request, TEST_PATTERN_5A,
long_test_free_end_io_fn);
if (ret) {
pr_err("%s: failed to create request" ,
__func__);
@ -931,17 +998,11 @@ static int run_long_seq_test(struct test_data *td)
}
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 */
if (LONG_SEQ_TEST_NUM_REQS < QUEUE_MAX_REQUESTS)
if (long_test_num_requests < QUEUE_MAX_REQUESTS)
blk_run_queue(td->req_q);
return ret;
@ -952,18 +1013,38 @@ static int run_mixed_long_seq_test(struct test_data *td)
int ret;
utd->test_stage = UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE1;
ret = run_long_seq_test(td);
ret = run_long_test(td);
if (ret)
goto out;
pr_info("%s: First write iteration completed.", __func__);
pr_info("%s: Starting mixed write and reads sequence.", __func__);
utd->test_stage = UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE2;
ret = run_long_seq_test(td);
ret = run_long_test(td);
out:
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)
{
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.check_test_result_fn = ufs_test_check_result;
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_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.check_test_result_fn = ufs_test_check_result;
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(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_write, LONG_SEQUENTIAL_WRITE);
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);
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)
goto exit_err;
ret = add_test(utd, long_sequential_read, LONG_SEQUENTIAL_READ);