Skip to content

Commit e248021

Browse files
committed
add support for IPC on L0 + Win
1 parent 10b0aec commit e248021

File tree

10 files changed

+618
-103
lines changed

10 files changed

+618
-103
lines changed

include/umf/providers/provider_level_zero.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ umf_result_t umfLevelZeroMemoryProviderParamsSetFreePolicy(
8585
umf_level_zero_memory_provider_params_handle_t hParams,
8686
umf_level_zero_memory_provider_free_policy_t policy);
8787

88+
typedef enum umf_level_zero_memory_provider_memory_exchange_policy_t {
89+
UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC =
90+
0, ///< Memory exchange policy based on IPC. Default.
91+
UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT,
92+
///< Memory exchange policy based on import/export APIs. Should be used if IPC exchange policy is not supported.
93+
} umf_level_zero_memory_provider_memory_exchange_policy_t;
94+
8895
/// @brief Set the device ordinal in the parameters struct.
8996
/// @param hParams handle to the parameters of the Level Zero Memory Provider.
9097
/// @param deviceOrdinal device ordinal.

src/provider/provider_level_zero.c

Lines changed: 151 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,26 @@ void fini_ze_global_state(void) {
4444

4545
// Level Zero Memory Provider settings struct
4646
typedef struct umf_level_zero_memory_provider_params_t {
47-
ze_context_handle_t
48-
level_zero_context_handle; ///< Handle to the Level Zero context
49-
ze_device_handle_t
50-
level_zero_device_handle; ///< Handle to the Level Zero device
47+
// Handle to the Level Zero context
48+
ze_context_handle_t level_zero_context_handle;
5149

52-
umf_usm_memory_type_t memory_type; ///< Allocation memory type
50+
// Handle to the Level Zero device
51+
ze_device_handle_t level_zero_device_handle;
5352

54-
ze_device_handle_t *
55-
resident_device_handles; ///< Array of devices for which the memory should be made resident
56-
uint32_t
57-
resident_device_count; ///< Number of devices for which the memory should be made resident
53+
// Allocation memory type
54+
umf_usm_memory_type_t memory_type;
5855

59-
umf_level_zero_memory_provider_free_policy_t
60-
freePolicy; ///< Memory free policy
56+
// Array of devices for which the memory should be made resident
57+
ze_device_handle_t *resident_device_handles;
58+
59+
// Number of devices for which the memory should be made resident
60+
uint32_t resident_device_count;
61+
62+
// Memory free policy
63+
umf_level_zero_memory_provider_free_policy_t freePolicy;
64+
65+
// Memory exchange policy
66+
umf_level_zero_memory_provider_memory_exchange_policy_t exchangePolicy;
6167

6268
uint32_t device_ordinal;
6369
char name[64];
@@ -77,6 +83,8 @@ typedef struct ze_memory_provider_t {
7783

7884
ze_driver_memory_free_policy_ext_flags_t freePolicyFlags;
7985

86+
umf_level_zero_memory_provider_memory_exchange_policy_t exchangePolicy;
87+
8088
size_t min_page_size;
8189

8290
uint32_t device_ordinal;
@@ -134,7 +142,48 @@ static void store_last_native_error(int32_t native_error) {
134142
struct ctl ze_memory_ctl_root;
135143
static UTIL_ONCE_FLAG ctl_initialized = UTIL_ONCE_FLAG_INIT;
136144

145+
static ze_relaxed_allocation_limits_exp_desc_t relaxed_device_allocation_desc =
146+
{.stype = ZE_STRUCTURE_TYPE_RELAXED_ALLOCATION_LIMITS_EXP_DESC,
147+
.pNext = NULL,
148+
.flags = ZE_RELAXED_ALLOCATION_LIMITS_EXP_FLAG_MAX_SIZE};
149+
150+
static ze_external_memory_export_desc_t memory_export_desc = {
151+
.stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_DESC,
152+
.pNext = NULL,
153+
.flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_WIN32};
154+
155+
static umf_result_t CTL_READ_HANDLER(memory_exchange_policy)(
156+
void *ctx, umf_ctl_query_source_t source, void *arg, size_t size,
157+
umf_ctl_index_utlist_t *indexes) {
158+
/* suppress unused-parameter errors */
159+
(void)source, (void)indexes, (void)size;
160+
161+
umf_level_zero_memory_provider_memory_exchange_policy_t *arg_out = arg;
162+
ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)ctx;
163+
*arg_out = ze_provider->exchangePolicy;
164+
return UMF_RESULT_SUCCESS;
165+
}
166+
167+
static umf_result_t CTL_WRITE_HANDLER(memory_exchange_policy)(
168+
void *ctx, umf_ctl_query_source_t source, void *arg, size_t size,
169+
umf_ctl_index_utlist_t *indexes) {
170+
/* suppress unused-parameter errors */
171+
(void)source, (void)indexes, (void)size;
172+
173+
umf_level_zero_memory_provider_memory_exchange_policy_t arg_in =
174+
*(umf_level_zero_memory_provider_memory_exchange_policy_t *)arg;
175+
ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)ctx;
176+
ze_provider->exchangePolicy = arg_in;
177+
return UMF_RESULT_SUCCESS;
178+
}
179+
180+
static const struct ctl_argument CTL_ARG(memory_exchange_policy) = CTL_ARG_INT;
181+
182+
static const umf_ctl_node_t CTL_NODE(params)[] = {
183+
CTL_LEAF_RW(memory_exchange_policy), CTL_NODE_END};
184+
137185
static void initialize_ze_ctl(void) {
186+
CTL_REGISTER_MODULE(&ze_memory_ctl_root, params);
138187
CTL_REGISTER_MODULE(&ze_memory_ctl_root, stats);
139188
}
140189

@@ -268,6 +317,8 @@ umf_result_t umfLevelZeroMemoryProviderParamsCreate(
268317
params->resident_device_handles = NULL;
269318
params->resident_device_count = 0;
270319
params->freePolicy = UMF_LEVEL_ZERO_MEMORY_PROVIDER_FREE_POLICY_DEFAULT;
320+
params->exchangePolicy =
321+
UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC;
271322
params->device_ordinal = 0;
272323
strncpy(params->name, DEFAULT_NAME, sizeof(params->name) - 1);
273324
params->name[sizeof(params->name) - 1] = '\0';
@@ -421,11 +472,6 @@ static bool use_relaxed_allocation(ze_memory_provider_t *ze_provider,
421472
return size > ze_provider->device_properties.maxMemAllocSize;
422473
}
423474

424-
static ze_relaxed_allocation_limits_exp_desc_t relaxed_device_allocation_desc =
425-
{.stype = ZE_STRUCTURE_TYPE_RELAXED_ALLOCATION_LIMITS_EXP_DESC,
426-
.pNext = NULL,
427-
.flags = ZE_RELAXED_ALLOCATION_LIMITS_EXP_FLAG_MAX_SIZE};
428-
429475
static umf_result_t ze_memory_provider_free_helper(void *provider, void *ptr,
430476
size_t bytes,
431477
int update_stats) {
@@ -483,11 +529,29 @@ static umf_result_t ze_memory_provider_alloc_helper(void *provider, size_t size,
483529
case UMF_MEMORY_TYPE_DEVICE: {
484530
ze_device_mem_alloc_desc_t dev_desc = {
485531
.stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC,
486-
.pNext = use_relaxed_allocation(ze_provider, size)
487-
? &relaxed_device_allocation_desc
488-
: NULL,
532+
.pNext = NULL,
489533
.flags = 0,
490534
.ordinal = ze_provider->device_ordinal};
535+
void *lastNext = &dev_desc.pNext;
536+
537+
ze_relaxed_allocation_limits_exp_desc_t
538+
relaxed_device_allocation_desc_copy =
539+
relaxed_device_allocation_desc;
540+
if (use_relaxed_allocation(ze_provider, size)) {
541+
// add relaxed allocation desc to the pNext chain
542+
*(void **)lastNext = &relaxed_device_allocation_desc_copy;
543+
lastNext = &relaxed_device_allocation_desc_copy.pNext;
544+
}
545+
546+
ze_external_memory_export_desc_t memory_export_desc_copy =
547+
memory_export_desc;
548+
if (ze_provider->exchangePolicy ==
549+
UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT) {
550+
// add external memory export desc to the pNext chain
551+
*(void **)lastNext = &memory_export_desc_copy;
552+
lastNext = &memory_export_desc_copy.pNext;
553+
}
554+
491555
ze_result = g_ze_ops.zeMemAllocDevice(ze_provider->context, &dev_desc,
492556
size, alignment,
493557
ze_provider->device, resultPtr);
@@ -647,6 +711,7 @@ static umf_result_t ze_memory_provider_initialize(const void *params,
647711
ze_provider->memory_type = umf2ze_memory_type(ze_params->memory_type);
648712
ze_provider->freePolicyFlags =
649713
umfFreePolicyToZePolicy(ze_params->freePolicy);
714+
ze_provider->exchangePolicy = ze_params->exchangePolicy;
650715
ze_provider->min_page_size = 0;
651716
ze_provider->device_ordinal = ze_params->device_ordinal;
652717

@@ -812,6 +877,7 @@ static umf_result_t ze_memory_provider_allocation_split(void *provider,
812877

813878
typedef struct ze_ipc_data_t {
814879
int pid;
880+
size_t size;
815881
ze_ipc_mem_handle_t ze_handle;
816882
} ze_ipc_data_t;
817883

@@ -827,20 +893,45 @@ static umf_result_t ze_memory_provider_get_ipc_handle(void *provider,
827893
const void *ptr,
828894
size_t size,
829895
void *providerIpcData) {
830-
(void)size;
831-
832896
ze_result_t ze_result;
833897
ze_ipc_data_t *ze_ipc_data = (ze_ipc_data_t *)providerIpcData;
834898
struct ze_memory_provider_t *ze_provider =
835899
(struct ze_memory_provider_t *)provider;
836900

837-
ze_result = g_ze_ops.zeMemGetIpcHandle(ze_provider->context, ptr,
838-
&ze_ipc_data->ze_handle);
839-
if (ze_result != ZE_RESULT_SUCCESS) {
840-
LOG_ERR("zeMemGetIpcHandle() failed.");
841-
return ze2umf_result(ze_result);
901+
if (ze_provider->exchangePolicy ==
902+
UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC) {
903+
ze_result = g_ze_ops.zeMemGetIpcHandle(ze_provider->context, ptr,
904+
&ze_ipc_data->ze_handle);
905+
906+
if (ze_result != ZE_RESULT_SUCCESS) {
907+
LOG_ERR("zeMemGetIpcHandle() failed.");
908+
return ze2umf_result(ze_result);
909+
}
910+
} else { // UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT
911+
ze_external_memory_export_fd_t fd_desc = {
912+
.stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_FD,
913+
.pNext = NULL,
914+
.flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_WIN32,
915+
.fd = 0};
916+
917+
ze_memory_allocation_properties_t mem_alloc_props = {
918+
.stype = ZE_STRUCTURE_TYPE_MEMORY_ALLOCATION_PROPERTIES,
919+
.pNext = &fd_desc,
920+
.type = 0,
921+
.id = 0,
922+
.pageSize = 0};
923+
924+
ze_result = g_ze_ops.zeMemGetAllocProperties(ze_provider->context, ptr,
925+
&mem_alloc_props, NULL);
926+
if (ze_result != ZE_RESULT_SUCCESS) {
927+
LOG_ERR("zeMemGetAllocProperties() failed.");
928+
return ze2umf_result(ze_result);
929+
}
930+
931+
memcpy(&ze_ipc_data->ze_handle, &fd_desc.fd, sizeof(fd_desc.fd));
842932
}
843933

934+
ze_ipc_data->size = size;
844935
ze_ipc_data->pid = utils_getpid();
845936

846937
return UMF_RESULT_SUCCESS;
@@ -891,14 +982,40 @@ static umf_result_t ze_memory_provider_open_ipc_handle(void *provider,
891982
memcpy(&ze_ipc_handle, &fd_local, sizeof(fd_local));
892983
}
893984

894-
ze_result = g_ze_ops.zeMemOpenIpcHandle(
895-
ze_provider->context, ze_provider->device, ze_ipc_handle, 0, ptr);
896-
if (fd_local != -1) {
897-
(void)utils_close_fd(fd_local);
898-
}
899-
if (ze_result != ZE_RESULT_SUCCESS) {
900-
LOG_ERR("zeMemOpenIpcHandle() failed.");
901-
return ze2umf_result(ze_result);
985+
if (ze_provider->exchangePolicy ==
986+
UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC) {
987+
ze_result = g_ze_ops.zeMemOpenIpcHandle(
988+
ze_provider->context, ze_provider->device, ze_ipc_handle, 0, ptr);
989+
if (fd_local != -1) {
990+
(void)utils_close_fd(fd_local);
991+
}
992+
if (ze_result != ZE_RESULT_SUCCESS) {
993+
LOG_ERR("zeMemOpenIpcHandle() failed.");
994+
return ze2umf_result(ze_result);
995+
}
996+
} else { // UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT
997+
ze_external_memory_import_fd_t import_fd = {
998+
.stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_FD,
999+
.pNext = NULL,
1000+
.flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_DMA_BUF,
1001+
.fd = fd_local};
1002+
1003+
ze_device_mem_alloc_desc_t alloc_desc = {
1004+
.stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC,
1005+
.pNext = &import_fd,
1006+
.flags = 0,
1007+
.ordinal = 0};
1008+
ze_result = g_ze_ops.zeMemAllocDevice(ze_provider->context, &alloc_desc,
1009+
ze_ipc_data->size, 0,
1010+
ze_provider->device, ptr);
1011+
if (fd_local != -1) {
1012+
(void)utils_close_fd(fd_local);
1013+
}
1014+
1015+
if (ze_result != ZE_RESULT_SUCCESS) {
1016+
LOG_ERR("zeMemAllocDevice() failed.");
1017+
return ze2umf_result(ze_result);
1018+
}
9021019
}
9031020

9041021
return UMF_RESULT_SUCCESS;

src/utils/utils_windows_common.c

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <windows.h>
1111

1212
#include <assert.h>
13+
#include <handleapi.h>
1314
#include <processenv.h>
1415
#include <processthreadsapi.h>
1516
#include <stdio.h>
@@ -47,21 +48,49 @@ int utils_getpid(void) { return GetCurrentProcessId(); }
4748

4849
int utils_gettid(void) { return GetCurrentThreadId(); }
4950

50-
int utils_close_fd(int fd) {
51-
(void)fd; // unused
52-
return -1;
53-
}
51+
int utils_close_fd(int fd) { return CloseHandle((HANDLE)(uintptr_t)fd); }
5452

5553
umf_result_t utils_errno_to_umf_result(int err) {
5654
(void)err; // unused
5755
return UMF_RESULT_ERROR_NOT_SUPPORTED;
5856
}
5957

6058
umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out) {
61-
(void)pid; // unused
62-
(void)fd_in; // unused
63-
(void)fd_out; // unused
64-
return UMF_RESULT_ERROR_NOT_SUPPORTED;
59+
umf_result_t ret = UMF_RESULT_SUCCESS;
60+
HANDLE current_process_handle = GetCurrentProcess();
61+
if (!current_process_handle) {
62+
LOG_ERR("GetCurrentProcess() failed.");
63+
return UMF_RESULT_ERROR_UNKNOWN;
64+
}
65+
66+
HANDLE source_process_handle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
67+
if (!source_process_handle) {
68+
LOG_ERR("OpenProcess() failed for pid=%d.", pid);
69+
ret = UMF_RESULT_ERROR_UNKNOWN;
70+
goto release_current;
71+
}
72+
73+
HANDLE handle_in = (HANDLE)(uintptr_t)fd_in;
74+
HANDLE handle_out = NULL;
75+
BOOL result = DuplicateHandle(source_process_handle, handle_in,
76+
current_process_handle, &handle_out,
77+
GENERIC_READ | GENERIC_WRITE, FALSE, 0);
78+
if (!result) {
79+
LOG_ERR("DuplicateHandle() failed for pid=%d fd_in=%d handle_in=%p",
80+
pid, fd_in, handle_in);
81+
ret = UMF_RESULT_ERROR_UNKNOWN;
82+
goto release_source;
83+
}
84+
85+
*fd_out = (int)(uintptr_t)handle_out;
86+
87+
release_source:
88+
CloseHandle(source_process_handle);
89+
90+
release_current:
91+
CloseHandle(current_process_handle);
92+
93+
return ret;
6594
}
6695

6796
umf_result_t utils_translate_mem_protection_flags(unsigned in_protection,

0 commit comments

Comments
 (0)