xref: /dpdk/app/test-gpudev/main.c (revision 6e97b5fc)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2021 NVIDIA Corporation & Affiliates
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdint.h>
9 #include <inttypes.h>
10 #include <stdarg.h>
11 #include <errno.h>
12 #include <getopt.h>
13 
14 #include <rte_common.h>
15 #include <rte_malloc.h>
16 #include <rte_memory.h>
17 #include <rte_eal.h>
18 #include <rte_ether.h>
19 #include <rte_ethdev.h>
20 #include <rte_mempool.h>
21 #include <rte_mbuf.h>
22 
23 #include <rte_gpudev.h>
24 
25 enum app_args {
26 	ARG_HELP,
27 	ARG_MEMPOOL
28 };
29 
30 static void
31 usage(const char *prog_name)
32 {
33 	printf("%s [EAL options] --\n",
34 		prog_name);
35 }
36 
37 static void
38 args_parse(int argc, char **argv)
39 {
40 	char **argvopt;
41 	int opt;
42 	int opt_idx;
43 
44 	static struct option lgopts[] = {
45 		{ "help", 0, 0, ARG_HELP},
46 		/* End of options */
47 		{ 0, 0, 0, 0 }
48 	};
49 
50 	argvopt = argv;
51 	while ((opt = getopt_long(argc, argvopt, "",
52 				lgopts, &opt_idx)) != EOF) {
53 		switch (opt) {
54 		case ARG_HELP:
55 			usage(argv[0]);
56 			break;
57 		default:
58 			usage(argv[0]);
59 			rte_exit(EXIT_FAILURE, "Invalid option: %s\n", argv[optind]);
60 			break;
61 		}
62 	}
63 }
64 
65 static int
66 alloc_gpu_memory(uint16_t gpu_id)
67 {
68 	void *ptr_1 = NULL;
69 	void *ptr_2 = NULL;
70 	size_t buf_bytes = 1024;
71 	unsigned int align = 4096;
72 	int ret;
73 
74 	printf("\n=======> TEST: Allocate GPU memory\n\n");
75 
76 	/* Alloc memory on GPU 0 without any specific alignment */
77 	ptr_1 = rte_gpu_mem_alloc(gpu_id, buf_bytes, 0);
78 	if (ptr_1 == NULL) {
79 		fprintf(stderr, "rte_gpu_mem_alloc GPU memory returned error\n");
80 		goto error;
81 	}
82 	printf("GPU memory allocated at 0x%p size is %zd bytes\n",
83 			ptr_1, buf_bytes);
84 
85 	/* Alloc memory on GPU 0 with 4kB alignment */
86 	ptr_2 = rte_gpu_mem_alloc(gpu_id, buf_bytes, align);
87 	if (ptr_2 == NULL) {
88 		fprintf(stderr, "rte_gpu_mem_alloc GPU memory returned error\n");
89 		goto error;
90 	}
91 	printf("GPU memory allocated at 0x%p size is %zd bytes\n",
92 			ptr_2, buf_bytes);
93 
94 	if (((uintptr_t)ptr_2) % align) {
95 		fprintf(stderr, "Memory address 0x%p is not aligned to %u\n", ptr_2, align);
96 		goto error;
97 	}
98 
99 	ret = rte_gpu_mem_free(gpu_id, (uint8_t *)(ptr_1)+0x700);
100 	if (ret < 0) {
101 		printf("GPU memory 0x%p NOT freed: GPU driver didn't find this memory address internally.\n",
102 				(uint8_t *)(ptr_1)+0x700);
103 	} else {
104 		fprintf(stderr, "ERROR: rte_gpu_mem_free freed GPU memory 0x%p\n",
105 				(uint8_t *)(ptr_1)+0x700);
106 		goto error;
107 	}
108 
109 	ret = rte_gpu_mem_free(gpu_id, ptr_2);
110 	if (ret < 0) {
111 		fprintf(stderr, "rte_gpu_mem_free returned error %d\n", ret);
112 		goto error;
113 	}
114 	printf("GPU memory 0x%p freed\n", ptr_2);
115 
116 	ret = rte_gpu_mem_free(gpu_id, ptr_1);
117 	if (ret < 0) {
118 		fprintf(stderr, "rte_gpu_mem_free returned error %d\n", ret);
119 		goto error;
120 	}
121 	printf("GPU memory 0x%p freed\n", ptr_1);
122 
123 	printf("\n=======> TEST: PASSED\n");
124 	return 0;
125 
126 error:
127 
128 	rte_gpu_mem_free(gpu_id, ptr_1);
129 	rte_gpu_mem_free(gpu_id, ptr_2);
130 
131 	printf("\n=======> TEST: FAILED\n");
132 	return -1;
133 }
134 
135 static int
136 register_cpu_memory(uint16_t gpu_id)
137 {
138 	void *ptr = NULL;
139 	size_t buf_bytes = 1024;
140 	int ret;
141 
142 	printf("\n=======> TEST: Register CPU memory\n\n");
143 
144 	/* Alloc memory on CPU visible from GPU 0 */
145 	ptr = rte_zmalloc(NULL, buf_bytes, 0);
146 	if (ptr == NULL) {
147 		fprintf(stderr, "Failed to allocate CPU memory.\n");
148 		goto error;
149 	}
150 
151 	ret = rte_gpu_mem_register(gpu_id, buf_bytes, ptr);
152 	if (ret < 0) {
153 		fprintf(stderr, "rte_gpu_mem_register CPU memory returned error %d\n", ret);
154 		goto error;
155 	}
156 	printf("CPU memory registered at 0x%p %zdB\n", ptr, buf_bytes);
157 
158 	ret = rte_gpu_mem_unregister(gpu_id, (uint8_t *)(ptr)+0x700);
159 	if (ret < 0) {
160 		printf("CPU memory 0x%p NOT unregistered: GPU driver didn't find this memory address internally\n",
161 				(uint8_t *)(ptr)+0x700);
162 	} else {
163 		fprintf(stderr, "ERROR: rte_gpu_mem_unregister unregistered GPU memory 0x%p\n",
164 				(uint8_t *)(ptr)+0x700);
165 		goto error;
166 	}
167 
168 	ret = rte_gpu_mem_unregister(gpu_id, ptr);
169 	if (ret < 0) {
170 		fprintf(stderr, "rte_gpu_mem_unregister returned error %d\n", ret);
171 		goto error;
172 	}
173 	printf("CPU memory 0x%p unregistered\n", ptr);
174 
175 	rte_free(ptr);
176 
177 	printf("\n=======> TEST: PASSED\n");
178 	return 0;
179 
180 error:
181 
182 	rte_gpu_mem_unregister(gpu_id, ptr);
183 	rte_free(ptr);
184 	printf("\n=======> TEST: FAILED\n");
185 	return -1;
186 }
187 
188 static int
189 create_update_comm_flag(uint16_t gpu_id)
190 {
191 	struct rte_gpu_comm_flag devflag;
192 	int ret = 0;
193 	uint32_t set_val;
194 	uint32_t get_val;
195 
196 	printf("\n=======> TEST: Communication flag\n\n");
197 
198 	ret = rte_gpu_comm_create_flag(gpu_id, &devflag, RTE_GPU_COMM_FLAG_CPU);
199 	if (ret < 0) {
200 		fprintf(stderr, "rte_gpu_comm_create_flag returned error %d\n", ret);
201 		goto error;
202 	}
203 
204 	set_val = 25;
205 	ret = rte_gpu_comm_set_flag(&devflag, set_val);
206 	if (ret < 0) {
207 		fprintf(stderr, "rte_gpu_comm_set_flag returned error %d\n", ret);
208 		goto error;
209 	}
210 
211 	ret = rte_gpu_comm_get_flag_value(&devflag, &get_val);
212 	if (ret < 0) {
213 		fprintf(stderr, "rte_gpu_comm_get_flag_value returned error %d\n", ret);
214 		goto error;
215 	}
216 
217 	printf("Communication flag value at 0x%p was set to %d and current value is %d\n",
218 			devflag.ptr, set_val, get_val);
219 
220 	set_val = 38;
221 	ret = rte_gpu_comm_set_flag(&devflag, set_val);
222 	if (ret < 0) {
223 		fprintf(stderr, "rte_gpu_comm_set_flag returned error %d\n", ret);
224 		goto error;
225 	}
226 
227 	ret = rte_gpu_comm_get_flag_value(&devflag, &get_val);
228 	if (ret < 0) {
229 		fprintf(stderr, "rte_gpu_comm_get_flag_value returned error %d\n", ret);
230 		goto error;
231 	}
232 
233 	printf("Communication flag value at 0x%p was set to %d and current value is %d\n",
234 			devflag.ptr, set_val, get_val);
235 
236 	ret = rte_gpu_comm_destroy_flag(&devflag);
237 	if (ret < 0) {
238 		fprintf(stderr, "rte_gpu_comm_destroy_flags returned error %d\n", ret);
239 		goto error;
240 	}
241 
242 	printf("\n=======> TEST: PASSED\n");
243 	return 0;
244 
245 error:
246 
247 	rte_gpu_comm_destroy_flag(&devflag);
248 	printf("\n=======> TEST: FAILED\n");
249 	return -1;
250 }
251 
252 static int
253 simulate_gpu_task(struct rte_gpu_comm_list *comm_list_item, int num_pkts)
254 {
255 	int idx;
256 
257 	if (comm_list_item == NULL)
258 		return -1;
259 
260 	for (idx = 0; idx < num_pkts; idx++) {
261 		/**
262 		 * consume(comm_list_item->pkt_list[idx].addr);
263 		 */
264 	}
265 	comm_list_item->status = RTE_GPU_COMM_LIST_DONE;
266 
267 	return 0;
268 }
269 
270 static int
271 create_update_comm_list(uint16_t gpu_id)
272 {
273 	int ret = 0;
274 	int i = 0;
275 	struct rte_gpu_comm_list *comm_list = NULL;
276 	uint32_t num_comm_items = 1024;
277 	struct rte_mbuf *mbufs[10];
278 
279 	printf("\n=======> TEST: Communication list\n\n");
280 
281 	comm_list = rte_gpu_comm_create_list(gpu_id, num_comm_items);
282 	if (comm_list == NULL) {
283 		fprintf(stderr, "rte_gpu_comm_create_list returned error %d\n", ret);
284 		goto error;
285 	}
286 
287 	/**
288 	 * Simulate DPDK receive functions like rte_eth_rx_burst()
289 	 */
290 	for (i = 0; i < 10; i++) {
291 		mbufs[i] = rte_zmalloc(NULL, sizeof(struct rte_mbuf), 0);
292 		if (mbufs[i] == NULL) {
293 			fprintf(stderr, "Failed to allocate fake mbufs in CPU memory.\n");
294 			goto error;
295 		}
296 
297 		memset(mbufs[i], 0, sizeof(struct rte_mbuf));
298 	}
299 
300 	/**
301 	 * Populate just the first item of  the list
302 	 */
303 	ret = rte_gpu_comm_populate_list_pkts(&(comm_list[0]), mbufs, 10);
304 	if (ret < 0) {
305 		fprintf(stderr, "rte_gpu_comm_populate_list_pkts returned error %d\n", ret);
306 		goto error;
307 	}
308 
309 	ret = rte_gpu_comm_cleanup_list(&(comm_list[0]));
310 	if (ret == 0) {
311 		fprintf(stderr, "rte_gpu_comm_cleanup_list erroneously cleaned the list even if packets have not been consumed yet\n");
312 		goto error;
313 	}
314 	printf("Communication list not cleaned because packets have not been consumed yet.\n");
315 
316 	/**
317 	 * Simulate a GPU tasks going through the packet list to consume
318 	 * mbufs packets and release them
319 	 */
320 	printf("Consuming packets...\n");
321 	simulate_gpu_task(&(comm_list[0]), 10);
322 
323 	/**
324 	 * Packets have been consumed, now the communication item
325 	 * and the related mbufs can be all released
326 	 */
327 	ret = rte_gpu_comm_cleanup_list(&(comm_list[0]));
328 	if (ret < 0) {
329 		fprintf(stderr, "rte_gpu_comm_cleanup_list returned error %d\n", ret);
330 		goto error;
331 	}
332 
333 	printf("Communication list cleaned because packets have been consumed now.\n");
334 
335 	ret = rte_gpu_comm_destroy_list(comm_list, num_comm_items);
336 	if (ret < 0) {
337 		fprintf(stderr, "rte_gpu_comm_destroy_list returned error %d\n", ret);
338 		goto error;
339 	}
340 
341 	for (i = 0; i < 10; i++)
342 		rte_free(mbufs[i]);
343 
344 	printf("\n=======> TEST: PASSED\n");
345 	return 0;
346 
347 error:
348 
349 	rte_gpu_comm_destroy_list(comm_list, num_comm_items);
350 	for (i = 0; i < 10; i++)
351 		rte_free(mbufs[i]);
352 	printf("\n=======> TEST: FAILED\n");
353 	return -1;
354 }
355 
356 int
357 main(int argc, char **argv)
358 {
359 	int ret;
360 	int nb_gpus = 0;
361 	int16_t gpu_id = 0;
362 	struct rte_gpu_info ginfo;
363 
364 	/* Init EAL. */
365 	ret = rte_eal_init(argc, argv);
366 	if (ret < 0)
367 		rte_exit(EXIT_FAILURE, "EAL init failed\n");
368 	argc -= ret;
369 	argv += ret;
370 	if (argc > 1)
371 		args_parse(argc, argv);
372 	argc -= ret;
373 	argv += ret;
374 
375 	nb_gpus = rte_gpu_count_avail();
376 	printf("\n\nDPDK found %d GPUs:\n", nb_gpus);
377 	RTE_GPU_FOREACH(gpu_id)
378 	{
379 		if (rte_gpu_info_get(gpu_id, &ginfo))
380 			rte_exit(EXIT_FAILURE, "rte_gpu_info_get error - bye\n");
381 
382 		printf("\tGPU ID %d\n\t\tparent ID %d GPU Bus ID %s NUMA node %d Tot memory %.02f MB, Tot processors %d\n",
383 				ginfo.dev_id,
384 				ginfo.parent,
385 				ginfo.name,
386 				ginfo.numa_node,
387 				(((float)ginfo.total_memory)/(float)1024)/(float)1024,
388 				ginfo.processor_count
389 			);
390 	}
391 	printf("\n\n");
392 
393 	if (nb_gpus == 0) {
394 		fprintf(stderr, "Need at least one GPU on the system to run the example\n");
395 		return EXIT_FAILURE;
396 	}
397 
398 	gpu_id = 0;
399 
400 	/**
401 	 * Memory tests
402 	 */
403 	alloc_gpu_memory(gpu_id);
404 	register_cpu_memory(gpu_id);
405 
406 	/**
407 	 * Communication items test
408 	 */
409 	create_update_comm_flag(gpu_id);
410 	create_update_comm_list(gpu_id);
411 
412 	/* clean up the EAL */
413 	rte_eal_cleanup();
414 
415 	return EXIT_SUCCESS;
416 }
417