]> git.droids-corp.org - dpdk.git/commitdiff
gpudev: expose GPU memory to CPU
authorElena Agostini <eagostini@nvidia.com>
Thu, 27 Jan 2022 03:50:28 +0000 (03:50 +0000)
committerThomas Monjalon <thomas@monjalon.net>
Thu, 10 Feb 2022 09:06:56 +0000 (10:06 +0100)
Enable the possibility to expose a GPU memory area and make it
accessible from the CPU.

GPU memory has to be allocated via rte_gpu_mem_alloc().

This patch allows the gpudev library to map (and unmap),
through the GPU driver, a chunk of GPU memory and to return
a memory pointer usable by the CPU to access the GPU memory area.

Signed-off-by: Elena Agostini <eagostini@nvidia.com>
app/test-gpudev/main.c
doc/guides/prog_guide/gpudev.rst
drivers/gpu/cuda/cuda.c
lib/gpudev/gpudev.c
lib/gpudev/gpudev_driver.h
lib/gpudev/rte_gpudev.h
lib/gpudev/version.map

index 4500a8660b9d9e3483c5e6a9c93fce8acc5e75be..417f2d78b7dbfa6b942ae9cacbd865bac4f364f4 100644 (file)
@@ -185,6 +185,68 @@ error:
        return -1;
 }
 
+static int
+gpu_mem_cpu_map(uint16_t gpu_id)
+{
+       void *ptr_gpu = NULL;
+       void *ptr_cpu = NULL;
+       size_t buf_bytes = 1024;
+       unsigned int align = 4096;
+       int ret;
+
+       printf("\n=======> TEST: Map GPU memory for CPU visibility\n\n");
+
+       /* Alloc memory on GPU 0 with 4kB alignment */
+       ptr_gpu = rte_gpu_mem_alloc(gpu_id, buf_bytes, align);
+       if (ptr_gpu == NULL) {
+               fprintf(stderr, "rte_gpu_mem_alloc GPU memory returned error\n");
+               goto error;
+       }
+       printf("GPU memory allocated at 0x%p size is %zd bytes\n",
+                       ptr_gpu, buf_bytes);
+
+       ptr_cpu = rte_gpu_mem_cpu_map(gpu_id, buf_bytes, ptr_gpu);
+       if (ptr_cpu == NULL) {
+               fprintf(stderr, "rte_gpu_mem_cpu_map returned error\n");
+               goto error;
+       }
+       printf("GPU memory mapped for CPU access at 0x%p\n", ptr_cpu);
+
+       ((uint8_t *)ptr_cpu)[0] = 0x4;
+       ((uint8_t *)ptr_cpu)[1] = 0x5;
+       ((uint8_t *)ptr_cpu)[2] = 0x6;
+
+       printf("GPU memory first 3 bytes set from CPU: %x %x %x\n",
+                       ((uint8_t *)ptr_cpu)[0],
+                       ((uint8_t *)ptr_cpu)[1],
+                       ((uint8_t *)ptr_cpu)[2]);
+
+       ret = rte_gpu_mem_cpu_unmap(gpu_id, ptr_cpu);
+       if (ret < 0) {
+               fprintf(stderr, "rte_gpu_mem_cpu_unmap returned error %d\n", ret);
+               goto error;
+       }
+       printf("GPU memory mapped for CPU access at 0x%p\n", ptr_cpu);
+
+       ret = rte_gpu_mem_free(gpu_id, ptr_gpu);
+       if (ret < 0) {
+               fprintf(stderr, "rte_gpu_mem_free returned error %d\n", ret);
+               goto error;
+       }
+       printf("GPU memory 0x%p freed\n", ptr_gpu);
+
+       printf("\n=======> TEST: PASSED\n");
+       return 0;
+
+error:
+
+       rte_gpu_mem_cpu_unmap(gpu_id, ptr_cpu);
+       rte_gpu_mem_free(gpu_id, ptr_gpu);
+
+       printf("\n=======> TEST: FAILED\n");
+       return -1;
+}
+
 static int
 create_update_comm_flag(uint16_t gpu_id)
 {
@@ -402,6 +464,7 @@ main(int argc, char **argv)
         */
        alloc_gpu_memory(gpu_id);
        register_cpu_memory(gpu_id);
+       gpu_mem_cpu_map(gpu_id);
 
        /**
         * Communication items test
index ff4626812becda59fed854d92fc242f52ac8104a..6223207a33c1390d9bfe40ff65dd7b5c3951afc4 100644 (file)
@@ -73,6 +73,15 @@ Later, it's also possible to unregister that memory with gpudev.
 CPU memory registered outside of the gpudev library
 (e.g. with GPU specific library) cannot be unregistered by the gpudev library.
 
+CPU mapping
+~~~~~~~~~~~
+
+gpudev can map into the CPU address space a GPU memory address allocated with gpudev.
+gpudev returns a pointer the CPU can use to access (ready or write) GPU memory.
+Later, it's also possible to unmap that memory with gpudev.
+GPU memory CPU mapped outside of the gpudev library (e.g. with GPU specific library)
+cannot be unmapped by the gpudev library.
+
 Memory Barrier
 ~~~~~~~~~~~~~~
 
index 0ece1bb61207d4537a310b4c400291dcdbe9c475..408b659fce7bc2f611c697c3dc8849dcb4adac64 100644 (file)
@@ -1177,6 +1177,8 @@ cuda_gpu_probe(__rte_unused struct rte_pci_driver *pci_drv, struct rte_pci_devic
        dev->ops.mem_free = cuda_mem_free;
        dev->ops.mem_register = cuda_mem_register;
        dev->ops.mem_unregister = cuda_mem_unregister;
+       dev->ops.mem_cpu_map = NULL;
+       dev->ops.mem_cpu_unmap = NULL;
        dev->ops.wmb = cuda_wmb;
 
        rte_gpu_complete_new(dev);
index 59e21692929af8ccbb8a7c51b157b31c1ddb0a41..ce92d632573e40c3ab337a3fb3e4e78b77cefde3 100644 (file)
@@ -640,6 +640,67 @@ rte_gpu_mem_unregister(int16_t dev_id, void *ptr)
        return GPU_DRV_RET(dev->ops.mem_unregister(dev, ptr));
 }
 
+void *
+rte_gpu_mem_cpu_map(int16_t dev_id, size_t size, void *ptr)
+{
+       struct rte_gpu *dev;
+       void *ptr_out;
+       int ret;
+
+       dev = gpu_get_by_id(dev_id);
+       if (dev == NULL) {
+               GPU_LOG(ERR, "mem CPU map for invalid device ID %d", dev_id);
+               rte_errno = ENODEV;
+               return NULL;
+       }
+
+       if (dev->ops.mem_cpu_map == NULL) {
+               GPU_LOG(ERR, "mem CPU map not supported");
+               rte_errno = ENOTSUP;
+               return NULL;
+       }
+
+       if (ptr == NULL || size == 0) /* dry-run  */
+               return NULL;
+
+       ret = GPU_DRV_RET(dev->ops.mem_cpu_map(dev, size, ptr, &ptr_out));
+
+       switch (ret) {
+       case 0:
+               return ptr_out;
+       case -ENOMEM:
+       case -E2BIG:
+               rte_errno = -ret;
+               return NULL;
+       default:
+               rte_errno = -EPERM;
+               return NULL;
+       }
+}
+
+int
+rte_gpu_mem_cpu_unmap(int16_t dev_id, void *ptr)
+{
+       struct rte_gpu *dev;
+
+       dev = gpu_get_by_id(dev_id);
+       if (dev == NULL) {
+               GPU_LOG(ERR, "cpu_unmap mem for invalid device ID %d", dev_id);
+               rte_errno = ENODEV;
+               return -rte_errno;
+       }
+
+       if (dev->ops.mem_cpu_unmap == NULL) {
+               rte_errno = ENOTSUP;
+               return -rte_errno;
+       }
+
+       if (ptr == NULL) /* dry-run */
+               return 0;
+
+       return GPU_DRV_RET(dev->ops.mem_cpu_unmap(dev, ptr));
+}
+
 int
 rte_gpu_wmb(int16_t dev_id)
 {
index 0ed7478e9b152c77645c52241683e5c1ff8fe143..0e55b00bfe54c0720d24f3347d68c137fcf53f7d 100644 (file)
@@ -31,6 +31,8 @@ typedef int (rte_gpu_mem_alloc_t)(struct rte_gpu *dev, size_t size, unsigned int
 typedef int (rte_gpu_mem_free_t)(struct rte_gpu *dev, void *ptr);
 typedef int (rte_gpu_mem_register_t)(struct rte_gpu *dev, size_t size, void *ptr);
 typedef int (rte_gpu_mem_unregister_t)(struct rte_gpu *dev, void *ptr);
+typedef int (rte_gpu_mem_cpu_map_t)(struct rte_gpu *dev, size_t size, void *ptr_in, void **ptr_out);
+typedef int (rte_gpu_mem_cpu_unmap_t)(struct rte_gpu *dev, void *ptr);
 typedef int (rte_gpu_wmb_t)(struct rte_gpu *dev);
 
 struct rte_gpu_ops {
@@ -46,6 +48,10 @@ struct rte_gpu_ops {
        rte_gpu_mem_register_t *mem_register;
        /* Unregister CPU memory from device. */
        rte_gpu_mem_unregister_t *mem_unregister;
+       /* Map GPU memory for CPU visibility. */
+       rte_gpu_mem_cpu_map_t *mem_cpu_map;
+       /* Unmap GPU memory for CPU visibility. */
+       rte_gpu_mem_cpu_unmap_t *mem_cpu_unmap;
        /* Enforce GPU write memory barrier. */
        rte_gpu_wmb_t *wmb;
 };
index ff3ca78c895e6afa1f6b95ef3feaffc0ee648373..5cc4eb5828a9aaa51e1b8ba318ecdea61f43699b 100644 (file)
@@ -452,6 +452,55 @@ int rte_gpu_mem_register(int16_t dev_id, size_t size, void *ptr);
 __rte_experimental
 int rte_gpu_mem_unregister(int16_t dev_id, void *ptr);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Map a chunk of GPU memory to make it accessible from the CPU
+ * using the memory pointer returned by the function.
+ * GPU memory has to be allocated via rte_gpu_mem_alloc().
+ *
+ * @param dev_id
+ *   Device ID requiring mapped memory.
+ * @param size
+ *   Number of bytes to map.
+ *   Requesting 0 will do nothing.
+ * @param ptr
+ *   Pointer to the GPU memory area to be mapped.
+ *   NULL is a no-op accepted value.
+
+ * @return
+ *   A pointer to the mapped GPU memory usable by the CPU, otherwise NULL and rte_errno is set:
+ *   - ENODEV if invalid dev_id
+ *   - ENOTSUP if operation not supported by the driver
+ *   - E2BIG if size is higher than limit
+ *   - ENOMEM if out of space
+ *   - EPERM if driver error
+ */
+__rte_experimental
+void *rte_gpu_mem_cpu_map(int16_t dev_id, size_t size, void *ptr);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Unmap a chunk of GPU memory previously mapped with rte_gpu_mem_cpu_map()
+ *
+ * @param dev_id
+ *   Reference device ID.
+ * @param ptr
+ *   Pointer to the memory area to be unmapped.
+ *   NULL is a no-op accepted value.
+ *
+ * @return
+ *   0 on success, -rte_errno otherwise:
+ *   - ENODEV if invalid dev_id
+ *   - ENOTSUP if operation not supported by the driver
+ *   - EPERM if driver error
+ */
+__rte_experimental
+int rte_gpu_mem_cpu_unmap(int16_t dev_id, void *ptr);
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice.
index 2e414c65cc13abfead14010b673aeaba886da614..5bc5d154cd9e933194886178362b139519369e76 100644 (file)
@@ -20,8 +20,10 @@ EXPERIMENTAL {
        rte_gpu_init;
        rte_gpu_is_valid;
        rte_gpu_mem_alloc;
+       rte_gpu_mem_cpu_map;
        rte_gpu_mem_free;
        rte_gpu_mem_register;
+       rte_gpu_mem_cpu_unmap;
        rte_gpu_mem_unregister;
        rte_gpu_wmb;
 };