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 int ret; 72 73 printf("\n=======> TEST: Allocate GPU memory\n"); 74 75 /* Alloc memory on GPU 0 */ 76 ptr_1 = rte_gpu_mem_alloc(gpu_id, buf_bytes); 77 if (ptr_1 == NULL) { 78 fprintf(stderr, "rte_gpu_mem_alloc GPU memory returned error\n"); 79 return -1; 80 } 81 printf("GPU memory allocated at 0x%p %zdB\n", ptr_1, buf_bytes); 82 83 ptr_2 = rte_gpu_mem_alloc(gpu_id, buf_bytes); 84 if (ptr_2 == NULL) { 85 fprintf(stderr, "rte_gpu_mem_alloc GPU memory returned error\n"); 86 return -1; 87 } 88 printf("GPU memory allocated at 0x%p %zdB\n", ptr_2, buf_bytes); 89 90 ret = rte_gpu_mem_free(gpu_id, (uint8_t *)(ptr_1)+0x700); 91 if (ret < 0) { 92 printf("GPU memory 0x%p + 0x700 NOT freed because of memory address not recognized by driver\n", ptr_1); 93 } else { 94 fprintf(stderr, "rte_gpu_mem_free erroneously freed GPU memory 0x%p + 0x700\n", ptr_1); 95 return -1; 96 } 97 98 ret = rte_gpu_mem_free(gpu_id, ptr_2); 99 if (ret < 0) { 100 fprintf(stderr, "rte_gpu_mem_free returned error %d\n", ret); 101 return -1; 102 } 103 printf("GPU memory 0x%p freed\n", ptr_2); 104 105 ret = rte_gpu_mem_free(gpu_id, ptr_1); 106 if (ret < 0) { 107 fprintf(stderr, "rte_gpu_mem_free returned error %d\n", ret); 108 return -1; 109 } 110 printf("GPU memory 0x%p freed\n", ptr_1); 111 112 return 0; 113 } 114 115 static int 116 register_cpu_memory(uint16_t gpu_id) 117 { 118 void *ptr = NULL; 119 size_t buf_bytes = 1024; 120 int ret; 121 122 printf("\n=======> TEST: Register CPU memory\n"); 123 124 /* Alloc memory on CPU visible from GPU 0 */ 125 ptr = rte_zmalloc(NULL, buf_bytes, 0); 126 if (ptr == NULL) { 127 fprintf(stderr, "Failed to allocate CPU memory.\n"); 128 return -1; 129 } 130 131 ret = rte_gpu_mem_register(gpu_id, buf_bytes, ptr); 132 if (ret < 0) { 133 fprintf(stderr, "rte_gpu_mem_register CPU memory returned error %d\n", ret); 134 return -1; 135 } 136 printf("CPU memory registered at 0x%p %zdB\n", ptr, buf_bytes); 137 138 ret = rte_gpu_mem_unregister(gpu_id, (uint8_t *)(ptr)+0x700); 139 if (ret < 0) { 140 printf("CPU memory 0x%p + 0x700 NOT unregistered because of memory address not recognized by driver\n", ptr); 141 } else { 142 fprintf(stderr, "rte_gpu_mem_free erroneously freed GPU memory 0x%p + 0x700\n", ptr); 143 return -1; 144 } 145 printf("CPU memory 0x%p unregistered\n", ptr); 146 147 ret = rte_gpu_mem_unregister(gpu_id, ptr); 148 if (ret < 0) { 149 fprintf(stderr, "rte_gpu_mem_unregister returned error %d\n", ret); 150 return -1; 151 } 152 printf("CPU memory 0x%p unregistered\n", ptr); 153 154 return 0; 155 } 156 157 static int 158 create_update_comm_flag(uint16_t gpu_id) 159 { 160 struct rte_gpu_comm_flag devflag; 161 int ret = 0; 162 uint32_t set_val; 163 uint32_t get_val; 164 165 printf("\n=======> TEST: Communication flag\n"); 166 167 ret = rte_gpu_comm_create_flag(gpu_id, &devflag, RTE_GPU_COMM_FLAG_CPU); 168 if (ret < 0) { 169 fprintf(stderr, "rte_gpu_comm_create_flag returned error %d\n", ret); 170 return -1; 171 } 172 173 set_val = 25; 174 ret = rte_gpu_comm_set_flag(&devflag, set_val); 175 if (ret < 0) { 176 fprintf(stderr, "rte_gpu_comm_set_flag returned error %d\n", ret); 177 return -1; 178 } 179 180 ret = rte_gpu_comm_get_flag_value(&devflag, &get_val); 181 if (ret < 0) { 182 fprintf(stderr, "rte_gpu_comm_get_flag_value returned error %d\n", ret); 183 return -1; 184 } 185 186 printf("Communication flag value at 0x%p was set to %d and current value is %d\n", devflag.ptr, set_val, get_val); 187 188 set_val = 38; 189 ret = rte_gpu_comm_set_flag(&devflag, set_val); 190 if (ret < 0) { 191 fprintf(stderr, "rte_gpu_comm_set_flag returned error %d\n", ret); 192 return -1; 193 } 194 195 ret = rte_gpu_comm_get_flag_value(&devflag, &get_val); 196 if (ret < 0) { 197 fprintf(stderr, "rte_gpu_comm_get_flag_value returned error %d\n", ret); 198 return -1; 199 } 200 201 printf("Communication flag value at 0x%p was set to %d and current value is %d\n", devflag.ptr, set_val, get_val); 202 203 ret = rte_gpu_comm_destroy_flag(&devflag); 204 if (ret < 0) { 205 fprintf(stderr, "rte_gpu_comm_destroy_flags returned error %d\n", ret); 206 return -1; 207 } 208 209 return 0; 210 } 211 212 static int 213 simulate_gpu_task(struct rte_gpu_comm_list *comm_list_item, int num_pkts) 214 { 215 int idx; 216 217 if (comm_list_item == NULL) 218 return -1; 219 220 for (idx = 0; idx < num_pkts; idx++) { 221 /** 222 * consume(comm_list_item->pkt_list[idx].addr); 223 */ 224 } 225 comm_list_item->status = RTE_GPU_COMM_LIST_DONE; 226 227 return 0; 228 } 229 230 static int 231 create_update_comm_list(uint16_t gpu_id) 232 { 233 int ret = 0; 234 int i = 0; 235 struct rte_gpu_comm_list *comm_list; 236 uint32_t num_comm_items = 1024; 237 struct rte_mbuf *mbufs[10]; 238 239 printf("\n=======> TEST: Communication list\n"); 240 241 comm_list = rte_gpu_comm_create_list(gpu_id, num_comm_items); 242 if (comm_list == NULL) { 243 fprintf(stderr, "rte_gpu_comm_create_list returned error %d\n", ret); 244 return -1; 245 } 246 247 /** 248 * Simulate DPDK receive functions like rte_eth_rx_burst() 249 */ 250 for (i = 0; i < 10; i++) { 251 mbufs[i] = rte_zmalloc(NULL, sizeof(struct rte_mbuf), 0); 252 if (mbufs[i] == NULL) { 253 fprintf(stderr, "Failed to allocate fake mbufs in CPU memory.\n"); 254 return -1; 255 } 256 257 memset(mbufs[i], 0, sizeof(struct rte_mbuf)); 258 } 259 260 /** 261 * Populate just the first item of the list 262 */ 263 ret = rte_gpu_comm_populate_list_pkts(&(comm_list[0]), mbufs, 10); 264 if (ret < 0) { 265 fprintf(stderr, "rte_gpu_comm_populate_list_pkts returned error %d\n", ret); 266 return -1; 267 } 268 269 ret = rte_gpu_comm_cleanup_list(&(comm_list[0])); 270 if (ret == 0) { 271 fprintf(stderr, "rte_gpu_comm_cleanup_list erroneously cleaned the list even if packets have not been consumed yet\n"); 272 return -1; 273 } 274 fprintf(stderr, "rte_gpu_comm_cleanup_list correctly didn't clean up the packets because they have not been consumed yet\n"); 275 276 /** 277 * Simulate a GPU tasks going through the packet list to consume 278 * mbufs packets and release them 279 */ 280 simulate_gpu_task(&(comm_list[0]), 10); 281 282 /** 283 * Packets have been consumed, now the communication item 284 * and the related mbufs can be all released 285 */ 286 ret = rte_gpu_comm_cleanup_list(&(comm_list[0])); 287 if (ret < 0) { 288 fprintf(stderr, "rte_gpu_comm_cleanup_list returned error %d\n", ret); 289 return -1; 290 } 291 292 ret = rte_gpu_comm_destroy_list(comm_list, num_comm_items); 293 if (ret < 0) { 294 fprintf(stderr, "rte_gpu_comm_destroy_list returned error %d\n", ret); 295 return -1; 296 } 297 298 for (i = 0; i < 10; i++) 299 rte_free(mbufs[i]); 300 301 printf("\nCommunication list test passed!\n"); 302 return 0; 303 } 304 305 int 306 main(int argc, char **argv) 307 { 308 int ret; 309 int nb_gpus = 0; 310 int16_t gpu_id = 0; 311 struct rte_gpu_info ginfo; 312 313 /* Init EAL. */ 314 ret = rte_eal_init(argc, argv); 315 if (ret < 0) 316 rte_exit(EXIT_FAILURE, "EAL init failed\n"); 317 argc -= ret; 318 argv += ret; 319 if (argc > 1) 320 args_parse(argc, argv); 321 argc -= ret; 322 argv += ret; 323 324 nb_gpus = rte_gpu_count_avail(); 325 printf("\n\nDPDK found %d GPUs:\n", nb_gpus); 326 RTE_GPU_FOREACH(gpu_id) 327 { 328 if (rte_gpu_info_get(gpu_id, &ginfo)) 329 rte_exit(EXIT_FAILURE, "rte_gpu_info_get error - bye\n"); 330 331 printf("\tGPU ID %d\n\t\tparent ID %d GPU Bus ID %s NUMA node %d Tot memory %.02f MB, Tot processors %d\n", 332 ginfo.dev_id, 333 ginfo.parent, 334 ginfo.name, 335 ginfo.numa_node, 336 (((float)ginfo.total_memory)/(float)1024)/(float)1024, 337 ginfo.processor_count 338 ); 339 } 340 printf("\n\n"); 341 342 if (nb_gpus == 0) { 343 fprintf(stderr, "Need at least one GPU on the system to run the example\n"); 344 return EXIT_FAILURE; 345 } 346 347 gpu_id = 0; 348 349 /** 350 * Memory tests 351 */ 352 alloc_gpu_memory(gpu_id); 353 register_cpu_memory(gpu_id); 354 355 /** 356 * Communication items test 357 */ 358 create_update_comm_flag(gpu_id); 359 create_update_comm_list(gpu_id); 360 361 /* clean up the EAL */ 362 rte_eal_cleanup(); 363 printf("Bye...\n"); 364 365 return EXIT_SUCCESS; 366 } 367