Skip to content

Commit d517433

Browse files
committed
Enable IPC cache for Open/Close functions
1 parent 60c1b2c commit d517433

File tree

8 files changed

+448
-75
lines changed

8 files changed

+448
-75
lines changed

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ set(UMF_SOURCES
104104
${BA_SOURCES}
105105
libumf.c
106106
ipc.c
107+
ipc_cache.c
107108
memory_pool.c
108109
memory_provider.c
109110
memory_provider_get_last_failed.c
@@ -247,6 +248,7 @@ target_include_directories(
247248
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/provider>
248249
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/memspaces>
249250
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/memtargets>
251+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/uthash>
250252
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
251253

252254
install(TARGETS umf EXPORT ${PROJECT_NAME}-targets)

src/ipc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ umf_result_t umfGetIPCHandle(const void *ptr, umf_ipc_handle_t *umfIPCHandle,
9090
return ret;
9191
}
9292

93+
// ipcData->handle_id is filled by tracking provider
94+
ipcData->base = allocInfo.base;
9395
ipcData->pid = utils_getpid();
9496
ipcData->baseSize = allocInfo.baseSize;
9597
ipcData->offset = (uintptr_t)ptr - (uintptr_t)allocInfo.base;

src/ipc_cache.c

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
/*
2+
*
3+
* Copyright (C) 2024 Intel Corporation
4+
*
5+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
6+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
*
8+
*/
9+
10+
#include <stdbool.h>
11+
12+
#include "base_alloc_global.h"
13+
#include "ipc_cache.h"
14+
#include "uthash.h"
15+
#include "utils_common.h"
16+
#include "utils_concurrency.h"
17+
#include "utils_log.h"
18+
#include "utlist.h"
19+
20+
struct ipc_handle_cache_entry_t;
21+
22+
typedef struct ipc_handle_cache_entry_t *hash_map_t;
23+
typedef struct ipc_handle_cache_entry_t *lru_list_t;
24+
25+
typedef struct ipc_handle_cache_entry_t {
26+
UT_hash_handle hh;
27+
struct ipc_handle_cache_entry_t *next, *prev;
28+
ipc_mapped_handle_cache_key_t key;
29+
uint64_t ref_count;
30+
uint64_t handle_id;
31+
hash_map_t
32+
*hash_table; // pointer to the hash table to which the entry belongs
33+
ipc_mapped_handle_cache_value_t value;
34+
} ipc_handle_cache_entry_t;
35+
36+
typedef struct ipc_mapped_handle_cache_global_t {
37+
utils_mutex_t cache_lock;
38+
umf_ba_pool_t *cache_allocator;
39+
size_t max_size;
40+
size_t cur_size;
41+
lru_list_t lru_list;
42+
} ipc_mapped_handle_cache_global_t;
43+
44+
typedef struct ipc_mapped_handle_cache_t {
45+
ipc_mapped_handle_cache_global_t *global;
46+
hash_map_t hash_table;
47+
ipc_mapped_handle_cache_eviction_cb_t eviction_cb;
48+
} ipc_mapped_handle_cache_t;
49+
50+
ipc_mapped_handle_cache_global_t *IPC_MAPPED_CACHE_GLOBAL = NULL;
51+
52+
umf_result_t umfIpcCacheGlobalInit(void) {
53+
ipc_mapped_handle_cache_global_t *cache_global =
54+
umf_ba_global_alloc(sizeof(*cache_global));
55+
if (!cache_global) {
56+
LOG_ERR("Failed to allocate memory for the IPC cache global data");
57+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
58+
}
59+
60+
if (NULL == utils_mutex_init(&(cache_global->cache_lock))) {
61+
LOG_ERR("Failed to initialize mutex for the IPC global cache");
62+
umf_ba_global_free(cache_global);
63+
return UMF_RESULT_ERROR_UNKNOWN;
64+
}
65+
66+
cache_global->cache_allocator =
67+
umf_ba_create(sizeof(ipc_handle_cache_entry_t));
68+
if (!cache_global->cache_allocator) {
69+
LOG_ERR("Failed to create IPC cache allocator");
70+
umf_ba_global_free(cache_global);
71+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
72+
}
73+
74+
cache_global->max_size = 0;
75+
cache_global->cur_size = 0;
76+
cache_global->lru_list = NULL;
77+
78+
IPC_MAPPED_CACHE_GLOBAL = cache_global;
79+
80+
return UMF_RESULT_SUCCESS;
81+
}
82+
83+
static size_t getGlobalLruListSize(lru_list_t lru_list) {
84+
size_t size = 0;
85+
ipc_handle_cache_entry_t *tmp;
86+
DL_COUNT(lru_list, tmp, size);
87+
return size;
88+
}
89+
90+
void umfIpcCacheGlobalTearDown(void) {
91+
ipc_mapped_handle_cache_global_t *cache_global = IPC_MAPPED_CACHE_GLOBAL;
92+
IPC_MAPPED_CACHE_GLOBAL = NULL;
93+
94+
if (!cache_global) {
95+
return;
96+
}
97+
98+
assert(cache_global->cur_size == 0);
99+
assert(getGlobalLruListSize(cache_global->lru_list) == 0);
100+
101+
umf_ba_destroy(cache_global->cache_allocator);
102+
umf_ba_global_free(cache_global);
103+
}
104+
105+
ipc_mapped_handle_cache_handle_t umfIpcHandleMappedCacheCreate(
106+
ipc_mapped_handle_cache_eviction_cb_t eviction_cb) {
107+
if (eviction_cb == NULL) {
108+
LOG_ERR("Eviction callback is NULL");
109+
return NULL;
110+
}
111+
112+
ipc_mapped_handle_cache_t *cache = umf_ba_global_alloc(sizeof(*cache));
113+
114+
if (!cache) {
115+
LOG_ERR("Failed to allocate memory for the IPC cache");
116+
return NULL;
117+
}
118+
119+
assert(IPC_MAPPED_CACHE_GLOBAL != NULL);
120+
121+
cache->global = IPC_MAPPED_CACHE_GLOBAL;
122+
cache->hash_table = NULL;
123+
cache->eviction_cb = eviction_cb;
124+
125+
return cache;
126+
}
127+
128+
void umfIpcHandleMappedCacheDestroy(ipc_mapped_handle_cache_handle_t cache) {
129+
ipc_handle_cache_entry_t *entry, *tmp;
130+
HASH_ITER(hh, cache->hash_table, entry, tmp) {
131+
DL_DELETE(cache->global->lru_list, entry);
132+
HASH_DEL(cache->hash_table, entry);
133+
cache->global->cur_size -= 1;
134+
cache->eviction_cb(&entry->key, &entry->value);
135+
umf_ba_free(cache->global->cache_allocator, entry);
136+
}
137+
HASH_CLEAR(hh, cache->hash_table);
138+
139+
umf_ba_global_free(cache);
140+
}
141+
142+
umf_result_t
143+
umfIpcHandleMappedCacheGet(ipc_mapped_handle_cache_handle_t cache,
144+
const ipc_mapped_handle_cache_key_t *key,
145+
uint64_t handle_id,
146+
ipc_mapped_handle_cache_value_t **retEntry) {
147+
ipc_handle_cache_entry_t *entry = NULL;
148+
umf_result_t ret = UMF_RESULT_SUCCESS;
149+
bool evicted = false;
150+
ipc_mapped_handle_cache_value_t evicted_value;
151+
152+
if (!cache || !key || !retEntry) {
153+
LOG_ERR("Some arguments are NULL, cache=%p, key=%p, retEntry=%p",
154+
(void *)cache, (const void *)key, (void *)retEntry);
155+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
156+
}
157+
158+
assert(cache->global != NULL);
159+
160+
utils_mutex_lock(&(cache->global->cache_lock));
161+
162+
HASH_FIND(hh, cache->hash_table, key, sizeof(*key), entry);
163+
if (entry && entry->handle_id == handle_id) { // cache hit
164+
// update frequency list
165+
// remove the entry from the current position
166+
DL_DELETE(cache->global->lru_list, entry);
167+
// add the entry to the head of the list
168+
DL_PREPEND(cache->global->lru_list, entry);
169+
} else { //cache miss
170+
// Look for eviction candidate
171+
if (entry == NULL && cache->global->max_size != 0 &&
172+
cache->global->cur_size >= cache->global->max_size) {
173+
// If max_size is set and the cache is full, evict the least recently used entry.
174+
entry = cache->global->lru_list->prev;
175+
}
176+
177+
if (entry) { // we have eviction candidate
178+
// remove the entry from the frequency list
179+
DL_DELETE(cache->global->lru_list, entry);
180+
// remove the entry from the hash table it belongs to
181+
HASH_DEL(*(entry->hash_table), entry);
182+
cache->global->cur_size -= 1;
183+
evicted_value.mapped_base_ptr = entry->value.mapped_base_ptr;
184+
evicted_value.mapped_size = entry->value.mapped_size;
185+
evicted = true;
186+
} else { // allocate the new entry
187+
entry = umf_ba_alloc(cache->global->cache_allocator);
188+
if (!entry) {
189+
ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
190+
LOG_ERR("Failed to allocate memory for a new IPC cache entry");
191+
goto exit;
192+
}
193+
if (NULL == utils_mutex_init(&(entry->value.mmap_lock))) {
194+
LOG_ERR("Failed to initialize mutex for the IPC cache entry");
195+
umf_ba_global_free(entry);
196+
ret = UMF_RESULT_ERROR_UNKNOWN;
197+
goto exit;
198+
}
199+
}
200+
201+
entry->key = *key;
202+
entry->ref_count = 0;
203+
entry->handle_id = handle_id;
204+
entry->hash_table = &cache->hash_table;
205+
entry->value.mapped_size = 0;
206+
entry->value.mapped_base_ptr = NULL;
207+
208+
HASH_ADD(hh, cache->hash_table, key, sizeof(entry->key), entry);
209+
DL_PREPEND(cache->global->lru_list, entry);
210+
cache->global->cur_size += 1;
211+
}
212+
213+
exit:
214+
if (ret == UMF_RESULT_SUCCESS) {
215+
utils_atomic_increment(&entry->ref_count);
216+
*retEntry = &entry->value;
217+
}
218+
219+
utils_mutex_unlock(&(cache->global->cache_lock));
220+
221+
if (evicted) {
222+
cache->eviction_cb(key, &evicted_value);
223+
}
224+
225+
return ret;
226+
}

src/ipc_cache.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
*
3+
* Copyright (C) 2024 Intel Corporation
4+
*
5+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
6+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
*
8+
*/
9+
10+
#ifndef UMF_IPC_CACHE_H
11+
#define UMF_IPC_CACHE_H 1
12+
13+
#include <umf/memory_provider.h>
14+
15+
#include "utils_concurrency.h"
16+
17+
typedef struct ipc_mapped_handle_cache_key_t {
18+
void *remote_base_ptr;
19+
umf_memory_provider_handle_t local_provider;
20+
int remote_pid;
21+
} ipc_mapped_handle_cache_key_t;
22+
23+
typedef struct ipc_mapped_handle_cache_value_t {
24+
void *mapped_base_ptr;
25+
size_t mapped_size;
26+
utils_mutex_t mmap_lock;
27+
} ipc_mapped_handle_cache_value_t;
28+
29+
struct ipc_mapped_handle_cache_t;
30+
31+
typedef struct ipc_mapped_handle_cache_t *ipc_mapped_handle_cache_handle_t;
32+
33+
umf_result_t umfIpcCacheGlobalInit(void);
34+
void umfIpcCacheGlobalTearDown(void);
35+
36+
// define pointer to the eviction callback function
37+
typedef void (*ipc_mapped_handle_cache_eviction_cb_t)(
38+
const ipc_mapped_handle_cache_key_t *key,
39+
const ipc_mapped_handle_cache_value_t *value);
40+
41+
ipc_mapped_handle_cache_handle_t umfIpcHandleMappedCacheCreate(
42+
ipc_mapped_handle_cache_eviction_cb_t eviction_cb);
43+
44+
void umfIpcHandleMappedCacheDestroy(ipc_mapped_handle_cache_handle_t cache);
45+
46+
umf_result_t
47+
umfIpcHandleMappedCacheGet(ipc_mapped_handle_cache_handle_t cache,
48+
const ipc_mapped_handle_cache_key_t *key,
49+
uint64_t handle_id,
50+
ipc_mapped_handle_cache_value_t **retEntry);
51+
52+
#endif /* UMF_IPC_CACHE_H */

src/ipc_internal.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ extern "C" {
2121
// providerIpcData is a Flexible Array Member because its size varies
2222
// depending on the provider.
2323
typedef struct umf_ipc_data_t {
24-
int pid; // process ID of the process that allocated the memory
25-
size_t baseSize; // size of base (coarse-grain) allocation
24+
uint64_t handle_id; // unique ID of this handle
25+
void *base; // base address of the memory
26+
int pid; // process ID of the process that allocated the memory
27+
size_t baseSize; // size of base (coarse-grain) allocation
2628
uint64_t offset;
2729
char providerIpcData[];
2830
} umf_ipc_data_t;

src/libumf.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stddef.h>
1111

1212
#include "base_alloc_global.h"
13+
#include "ipc_cache.h"
1314
#include "memspace_internal.h"
1415
#include "provider_tracking.h"
1516
#include "utils_log.h"
@@ -25,9 +26,18 @@ int umfInit(void) {
2526
if (utils_fetch_and_add64(&umfRefCount, 1) == 0) {
2627
utils_log_init();
2728
TRACKER = umfMemoryTrackerCreate();
29+
if (!TRACKER) {
30+
LOG_ERR("Failed to create memory tracker");
31+
return -1;
32+
}
33+
umf_result_t umf_result = umfIpcCacheGlobalInit();
34+
if (umf_result != UMF_RESULT_SUCCESS) {
35+
LOG_ERR("Failed to initialize IPC cache");
36+
return -1;
37+
}
2838
}
2939

30-
return (TRACKER) ? 0 : -1;
40+
return 0;
3141
}
3242

3343
void umfTearDown(void) {
@@ -39,6 +49,7 @@ void umfTearDown(void) {
3949
umfMemspaceLowestLatencyDestroy();
4050
umfDestroyTopology();
4151
#endif
52+
umfIpcCacheGlobalTearDown();
4253
// make sure TRACKER is not used after being destroyed
4354
umf_memory_tracker_handle_t t = TRACKER;
4455
TRACKER = NULL;

0 commit comments

Comments
 (0)