mm/gup_benchmark: rename to mm/gup_test
authorJohn Hubbard <jhubbard@nvidia.com>
Tue, 15 Dec 2020 03:05:05 +0000 (19:05 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 15 Dec 2020 20:13:38 +0000 (12:13 -0800)
Patch series "selftests/vm: gup_test, hmm-tests, assorted improvements", v3.

Summary: This series provides two main things, and a number of smaller
supporting goodies.  The two main points are:

1) Add a new sub-test to gup_test, which in turn is a renamed version
   of gup_benchmark.  This sub-test allows nicer testing of dump_pages(),
   at least on user-space pages.

   For quite a while, I was doing a quick hack to gup_test.c whenever I
   wanted to try out changes to dump_page().  Then Matthew Wilcox asked me
   what I meant when I said "I used my dump_page() unit test", and I
   realized that it might be nice to check in a polished up version of
   that.

   Details about how it works and how to use it are in the commit
   description for patch #6 ("selftests/vm: gup_test: introduce the
   dump_pages() sub-test").

2) Fixes a limitation of hmm-tests: these tests are incredibly useful,
   but only if people actually build and run them.  And it turns out that
   libhugetlbfs is a little too effective at throwing a wrench in the
   works, there.  So I've added a little configuration check that removes
   just two of the 21 hmm-tests, if libhugetlbfs is not available.

   Further details in the commit description of patch #8
   ("selftests/vm: hmm-tests: remove the libhugetlbfs dependency").

Other smaller things that this series does:

a) Remove code duplication by creating gup_test.h.

b) Clear up the sub-test organization, and their invocation within
   run_vmtests.sh.

c) Other minor assorted improvements.

[1] v2 is here:
https://lore.kernel.org/linux-doc/20200929212747.251804-1-jhubbard@nvidia.com/

[2] https://lore.kernel.org/r/CAHk-=wgh-TMPHLY3jueHX7Y2fWh3D+nMBqVS__AZm6-oorquWA@mail.gmail.com

This patch (of 9):

Rename nearly every "gup_benchmark" reference and file name to "gup_test".
The one exception is for the actual gup benchmark test itself.

The current code already does a *little* bit more than benchmarking, and
definitely covers more than get_user_pages_fast().  More importantly,
however, subsequent patches are about to add some functionality that is
non-benchmark related.

Closely related changes:

* Kconfig: in addition to renaming the options from GUP_BENCHMARK to
  GUP_TEST, update the help text to reflect that it's no longer a
  benchmark-only test.

Link: https://lkml.kernel.org/r/20201026064021.3545418-1-jhubbard@nvidia.com
Link: https://lkml.kernel.org/r/20201026064021.3545418-2-jhubbard@nvidia.com
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Jérôme Glisse <jglisse@redhat.com>
Cc: Ralph Campbell <rcampbell@nvidia.com>
Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
13 files changed:
Documentation/core-api/pin_user_pages.rst
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
mm/Kconfig
mm/Makefile
mm/gup_benchmark.c [deleted file]
mm/gup_test.c [new file with mode: 0644]
tools/testing/selftests/vm/.gitignore
tools/testing/selftests/vm/Makefile
tools/testing/selftests/vm/config
tools/testing/selftests/vm/gup_benchmark.c [deleted file]
tools/testing/selftests/vm/gup_test.c [new file with mode: 0644]
tools/testing/selftests/vm/run_vmtests

index 7ca8c7bac65026764867a15ef089d12cd1599fba..eae972b232243aeb354f9074d80f4ca41b24ae86 100644 (file)
@@ -221,12 +221,12 @@ Unit testing
 ============
 This file::
 
- tools/testing/selftests/vm/gup_benchmark.c
+ tools/testing/selftests/vm/gup_test.c
 
 has the following new calls to exercise the new pin*() wrapper functions:
 
-* PIN_FAST_BENCHMARK (./gup_benchmark -a)
-* PIN_BENCHMARK (./gup_benchmark -b)
+* PIN_FAST_BENCHMARK (./gup_test -a)
+* PIN_BENCHMARK (./gup_test -b)
 
 You can monitor how many total dma-pinned pages have been acquired and released
 since the system was booted, via two new /proc/vmstat entries: ::
index fe6f529ac82cf27bf23e3d50b1a4017d39d9f746..3601c28d15260e0e86b3581593809c96684845e6 100644 (file)
@@ -102,7 +102,7 @@ CONFIG_ZSMALLOC_STAT=y
 CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
 CONFIG_IDLE_PAGE_TRACKING=y
 CONFIG_PERCPU_STATS=y
-CONFIG_GUP_BENCHMARK=y
+CONFIG_GUP_TEST=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
index 17d5df2c1eff34833f81fd8d6ad29c39a9aa0ec4..e2171a0088094a299b107634df047c6e5bbb31cd 100644 (file)
@@ -95,7 +95,7 @@ CONFIG_ZSMALLOC_STAT=y
 CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
 CONFIG_IDLE_PAGE_TRACKING=y
 CONFIG_PERCPU_STATS=y
-CONFIG_GUP_BENCHMARK=y
+CONFIG_GUP_TEST=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
index 390165ffbb0fc2395a7460836eea971e0c0176f3..e25e5cb2989f423603f995d38719863626cbf890 100644 (file)
@@ -821,13 +821,18 @@ config PERCPU_STATS
          information includes global and per chunk statistics, which can
          be used to help understand percpu memory usage.
 
-config GUP_BENCHMARK
-       bool "Enable infrastructure for get_user_pages() and related calls benchmarking"
+config GUP_TEST
+       bool "Enable infrastructure for get_user_pages()-related unit tests"
        help
-         Provides /sys/kernel/debug/gup_benchmark that helps with testing
-         performance of get_user_pages() and related calls.
+         Provides /sys/kernel/debug/gup_test, which in turn provides a way
+         to make ioctl calls that can launch kernel-based unit tests for
+         the get_user_pages*() and pin_user_pages*() family of API calls.
 
-         See tools/testing/selftests/vm/gup_benchmark.c
+         These tests include benchmark testing of the _fast variants of
+         get_user_pages*() and pin_user_pages*(), as well as smoke tests of
+         the non-_fast variants.
+
+         See tools/testing/selftests/vm/gup_test.c
 
 config GUP_GET_PTE_LOW_HIGH
        bool
index d73aed0fc99c1d408090c8175f482bbd24a6f2a9..069f216e109ea66a4a012a47107b3d5554f9659f 100644 (file)
@@ -90,7 +90,7 @@ obj-$(CONFIG_PAGE_COUNTER) += page_counter.o
 obj-$(CONFIG_MEMCG) += memcontrol.o vmpressure.o
 obj-$(CONFIG_MEMCG_SWAP) += swap_cgroup.o
 obj-$(CONFIG_CGROUP_HUGETLB) += hugetlb_cgroup.o
-obj-$(CONFIG_GUP_BENCHMARK) += gup_benchmark.o
+obj-$(CONFIG_GUP_TEST) += gup_test.o
 obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
 obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o
 obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o
diff --git a/mm/gup_benchmark.c b/mm/gup_benchmark.c
deleted file mode 100644 (file)
index 8b3e5b5..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/ktime.h>
-#include <linux/debugfs.h>
-
-#define GUP_FAST_BENCHMARK     _IOWR('g', 1, struct gup_benchmark)
-#define GUP_BENCHMARK          _IOWR('g', 2, struct gup_benchmark)
-#define PIN_FAST_BENCHMARK     _IOWR('g', 3, struct gup_benchmark)
-#define PIN_BENCHMARK          _IOWR('g', 4, struct gup_benchmark)
-#define PIN_LONGTERM_BENCHMARK _IOWR('g', 5, struct gup_benchmark)
-
-struct gup_benchmark {
-       __u64 get_delta_usec;
-       __u64 put_delta_usec;
-       __u64 addr;
-       __u64 size;
-       __u32 nr_pages_per_call;
-       __u32 flags;
-       __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_BENCHMARK:
-               for (i = 0; i < nr_pages; i++)
-                       put_page(pages[i]);
-               break;
-
-       case PIN_FAST_BENCHMARK:
-       case PIN_BENCHMARK:
-       case PIN_LONGTERM_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:
-       case PIN_LONGTERM_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)
-{
-       ktime_t start_time, end_time;
-       unsigned long i, nr_pages, addr, next;
-       int nr;
-       struct page **pages;
-       int ret = 0;
-       bool needs_mmap_lock =
-               cmd != GUP_FAST_BENCHMARK && cmd != PIN_FAST_BENCHMARK;
-
-       if (gup->size > ULONG_MAX)
-               return -EINVAL;
-
-       nr_pages = gup->size / PAGE_SIZE;
-       pages = kvcalloc(nr_pages, sizeof(void *), GFP_KERNEL);
-       if (!pages)
-               return -ENOMEM;
-
-       if (needs_mmap_lock && mmap_read_lock_killable(current->mm)) {
-               ret = -EINTR;
-               goto free_pages;
-       }
-
-       i = 0;
-       nr = gup->nr_pages_per_call;
-       start_time = ktime_get();
-       for (addr = gup->addr; addr < gup->addr + gup->size; addr = next) {
-               if (nr != gup->nr_pages_per_call)
-                       break;
-
-               next = addr + nr * PAGE_SIZE;
-               if (next > gup->addr + gup->size) {
-                       next = gup->addr + gup->size;
-                       nr = (next - addr) / PAGE_SIZE;
-               }
-
-               /* Filter out most gup flags: only allow a tiny subset here: */
-               gup->flags &= FOLL_WRITE;
-
-               switch (cmd) {
-               case GUP_FAST_BENCHMARK:
-                       nr = get_user_pages_fast(addr, nr, gup->flags,
-                                                pages + i);
-                       break;
-               case GUP_BENCHMARK:
-                       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;
-               case PIN_LONGTERM_BENCHMARK:
-                       nr = pin_user_pages(addr, nr,
-                                           gup->flags | FOLL_LONGTERM,
-                                           pages + i, NULL);
-                       break;
-               default:
-                       ret = -EINVAL;
-                       goto unlock;
-               }
-
-               if (nr <= 0)
-                       break;
-               i += nr;
-       }
-       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();
-
-       put_back_pages(cmd, pages, nr_pages);
-
-       end_time = ktime_get();
-       gup->put_delta_usec = ktime_us_delta(end_time, start_time);
-
-unlock:
-       if (needs_mmap_lock)
-               mmap_read_unlock(current->mm);
-free_pages:
-       kvfree(pages);
-       return ret;
-}
-
-static long gup_benchmark_ioctl(struct file *filep, unsigned int cmd,
-               unsigned long arg)
-{
-       struct gup_benchmark gup;
-       int ret;
-
-       switch (cmd) {
-       case GUP_FAST_BENCHMARK:
-       case GUP_BENCHMARK:
-       case PIN_FAST_BENCHMARK:
-       case PIN_BENCHMARK:
-       case PIN_LONGTERM_BENCHMARK:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (copy_from_user(&gup, (void __user *)arg, sizeof(gup)))
-               return -EFAULT;
-
-       ret = __gup_benchmark_ioctl(cmd, &gup);
-       if (ret)
-               return ret;
-
-       if (copy_to_user((void __user *)arg, &gup, sizeof(gup)))
-               return -EFAULT;
-
-       return 0;
-}
-
-static const struct file_operations gup_benchmark_fops = {
-       .open = nonseekable_open,
-       .unlocked_ioctl = gup_benchmark_ioctl,
-};
-
-static int gup_benchmark_init(void)
-{
-       debugfs_create_file_unsafe("gup_benchmark", 0600, NULL, NULL,
-                                  &gup_benchmark_fops);
-
-       return 0;
-}
-
-late_initcall(gup_benchmark_init);
diff --git a/mm/gup_test.c b/mm/gup_test.c
new file mode 100644 (file)
index 0000000..59472ea
--- /dev/null
@@ -0,0 +1,210 @@
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
+
+#define GUP_FAST_BENCHMARK     _IOWR('g', 1, struct gup_test)
+#define GUP_BENCHMARK          _IOWR('g', 2, struct gup_test)
+#define PIN_FAST_BENCHMARK     _IOWR('g', 3, struct gup_test)
+#define PIN_BENCHMARK          _IOWR('g', 4, struct gup_test)
+#define PIN_LONGTERM_BENCHMARK _IOWR('g', 5, struct gup_test)
+
+struct gup_test {
+       __u64 get_delta_usec;
+       __u64 put_delta_usec;
+       __u64 addr;
+       __u64 size;
+       __u32 nr_pages_per_call;
+       __u32 flags;
+       __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_BENCHMARK:
+               for (i = 0; i < nr_pages; i++)
+                       put_page(pages[i]);
+               break;
+
+       case PIN_FAST_BENCHMARK:
+       case PIN_BENCHMARK:
+       case PIN_LONGTERM_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:
+       case PIN_LONGTERM_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_test failure");
+                               break;
+                       }
+               }
+               break;
+       }
+}
+
+static int __gup_test_ioctl(unsigned int cmd,
+               struct gup_test *gup)
+{
+       ktime_t start_time, end_time;
+       unsigned long i, nr_pages, addr, next;
+       int nr;
+       struct page **pages;
+       int ret = 0;
+       bool needs_mmap_lock =
+               cmd != GUP_FAST_BENCHMARK && cmd != PIN_FAST_BENCHMARK;
+
+       if (gup->size > ULONG_MAX)
+               return -EINVAL;
+
+       nr_pages = gup->size / PAGE_SIZE;
+       pages = kvcalloc(nr_pages, sizeof(void *), GFP_KERNEL);
+       if (!pages)
+               return -ENOMEM;
+
+       if (needs_mmap_lock && mmap_read_lock_killable(current->mm)) {
+               ret = -EINTR;
+               goto free_pages;
+       }
+
+       i = 0;
+       nr = gup->nr_pages_per_call;
+       start_time = ktime_get();
+       for (addr = gup->addr; addr < gup->addr + gup->size; addr = next) {
+               if (nr != gup->nr_pages_per_call)
+                       break;
+
+               next = addr + nr * PAGE_SIZE;
+               if (next > gup->addr + gup->size) {
+                       next = gup->addr + gup->size;
+                       nr = (next - addr) / PAGE_SIZE;
+               }
+
+               /* Filter out most gup flags: only allow a tiny subset here: */
+               gup->flags &= FOLL_WRITE;
+
+               switch (cmd) {
+               case GUP_FAST_BENCHMARK:
+                       nr = get_user_pages_fast(addr, nr, gup->flags,
+                                                pages + i);
+                       break;
+               case GUP_BENCHMARK:
+                       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;
+               case PIN_LONGTERM_BENCHMARK:
+                       nr = pin_user_pages(addr, nr,
+                                           gup->flags | FOLL_LONGTERM,
+                                           pages + i, NULL);
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto unlock;
+               }
+
+               if (nr <= 0)
+                       break;
+               i += nr;
+       }
+       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();
+
+       put_back_pages(cmd, pages, nr_pages);
+
+       end_time = ktime_get();
+       gup->put_delta_usec = ktime_us_delta(end_time, start_time);
+
+unlock:
+       if (needs_mmap_lock)
+               mmap_read_unlock(current->mm);
+free_pages:
+       kvfree(pages);
+       return ret;
+}
+
+static long gup_test_ioctl(struct file *filep, unsigned int cmd,
+               unsigned long arg)
+{
+       struct gup_test gup;
+       int ret;
+
+       switch (cmd) {
+       case GUP_FAST_BENCHMARK:
+       case GUP_BENCHMARK:
+       case PIN_FAST_BENCHMARK:
+       case PIN_BENCHMARK:
+       case PIN_LONGTERM_BENCHMARK:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (copy_from_user(&gup, (void __user *)arg, sizeof(gup)))
+               return -EFAULT;
+
+       ret = __gup_test_ioctl(cmd, &gup);
+       if (ret)
+               return ret;
+
+       if (copy_to_user((void __user *)arg, &gup, sizeof(gup)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static const struct file_operations gup_test_fops = {
+       .open = nonseekable_open,
+       .unlocked_ioctl = gup_test_ioctl,
+};
+
+static int gup_test_init(void)
+{
+       debugfs_create_file_unsafe("gup_test", 0600, NULL, NULL,
+                                  &gup_test_fops);
+
+       return 0;
+}
+
+late_initcall(gup_test_init);
index 849e8226395aaca9dd0f22ec61f08221e44aeccf..2c8ddcf41c0e3ae799a178c6124427e1adfe24a5 100644 (file)
@@ -15,7 +15,7 @@ userfaultfd
 mlock-intersect-test
 mlock-random-test
 virtual_address_range
-gup_benchmark
+gup_test
 va_128TBswitch
 map_fixed_noreplace
 write_to_hugetlbfs
index 691893afc15d87b181b819c745605ef92412eb12..43723df2c6c46c929e97655e4d8ca18f989d1d3c 100644 (file)
@@ -23,7 +23,7 @@ MAKEFLAGS += --no-builtin-rules
 CFLAGS = -Wall -I ../../../../usr/include $(EXTRA_CFLAGS)
 LDLIBS = -lrt
 TEST_GEN_FILES = compaction_test
-TEST_GEN_FILES += gup_benchmark
+TEST_GEN_FILES += gup_test
 TEST_GEN_FILES += hmm-tests
 TEST_GEN_FILES += hugepage-mmap
 TEST_GEN_FILES += hugepage-shm
index 69dd0d1aa30b20291730a61ffafaa4267794fc22..60e82da0de850273f6f9e8bf86d16f91f7bee749 100644 (file)
@@ -3,4 +3,4 @@ CONFIG_USERFAULTFD=y
 CONFIG_TEST_VMALLOC=m
 CONFIG_DEVICE_PRIVATE=y
 CONFIG_TEST_HMM=m
-CONFIG_GUP_BENCHMARK=y
+CONFIG_GUP_TEST=y
diff --git a/tools/testing/selftests/vm/gup_benchmark.c b/tools/testing/selftests/vm/gup_benchmark.c
deleted file mode 100644 (file)
index 1d43593..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <linux/types.h>
-
-#define MB (1UL << 20)
-#define PAGE_SIZE sysconf(_SC_PAGESIZE)
-
-#define GUP_FAST_BENCHMARK     _IOWR('g', 1, struct gup_benchmark)
-#define GUP_BENCHMARK          _IOWR('g', 2, struct gup_benchmark)
-
-/* Similar to above, but use FOLL_PIN instead of FOLL_GET. */
-#define PIN_FAST_BENCHMARK     _IOWR('g', 3, struct gup_benchmark)
-#define PIN_BENCHMARK          _IOWR('g', 4, struct gup_benchmark)
-#define PIN_LONGTERM_BENCHMARK _IOWR('g', 5, struct gup_benchmark)
-
-/* Just the flags we need, copied from mm.h: */
-#define FOLL_WRITE     0x01    /* check pte is writable */
-
-struct gup_benchmark {
-       __u64 get_delta_usec;
-       __u64 put_delta_usec;
-       __u64 addr;
-       __u64 size;
-       __u32 nr_pages_per_call;
-       __u32 flags;
-       __u64 expansion[10];    /* For future use */
-};
-
-int main(int argc, char **argv)
-{
-       struct gup_benchmark gup;
-       unsigned long size = 128 * MB;
-       int i, fd, filed, opt, nr_pages = 1, thp = -1, repeats = 1, write = 0;
-       int cmd = GUP_FAST_BENCHMARK, flags = MAP_PRIVATE;
-       char *file = "/dev/zero";
-       char *p;
-
-       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 'L':
-                       cmd = PIN_LONGTERM_BENCHMARK;
-                       break;
-               case 'm':
-                       size = atoi(optarg) * MB;
-                       break;
-               case 'r':
-                       repeats = atoi(optarg);
-                       break;
-               case 'n':
-                       nr_pages = atoi(optarg);
-                       break;
-               case 't':
-                       thp = 1;
-                       break;
-               case 'T':
-                       thp = 0;
-                       break;
-               case 'U':
-                       cmd = GUP_BENCHMARK;
-                       break;
-               case 'u':
-                       cmd = GUP_FAST_BENCHMARK;
-                       break;
-               case 'w':
-                       write = 1;
-                       break;
-               case 'f':
-                       file = optarg;
-                       break;
-               case 'S':
-                       flags &= ~MAP_PRIVATE;
-                       flags |= MAP_SHARED;
-                       break;
-               case 'H':
-                       flags |= (MAP_HUGETLB | MAP_ANONYMOUS);
-                       break;
-               default:
-                       return -1;
-               }
-       }
-
-       filed = open(file, O_RDWR|O_CREAT);
-       if (filed < 0) {
-               perror("open");
-               exit(filed);
-       }
-
-       gup.nr_pages_per_call = nr_pages;
-       if (write)
-               gup.flags |= FOLL_WRITE;
-
-       fd = open("/sys/kernel/debug/gup_benchmark", O_RDWR);
-       if (fd == -1) {
-               perror("open");
-               exit(1);
-       }
-
-       p = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, filed, 0);
-       if (p == MAP_FAILED) {
-               perror("mmap");
-               exit(1);
-       }
-       gup.addr = (unsigned long)p;
-
-       if (thp == 1)
-               madvise(p, size, MADV_HUGEPAGE);
-       else if (thp == 0)
-               madvise(p, size, MADV_NOHUGEPAGE);
-
-       for (; (unsigned long)p < gup.addr + size; p += PAGE_SIZE)
-               p[0] = 0;
-
-       for (i = 0; i < repeats; i++) {
-               gup.size = size;
-               if (ioctl(fd, cmd, &gup)) {
-                       perror("ioctl");
-                       exit(1);
-               }
-
-               printf("Time: get:%lld put:%lld us", gup.get_delta_usec,
-                       gup.put_delta_usec);
-               if (gup.size != size)
-                       printf(", truncated (size: %lld)", gup.size);
-               printf("\n");
-       }
-
-       return 0;
-}
diff --git a/tools/testing/selftests/vm/gup_test.c b/tools/testing/selftests/vm/gup_test.c
new file mode 100644 (file)
index 0000000..00b4731
--- /dev/null
@@ -0,0 +1,143 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/types.h>
+
+#define MB (1UL << 20)
+#define PAGE_SIZE sysconf(_SC_PAGESIZE)
+
+#define GUP_FAST_BENCHMARK     _IOWR('g', 1, struct gup_test)
+#define GUP_BENCHMARK          _IOWR('g', 2, struct gup_test)
+
+/* Similar to above, but use FOLL_PIN instead of FOLL_GET. */
+#define PIN_FAST_BENCHMARK     _IOWR('g', 3, struct gup_test)
+#define PIN_BENCHMARK          _IOWR('g', 4, struct gup_test)
+#define PIN_LONGTERM_BENCHMARK _IOWR('g', 5, struct gup_test)
+
+/* Just the flags we need, copied from mm.h: */
+#define FOLL_WRITE     0x01    /* check pte is writable */
+
+struct gup_test {
+       __u64 get_delta_usec;
+       __u64 put_delta_usec;
+       __u64 addr;
+       __u64 size;
+       __u32 nr_pages_per_call;
+       __u32 flags;
+       __u64 expansion[10];    /* For future use */
+};
+
+int main(int argc, char **argv)
+{
+       struct gup_test gup;
+       unsigned long size = 128 * MB;
+       int i, fd, filed, opt, nr_pages = 1, thp = -1, repeats = 1, write = 0;
+       int cmd = GUP_FAST_BENCHMARK, flags = MAP_PRIVATE;
+       char *file = "/dev/zero";
+       char *p;
+
+       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 'L':
+                       cmd = PIN_LONGTERM_BENCHMARK;
+                       break;
+               case 'm':
+                       size = atoi(optarg) * MB;
+                       break;
+               case 'r':
+                       repeats = atoi(optarg);
+                       break;
+               case 'n':
+                       nr_pages = atoi(optarg);
+                       break;
+               case 't':
+                       thp = 1;
+                       break;
+               case 'T':
+                       thp = 0;
+                       break;
+               case 'U':
+                       cmd = GUP_BENCHMARK;
+                       break;
+               case 'u':
+                       cmd = GUP_FAST_BENCHMARK;
+                       break;
+               case 'w':
+                       write = 1;
+                       break;
+               case 'f':
+                       file = optarg;
+                       break;
+               case 'S':
+                       flags &= ~MAP_PRIVATE;
+                       flags |= MAP_SHARED;
+                       break;
+               case 'H':
+                       flags |= (MAP_HUGETLB | MAP_ANONYMOUS);
+                       break;
+               default:
+                       return -1;
+               }
+       }
+
+       filed = open(file, O_RDWR|O_CREAT);
+       if (filed < 0) {
+               perror("open");
+               exit(filed);
+       }
+
+       gup.nr_pages_per_call = nr_pages;
+       if (write)
+               gup.flags |= FOLL_WRITE;
+
+       fd = open("/sys/kernel/debug/gup_test", O_RDWR);
+       if (fd == -1) {
+               perror("open");
+               exit(1);
+       }
+
+       p = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, filed, 0);
+       if (p == MAP_FAILED) {
+               perror("mmap");
+               exit(1);
+       }
+       gup.addr = (unsigned long)p;
+
+       if (thp == 1)
+               madvise(p, size, MADV_HUGEPAGE);
+       else if (thp == 0)
+               madvise(p, size, MADV_NOHUGEPAGE);
+
+       for (; (unsigned long)p < gup.addr + size; p += PAGE_SIZE)
+               p[0] = 0;
+
+       for (i = 0; i < repeats; i++) {
+               gup.size = size;
+               if (ioctl(fd, cmd, &gup)) {
+                       perror("ioctl");
+                       exit(1);
+               }
+
+               printf("Time: get:%lld put:%lld us", gup.get_delta_usec,
+                       gup.put_delta_usec);
+               if (gup.size != size)
+                       printf(", truncated (size: %lld)", gup.size);
+               printf("\n");
+       }
+
+       return 0;
+}
index a3f4f30f0a2e873a2b6692f4b17420eae688247c..d1843d5f3c308c95e73b6f6801bd69f0b44ebae5 100755 (executable)
@@ -124,9 +124,9 @@ else
 fi
 
 echo "--------------------------------------------"
-echo "running 'gup_benchmark -U' (normal/slow gup)"
+echo "running 'gup_test -U' (normal/slow gup)"
 echo "--------------------------------------------"
-./gup_benchmark -U
+./gup_test -U
 if [ $? -ne 0 ]; then
        echo "[FAIL]"
        exitcode=1
@@ -135,9 +135,9 @@ else
 fi
 
 echo "------------------------------------------"
-echo "running gup_benchmark -b (pin_user_pages)"
+echo "running gup_test -b (pin_user_pages)"
 echo "------------------------------------------"
-./gup_benchmark -b
+./gup_test -b
 if [ $? -ne 0 ]; then
        echo "[FAIL]"
        exitcode=1