mm/gup_benchmark: support pin_user_pages() and related calls
Up until now, gup_benchmark supported testing of the following kernel
functions:
* get_user_pages(): via the '-U' command line option
* get_user_pages_longterm(): via the '-L' command line option
* get_user_pages_fast(): as the default (no options required)
Add test coverage for the new corresponding pin_*() functions:
* pin_user_pages_fast(): via the '-a' command line option
* pin_user_pages():      via the '-b' command line option
Also, add an option for clarity: '-u' for what is now (still) the default
choice: get_user_pages_fast().
Also, for the commands that set FOLL_PIN, verify that the pages really are
dma-pinned, via the new is_dma_pinned() routine.  Those commands are:
    PIN_FAST_BENCHMARK     : calls pin_user_pages_fast()
    PIN_BENCHMARK          : calls pin_user_pages()
In between the calls to pin_*() and unpin_user_pages(), check each page:
if page_maybe_dma_pinned() returns false, then WARN and return.
Do this outside of the benchmark timestamps, so that it doesn't affect
reported times.
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Jérôme Glisse <jglisse@redhat.com>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Link: http://lkml.kernel.org/r/20200211001536.1027652-10-jhubbard@nvidia.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
			
			
This commit is contained in:
		
							parent
							
								
									1970dc6f52
								
							
						
					
					
						commit
						41c45d37b9
					
				| @ -8,6 +8,8 @@ | ||||
| #define GUP_FAST_BENCHMARK	_IOWR('g', 1, struct gup_benchmark) | ||||
| #define GUP_LONGTERM_BENCHMARK	_IOWR('g', 2, struct gup_benchmark) | ||||
| #define GUP_BENCHMARK		_IOWR('g', 3, struct gup_benchmark) | ||||
| #define PIN_FAST_BENCHMARK	_IOWR('g', 4, struct gup_benchmark) | ||||
| #define PIN_BENCHMARK		_IOWR('g', 5, struct gup_benchmark) | ||||
| 
 | ||||
| struct gup_benchmark { | ||||
| 	__u64 get_delta_usec; | ||||
| @ -19,6 +21,48 @@ struct gup_benchmark { | ||||
| 	__u64 expansion[10];	/* For future use */ | ||||
| }; | ||||
| 
 | ||||
| static void put_back_pages(unsigned int cmd, struct page **pages, | ||||
| 			   unsigned long nr_pages) | ||||
| { | ||||
| 	unsigned long i; | ||||
| 
 | ||||
| 	switch (cmd) { | ||||
| 	case GUP_FAST_BENCHMARK: | ||||
| 	case GUP_LONGTERM_BENCHMARK: | ||||
| 	case GUP_BENCHMARK: | ||||
| 		for (i = 0; i < nr_pages; i++) | ||||
| 			put_page(pages[i]); | ||||
| 		break; | ||||
| 
 | ||||
| 	case PIN_FAST_BENCHMARK: | ||||
| 	case PIN_BENCHMARK: | ||||
| 		unpin_user_pages(pages, nr_pages); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void verify_dma_pinned(unsigned int cmd, struct page **pages, | ||||
| 			      unsigned long nr_pages) | ||||
| { | ||||
| 	unsigned long i; | ||||
| 	struct page *page; | ||||
| 
 | ||||
| 	switch (cmd) { | ||||
| 	case PIN_FAST_BENCHMARK: | ||||
| 	case PIN_BENCHMARK: | ||||
| 		for (i = 0; i < nr_pages; i++) { | ||||
| 			page = pages[i]; | ||||
| 			if (WARN(!page_maybe_dma_pinned(page), | ||||
| 				 "pages[%lu] is NOT dma-pinned\n", i)) { | ||||
| 
 | ||||
| 				dump_page(page, "gup_benchmark failure"); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int __gup_benchmark_ioctl(unsigned int cmd, | ||||
| 		struct gup_benchmark *gup) | ||||
| { | ||||
| @ -66,6 +110,14 @@ static int __gup_benchmark_ioctl(unsigned int cmd, | ||||
| 			nr = get_user_pages(addr, nr, gup->flags, pages + i, | ||||
| 					    NULL); | ||||
| 			break; | ||||
| 		case PIN_FAST_BENCHMARK: | ||||
| 			nr = pin_user_pages_fast(addr, nr, gup->flags, | ||||
| 						 pages + i); | ||||
| 			break; | ||||
| 		case PIN_BENCHMARK: | ||||
| 			nr = pin_user_pages(addr, nr, gup->flags, pages + i, | ||||
| 					    NULL); | ||||
| 			break; | ||||
| 		default: | ||||
| 			kvfree(pages); | ||||
| 			ret = -EINVAL; | ||||
| @ -78,15 +130,22 @@ static int __gup_benchmark_ioctl(unsigned int cmd, | ||||
| 	} | ||||
| 	end_time = ktime_get(); | ||||
| 
 | ||||
| 	/* Shifting the meaning of nr_pages: now it is actual number pinned: */ | ||||
| 	nr_pages = i; | ||||
| 
 | ||||
| 	gup->get_delta_usec = ktime_us_delta(end_time, start_time); | ||||
| 	gup->size = addr - gup->addr; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Take an un-benchmark-timed moment to verify DMA pinned | ||||
| 	 * state: print a warning if any non-dma-pinned pages are found: | ||||
| 	 */ | ||||
| 	verify_dma_pinned(cmd, pages, nr_pages); | ||||
| 
 | ||||
| 	start_time = ktime_get(); | ||||
| 	for (i = 0; i < nr_pages; i++) { | ||||
| 		if (!pages[i]) | ||||
| 			break; | ||||
| 		put_page(pages[i]); | ||||
| 	} | ||||
| 
 | ||||
| 	put_back_pages(cmd, pages, nr_pages); | ||||
| 
 | ||||
| 	end_time = ktime_get(); | ||||
| 	gup->put_delta_usec = ktime_us_delta(end_time, start_time); | ||||
| 
 | ||||
| @ -105,6 +164,8 @@ static long gup_benchmark_ioctl(struct file *filep, unsigned int cmd, | ||||
| 	case GUP_FAST_BENCHMARK: | ||||
| 	case GUP_LONGTERM_BENCHMARK: | ||||
| 	case GUP_BENCHMARK: | ||||
| 	case PIN_FAST_BENCHMARK: | ||||
| 	case PIN_BENCHMARK: | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -EINVAL; | ||||
|  | ||||
| @ -18,6 +18,10 @@ | ||||
| #define GUP_LONGTERM_BENCHMARK	_IOWR('g', 2, struct gup_benchmark) | ||||
| #define GUP_BENCHMARK		_IOWR('g', 3, struct gup_benchmark) | ||||
| 
 | ||||
| /* Similar to above, but use FOLL_PIN instead of FOLL_GET. */ | ||||
| #define PIN_FAST_BENCHMARK	_IOWR('g', 4, struct gup_benchmark) | ||||
| #define PIN_BENCHMARK		_IOWR('g', 5, struct gup_benchmark) | ||||
| 
 | ||||
| /* Just the flags we need, copied from mm.h: */ | ||||
| #define FOLL_WRITE	0x01	/* check pte is writable */ | ||||
| 
 | ||||
| @ -40,8 +44,14 @@ int main(int argc, char **argv) | ||||
| 	char *file = "/dev/zero"; | ||||
| 	char *p; | ||||
| 
 | ||||
| 	while ((opt = getopt(argc, argv, "m:r:n:f:tTLUwSH")) != -1) { | ||||
| 	while ((opt = getopt(argc, argv, "m:r:n:f:abtTLUuwSH")) != -1) { | ||||
| 		switch (opt) { | ||||
| 		case 'a': | ||||
| 			cmd = PIN_FAST_BENCHMARK; | ||||
| 			break; | ||||
| 		case 'b': | ||||
| 			cmd = PIN_BENCHMARK; | ||||
| 			break; | ||||
| 		case 'm': | ||||
| 			size = atoi(optarg) * MB; | ||||
| 			break; | ||||
| @ -63,6 +73,9 @@ int main(int argc, char **argv) | ||||
| 		case 'U': | ||||
| 			cmd = GUP_BENCHMARK; | ||||
| 			break; | ||||
| 		case 'u': | ||||
| 			cmd = GUP_FAST_BENCHMARK; | ||||
| 			break; | ||||
| 		case 'w': | ||||
| 			write = 1; | ||||
| 			break; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user