Add kunit tests to benchmark 256MiB copies to a UBUF iterator and an IOVEC iterator. This attaches a userspace VM with a mapped file in it temporarily to the test thread. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> cc: Christoph Hellwig <hch@xxxxxx> cc: Christian Brauner <brauner@xxxxxxxxxx> cc: Jens Axboe <axboe@xxxxxxxxx> cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> cc: Matthew Wilcox <willy@xxxxxxxxxxxxx> cc: David Hildenbrand <david@xxxxxxxxxx> cc: John Hubbard <jhubbard@xxxxxxxxxx> cc: Brendan Higgins <brendanhiggins@xxxxxxxxxx> cc: David Gow <davidgow@xxxxxxxxxx> cc: linux-kselftest@xxxxxxxxxxxxxxx cc: kunit-dev@xxxxxxxxxxxxxxxx cc: linux-mm@xxxxxxxxx cc: linux-fsdevel@xxxxxxxxxxxxxxx --- lib/kunit_iov_iter.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/lib/kunit_iov_iter.c b/lib/kunit_iov_iter.c index 17f85f24b239..4ee939a1c5ec 100644 --- a/lib/kunit_iov_iter.c +++ b/lib/kunit_iov_iter.c @@ -1324,6 +1324,99 @@ static void *__init iov_kunit_create_source(struct kunit *test, size_t npages) return scratch; } +/* + * Time copying 256MiB through an ITER_UBUF. + */ +static void __init iov_kunit_benchmark_ubuf(struct kunit *test) +{ + struct iov_iter iter; + unsigned int samples[IOV_KUNIT_NR_SAMPLES]; + ktime_t a, b; + ssize_t copied; + size_t size = 256 * 1024 * 1024, npages = size / PAGE_SIZE; + void *scratch; + int i; + u8 __user *buffer; + + /* Allocate a huge buffer and populate it with pages. */ + buffer = iov_kunit_create_user_buf(test, npages, NULL); + + /* Create a single large buffer to copy to/from. */ + scratch = iov_kunit_create_source(test, npages); + + /* Perform and time a bunch of copies. */ + kunit_info(test, "Benchmarking copy_to_iter() over UBUF:\n"); + for (i = 0; i < IOV_KUNIT_NR_SAMPLES; i++) { + size_t remain = size; + + a = ktime_get_real(); + do { + size_t part = min(remain, PAGE_SIZE); + + iov_iter_ubuf(&iter, ITER_SOURCE, buffer, part); + copied = copy_from_iter(scratch, part, &iter); + KUNIT_EXPECT_EQ(test, copied, part); + remain -= part; + } while (remain > 0); + b = ktime_get_real(); + samples[i] = ktime_to_us(ktime_sub(b, a)); + } + + iov_kunit_benchmark_print_stats(test, samples); + KUNIT_SUCCEED(); +} + +/* + * Time copying 256MiB through an ITER_IOVEC. + */ +static void __init iov_kunit_benchmark_iovec(struct kunit *test) +{ + struct iov_iter iter; + struct iovec *iov; + unsigned int samples[IOV_KUNIT_NR_SAMPLES]; + ktime_t a, b; + ssize_t copied; + size_t size = 256 * 1024 * 1024, npages = size / PAGE_SIZE, part; + size_t ioc = size / PAGE_SIZE; + void *scratch; + int i; + u8 __user *buffer; + + iov = kunit_kmalloc_array(test, ioc, sizeof(*iov), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, iov); + + /* Allocate a huge buffer and populate it with pages. */ + buffer = iov_kunit_create_user_buf(test, npages, NULL); + + /* Create a single large buffer to copy to/from. */ + scratch = iov_kunit_create_source(test, npages); + + /* Split the target over a number of iovecs */ + copied = 0; + for (i = 0; i < ioc; i++) { + part = size / ioc; + iov[i].iov_base = buffer + copied; + iov[i].iov_len = part; + copied += part; + } + iov[i - 1].iov_len += size - part; + + /* Perform and time a bunch of copies. */ + kunit_info(test, "Benchmarking copy_to_iter() over IOVEC:\n"); + for (i = 0; i < IOV_KUNIT_NR_SAMPLES; i++) { + iov_iter_init(&iter, ITER_SOURCE, iov, npages, size); + + a = ktime_get_real(); + copied = copy_from_iter(scratch, size, &iter); + b = ktime_get_real(); + KUNIT_EXPECT_EQ(test, copied, size); + samples[i] = ktime_to_us(ktime_sub(b, a)); + } + + iov_kunit_benchmark_print_stats(test, samples); + KUNIT_SUCCEED(); +} + /* * Time copying 256MiB through an ITER_KVEC. */ @@ -1524,6 +1617,8 @@ static struct kunit_case __refdata iov_kunit_cases[] = { KUNIT_CASE(iov_kunit_extract_pages_kvec), KUNIT_CASE(iov_kunit_extract_pages_bvec), KUNIT_CASE(iov_kunit_extract_pages_xarray), + KUNIT_CASE(iov_kunit_benchmark_ubuf), + KUNIT_CASE(iov_kunit_benchmark_iovec), KUNIT_CASE(iov_kunit_benchmark_kvec), KUNIT_CASE(iov_kunit_benchmark_bvec), KUNIT_CASE(iov_kunit_benchmark_bvec_split),