Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  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 <pthread.h>
 10#include <assert.h>
 11#include "../../../../mm/gup_test.h"
 12
 13#define MB (1UL << 20)
 14#define PAGE_SIZE sysconf(_SC_PAGESIZE)
 15
 16/* Just the flags we need, copied from mm.h: */
 17#define FOLL_WRITE	0x01	/* check pte is writable */
 18#define FOLL_TOUCH	0x02	/* mark page accessed */
 19
 20static unsigned long cmd = GUP_FAST_BENCHMARK;
 21static int gup_fd, repeats = 1;
 22static unsigned long size = 128 * MB;
 23/* Serialize prints */
 24static pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER;
 25
 26static char *cmd_to_str(unsigned long cmd)
 27{
 28	switch (cmd) {
 29	case GUP_FAST_BENCHMARK:
 30		return "GUP_FAST_BENCHMARK";
 31	case PIN_FAST_BENCHMARK:
 32		return "PIN_FAST_BENCHMARK";
 33	case PIN_LONGTERM_BENCHMARK:
 34		return "PIN_LONGTERM_BENCHMARK";
 35	case GUP_BASIC_TEST:
 36		return "GUP_BASIC_TEST";
 37	case PIN_BASIC_TEST:
 38		return "PIN_BASIC_TEST";
 39	case DUMP_USER_PAGES_TEST:
 40		return "DUMP_USER_PAGES_TEST";
 41	}
 42	return "Unknown command";
 43}
 44
 45void *gup_thread(void *data)
 46{
 47	struct gup_test gup = *(struct gup_test *)data;
 48	int i;
 49
 50	/* Only report timing information on the *_BENCHMARK commands: */
 51	if ((cmd == PIN_FAST_BENCHMARK) || (cmd == GUP_FAST_BENCHMARK) ||
 52	     (cmd == PIN_LONGTERM_BENCHMARK)) {
 53		for (i = 0; i < repeats; i++) {
 54			gup.size = size;
 55			if (ioctl(gup_fd, cmd, &gup))
 56				perror("ioctl"), exit(1);
 57
 58			pthread_mutex_lock(&print_mutex);
 59			printf("%s: Time: get:%lld put:%lld us",
 60			       cmd_to_str(cmd), gup.get_delta_usec,
 61			       gup.put_delta_usec);
 62			if (gup.size != size)
 63				printf(", truncated (size: %lld)", gup.size);
 64			printf("\n");
 65			pthread_mutex_unlock(&print_mutex);
 66		}
 67	} else {
 68		gup.size = size;
 69		if (ioctl(gup_fd, cmd, &gup)) {
 70			perror("ioctl");
 71			exit(1);
 72		}
 73
 74		pthread_mutex_lock(&print_mutex);
 75		printf("%s: done\n", cmd_to_str(cmd));
 76		if (gup.size != size)
 77			printf("Truncated (size: %lld)\n", gup.size);
 78		pthread_mutex_unlock(&print_mutex);
 79	}
 80
 81	return NULL;
 82}
 83
 84int main(int argc, char **argv)
 85{
 86	struct gup_test gup = { 0 };
 87	int filed, i, opt, nr_pages = 1, thp = -1, write = 1, nthreads = 1, ret;
 88	int flags = MAP_PRIVATE, touch = 0;
 89	char *file = "/dev/zero";
 90	pthread_t *tid;
 91	char *p;
 92
 93	while ((opt = getopt(argc, argv, "m:r:n:F:f:abcj:tTLUuwWSHpz")) != -1) {
 94		switch (opt) {
 95		case 'a':
 96			cmd = PIN_FAST_BENCHMARK;
 97			break;
 98		case 'b':
 99			cmd = PIN_BASIC_TEST;
100			break;
101		case 'L':
102			cmd = PIN_LONGTERM_BENCHMARK;
103			break;
104		case 'c':
105			cmd = DUMP_USER_PAGES_TEST;
106			/*
107			 * Dump page 0 (index 1). May be overridden later, by
108			 * user's non-option arguments.
109			 *
110			 * .which_pages is zero-based, so that zero can mean "do
111			 * nothing".
112			 */
113			gup.which_pages[0] = 1;
114			break;
115		case 'p':
116			/* works only with DUMP_USER_PAGES_TEST */
117			gup.test_flags |= GUP_TEST_FLAG_DUMP_PAGES_USE_PIN;
118			break;
119		case 'F':
120			/* strtol, so you can pass flags in hex form */
121			gup.gup_flags = strtol(optarg, 0, 0);
122			break;
123		case 'j':
124			nthreads = atoi(optarg);
125			break;
126		case 'm':
127			size = atoi(optarg) * MB;
128			break;
129		case 'r':
130			repeats = atoi(optarg);
131			break;
132		case 'n':
133			nr_pages = atoi(optarg);
134			break;
135		case 't':
136			thp = 1;
137			break;
138		case 'T':
139			thp = 0;
140			break;
141		case 'U':
142			cmd = GUP_BASIC_TEST;
143			break;
144		case 'u':
145			cmd = GUP_FAST_BENCHMARK;
146			break;
147		case 'w':
148			write = 1;
149			break;
150		case 'W':
151			write = 0;
152			break;
153		case 'f':
154			file = optarg;
155			break;
156		case 'S':
157			flags &= ~MAP_PRIVATE;
158			flags |= MAP_SHARED;
159			break;
160		case 'H':
161			flags |= (MAP_HUGETLB | MAP_ANONYMOUS);
162			break;
163		case 'z':
164			/* fault pages in gup, do not fault in userland */
165			touch = 1;
166			break;
167		default:
168			return -1;
169		}
170	}
171
172	if (optind < argc) {
173		int extra_arg_count = 0;
174		/*
175		 * For example:
176		 *
177		 *   ./gup_test -c 0 1 0x1001
178		 *
179		 * ...to dump pages 0, 1, and 4097
180		 */
181
182		while ((optind < argc) &&
183		       (extra_arg_count < GUP_TEST_MAX_PAGES_TO_DUMP)) {
184			/*
185			 * Do the 1-based indexing here, so that the user can
186			 * use normal 0-based indexing on the command line.
187			 */
188			long page_index = strtol(argv[optind], 0, 0) + 1;
189
190			gup.which_pages[extra_arg_count] = page_index;
191			extra_arg_count++;
192			optind++;
193		}
194	}
195
196	filed = open(file, O_RDWR|O_CREAT);
197	if (filed < 0) {
198		perror("open");
199		exit(filed);
200	}
201
202	gup.nr_pages_per_call = nr_pages;
203	if (write)
204		gup.gup_flags |= FOLL_WRITE;
205
206	gup_fd = open("/sys/kernel/debug/gup_test", O_RDWR);
207	if (gup_fd == -1) {
208		perror("open");
209		exit(1);
210	}
211
212	p = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, filed, 0);
213	if (p == MAP_FAILED) {
214		perror("mmap");
215		exit(1);
216	}
217	gup.addr = (unsigned long)p;
218
219	if (thp == 1)
220		madvise(p, size, MADV_HUGEPAGE);
221	else if (thp == 0)
222		madvise(p, size, MADV_NOHUGEPAGE);
223
224	/*
225	 * FOLL_TOUCH, in gup_test, is used as an either/or case: either
226	 * fault pages in from the kernel via FOLL_TOUCH, or fault them
227	 * in here, from user space. This allows comparison of performance
228	 * between those two cases.
229	 */
230	if (touch) {
231		gup.gup_flags |= FOLL_TOUCH;
232	} else {
233		for (; (unsigned long)p < gup.addr + size; p += PAGE_SIZE)
234			p[0] = 0;
235	}
236
237	tid = malloc(sizeof(pthread_t) * nthreads);
238	assert(tid);
239	for (i = 0; i < nthreads; i++) {
240		ret = pthread_create(&tid[i], NULL, gup_thread, &gup);
241		assert(ret == 0);
242	}
243	for (i = 0; i < nthreads; i++) {
244		ret = pthread_join(tid[i], NULL);
245		assert(ret == 0);
246	}
247	free(tid);
248
249	return 0;
250}