Skip to content

Commit c72f658

Browse files
committed
add support for IPC on L0 + Win
1 parent 1209db2 commit c72f658

12 files changed

Lines changed: 593 additions & 103 deletions

include/umf/providers/provider_level_zero.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,21 @@ 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+
95+
/// @brief Set the memory exchange policy.
96+
/// @param hParams handle to the parameters of the Level Zero Memory Provider.
97+
/// @param policy memory exchange policy.
98+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
99+
umf_result_t umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy(
100+
umf_level_zero_memory_provider_params_handle_t hParams,
101+
umf_level_zero_memory_provider_memory_exchange_policy_t policy);
102+
88103
/// @brief Set the device ordinal in the parameters struct.
89104
/// @param hParams handle to the parameters of the Level Zero Memory Provider.
90105
/// @param deviceOrdinal device ordinal.

src/libumf.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ EXPORTS
153153
umfGetMemoryProperty
154154
umfGetMemoryPropertySize
155155
umfJemallocPoolParamsSetName
156+
umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy
156157
umfLevelZeroMemoryProviderParamsSetName
157158
umfLevelZeroMemoryProviderResidentDeviceChange
158159
umfOsMemoryProviderParamsSetName

src/libumf.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ UMF_1.1 {
151151
umfGetMemoryProperty;
152152
umfGetMemoryPropertySize;
153153
umfJemallocPoolParamsSetName;
154+
umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy;
154155
umfLevelZeroMemoryProviderParamsSetName;
155156
umfLevelZeroMemoryProviderResidentDeviceChange;
156157
umfOsMemoryProviderParamsSetName;

src/provider/provider_level_zero.c

Lines changed: 140 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;
@@ -132,6 +140,16 @@ static void store_last_native_error(int32_t native_error) {
132140
struct ctl ze_memory_ctl_root;
133141
static UTIL_ONCE_FLAG ctl_initialized = UTIL_ONCE_FLAG_INIT;
134142

143+
static ze_relaxed_allocation_limits_exp_desc_t relaxed_device_allocation_desc =
144+
{.stype = ZE_STRUCTURE_TYPE_RELAXED_ALLOCATION_LIMITS_EXP_DESC,
145+
.pNext = NULL,
146+
.flags = ZE_RELAXED_ALLOCATION_LIMITS_EXP_FLAG_MAX_SIZE};
147+
148+
static ze_external_memory_export_desc_t memory_export_desc = {
149+
.stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_DESC,
150+
.pNext = NULL,
151+
.flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_WIN32};
152+
135153
static void initialize_ze_ctl(void) {
136154
CTL_REGISTER_MODULE(&ze_memory_ctl_root, stats);
137155
}
@@ -263,6 +281,8 @@ umf_result_t umfLevelZeroMemoryProviderParamsCreate(
263281
params->resident_device_handles = NULL;
264282
params->resident_device_count = 0;
265283
params->freePolicy = UMF_LEVEL_ZERO_MEMORY_PROVIDER_FREE_POLICY_DEFAULT;
284+
params->exchangePolicy =
285+
UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC;
266286
params->device_ordinal = 0;
267287
strncpy(params->name, DEFAULT_NAME, sizeof(params->name) - 1);
268288
params->name[sizeof(params->name) - 1] = '\0';
@@ -394,6 +414,18 @@ umf_result_t umfLevelZeroMemoryProviderParamsSetFreePolicy(
394414
return UMF_RESULT_SUCCESS;
395415
}
396416

417+
umf_result_t umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy(
418+
umf_level_zero_memory_provider_params_handle_t hParams,
419+
umf_level_zero_memory_provider_memory_exchange_policy_t policy) {
420+
if (!hParams) {
421+
LOG_ERR("Level Zero memory provider params handle is NULL");
422+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
423+
}
424+
425+
hParams->exchangePolicy = policy;
426+
return UMF_RESULT_SUCCESS;
427+
}
428+
397429
static ze_driver_memory_free_policy_ext_flags_t
398430
umfFreePolicyToZePolicy(umf_level_zero_memory_provider_free_policy_t policy) {
399431
switch (policy) {
@@ -416,11 +448,6 @@ static bool use_relaxed_allocation(ze_memory_provider_t *ze_provider,
416448
return size > ze_provider->device_properties.maxMemAllocSize;
417449
}
418450

419-
static ze_relaxed_allocation_limits_exp_desc_t relaxed_device_allocation_desc =
420-
{.stype = ZE_STRUCTURE_TYPE_RELAXED_ALLOCATION_LIMITS_EXP_DESC,
421-
.pNext = NULL,
422-
.flags = ZE_RELAXED_ALLOCATION_LIMITS_EXP_FLAG_MAX_SIZE};
423-
424451
static umf_result_t ze_memory_provider_free_helper(void *provider, void *ptr,
425452
size_t bytes,
426453
int update_stats) {
@@ -478,11 +505,29 @@ static umf_result_t ze_memory_provider_alloc_helper(void *provider, size_t size,
478505
case UMF_MEMORY_TYPE_DEVICE: {
479506
ze_device_mem_alloc_desc_t dev_desc = {
480507
.stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC,
481-
.pNext = use_relaxed_allocation(ze_provider, size)
482-
? &relaxed_device_allocation_desc
483-
: NULL,
508+
.pNext = NULL,
484509
.flags = 0,
485510
.ordinal = ze_provider->device_ordinal};
511+
void *lastNext = &dev_desc.pNext;
512+
513+
ze_relaxed_allocation_limits_exp_desc_t
514+
relaxed_device_allocation_desc_copy =
515+
relaxed_device_allocation_desc;
516+
if (use_relaxed_allocation(ze_provider, size)) {
517+
// add relaxed allocation desc to the pNext chain
518+
*(void **)lastNext = &relaxed_device_allocation_desc_copy;
519+
lastNext = &relaxed_device_allocation_desc_copy.pNext;
520+
}
521+
522+
ze_external_memory_export_desc_t memory_export_desc_copy =
523+
memory_export_desc;
524+
if (ze_provider->exchangePolicy ==
525+
UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT) {
526+
// add external memory export desc to the pNext chain
527+
*(void **)lastNext = &memory_export_desc_copy;
528+
lastNext = &memory_export_desc_copy.pNext;
529+
}
530+
486531
ze_result = g_ze_ops.zeMemAllocDevice(ze_provider->context, &dev_desc,
487532
size, alignment,
488533
ze_provider->device, resultPtr);
@@ -642,6 +687,7 @@ static umf_result_t ze_memory_provider_initialize(const void *params,
642687
ze_provider->memory_type = umf2ze_memory_type(ze_params->memory_type);
643688
ze_provider->freePolicyFlags =
644689
umfFreePolicyToZePolicy(ze_params->freePolicy);
690+
ze_provider->exchangePolicy = ze_params->exchangePolicy;
645691
ze_provider->min_page_size = 0;
646692
ze_provider->device_ordinal = ze_params->device_ordinal;
647693

@@ -807,6 +853,7 @@ static umf_result_t ze_memory_provider_allocation_split(void *provider,
807853

808854
typedef struct ze_ipc_data_t {
809855
int pid;
856+
size_t size;
810857
ze_ipc_mem_handle_t ze_handle;
811858
} ze_ipc_data_t;
812859

@@ -822,20 +869,45 @@ static umf_result_t ze_memory_provider_get_ipc_handle(void *provider,
822869
const void *ptr,
823870
size_t size,
824871
void *providerIpcData) {
825-
(void)size;
826-
827872
ze_result_t ze_result;
828873
ze_ipc_data_t *ze_ipc_data = (ze_ipc_data_t *)providerIpcData;
829874
struct ze_memory_provider_t *ze_provider =
830875
(struct ze_memory_provider_t *)provider;
831876

832-
ze_result = g_ze_ops.zeMemGetIpcHandle(ze_provider->context, ptr,
833-
&ze_ipc_data->ze_handle);
834-
if (ze_result != ZE_RESULT_SUCCESS) {
835-
LOG_ERR("zeMemGetIpcHandle() failed.");
836-
return ze2umf_result(ze_result);
877+
if (ze_provider->exchangePolicy ==
878+
UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC) {
879+
ze_result = g_ze_ops.zeMemGetIpcHandle(ze_provider->context, ptr,
880+
&ze_ipc_data->ze_handle);
881+
882+
if (ze_result != ZE_RESULT_SUCCESS) {
883+
LOG_ERR("zeMemGetIpcHandle() failed.");
884+
return ze2umf_result(ze_result);
885+
}
886+
} else { // UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT
887+
ze_external_memory_export_fd_t fd_desc = {
888+
.stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_FD,
889+
.pNext = NULL,
890+
.flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_WIN32,
891+
.fd = 0};
892+
893+
ze_memory_allocation_properties_t mem_alloc_props = {
894+
.stype = ZE_STRUCTURE_TYPE_MEMORY_ALLOCATION_PROPERTIES,
895+
.pNext = &fd_desc,
896+
.type = 0,
897+
.id = 0,
898+
.pageSize = 0};
899+
900+
ze_result = g_ze_ops.zeMemGetAllocProperties(ze_provider->context, ptr,
901+
&mem_alloc_props, NULL);
902+
if (ze_result != ZE_RESULT_SUCCESS) {
903+
LOG_ERR("zeMemGetAllocProperties() failed.");
904+
return ze2umf_result(ze_result);
905+
}
906+
907+
memcpy(&ze_ipc_data->ze_handle, &fd_desc.fd, sizeof(fd_desc.fd));
837908
}
838909

910+
ze_ipc_data->size = size;
839911
ze_ipc_data->pid = utils_getpid();
840912

841913
return UMF_RESULT_SUCCESS;
@@ -886,14 +958,40 @@ static umf_result_t ze_memory_provider_open_ipc_handle(void *provider,
886958
memcpy(&ze_ipc_handle, &fd_local, sizeof(fd_local));
887959
}
888960

889-
ze_result = g_ze_ops.zeMemOpenIpcHandle(
890-
ze_provider->context, ze_provider->device, ze_ipc_handle, 0, ptr);
891-
if (fd_local != -1) {
892-
(void)utils_close_fd(fd_local);
893-
}
894-
if (ze_result != ZE_RESULT_SUCCESS) {
895-
LOG_ERR("zeMemOpenIpcHandle() failed.");
896-
return ze2umf_result(ze_result);
961+
if (ze_provider->exchangePolicy ==
962+
UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC) {
963+
ze_result = g_ze_ops.zeMemOpenIpcHandle(
964+
ze_provider->context, ze_provider->device, ze_ipc_handle, 0, ptr);
965+
if (fd_local != -1) {
966+
(void)utils_close_fd(fd_local);
967+
}
968+
if (ze_result != ZE_RESULT_SUCCESS) {
969+
LOG_ERR("zeMemOpenIpcHandle() failed.");
970+
return ze2umf_result(ze_result);
971+
}
972+
} else { // UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT
973+
ze_external_memory_import_fd_t import_fd = {
974+
.stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_FD,
975+
.pNext = NULL,
976+
.flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_DMA_BUF,
977+
.fd = fd_local};
978+
979+
ze_device_mem_alloc_desc_t alloc_desc = {
980+
.stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC,
981+
.pNext = &import_fd,
982+
.flags = 0,
983+
.ordinal = 0};
984+
ze_result = g_ze_ops.zeMemAllocDevice(ze_provider->context, &alloc_desc,
985+
ze_ipc_data->size, 0,
986+
ze_provider->device, ptr);
987+
if (fd_local != -1) {
988+
(void)utils_close_fd(fd_local);
989+
}
990+
991+
if (ze_result != ZE_RESULT_SUCCESS) {
992+
LOG_ERR("zeMemAllocDevice() failed.");
993+
return ze2umf_result(ze_result);
994+
}
897995
}
898996

899997
return UMF_RESULT_SUCCESS;
@@ -1238,6 +1336,14 @@ umf_result_t umfLevelZeroMemoryProviderParamsSetFreePolicy(
12381336
return UMF_RESULT_ERROR_NOT_SUPPORTED;
12391337
}
12401338

1339+
umf_result_t umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy(
1340+
umf_level_zero_memory_provider_params_handle_t hParams,
1341+
umf_level_zero_memory_provider_memory_exchange_policy_t policy) {
1342+
(void)hParams;
1343+
(void)policy;
1344+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1345+
}
1346+
12411347
umf_result_t umfLevelZeroMemoryProviderParamsSetDeviceOrdinal(
12421348
umf_level_zero_memory_provider_params_handle_t hParams,
12431349
uint32_t deviceOrdinal) {

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)