Skip to content

Commit 0823eaf

Browse files
committed
Enable IPC cache for Open/Close functions
1 parent 8d58958 commit 0823eaf

File tree

8 files changed

+397
-54
lines changed

8 files changed

+397
-54
lines changed

src/CMakeLists.txt

+2
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

+2
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

+204
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
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+
#include "ipc_cache.h"
10+
11+
#include <stdbool.h>
12+
13+
#include "base_alloc_global.h"
14+
#include "utils_common.h"
15+
#include "utils_concurrency.h"
16+
#include "utils_log.h"
17+
#include "utlist.h"
18+
19+
struct ipc_handle_cache_entry_t;
20+
21+
typedef struct ipc_handle_cache_entry_t *hash_map_t;
22+
typedef struct ipc_handle_cache_entry_t *lru_list_t;
23+
24+
typedef struct ipc_handle_cache_entry_t {
25+
UT_hash_handle hh;
26+
struct ipc_handle_cache_entry_t *next, *prev;
27+
ipc_mapped_handle_cache_key_t key;
28+
uint64_t ref_count;
29+
uint64_t handle_id;
30+
hash_map_t
31+
*hash_table; // pointer to the hash table to which the entry belongs
32+
ipc_mapped_handle_cache_value_t value;
33+
} ipc_handle_cache_entry_t;
34+
35+
typedef struct ipc_handle_mapped_cache_global_t {
36+
utils_mutex_t cache_lock;
37+
umf_ba_pool_t *cache_allocator;
38+
size_t max_size;
39+
size_t cur_size;
40+
lru_list_t lru_list;
41+
} ipc_handle_mapped_cache_global_t;
42+
43+
typedef struct ipc_handle_mapped_cache_t {
44+
ipc_handle_mapped_cache_global_t *global;
45+
hash_map_t hash_table;
46+
ipc_handle_mapped_cache_eviction_cb_t eviction_cb;
47+
} ipc_handle_mapped_cache_t;
48+
49+
ipc_handle_mapped_cache_global_t *IPC_MAPPED_CACHE_GLOBAL = NULL;
50+
51+
void umfIpcCacheInit(void) {
52+
ipc_handle_mapped_cache_global_t *cache_global =
53+
umf_ba_global_alloc(sizeof(*cache_global));
54+
if (!cache_global) {
55+
return;
56+
}
57+
58+
if (NULL == utils_mutex_init(&(cache_global->cache_lock))) {
59+
LOG_ERR("Failed to initialize mutex for the IPC cache");
60+
umf_ba_global_free(cache_global);
61+
return;
62+
}
63+
64+
cache_global->cache_allocator =
65+
umf_ba_create(sizeof(ipc_handle_cache_entry_t));
66+
if (!cache_global->cache_allocator) {
67+
LOG_ERR("Failed to create IPC cache allocator");
68+
umf_ba_global_free(cache_global);
69+
return;
70+
}
71+
72+
cache_global->max_size = 0;
73+
cache_global->cur_size = 0;
74+
cache_global->lru_list = NULL;
75+
76+
IPC_MAPPED_CACHE_GLOBAL = cache_global;
77+
}
78+
79+
static size_t getGlobalLruListSize(lru_list_t lru_list) {
80+
size_t size = 0;
81+
ipc_handle_cache_entry_t *tmp;
82+
DL_COUNT(lru_list, tmp, size);
83+
return size;
84+
}
85+
86+
void umfIpcCacheTearDown(void) {
87+
ipc_handle_mapped_cache_global_t *cache_global = IPC_MAPPED_CACHE_GLOBAL;
88+
IPC_MAPPED_CACHE_GLOBAL = NULL;
89+
90+
if (!cache_global) {
91+
return;
92+
}
93+
94+
assert(cache_global->cur_size == 0);
95+
assert(getGlobalLruListSize(cache_global->lru_list) == 0);
96+
97+
umf_ba_destroy(cache_global->cache_allocator);
98+
umf_ba_global_free(cache_global);
99+
}
100+
101+
ipc_handle_mapped_cache_handle_t umfIpcHandleMappedCacheCreate(
102+
ipc_handle_mapped_cache_eviction_cb_t eviction_cb) {
103+
ipc_handle_mapped_cache_t *cache = umf_ba_global_alloc(sizeof(*cache));
104+
105+
if (!cache) {
106+
return NULL;
107+
}
108+
109+
cache->global = IPC_MAPPED_CACHE_GLOBAL;
110+
cache->hash_table = NULL;
111+
cache->eviction_cb = eviction_cb;
112+
113+
return cache;
114+
}
115+
116+
void umfIpcHandleMappedCacheDestroy(ipc_handle_mapped_cache_handle_t cache) {
117+
ipc_handle_cache_entry_t *entry, *tmp;
118+
HASH_ITER(hh, cache->hash_table, entry, tmp) {
119+
DL_DELETE(cache->global->lru_list, entry);
120+
HASH_DEL(cache->hash_table, entry);
121+
cache->global->cur_size -= 1;
122+
cache->eviction_cb(&entry->key, &entry->value);
123+
umf_ba_free(cache->global->cache_allocator, entry);
124+
}
125+
HASH_CLEAR(hh, cache->hash_table);
126+
127+
umf_ba_global_free(cache);
128+
}
129+
130+
umf_result_t
131+
umfIpcHandleMappedCacheGet(ipc_handle_mapped_cache_handle_t cache,
132+
const ipc_mapped_handle_cache_key_t *key,
133+
uint64_t handle_id,
134+
ipc_mapped_handle_cache_value_t **retEntry) {
135+
ipc_handle_cache_entry_t *entry = NULL;
136+
umf_result_t ret = UMF_RESULT_SUCCESS;
137+
bool evicted = false;
138+
ipc_mapped_handle_cache_value_t evicted_value;
139+
140+
if (!cache) {
141+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
142+
}
143+
144+
utils_mutex_lock(&(cache->global->cache_lock));
145+
146+
HASH_FIND(hh, cache->hash_table, key, sizeof(*key), entry);
147+
if (entry && entry->handle_id == handle_id) { // cache hit
148+
// update frequency list
149+
DL_DELETE(cache->global->lru_list, entry);
150+
DL_PREPEND(cache->global->lru_list, entry);
151+
} else { //cache miss
152+
// Look for eviction candidate
153+
if (entry == NULL && cache->global->max_size != 0 &&
154+
cache->global->cur_size >= cache->global->max_size) {
155+
entry = cache->global->lru_list->prev;
156+
}
157+
158+
if (entry) { // we have eviction candidate
159+
DL_DELETE(cache->global->lru_list, entry);
160+
HASH_DEL(*(entry->hash_table), entry);
161+
cache->global->cur_size -= 1;
162+
evicted_value.mapped_base_ptr = entry->value.mapped_base_ptr;
163+
evicted_value.mapped_size = entry->value.mapped_size;
164+
evicted = true;
165+
} else {
166+
entry = umf_ba_alloc(cache->global->cache_allocator);
167+
if (!entry) {
168+
ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
169+
goto exit;
170+
}
171+
if (NULL == utils_mutex_init(&(entry->value.mmap_lock))) {
172+
LOG_ERR("Failed to initialize mutex for the IPC cache entry");
173+
umf_ba_global_free(entry);
174+
ret = UMF_RESULT_ERROR_UNKNOWN;
175+
goto exit;
176+
}
177+
}
178+
179+
entry->key = *key;
180+
entry->ref_count = 0;
181+
entry->handle_id = handle_id;
182+
entry->hash_table = &cache->hash_table;
183+
entry->value.mapped_size = 0;
184+
entry->value.mapped_base_ptr = NULL;
185+
186+
HASH_ADD(hh, cache->hash_table, key, sizeof(entry->key), entry);
187+
DL_PREPEND(cache->global->lru_list, entry);
188+
cache->global->cur_size += 1;
189+
}
190+
191+
exit:
192+
if (ret == UMF_RESULT_SUCCESS) {
193+
utils_atomic_increment(&entry->ref_count);
194+
*retEntry = &entry->value;
195+
}
196+
197+
utils_mutex_unlock(&(cache->global->cache_lock));
198+
199+
if (evicted) {
200+
cache->eviction_cb(key, &evicted_value);
201+
}
202+
203+
return ret;
204+
}

src/ipc_cache.h

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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 "base_alloc.h"
16+
#include "uthash.h"
17+
#include "utils_concurrency.h"
18+
19+
typedef struct ipc_mapped_handle_cache_key_t {
20+
void *remote_base_ptr;
21+
umf_memory_provider_handle_t local_provider;
22+
int remote_pid;
23+
} ipc_mapped_handle_cache_key_t;
24+
25+
typedef struct ipc_mapped_handle_cache_value_t {
26+
void *mapped_base_ptr;
27+
size_t mapped_size;
28+
utils_mutex_t mmap_lock;
29+
} ipc_mapped_handle_cache_value_t;
30+
31+
struct ipc_handle_mapped_cache_t;
32+
33+
typedef struct ipc_handle_mapped_cache_t *ipc_handle_mapped_cache_handle_t;
34+
35+
void umfIpcCacheInit(void);
36+
void umfIpcCacheTearDown(void);
37+
38+
// define pointer to the eviction callback function
39+
typedef void (*ipc_handle_mapped_cache_eviction_cb_t)(
40+
const ipc_mapped_handle_cache_key_t *key,
41+
const ipc_mapped_handle_cache_value_t *value);
42+
43+
ipc_handle_mapped_cache_handle_t umfIpcHandleMappedCacheCreate(
44+
ipc_handle_mapped_cache_eviction_cb_t eviction_cb);
45+
46+
void umfIpcHandleMappedCacheDestroy(ipc_handle_mapped_cache_handle_t cache);
47+
48+
umf_result_t
49+
umfIpcHandleMappedCacheGet(ipc_handle_mapped_cache_handle_t cache,
50+
const ipc_mapped_handle_cache_key_t *key,
51+
uint64_t handle_id,
52+
ipc_mapped_handle_cache_value_t **retEntry);
53+
54+
#endif /* UMF_IPC_CACHE_H */

src/ipc_internal.h

+4-2
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 handle ID
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

+3
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,6 +26,7 @@ int umfInit(void) {
2526
if (utils_fetch_and_add64(&umfRefCount, 1) == 0) {
2627
utils_log_init();
2728
TRACKER = umfMemoryTrackerCreate();
29+
umfIpcCacheInit();
2830
}
2931

3032
return (TRACKER) ? 0 : -1;
@@ -39,6 +41,7 @@ void umfTearDown(void) {
3941
umfMemspaceLowestLatencyDestroy();
4042
umfDestroyTopology();
4143
#endif
44+
umfIpcCacheTearDown();
4245
// make sure TRACKER is not used after being destroyed
4346
umf_memory_tracker_handle_t t = TRACKER;
4447
TRACKER = NULL;

0 commit comments

Comments
 (0)