Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e9d0d795 authored by Lee Susman's avatar Lee Susman Committed by Matt Wagantall
Browse files

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: default avatarLee Susman <lsusman@codeaurora.org>
[merez@codeaurora.org: fix trivial conflicts]
Signed-off-by: default avatarMaya Erez <merez@codeaurora.org>
parent 3120f0e9
Loading
Loading
Loading
Loading
+124 −27
Original line number Diff line number Diff line
/* 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);