Skip to content

Commit 1e74208

Browse files
committed
Add support for MAP_SHARED to OS memory provider for Linux only
Add support for MAP_SHARED to OS memory provider for Linux only and for the UMF_NUMA_MODE_DEFAULT only. Signed-off-by: Lukasz Dorau <[email protected]>
1 parent f31f7b0 commit 1e74208

File tree

7 files changed

+293
-20
lines changed

7 files changed

+293
-20
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ More detailed documentation is available here: https://oneapi-src.github.io/unif
138138
#### OS memory provider
139139

140140
A memory provider that provides memory from an operating system.
141+
It supports two types of memory mappings
142+
1) private memory mapping (`UMF_MEM_MAP_PRIVATE`)
143+
2) shared memory mapping (`UMF_MEM_MAP_SHARED` - supported on Linux only yet)
141144

142145
##### Requirements
143146

benchmark/ubench.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ UBENCH_EX(simple, glibc_malloc) {
107107

108108
static umf_os_memory_provider_params_t UMF_OS_MEMORY_PROVIDER_PARAMS = {
109109
/* .protection = */ UMF_PROTECTION_READ | UMF_PROTECTION_WRITE,
110+
/* .visibility */ UMF_MEM_MAP_PRIVATE,
110111

111112
// NUMA config
112113
/* .nodemask = */ NULL,

include/umf/providers/provider_os_memory.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ typedef enum umf_mem_protection_flags_t {
2929
/// @endcond
3030
} umf_mem_protection_flags_t;
3131

32+
/// @brief Memory visibility mode
33+
typedef enum umf_memory_visibility_t {
34+
UMF_MEM_MAP_PRIVATE = 1, ///< private memory mapping
35+
UMF_MEM_MAP_SHARED, ///< shared memory mapping (supported on Linux only)
36+
} umf_memory_visibility_t;
37+
3238
/// @brief Memory binding mode
3339
/// Specifies how memory is bound to NUMA nodes on systems that support NUMA.
3440
/// Not every mode is supported on every system.
@@ -61,6 +67,8 @@ typedef enum umf_numa_mode_t {
6167
typedef struct umf_os_memory_provider_params_t {
6268
/// Combination of 'umf_mem_protection_flags_t' flags
6369
unsigned protection;
70+
/// 'umf_memory_visibility_t' visibility mode
71+
unsigned visibility;
6472

6573
// NUMA config
6674
/// ordered list of numa nodes
@@ -91,6 +99,7 @@ static inline umf_os_memory_provider_params_t
9199
umfOsMemoryProviderParamsDefault(void) {
92100
umf_os_memory_provider_params_t params = {
93101
UMF_PROTECTION_READ | UMF_PROTECTION_WRITE, /* protection */
102+
UMF_MEM_MAP_PRIVATE, /* visibility mode */
94103
NULL, /* numa_list */
95104
0, /* numa_list_len */
96105
UMF_NUMA_MODE_DEFAULT, /* numa_mode */

src/provider/provider_os_memory.c

Lines changed: 135 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <string.h>
1616

1717
#include "base_alloc_global.h"
18+
#include "critnib.h"
1819
#include "provider_os_memory_internal.h"
1920
#include "utils_log.h"
2021

@@ -26,6 +27,13 @@
2627

2728
typedef struct os_memory_provider_t {
2829
unsigned protection; // combination of OS-specific protection flags
30+
unsigned visibility; // memory visibility mode
31+
int fd; // file descriptor for memory mapping
32+
size_t size_fd; // size of file used for memory mapping
33+
size_t max_size_fd; // maximum size of file used for memory mapping
34+
// A critnib map storing (ptr, fd_offset + 1) pairs (+ 1 to be able to store fd_offset == 0).
35+
// It is needed mainly in the get_ipc_handle and open_ipc_handle hooks to mmap a specific part of a file.
36+
critnib *fd_offset_map;
2937

3038
// NUMA config
3139
hwloc_bitmap_t nodeset;
@@ -191,6 +199,34 @@ static umf_result_t translate_params(umf_os_memory_provider_params_t *in_params,
191199
return result;
192200
}
193201

202+
result = os_translate_mem_visibility_flag(in_params->visibility,
203+
&provider->visibility);
204+
if (result != UMF_RESULT_SUCCESS) {
205+
LOG_ERR("incorrect memory visibility flag: %u", in_params->visibility);
206+
return result;
207+
}
208+
209+
provider->fd = os_create_anonymous_fd(provider->visibility);
210+
if (provider->fd == -1) {
211+
LOG_ERR(
212+
"creating an anonymous file descriptor for memory mapping failed");
213+
return UMF_RESULT_ERROR_UNKNOWN;
214+
}
215+
216+
provider->size_fd = 0; // will be increased during each allocation
217+
provider->max_size_fd = get_max_file_size();
218+
219+
if (provider->fd > 0) {
220+
int ret = os_set_file_size(provider->fd, provider->max_size_fd);
221+
if (ret) {
222+
LOG_ERR("setting file size %zu failed", provider->max_size_fd);
223+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
224+
}
225+
}
226+
227+
LOG_DEBUG("size of the memory mapped file set to %zu",
228+
provider->max_size_fd);
229+
194230
// NUMA config
195231
int emptyNodeset = in_params->numa_list_len == 0;
196232
result = translate_numa_mode(in_params->numa_mode, emptyNodeset,
@@ -218,6 +254,14 @@ static umf_result_t os_initialize(void *params, void **provider) {
218254
umf_os_memory_provider_params_t *in_params =
219255
(umf_os_memory_provider_params_t *)params;
220256

257+
if (in_params->visibility == UMF_MEM_MAP_SHARED &&
258+
in_params->numa_mode != UMF_NUMA_MODE_DEFAULT) {
259+
LOG_ERR("Unsupported NUMA mode for the UMF_MEM_MAP_SHARED memory "
260+
"visibility mode (only the UMF_NUMA_MODE_DEFAULT is supported "
261+
"for now)");
262+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
263+
}
264+
221265
os_memory_provider_t *os_provider =
222266
umf_ba_global_alloc(sizeof(os_memory_provider_t));
223267
if (!os_provider) {
@@ -261,10 +305,19 @@ static umf_result_t os_initialize(void *params, void **provider) {
261305
}
262306
}
263307

308+
os_provider->fd_offset_map = critnib_new();
309+
if (!os_provider->fd_offset_map) {
310+
LOG_ERR("creating file descriptor offset map failed");
311+
ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
312+
goto err_free_nodeset_str_buf;
313+
}
314+
264315
*provider = os_provider;
265316

266317
return UMF_RESULT_SUCCESS;
267318

319+
err_free_nodeset_str_buf:
320+
umf_ba_global_free(os_provider->nodeset_str_buf);
268321
err_destroy_hwloc_topology:
269322
hwloc_topology_destroy(os_provider->topo);
270323
err_free_os_provider:
@@ -279,6 +332,9 @@ static void os_finalize(void *provider) {
279332
}
280333

281334
os_memory_provider_t *os_provider = provider;
335+
336+
critnib_delete(os_provider->fd_offset_map);
337+
282338
if (os_provider->nodeset_str_buf) {
283339
umf_ba_global_free(os_provider->nodeset_str_buf);
284340
}
@@ -334,7 +390,9 @@ static inline void assert_is_page_aligned(uintptr_t ptr, size_t page_size) {
334390
}
335391

336392
static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment,
337-
size_t page_size, int prot, void **out_addr) {
393+
size_t page_size, int prot, int flag, int fd,
394+
size_t max_fd_size, void **out_addr,
395+
size_t *fd_size) {
338396
assert(out_addr);
339397

340398
size_t extended_length = length;
@@ -347,8 +405,20 @@ static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment,
347405
extended_length += alignment;
348406
}
349407

350-
void *ptr = os_mmap(hint_addr, extended_length, prot);
408+
size_t fd_offset = 0;
409+
410+
if (fd > 0) {
411+
fd_offset = *fd_size;
412+
*fd_size += extended_length;
413+
if (*fd_size > max_fd_size) {
414+
LOG_ERR("cannot grow a file size beyond %zu", max_fd_size);
415+
return -1;
416+
}
417+
}
418+
419+
void *ptr = os_mmap(hint_addr, extended_length, prot, flag, fd, fd_offset);
351420
if (ptr == NULL) {
421+
LOG_PDEBUG("memory mapping failed");
352422
return -1;
353423
}
354424

@@ -414,15 +484,17 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
414484
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
415485
}
416486

417-
int protection = os_provider->protection;
487+
size_t fd_offset = os_provider->size_fd; // needed for critnib_insert()
418488

419489
void *addr = NULL;
420490
errno = 0;
421-
ret = os_mmap_aligned(NULL, size, alignment, page_size, protection, &addr);
491+
ret = os_mmap_aligned(NULL, size, alignment, page_size,
492+
os_provider->protection, os_provider->visibility,
493+
os_provider->fd, os_provider->max_size_fd, &addr,
494+
&os_provider->size_fd);
422495
if (ret) {
423496
os_store_last_native_error(UMF_OS_RESULT_ERROR_ALLOC_FAILED, errno);
424497
LOG_PERR("memory allocation failed");
425-
426498
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC;
427499
}
428500

@@ -432,7 +504,6 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
432504
LOG_ERR("allocated address 0x%llx is not aligned to %zu (0x%zx) "
433505
"bytes",
434506
(unsigned long long)addr, alignment, alignment);
435-
436507
goto err_unmap;
437508
}
438509

@@ -463,6 +534,18 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
463534
}
464535
}
465536

537+
if (os_provider->fd > 0) {
538+
// store (fd_offset + 1) to be able to store fd_offset == 0
539+
ret =
540+
critnib_insert(os_provider->fd_offset_map, (uintptr_t)addr,
541+
(void *)(uintptr_t)(fd_offset + 1), 0 /* update */);
542+
if (ret) {
543+
LOG_ERR("os_alloc(): inserting a value to the file descriptor "
544+
"offset map failed (addr=%p, offset=%zu)",
545+
addr, fd_offset);
546+
}
547+
}
548+
466549
*resultPtr = addr;
467550

468551
return UMF_RESULT_SUCCESS;
@@ -477,6 +560,12 @@ static umf_result_t os_free(void *provider, void *ptr, size_t size) {
477560
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
478561
}
479562

563+
os_memory_provider_t *os_provider = (os_memory_provider_t *)provider;
564+
565+
if (os_provider->fd > 0) {
566+
critnib_remove(os_provider->fd_offset_map, (uintptr_t)ptr);
567+
}
568+
480569
errno = 0;
481570
int ret = os_munmap(ptr, size);
482571
// ignore error when size == 0
@@ -583,21 +672,54 @@ static const char *os_get_name(void *provider) {
583672

584673
static umf_result_t os_allocation_split(void *provider, void *ptr,
585674
size_t totalSize, size_t firstSize) {
586-
(void)provider;
587-
(void)ptr;
588675
(void)totalSize;
589-
(void)firstSize;
590-
// nop
676+
677+
os_memory_provider_t *os_provider = (os_memory_provider_t *)provider;
678+
if (os_provider->fd <= 0) {
679+
return UMF_RESULT_SUCCESS;
680+
}
681+
682+
void *value = critnib_get(os_provider->fd_offset_map, (uintptr_t)ptr);
683+
if (value == NULL) {
684+
LOG_ERR("os_allocation_split(): getting a value from the file "
685+
"descriptor offset map failed (addr=%p)",
686+
ptr);
687+
return UMF_RESULT_ERROR_UNKNOWN;
688+
} else {
689+
uintptr_t new_key = (uintptr_t)ptr + firstSize;
690+
void *new_value = (void *)((uintptr_t)value + firstSize);
691+
int ret = critnib_insert(os_provider->fd_offset_map, new_key, new_value,
692+
0 /* update */);
693+
if (ret) {
694+
LOG_ERR("os_allocation_split(): inserting a value to the file "
695+
"descriptor offset map failed (addr=%p, offset=%zu)",
696+
(void *)new_key, (size_t)new_value - 1);
697+
return UMF_RESULT_ERROR_UNKNOWN;
698+
}
699+
}
700+
591701
return UMF_RESULT_SUCCESS;
592702
}
593703

594704
static umf_result_t os_allocation_merge(void *provider, void *lowPtr,
595705
void *highPtr, size_t totalSize) {
596-
(void)provider;
597706
(void)lowPtr;
598-
(void)highPtr;
599707
(void)totalSize;
600-
// nop
708+
709+
os_memory_provider_t *os_provider = (os_memory_provider_t *)provider;
710+
if (os_provider->fd <= 0) {
711+
return UMF_RESULT_SUCCESS;
712+
}
713+
714+
void *value =
715+
critnib_remove(os_provider->fd_offset_map, (uintptr_t)highPtr);
716+
if (value == NULL) {
717+
LOG_ERR("os_allocation_merge(): removing a value from the file "
718+
"descriptor offset map failed (addr=%p)",
719+
highPtr);
720+
return UMF_RESULT_ERROR_UNKNOWN;
721+
}
722+
601723
return UMF_RESULT_SUCCESS;
602724
}
603725

src/provider/provider_os_memory_internal.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@ umf_result_t os_translate_flags(unsigned in_flags, unsigned max,
2828
umf_result_t os_translate_mem_protection_flags(unsigned in_protection,
2929
unsigned *out_protection);
3030

31-
void *os_mmap(void *hint_addr, size_t length, int prot);
31+
umf_result_t os_translate_mem_visibility_flag(unsigned in_flag,
32+
unsigned *out_flag);
33+
34+
int os_create_anonymous_fd(unsigned translated_memory_flag);
35+
36+
size_t get_max_file_size(void);
37+
38+
int os_set_file_size(int fd, size_t size);
39+
40+
void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd,
41+
size_t fd_offset);
3242

3343
int os_munmap(void *addr, size_t length);
3444

0 commit comments

Comments
 (0)