Skip to content

Commit 4fd30e3

Browse files
committed
Enable IPC cache for Open/Close functions
1 parent bb9f209 commit 4fd30e3

File tree

8 files changed

+363
-52
lines changed

8 files changed

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

src/ipc_cache.h

Lines changed: 54 additions & 0 deletions
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+
ipc_handle_mapped_cache_handle_t umfIpcHandleMappedCacheCreate(void);
39+
40+
void umfIpcHandleMappedCacheDestroy(ipc_handle_mapped_cache_handle_t cache);
41+
42+
// define pointer to the eviction callback function
43+
typedef void (*ipc_handle_mapped_cache_eviction_cb_t)(
44+
const ipc_mapped_handle_cache_key_t *key,
45+
const ipc_mapped_handle_cache_value_t *value);
46+
47+
umf_result_t
48+
umfIpcHandleMappedCacheGet(ipc_handle_mapped_cache_handle_t cache,
49+
const ipc_mapped_handle_cache_key_t *key,
50+
uint64_t handle_id,
51+
ipc_handle_mapped_cache_eviction_cb_t eviction_cb,
52+
ipc_mapped_handle_cache_value_t **retEntry);
53+
54+
#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 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

Lines changed: 3 additions & 0 deletions
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)