From a9af048abaacc2a0cbdc284e033390f13a0c2525 Mon Sep 17 00:00:00 2001 From: Thomas Monjalon Date: Mon, 8 Nov 2021 18:58:00 +0000 Subject: [PATCH] gpudev: support multi-process The device data shared between processes are moved in a struct allocated in a shared memory (a new memzone for all GPUs). The main struct rte_gpu references the shared memory via the pointer mpshared. The API function rte_gpu_attach() is added to attach a device from the secondary process. The function rte_gpu_allocate() can be used only by primary process. Signed-off-by: Thomas Monjalon --- lib/gpudev/gpudev.c | 127 +++++++++++++++++++++++++++++++------ lib/gpudev/gpudev_driver.h | 25 ++++++-- lib/gpudev/version.map | 1 + 3 files changed, 127 insertions(+), 26 deletions(-) diff --git a/lib/gpudev/gpudev.c b/lib/gpudev/gpudev.c index 4ed8426ef5..da76d6b94c 100644 --- a/lib/gpudev/gpudev.c +++ b/lib/gpudev/gpudev.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,12 @@ static int16_t gpu_max; /* Number of currently valid devices */ static int16_t gpu_count; +/* Shared memory between processes. */ +static const char *GPU_MEMZONE = "rte_gpu_shared"; +static struct { + __extension__ struct rte_gpu_mpshared gpus[0]; +} *gpu_shared_mem; + /* Event callback object */ struct rte_gpu_callback { TAILQ_ENTRY(rte_gpu_callback) next; @@ -76,7 +83,7 @@ bool rte_gpu_is_valid(int16_t dev_id) { if (dev_id >= 0 && dev_id < gpu_max && - gpus[dev_id].state == RTE_GPU_STATE_INITIALIZED) + gpus[dev_id].process_state == RTE_GPU_STATE_INITIALIZED) return true; return false; } @@ -86,7 +93,7 @@ gpu_match_parent(int16_t dev_id, int16_t parent) { if (parent == RTE_GPU_ID_ANY) return true; - return gpus[dev_id].info.parent == parent; + return gpus[dev_id].mpshared->info.parent == parent; } int16_t @@ -95,7 +102,7 @@ rte_gpu_find_next(int16_t dev_id, int16_t parent) if (dev_id < 0) dev_id = 0; while (dev_id < gpu_max && - (gpus[dev_id].state == RTE_GPU_STATE_UNUSED || + (gpus[dev_id].process_state == RTE_GPU_STATE_UNUSED || !gpu_match_parent(dev_id, parent))) dev_id++; @@ -110,7 +117,7 @@ gpu_find_free_id(void) int16_t dev_id; for (dev_id = 0; dev_id < gpu_max; dev_id++) { - if (gpus[dev_id].state == RTE_GPU_STATE_UNUSED) + if (gpus[dev_id].process_state == RTE_GPU_STATE_UNUSED) return dev_id; } return RTE_GPU_ID_NONE; @@ -137,12 +144,35 @@ rte_gpu_get_by_name(const char *name) RTE_GPU_FOREACH(dev_id) { dev = &gpus[dev_id]; - if (strncmp(name, dev->name, RTE_DEV_NAME_MAX_LEN) == 0) + if (strncmp(name, dev->mpshared->name, RTE_DEV_NAME_MAX_LEN) == 0) return dev; } return NULL; } +static int +gpu_shared_mem_init(void) +{ + const struct rte_memzone *memzone; + + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + memzone = rte_memzone_reserve(GPU_MEMZONE, + sizeof(*gpu_shared_mem) + + sizeof(*gpu_shared_mem->gpus) * gpu_max, + SOCKET_ID_ANY, 0); + } else { + memzone = rte_memzone_lookup(GPU_MEMZONE); + } + if (memzone == NULL) { + GPU_LOG(ERR, "cannot initialize shared memory"); + rte_errno = ENOMEM; + return -rte_errno; + } + + gpu_shared_mem = memzone->addr; + return 0; +} + struct rte_gpu * rte_gpu_allocate(const char *name) { @@ -164,6 +194,10 @@ rte_gpu_allocate(const char *name) if (gpus == NULL && rte_gpu_init(RTE_GPU_DEFAULT_MAX) < 0) return NULL; + /* initialize shared memory before adding first device */ + if (gpu_shared_mem == NULL && gpu_shared_mem_init() < 0) + return NULL; + if (rte_gpu_get_by_name(name) != NULL) { GPU_LOG(ERR, "device with name %s already exists", name); rte_errno = EEXIST; @@ -179,16 +213,20 @@ rte_gpu_allocate(const char *name) dev = &gpus[dev_id]; memset(dev, 0, sizeof(*dev)); - if (rte_strscpy(dev->name, name, RTE_DEV_NAME_MAX_LEN) < 0) { + dev->mpshared = &gpu_shared_mem->gpus[dev_id]; + memset(dev->mpshared, 0, sizeof(*dev->mpshared)); + + if (rte_strscpy(dev->mpshared->name, name, RTE_DEV_NAME_MAX_LEN) < 0) { GPU_LOG(ERR, "device name too long: %s", name); rte_errno = ENAMETOOLONG; return NULL; } - dev->info.name = dev->name; - dev->info.dev_id = dev_id; - dev->info.numa_node = -1; - dev->info.parent = RTE_GPU_ID_NONE; + dev->mpshared->info.name = dev->mpshared->name; + dev->mpshared->info.dev_id = dev_id; + dev->mpshared->info.numa_node = -1; + dev->mpshared->info.parent = RTE_GPU_ID_NONE; TAILQ_INIT(&dev->callbacks); + __atomic_fetch_add(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED); gpu_count++; GPU_LOG(DEBUG, "new device %s (id %d) of total %d", @@ -196,6 +234,55 @@ rte_gpu_allocate(const char *name) return dev; } +struct rte_gpu * +rte_gpu_attach(const char *name) +{ + int16_t dev_id; + struct rte_gpu *dev; + struct rte_gpu_mpshared *shared_dev; + + if (rte_eal_process_type() != RTE_PROC_SECONDARY) { + GPU_LOG(ERR, "only secondary process can attach device"); + rte_errno = EPERM; + return NULL; + } + if (name == NULL) { + GPU_LOG(ERR, "attach device without a name"); + rte_errno = EINVAL; + return NULL; + } + + /* implicit initialization of library before adding first device */ + if (gpus == NULL && rte_gpu_init(RTE_GPU_DEFAULT_MAX) < 0) + return NULL; + + /* initialize shared memory before adding first device */ + if (gpu_shared_mem == NULL && gpu_shared_mem_init() < 0) + return NULL; + + for (dev_id = 0; dev_id < gpu_max; dev_id++) { + shared_dev = &gpu_shared_mem->gpus[dev_id]; + if (strncmp(name, shared_dev->name, RTE_DEV_NAME_MAX_LEN) == 0) + break; + } + if (dev_id >= gpu_max) { + GPU_LOG(ERR, "device with name %s not found", name); + rte_errno = ENOENT; + return NULL; + } + dev = &gpus[dev_id]; + memset(dev, 0, sizeof(*dev)); + + TAILQ_INIT(&dev->callbacks); + dev->mpshared = shared_dev; + __atomic_fetch_add(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED); + + gpu_count++; + GPU_LOG(DEBUG, "attached device %s (id %d) of total %d", + name, dev_id, gpu_count); + return dev; +} + int16_t rte_gpu_add_child(const char *name, int16_t parent, uint64_t child_context) { @@ -211,11 +298,11 @@ rte_gpu_add_child(const char *name, int16_t parent, uint64_t child_context) if (dev == NULL) return -rte_errno; - dev->info.parent = parent; - dev->info.context = child_context; + dev->mpshared->info.parent = parent; + dev->mpshared->info.context = child_context; rte_gpu_complete_new(dev); - return dev->info.dev_id; + return dev->mpshared->info.dev_id; } void @@ -224,8 +311,7 @@ rte_gpu_complete_new(struct rte_gpu *dev) if (dev == NULL) return; - dev->state = RTE_GPU_STATE_INITIALIZED; - dev->state = RTE_GPU_STATE_INITIALIZED; + dev->process_state = RTE_GPU_STATE_INITIALIZED; rte_gpu_notify(dev, RTE_GPU_EVENT_NEW); } @@ -238,7 +324,7 @@ rte_gpu_release(struct rte_gpu *dev) rte_errno = ENODEV; return -rte_errno; } - dev_id = dev->info.dev_id; + dev_id = dev->mpshared->info.dev_id; RTE_GPU_FOREACH_CHILD(child, dev_id) { GPU_LOG(ERR, "cannot release device %d with child %d", dev_id, child); @@ -247,11 +333,12 @@ rte_gpu_release(struct rte_gpu *dev) } GPU_LOG(DEBUG, "free device %s (id %d)", - dev->info.name, dev->info.dev_id); + dev->mpshared->info.name, dev->mpshared->info.dev_id); rte_gpu_notify(dev, RTE_GPU_EVENT_DEL); gpu_free_callbacks(dev); - dev->state = RTE_GPU_STATE_UNUSED; + dev->process_state = RTE_GPU_STATE_UNUSED; + __atomic_fetch_sub(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED); gpu_count--; return 0; @@ -404,7 +491,7 @@ rte_gpu_notify(struct rte_gpu *dev, enum rte_gpu_event event) int16_t dev_id; struct rte_gpu_callback *callback; - dev_id = dev->info.dev_id; + dev_id = dev->mpshared->info.dev_id; rte_rwlock_read_lock(&gpu_callback_lock); TAILQ_FOREACH(callback, &dev->callbacks, next) { if (callback->event != event || callback->function == NULL) @@ -432,7 +519,7 @@ rte_gpu_info_get(int16_t dev_id, struct rte_gpu_info *info) } if (dev->ops.dev_info_get == NULL) { - *info = dev->info; + *info = dev->mpshared->info; return 0; } return GPU_DRV_RET(dev->ops.dev_info_get(dev, info)); diff --git a/lib/gpudev/gpudev_driver.h b/lib/gpudev/gpudev_driver.h index 4d0077161c..9459c7e30f 100644 --- a/lib/gpudev/gpudev_driver.h +++ b/lib/gpudev/gpudev_driver.h @@ -35,19 +35,28 @@ struct rte_gpu_ops { rte_gpu_close_t *dev_close; }; -struct rte_gpu { - /* Backing device. */ - struct rte_device *device; +struct rte_gpu_mpshared { /* Unique identifier name. */ char name[RTE_DEV_NAME_MAX_LEN]; /* Updated by this library. */ + /* Driver-specific private data shared in multi-process. */ + void *dev_private; /* Device info structure. */ struct rte_gpu_info info; + /* Counter of processes using the device. */ + uint16_t process_refcnt; /* Updated by this library. */ +}; + +struct rte_gpu { + /* Backing device. */ + struct rte_device *device; + /* Data shared between processes. */ + struct rte_gpu_mpshared *mpshared; /* Driver functions. */ struct rte_gpu_ops ops; /* Event callback list. */ TAILQ_HEAD(rte_gpu_callback_list, rte_gpu_callback) callbacks; /* Current state (used or not) in the running process. */ - enum rte_gpu_state state; /* Updated by this library. */ + enum rte_gpu_state process_state; /* Updated by this library. */ /* Driver-specific private data for the running process. */ void *process_private; } __rte_cache_aligned; @@ -55,15 +64,19 @@ struct rte_gpu { __rte_internal struct rte_gpu *rte_gpu_get_by_name(const char *name); -/* First step of initialization */ +/* First step of initialization in primary process. */ __rte_internal struct rte_gpu *rte_gpu_allocate(const char *name); +/* First step of initialization in secondary process. */ +__rte_internal +struct rte_gpu *rte_gpu_attach(const char *name); + /* Last step of initialization. */ __rte_internal void rte_gpu_complete_new(struct rte_gpu *dev); -/* Last step of removal. */ +/* Last step of removal (primary or secondary process). */ __rte_internal int rte_gpu_release(struct rte_gpu *dev); diff --git a/lib/gpudev/version.map b/lib/gpudev/version.map index 4a934ed933..58dc632393 100644 --- a/lib/gpudev/version.map +++ b/lib/gpudev/version.map @@ -17,6 +17,7 @@ INTERNAL { global: rte_gpu_allocate; + rte_gpu_attach; rte_gpu_complete_new; rte_gpu_get_by_name; rte_gpu_notify; -- 2.39.5