9 #include "../../../../mm/gup_test.h"
11 #define MB (1UL << 20)
12 #define PAGE_SIZE sysconf(_SC_PAGESIZE)
14 /* Just the flags we need, copied from mm.h: */
15 #define FOLL_WRITE 0x01 /* check pte is writable */
16 #define FOLL_TOUCH 0x02 /* mark page accessed */
18 static char *cmd_to_str(unsigned long cmd)
21 case GUP_FAST_BENCHMARK:
22 return "GUP_FAST_BENCHMARK";
23 case PIN_FAST_BENCHMARK:
24 return "PIN_FAST_BENCHMARK";
25 case PIN_LONGTERM_BENCHMARK:
26 return "PIN_LONGTERM_BENCHMARK";
28 return "GUP_BASIC_TEST";
30 return "PIN_BASIC_TEST";
31 case DUMP_USER_PAGES_TEST:
32 return "DUMP_USER_PAGES_TEST";
34 return "Unknown command";
37 int main(int argc, char **argv)
39 struct gup_test gup = { 0 };
40 unsigned long size = 128 * MB;
41 int i, fd, filed, opt, nr_pages = 1, thp = -1, repeats = 1, write = 1;
42 unsigned long cmd = GUP_FAST_BENCHMARK;
43 int flags = MAP_PRIVATE, touch = 0;
44 char *file = "/dev/zero";
47 while ((opt = getopt(argc, argv, "m:r:n:F:f:abctTLUuwWSHpz")) != -1) {
50 cmd = PIN_FAST_BENCHMARK;
56 cmd = PIN_LONGTERM_BENCHMARK;
59 cmd = DUMP_USER_PAGES_TEST;
61 * Dump page 0 (index 1). May be overridden later, by
62 * user's non-option arguments.
64 * .which_pages is zero-based, so that zero can mean "do
67 gup.which_pages[0] = 1;
70 /* works only with DUMP_USER_PAGES_TEST */
71 gup.test_flags |= GUP_TEST_FLAG_DUMP_PAGES_USE_PIN;
74 /* strtol, so you can pass flags in hex form */
75 gup.gup_flags = strtol(optarg, 0, 0);
78 size = atoi(optarg) * MB;
81 repeats = atoi(optarg);
84 nr_pages = atoi(optarg);
96 cmd = GUP_FAST_BENCHMARK;
108 flags &= ~MAP_PRIVATE;
112 flags |= (MAP_HUGETLB | MAP_ANONYMOUS);
115 /* fault pages in gup, do not fault in userland */
124 int extra_arg_count = 0;
128 * ./gup_test -c 0 1 0x1001
130 * ...to dump pages 0, 1, and 4097
133 while ((optind < argc) &&
134 (extra_arg_count < GUP_TEST_MAX_PAGES_TO_DUMP)) {
136 * Do the 1-based indexing here, so that the user can
137 * use normal 0-based indexing on the command line.
139 long page_index = strtol(argv[optind], 0, 0) + 1;
141 gup.which_pages[extra_arg_count] = page_index;
147 filed = open(file, O_RDWR|O_CREAT);
153 gup.nr_pages_per_call = nr_pages;
155 gup.gup_flags |= FOLL_WRITE;
157 fd = open("/sys/kernel/debug/gup_test", O_RDWR);
163 p = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, filed, 0);
164 if (p == MAP_FAILED) {
168 gup.addr = (unsigned long)p;
171 madvise(p, size, MADV_HUGEPAGE);
173 madvise(p, size, MADV_NOHUGEPAGE);
176 * FOLL_TOUCH, in gup_test, is used as an either/or case: either
177 * fault pages in from the kernel via FOLL_TOUCH, or fault them
178 * in here, from user space. This allows comparison of performance
179 * between those two cases.
182 gup.gup_flags |= FOLL_TOUCH;
184 for (; (unsigned long)p < gup.addr + size; p += PAGE_SIZE)
188 /* Only report timing information on the *_BENCHMARK commands: */
189 if ((cmd == PIN_FAST_BENCHMARK) || (cmd == GUP_FAST_BENCHMARK) ||
190 (cmd == PIN_LONGTERM_BENCHMARK)) {
191 for (i = 0; i < repeats; i++) {
193 if (ioctl(fd, cmd, &gup))
194 perror("ioctl"), exit(1);
196 printf("%s: Time: get:%lld put:%lld us",
197 cmd_to_str(cmd), gup.get_delta_usec,
199 if (gup.size != size)
200 printf(", truncated (size: %lld)", gup.size);
205 if (ioctl(fd, cmd, &gup)) {
210 printf("%s: done\n", cmd_to_str(cmd));
211 if (gup.size != size)
212 printf("Truncated (size: %lld)\n", gup.size);