scsi: ufs: long sequential read/write tests

This test adds the ability to test the UFS task management feature
in the driver. It loads the queue with requests in order to allow
the task management to operate in full capacity.

Modify test-iosched infrastructure to support the new tests:
- expose  check_test_completion()

Note: we submit 16-bio requests since the current HW is very slow
and we don't want to exceed the timeout duration.

Change-Id: I8ee752cba3c6838d8edc05747fa0288c4b347ef6
Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
Signed-off-by: Lee Susman <lsusman@codeaurora.org>
This commit is contained in:
Lee Susman 2013-07-02 15:12:24 +03:00
parent ec0b821e4c
commit 9cb6eda24c
3 changed files with 343 additions and 16 deletions

View File

@ -784,10 +784,10 @@ int test_iosched_start_test(struct test_info *t_info)
test_pr_info("%s: Waiting for the test completion", __func__);
wait_event(ptd->wait_q, ptd->test_state == TEST_COMPLETED);
t_info->test_duration = ptd->test_info.test_duration;
t_info->test_byte_count = ptd->test_info.test_byte_count;
del_timer_sync(&ptd->timeout_timer);
memcpy(t_info, &ptd->test_info, sizeof(struct test_info));
ret = check_test_result(ptd);
if (ret) {
test_pr_err("%s: check_test_result failed\n",

View File

@ -18,13 +18,27 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <../sd.h>
#include <linux/delay.h>
#define MODULE_NAME "ufs_test"
#define TEST_MAX_BIOS_PER_REQ 120
#define TEST_MAX_BIOS_PER_REQ 16
#define LARGE_PRIME_1 1103515367
#define LARGE_PRIME_2 35757
#define DEFAULT_NUM_OF_BIOS 2
#define DEFAULT_NUM_OF_BIOS 2
/* the amount of requests that will be inserted */
#define LONG_SEQ_TEST_NUM_REQS 256
/* 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)
/* actual number of MiB in test multiplied by 10, for single digit precision*/
#define BYTE_TO_MB_x_10(x) ((x * 10) / (1024 * 1024))
/* extract integer value */
#define LONG_TEST_SIZE_INTEGER(x) (BYTE_TO_MB_x_10(x) / 10)
/* and calculate the MiB value fraction */
#define LONG_TEST_SIZE_FRACTION(x) (BYTE_TO_MB_x_10(x) - \
(LONG_TEST_SIZE_INTEGER(x) * 10))
#define test_pr_debug(fmt, args...) pr_debug("%s: "fmt"\n", MODULE_NAME, args)
#define test_pr_info(fmt, args...) pr_info("%s: "fmt"\n", MODULE_NAME, args)
@ -32,11 +46,16 @@
enum ufs_test_testcases {
UFS_TEST_WRITE_READ_TEST,
TEST_LONG_SEQUENTIAL_READ,
TEST_LONG_SEQUENTIAL_WRITE,
};
struct ufs_test_debug {
struct dentry *write_read_test; /* basic test */
struct dentry *random_test_seed; /* parameters in utils */
struct dentry *long_sequential_read_test;
struct dentry *long_sequential_write_test;
};
struct ufs_test_data {
@ -60,6 +79,8 @@ struct ufs_test_data {
* disabled and 2 BIOs are written.
*/
unsigned int random_test_seed;
/* A counter for the number of test requests completed */
unsigned int completed_req_count;
};
static struct ufs_test_data *utd;
@ -77,6 +98,12 @@ static char *ufs_test_get_test_case_str(struct test_data *td)
case UFS_TEST_WRITE_READ_TEST:
return "UFS write read test";
break;
case TEST_LONG_SEQUENTIAL_READ:
return "UFS long sequential read test";
break;
case TEST_LONG_SEQUENTIAL_WRITE:
return "UFS long sequential write test";
break;
default:
return "Unknown test";
}
@ -166,8 +193,9 @@ static int ufs_test_run_write_read_test(struct test_data *td)
num_bios = DEFAULT_NUM_OF_BIOS;
/* Adding a write request */
test_pr_info("%s: Adding a write requests to Q, first req_id=%d",
__func__, td->wr_rd_next_req_id);
test_pr_info(
"%s: Adding a write request with %d bios to Q, req_id=%d"
, __func__, num_bios, td->wr_rd_next_req_id);
utd->write_completed = false;
ret = test_iosched_add_wr_rd_test_req(0, WRITE, start_sec,
@ -265,21 +293,290 @@ const struct file_operations write_read_test_ops = {
.read = ufs_test_write_read_test_read_cb,
};
static void long_seq_test_free_end_io_fn(struct request *rq, int err)
{
struct test_request *test_rq;
struct test_data *ptd = test_get_test_data();
if (rq)
test_rq = (struct test_request *)rq->elv.priv[0];
else {
test_pr_err("%s: error: NULL request", __func__);
return;
}
BUG_ON(!test_rq);
spin_lock_irq(&ptd->lock);
ptd->dispatched_count--;
list_del_init(&test_rq->queuelist);
__blk_put_request(ptd->req_q, test_rq->rq);
spin_unlock_irq(&ptd->lock);
kfree(test_rq->bios_buffer);
kfree(test_rq);
utd->completed_req_count++;
test_pr_err("%s: request %d completed, err=%d",
__func__, test_rq->req_id, err);
check_test_completion();
}
static int run_long_seq_test(struct test_data *td)
{
int ret = 0;
int direction;
static unsigned int inserted_requests;
BUG_ON(!td);
td->test_count = 0;
utd->completed_req_count = 0;
inserted_requests = 0;
if (td->test_info.testcase == TEST_LONG_SEQUENTIAL_READ)
direction = READ;
else
direction = WRITE;
test_pr_info("%s: Adding %d requests, first req_id=%d",
__func__, LONG_SEQ_TEST_NUM_REQS,
td->wr_rd_next_req_id);
do {
/*
* since our requests come from a pool containing 128
* requests, we don't want to exhaust this quantity,
* therefore we add up to QUEUE_MAX_REQUESTS (which
* includes a safety margin) and then call the mmc layer
* to fetch them
*/
if (td->test_count >= QUEUE_MAX_REQUESTS) {
blk_run_queue(td->req_q);
continue;
}
ret = test_iosched_add_wr_rd_test_req(0, direction,
td->start_sector, TEST_MAX_BIOS_PER_REQ,
TEST_PATTERN_5A,
long_seq_test_free_end_io_fn);
if (ret) {
test_pr_err("%s: failed to create request" , __func__);
break;
}
inserted_requests++;
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);
/* in this case the queue will not run in the above loop */
if (LONG_SEQ_TEST_NUM_REQS < QUEUE_MAX_REQUESTS)
blk_run_queue(td->req_q);
return ret;
}
void long_seq_test_calc_throughput(unsigned long mtime,
unsigned long byte_count)
{
unsigned long fraction, integer;
test_pr_info("%s: time is %lu msec, size is %lu.%lu MiB",
__func__, mtime, LONG_TEST_SIZE_INTEGER(byte_count),
LONG_TEST_SIZE_FRACTION(byte_count));
/* we first multiply in order not to lose precision */
mtime *= MB_MSEC_RATIO_APPROXIMATION;
/* divide values to get a MiB/sec integer value with one
digit of precision
*/
fraction = integer = (byte_count * 10) / mtime;
integer /= 10;
/* and calculate the MiB value fraction */
fraction -= integer * 10;
test_pr_info("%s: Throughput: %lu.%lu MiB/sec\n",
__func__, integer, fraction);
}
static ssize_t long_sequential_read_test_write(struct file *file,
const char __user *buf,
size_t count,
loff_t *ppos)
{
int ret = 0;
int i = 0;
int number = -1;
unsigned long mtime, byte_count;
test_pr_info("%s: -- UFS Long Sequential Read TEST --", __func__);
sscanf(buf, "%d", &number);
if (number <= 0)
number = 1;
memset(&utd->test_info, 0, sizeof(struct test_info));
utd->test_info.data = utd;
utd->test_info.get_rq_disk_fn = ufs_test_get_rq_disk;
utd->test_info.run_test_fn = run_long_seq_test;
utd->test_info.get_test_case_str_fn = ufs_test_get_test_case_str;
utd->test_info.testcase = TEST_LONG_SEQUENTIAL_READ;
for (i = 0 ; i < number ; ++i) {
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
test_pr_info("%s: ====================", __func__);
ret = test_iosched_start_test(&utd->test_info);
if (ret)
break;
mtime = ktime_to_ms(utd->test_info.test_duration);
byte_count = utd->test_info.test_byte_count;
long_seq_test_calc_throughput(mtime, byte_count);
/* Allow FS requests to be dispatched */
msleep(1000);
}
return count;
}
static ssize_t long_sequential_read_test_read(struct file *file,
char __user *buffer,
size_t count,
loff_t *offset)
{
memset((void *)buffer, 0, count);
snprintf(buffer, count,
"\nufs_long_sequential_read_test\n"
"=========\n"
"Description:\n"
"This test runs the following scenarios\n"
"- Long Sequential Read Test: this test measures read "
"throughput at the driver level by sequentially reading many "
"large requests.\n");
if (message_repeat == 1) {
message_repeat = 0;
return strnlen(buffer, count);
} else
return 0;
}
static bool message_repeat;
static int test_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
message_repeat = 1;
return 0;
}
const struct file_operations long_sequential_read_test_ops = {
.open = test_open,
.write = long_sequential_read_test_write,
.read = long_sequential_read_test_read,
};
static ssize_t long_sequential_write_test_write(struct file *file,
const char __user *buf,
size_t count,
loff_t *ppos)
{
int ret = 0;
int i = 0;
int number = -1;
unsigned long mtime, byte_count;
test_pr_info("%s: -- UFS Long Sequential Write TEST --", __func__);
sscanf(buf, "%d", &number);
if (number <= 0)
number = 1;
memset(&utd->test_info, 0, sizeof(struct test_info));
utd->test_info.data = utd;
utd->test_info.get_rq_disk_fn = ufs_test_get_rq_disk;
utd->test_info.get_test_case_str_fn = ufs_test_get_test_case_str;
utd->test_info.run_test_fn = run_long_seq_test;
utd->test_info.testcase = TEST_LONG_SEQUENTIAL_WRITE;
for (i = 0 ; i < number ; ++i) {
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
test_pr_info("%s: ====================", __func__);
utd->test_info.test_byte_count = 0;
ret = test_iosched_start_test(&utd->test_info);
if (ret)
break;
mtime = ktime_to_ms(utd->test_info.test_duration);
byte_count = utd->test_info.test_byte_count;
long_seq_test_calc_throughput(mtime, byte_count);
/* Allow FS requests to be dispatched */
msleep(1000);
}
return count;
}
static ssize_t long_sequential_write_test_read(struct file *file,
char __user *buffer,
size_t count,
loff_t *offset)
{
memset((void *)buffer, 0, count);
snprintf(buffer, count,
"\nufs_long_sequential_write_test\n"
"=========\n"
"Description:\n"
"This test runs the following scenarios\n"
"- Long Sequential Write Test: this test measures write "
"throughput at the driver level by sequentially writing many "
"large requests\n");
if (message_repeat == 1) {
message_repeat = 0;
return strnlen(buffer, count);
} else
return 0;
}
const struct file_operations long_sequential_write_test_ops = {
.open = test_open,
.write = long_sequential_write_test_write,
.read = long_sequential_write_test_read,
};
static void ufs_test_debugfs_cleanup(void)
{
debugfs_remove(utd->debug.write_read_test);
debugfs_remove_recursive(test_iosched_get_debugfs_tests_root());
}
static int ufs_test_debugfs_init(void)
{
struct dentry *utils_root, *tests_root;
int ret = 0;
utils_root = test_iosched_get_debugfs_utils_root();
tests_root = test_iosched_get_debugfs_tests_root();
if (!utils_root || !tests_root) {
test_pr_err("%s: Failed to create debugfs root.", __func__);
return -EINVAL;
ret = -EINVAL;
goto exit;
}
utd->debug.random_test_seed = debugfs_create_u32("random_test_seed",
@ -288,21 +585,49 @@ static int ufs_test_debugfs_init(void)
if (!utd->debug.random_test_seed) {
test_pr_err("%s: Could not create debugfs random_test_seed.",
__func__);
return -ENOMEM;
ret = -ENOMEM;
goto exit;
}
utd->debug.write_read_test = debugfs_create_file("write_read_test",
utd->debug.write_read_test = debugfs_create_file("ufs_write_read_test",
S_IRUGO | S_IWUGO, tests_root,
NULL, &write_read_test_ops);
if (!utd->debug.write_read_test) {
debugfs_remove(utd->debug.random_test_seed);
test_pr_err("%s: Could not create debugfs write_read_test.",
__func__);
return -ENOMEM;
ret = -ENOMEM;
goto exit_err;
}
return 0;
utd->debug.long_sequential_read_test = debugfs_create_file(
"ufs_long_sequential_read_test",
S_IRUGO | S_IWUGO,
tests_root,
NULL,
&long_sequential_read_test_ops);
if (!utd->debug.long_sequential_read_test) {
ret = -ENOMEM;
goto exit_err;
}
utd->debug.long_sequential_write_test = debugfs_create_file(
"ufs_long_sequential_write_test",
S_IRUGO | S_IWUGO,
tests_root,
NULL,
&long_sequential_write_test_ops);
if (!utd->debug.long_sequential_write_test) {
ret = -ENOMEM;
goto exit_err;
}
goto exit;
exit_err:
debugfs_remove_recursive(tests_root);
exit:
return ret;
}
static void ufs_test_probe(void)

View File

@ -130,7 +130,7 @@ struct test_request {
* @check_test_result_fn: Test specific test result checking
* callback
* @get_test_case_str_fn: Test specific function to get the test name
* @test_duration: A jiffies value saved for timing
* @test_duration: A ktime value saved for timing
* calculations
* @data: Test specific private data
* @test_byte_count: Total number of bytes dispatched in
@ -263,4 +263,6 @@ extern struct test_data *test_get_test_data(void);
void test_iosched_add_urgent_req(struct test_request *test_rq);
int test_is_req_urgent(struct request *rq);
void check_test_completion(void);
#endif /* _LINUX_TEST_IOSCHED_H */