From 14358ee07f7b8d170a274bd5c1291e6e353cd672 Mon Sep 17 00:00:00 2001 From: Harish Kasiviswanathan Date: Wed, 13 Jan 2016 17:27:31 -0500 Subject: [PATCH] Don't limit number of supported GPUs Stop using NUM_OF_SUPPORTED_GPUS. For now the definitions itself cannot be removed as ioctl code is in upstream Kernel. Change-Id: If846625a8ad5062d5483e762850c793d3c00b9d0 [ROCm/ROCR-Runtime commit: ce83dc623f21c799868b46130db3bf0908889734] --- projects/rocr-runtime/src/fmm.c | 93 ++++++++++++++++----------- projects/rocr-runtime/src/fmm.h | 2 + projects/rocr-runtime/src/libhsakmt.h | 2 + projects/rocr-runtime/src/openclose.c | 33 +++++++--- projects/rocr-runtime/src/queues.c | 34 +++++++++- 5 files changed, 115 insertions(+), 49 deletions(-) diff --git a/projects/rocr-runtime/src/fmm.c b/projects/rocr-runtime/src/fmm.c index 99c5551816..b615311c65 100644 --- a/projects/rocr-runtime/src/fmm.c +++ b/projects/rocr-runtime/src/fmm.c @@ -36,11 +36,6 @@ #define NON_VALID_GPU_ID 0 #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0])) -#define INIT_APERTURE(base_value, limit_value) { \ - .base = (void *) base_value, \ - .limit = (void *) limit_value \ - } - #define INIT_MANAGEBLE_APERTURE(base_value, limit_value) { \ .base = (void *) base_value, \ .limit = (void *) limit_value, \ @@ -50,16 +45,6 @@ .fmm_mutex = PTHREAD_MUTEX_INITIALIZER \ } -#define INIT_GPU_MEM { \ - .gpu_id = NON_VALID_GPU_ID, \ - .lds_aperture = INIT_APERTURE(0, 0), \ - .scratch_physical = INIT_MANAGEBLE_APERTURE(0, 0), \ - .scratch_aperture = INIT_MANAGEBLE_APERTURE(0, 0), \ - .gpuvm_aperture = INIT_MANAGEBLE_APERTURE(0, 0), \ -} - -#define INIT_GPUs_MEM {[0 ... (NUM_OF_SUPPORTED_GPUS-1)] = INIT_GPU_MEM} - struct vm_object { void *start; uint64_t size; @@ -128,7 +113,8 @@ typedef struct { /* The other apertures are specific to each GPU. gpu_mem_t manages GPU * specific memory apertures. */ -static gpu_mem_t gpu_mem[] = INIT_GPUs_MEM; +static gpu_mem_t *gpu_mem; +static unsigned int gpu_mem_count; static void *dgpu_shared_aperture_base = NULL; static void *dgpu_shared_aperture_limit = NULL; @@ -431,9 +417,9 @@ static int aperture_allocate_object(manageble_aperture_t *app, static int32_t gpu_mem_find_by_gpu_id(uint32_t gpu_id) { - int32_t i; + uint32_t i; - for (i = 0 ; i < NUM_OF_SUPPORTED_GPUS ; i++) + for (i = 0 ; i < gpu_mem_count ; i++) if (gpu_mem[i].gpu_id == gpu_id) return i; @@ -486,9 +472,9 @@ err_object_allocation_failed: bool fmm_is_inside_some_aperture(void *address) { - int32_t i; + uint32_t i; - for (i = 0 ; i < NUM_OF_SUPPORTED_GPUS ; i++) { + for (i = 0; i < gpu_mem_count; i++) { if (gpu_mem[i].gpu_id == NON_VALID_GPU_ID) continue; if ((address >= gpu_mem[i].lds_aperture.base) && @@ -912,7 +898,7 @@ void fmm_release(void *address, uint64_t MemorySizeInBytes) uint32_t i; bool found = false; - for (i = 0; i < NUM_OF_SUPPORTED_GPUS && !found; i++) { + for (i = 0; i < gpu_mem_count && !found; i++) { if (gpu_mem[i].gpu_id == NON_VALID_GPU_ID) continue; if (address >= gpu_mem[i].scratch_physical.base && @@ -993,20 +979,35 @@ HSAKMT_STATUS fmm_init_process_apertures(void) if (ret != HSAKMT_STATUS_SUCCESS) return ret; - /* Initialize gpu_mem[] from sysfs topology. This is necessary because this function + /* Trade off - sys_props.NumNodes includes GPU nodes + CPU Node. So in + * systems with CPU node, slightly more memory is allocated than + * necessary*/ + gpu_mem = (gpu_mem_t *)calloc(sys_props.NumNodes * sizeof(gpu_mem_t), 1); + if (gpu_mem == NULL) + return HSAKMT_STATUS_NO_MEMORY; + + /* Initialize gpu_mem[] from sysfs topology. Rest of the members are set to + * 0 by calloc. This is necessary because this function * gets called before hsaKmtAcquireSystemProperties() is called.*/ + gpu_mem_count = 0; while (i < sys_props.NumNodes) { ret = topology_sysfs_get_node_props(i, &props, &gpu_id); if (ret != HSAKMT_STATUS_SUCCESS) - return ret; + goto sysfs_parse_failed; /* Skip non-GPU nodes */ if (gpu_id != 0) { - gpu_mem[gpu_mem_id].gpu_id = gpu_id; - gpu_mem[gpu_mem_id].local_mem_size = props.LocalMemSize; - gpu_mem[gpu_mem_id].device_id = props.DeviceId; - gpu_mem[gpu_mem_id].node_id = i; - gpu_mem_id++; + gpu_mem[gpu_mem_count].gpu_id = gpu_id; + gpu_mem[gpu_mem_count].local_mem_size = props.LocalMemSize; + gpu_mem[gpu_mem_count].device_id = props.DeviceId; + gpu_mem[gpu_mem_count].node_id = i; + gpu_mem[gpu_mem_count].scratch_physical.align = PAGE_SIZE; + pthread_mutex_init(&gpu_mem[gpu_mem_count].scratch_physical.fmm_mutex, NULL); + gpu_mem[gpu_mem_count].scratch_aperture.align = PAGE_SIZE; + pthread_mutex_init(&gpu_mem[gpu_mem_count].scratch_aperture.fmm_mutex, NULL); + gpu_mem[gpu_mem_count].gpuvm_aperture.align = PAGE_SIZE; + pthread_mutex_init(&gpu_mem[gpu_mem_count].gpuvm_aperture.fmm_mutex, NULL); + gpu_mem_count++; } i++; } @@ -1014,12 +1015,14 @@ HSAKMT_STATUS fmm_init_process_apertures(void) /* The ioctl will also return Number of Nodes if args.kfd_process_device_apertures_ptr * is set to NULL. This is not required since Number of nodes is already known. Kernel * will fill in the apertures in kfd_process_device_apertures_ptr */ - process_apertures = malloc(gpu_mem_id * sizeof(struct kfd_process_device_apertures)); - if (process_apertures == NULL) - return HSAKMT_STATUS_NO_MEMORY; + process_apertures = malloc(gpu_mem_count * sizeof(struct kfd_process_device_apertures)); + if (process_apertures == NULL) { + ret = HSAKMT_STATUS_NO_MEMORY; + goto sysfs_parse_failed; + } args.kfd_process_device_apertures_ptr = (uintptr_t)process_apertures; - args.num_of_nodes = gpu_mem_id; + args.num_of_nodes = gpu_mem_count; if (kmtIoctl(kfd_fd, AMDKFD_IOC_GET_PROCESS_APERTURES_NEW, (void *)&args)) { ret = HSAKMT_STATUS_ERROR; @@ -1114,12 +1117,26 @@ HSAKMT_STATUS fmm_init_process_apertures(void) } } + free(process_apertures); + return ret; + get_aperture_ioctl_failed: invalid_gpu_id : free(process_apertures); +sysfs_parse_failed: + fmm_destroy_process_apertures(); return ret; } +void fmm_destroy_process_apertures(void) +{ + if (gpu_mem) { + free(gpu_mem); + gpu_mem = NULL; + } + gpu_mem_count = 0; +} + HSAKMT_STATUS fmm_get_aperture_base_and_limit(aperture_type_e aperture_type, HSAuint32 gpu_id, HSAuint64 *aperture_base, HSAuint64 *aperture_limit) { @@ -1308,11 +1325,11 @@ err_object_not_found: int fmm_map_to_gpu(void *address, uint64_t size, uint64_t *gpuvm_address) { - int32_t i; + uint32_t i; uint64_t pi; /* Find an aperture the requested address belongs to */ - for (i = 0; i < NUM_OF_SUPPORTED_GPUS; i++) { + for (i = 0; i < gpu_mem_count; i++) { if (gpu_mem[i].gpu_id == NON_VALID_GPU_ID) continue; @@ -1432,10 +1449,10 @@ err: int fmm_unmap_from_gpu(void *address) { - int32_t i; + uint32_t i; /* Find the aperture the requested address belongs to */ - for (i = 0; i < NUM_OF_SUPPORTED_GPUS; i++) { + for (i = 0; i < gpu_mem_count; i++) { if (gpu_mem[i].gpu_id == NON_VALID_GPU_ID) continue; @@ -1608,7 +1625,7 @@ static HSAKMT_STATUS dgpu_mem_init(uint32_t gpu_mem_id, void **base, void **limi bool fmm_get_handle(void *address, uint64_t *handle) { - int32_t i; + uint32_t i; manageble_aperture_t *aperture; vm_object_t *object; bool found; @@ -1617,7 +1634,7 @@ bool fmm_get_handle(void *address, uint64_t *handle) aperture = NULL; /* Find the aperture the requested address belongs to */ - for (i = 0; i < NUM_OF_SUPPORTED_GPUS; i++) { + for (i = 0; i < gpu_mem_count; i++) { if (gpu_mem[i].gpu_id == NON_VALID_GPU_ID) continue; diff --git a/projects/rocr-runtime/src/fmm.h b/projects/rocr-runtime/src/fmm.h index 5bdbf5bbba..45fedb4d21 100644 --- a/projects/rocr-runtime/src/fmm.h +++ b/projects/rocr-runtime/src/fmm.h @@ -44,6 +44,8 @@ typedef struct { } aperture_properties_t; HSAKMT_STATUS fmm_init_process_apertures(void); +void fmm_destroy_process_apertures(void); + /* * Memory interface */ diff --git a/projects/rocr-runtime/src/libhsakmt.h b/projects/rocr-runtime/src/libhsakmt.h index c44bb528d0..b976d5a3e5 100644 --- a/projects/rocr-runtime/src/libhsakmt.h +++ b/projects/rocr-runtime/src/libhsakmt.h @@ -80,6 +80,8 @@ HSAuint32 PageSizeFromFlags(unsigned int pageSizeFlags); void* allocate_exec_aligned_memory_gpu(uint32_t size, uint32_t align, uint32_t NodeId, bool peer_to_peer); void free_exec_aligned_memory_gpu(void *addr, uint32_t size, uint32_t align); +HSAKMT_STATUS init_process_doorbells(void); +void destroy_process_doorbells(void); extern int kmtIoctl(int fd, unsigned long request, void *arg); diff --git a/projects/rocr-runtime/src/openclose.c b/projects/rocr-runtime/src/openclose.c index d5b91e23dd..620db3debf 100644 --- a/projects/rocr-runtime/src/openclose.c +++ b/projects/rocr-runtime/src/openclose.c @@ -41,27 +41,30 @@ HSAKMTAPI hsaKmtOpenKFD(void) { HSAKMT_STATUS result; + int fd; pthread_mutex_lock(&hsakmt_mutex); if (kfd_open_count == 0) { - int fd = open(kfd_device_name, O_RDWR | O_CLOEXEC); + fd = open(kfd_device_name, O_RDWR | O_CLOEXEC); - if (fd != -1) - { + if (fd != -1) { kfd_fd = fd; kfd_open_count = 1; - - result = fmm_init_process_apertures(); - if (result != HSAKMT_STATUS_SUCCESS) - close(fd); - } - else - { + } else { result = HSAKMT_STATUS_KERNEL_IO_CHANNEL_NOT_OPENED; + goto open_failed; } + result = fmm_init_process_apertures(); + if (result != HSAKMT_STATUS_SUCCESS) + goto init_process_aperture_failed; + + result = init_process_doorbells(); + if (result != HSAKMT_STATUS_SUCCESS) + goto init_doorbell_failed; + amd_hsa_thunk_lock_fd = open(tmp_file, O_CREAT | //create the file if it's not present. O_RDWR, //only need write access for the internal locking semantics. @@ -73,6 +76,14 @@ hsaKmtOpenKFD(void) result = HSAKMT_STATUS_SUCCESS; } + pthread_mutex_unlock(&hsakmt_mutex); + return result; + +init_doorbell_failed: + fmm_destroy_process_apertures(); +init_process_aperture_failed: + close(fd); +open_failed: pthread_mutex_unlock(&hsakmt_mutex); return result; @@ -90,6 +101,8 @@ hsaKmtCloseKFD(void) { if (--kfd_open_count == 0) { + destroy_process_doorbells(); + fmm_destroy_process_apertures(); close(kfd_fd); if (amd_hsa_thunk_lock_fd > 0) { diff --git a/projects/rocr-runtime/src/queues.c b/projects/rocr-runtime/src/queues.c index 247172ef4f..8567e6ce26 100644 --- a/projects/rocr-runtime/src/queues.c +++ b/projects/rocr-runtime/src/queues.c @@ -145,7 +145,39 @@ struct process_doorbells pthread_mutex_t doorbells_mutex; }; -struct process_doorbells doorbells[] = {[0 ... (NUM_OF_SUPPORTED_GPUS-1)] = {.need_mmap = true, .doorbells = NULL, .doorbells_mutex = PTHREAD_MUTEX_INITIALIZER}}; +static struct process_doorbells *doorbells; + +HSAKMT_STATUS init_process_doorbells(void) +{ + HsaSystemProperties sys_props; + unsigned int i; + HSAKMT_STATUS ret = HSAKMT_STATUS_SUCCESS; + + ret = topology_sysfs_get_system_props(&sys_props); + if (ret != HSAKMT_STATUS_SUCCESS) + return ret; + + /* doorbells[] is accessed using Topology NodeId. This means doorbells[0], + * which corresponds to CPU only Node, might not be used */ + doorbells = malloc(sys_props.NumNodes * sizeof(struct process_doorbells)); + if (doorbells == NULL) + return HSAKMT_STATUS_NO_MEMORY; + + for (i = 0; i < sys_props.NumNodes; i++) { + doorbells[i].need_mmap = true; + doorbells[i].doorbells = NULL; + pthread_mutex_init(&doorbells[i].doorbells_mutex, NULL); + } + return ret; +} + +void destroy_process_doorbells(void) +{ + if (doorbells) { + free(doorbells); + doorbells = NULL; + } +} static struct device_info *get_device_info_by_dev_id(uint16_t dev_id) {