]> git.samba.org - sfrench/cifs-2.6.git/blob - tools/testing/selftests/vm/gup_test.c
selinux: kill 'flags' argument in avc_has_perm_flags() and avc_audit()
[sfrench/cifs-2.6.git] / tools / testing / selftests / vm / gup_test.c
1 #include <fcntl.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <sys/ioctl.h>
6 #include <sys/mman.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include "../../../../mm/gup_test.h"
10
11 #define MB (1UL << 20)
12 #define PAGE_SIZE sysconf(_SC_PAGESIZE)
13
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 */
17
18 static char *cmd_to_str(unsigned long cmd)
19 {
20         switch (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";
27         case GUP_BASIC_TEST:
28                 return "GUP_BASIC_TEST";
29         case PIN_BASIC_TEST:
30                 return "PIN_BASIC_TEST";
31         case DUMP_USER_PAGES_TEST:
32                 return "DUMP_USER_PAGES_TEST";
33         }
34         return "Unknown command";
35 }
36
37 int main(int argc, char **argv)
38 {
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";
45         char *p;
46
47         while ((opt = getopt(argc, argv, "m:r:n:F:f:abctTLUuwWSHpz")) != -1) {
48                 switch (opt) {
49                 case 'a':
50                         cmd = PIN_FAST_BENCHMARK;
51                         break;
52                 case 'b':
53                         cmd = PIN_BASIC_TEST;
54                         break;
55                 case 'L':
56                         cmd = PIN_LONGTERM_BENCHMARK;
57                         break;
58                 case 'c':
59                         cmd = DUMP_USER_PAGES_TEST;
60                         /*
61                          * Dump page 0 (index 1). May be overridden later, by
62                          * user's non-option arguments.
63                          *
64                          * .which_pages is zero-based, so that zero can mean "do
65                          * nothing".
66                          */
67                         gup.which_pages[0] = 1;
68                         break;
69                 case 'p':
70                         /* works only with DUMP_USER_PAGES_TEST */
71                         gup.test_flags |= GUP_TEST_FLAG_DUMP_PAGES_USE_PIN;
72                         break;
73                 case 'F':
74                         /* strtol, so you can pass flags in hex form */
75                         gup.gup_flags = strtol(optarg, 0, 0);
76                         break;
77                 case 'm':
78                         size = atoi(optarg) * MB;
79                         break;
80                 case 'r':
81                         repeats = atoi(optarg);
82                         break;
83                 case 'n':
84                         nr_pages = atoi(optarg);
85                         break;
86                 case 't':
87                         thp = 1;
88                         break;
89                 case 'T':
90                         thp = 0;
91                         break;
92                 case 'U':
93                         cmd = GUP_BASIC_TEST;
94                         break;
95                 case 'u':
96                         cmd = GUP_FAST_BENCHMARK;
97                         break;
98                 case 'w':
99                         write = 1;
100                         break;
101                 case 'W':
102                         write = 0;
103                         break;
104                 case 'f':
105                         file = optarg;
106                         break;
107                 case 'S':
108                         flags &= ~MAP_PRIVATE;
109                         flags |= MAP_SHARED;
110                         break;
111                 case 'H':
112                         flags |= (MAP_HUGETLB | MAP_ANONYMOUS);
113                         break;
114                 case 'z':
115                         /* fault pages in gup, do not fault in userland */
116                         touch = 1;
117                         break;
118                 default:
119                         return -1;
120                 }
121         }
122
123         if (optind < argc) {
124                 int extra_arg_count = 0;
125                 /*
126                  * For example:
127                  *
128                  *   ./gup_test -c 0 1 0x1001
129                  *
130                  * ...to dump pages 0, 1, and 4097
131                  */
132
133                 while ((optind < argc) &&
134                        (extra_arg_count < GUP_TEST_MAX_PAGES_TO_DUMP)) {
135                         /*
136                          * Do the 1-based indexing here, so that the user can
137                          * use normal 0-based indexing on the command line.
138                          */
139                         long page_index = strtol(argv[optind], 0, 0) + 1;
140
141                         gup.which_pages[extra_arg_count] = page_index;
142                         extra_arg_count++;
143                         optind++;
144                 }
145         }
146
147         filed = open(file, O_RDWR|O_CREAT);
148         if (filed < 0) {
149                 perror("open");
150                 exit(filed);
151         }
152
153         gup.nr_pages_per_call = nr_pages;
154         if (write)
155                 gup.gup_flags |= FOLL_WRITE;
156
157         fd = open("/sys/kernel/debug/gup_test", O_RDWR);
158         if (fd == -1) {
159                 perror("open");
160                 exit(1);
161         }
162
163         p = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, filed, 0);
164         if (p == MAP_FAILED) {
165                 perror("mmap");
166                 exit(1);
167         }
168         gup.addr = (unsigned long)p;
169
170         if (thp == 1)
171                 madvise(p, size, MADV_HUGEPAGE);
172         else if (thp == 0)
173                 madvise(p, size, MADV_NOHUGEPAGE);
174
175         /*
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.
180          */
181         if (touch) {
182                 gup.gup_flags |= FOLL_TOUCH;
183         } else {
184                 for (; (unsigned long)p < gup.addr + size; p += PAGE_SIZE)
185                         p[0] = 0;
186         }
187
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++) {
192                         gup.size = size;
193                         if (ioctl(fd, cmd, &gup))
194                                 perror("ioctl"), exit(1);
195
196                         printf("%s: Time: get:%lld put:%lld us",
197                                cmd_to_str(cmd), gup.get_delta_usec,
198                                gup.put_delta_usec);
199                         if (gup.size != size)
200                                 printf(", truncated (size: %lld)", gup.size);
201                         printf("\n");
202                 }
203         } else {
204                 gup.size = size;
205                 if (ioctl(fd, cmd, &gup)) {
206                         perror("ioctl");
207                         exit(1);
208                 }
209
210                 printf("%s: done\n", cmd_to_str(cmd));
211                 if (gup.size != size)
212                         printf("Truncated (size: %lld)\n", gup.size);
213         }
214
215         return 0;
216 }