Skip to content

Commit 785c710

Browse files
authored
Merge pull request #998 from vinser52/svinogra_ipc_cache
Implement size limit for the cache of opened IPC handles
2 parents 53a318f + 5f4336d commit 785c710

18 files changed

+599
-179
lines changed

.cmake-format

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ with section("parse"):
2626
'kwargs': {
2727
'NAME': '*',
2828
'SRCS': '*',
29-
'LIBS': '*'}},
29+
'LIBS': '*',
30+
'ENVS': '*'}},
3031
'add_umf_library': {
3132
"pargs": 0,
3233
"flags": [],

.github/workflows/reusable_compatibility.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,11 @@ jobs:
9494
9595
- name: Run "tag" UMF tests with latest UMF libs (warnings enabled)
9696
working-directory: ${{github.workspace}}/tag_version/build
97+
# GTEST_FILTER is used below to skip test that is not compatible
9798
run: >
9899
UMF_LOG="level:warning;flush:debug;output:stderr;pid:no"
99100
LD_LIBRARY_PATH=${{github.workspace}}/latest_version/build/lib/
101+
GTEST_FILTER="-*umfIpcTest.GetPoolByOpenedHandle*"
100102
ctest --verbose
101103
102104
windows:
@@ -181,6 +183,7 @@ jobs:
181183
working-directory: ${{github.workspace}}/tag_version/build
182184
run: |
183185
$env:UMF_LOG="level:warning;flush:debug;output:stderr;pid:no"
186+
$env:GTEST_FILTER="-*umfIpcTest.GetPoolByOpenedHandle*"
184187
cp ${{github.workspace}}/latest_version/build/bin/Debug/umf.dll ${{github.workspace}}/tag_version/build/bin/Debug/umf.dll
185188
ctest -C Debug --verbose
186189
@@ -230,8 +233,10 @@ jobs:
230233
231234
- name: Run "tag" UMF tests
232235
working-directory: ${{github.workspace}}/tag_version/build
233-
run: |
234-
LD_LIBRARY_PATH=${{github.workspace}}/tag_version/build/lib/ ctest --output-on-failure
236+
run: >
237+
LD_LIBRARY_PATH=${{github.workspace}}/tag_version/build/lib/
238+
GTEST_FILTER="-*umfIpcTest.GetPoolByOpenedHandle*"
239+
ctest --output-on-failure
235240
236241
- name: Checkout latest UMF version
237242
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
@@ -266,4 +271,5 @@ jobs:
266271
run: >
267272
UMF_LOG="level:warning;flush:debug;output:stderr;pid:no"
268273
LD_LIBRARY_PATH=${{github.workspace}}/latest_version/build/lib/
274+
GTEST_FILTER="-*umfIpcTest.GetPoolByOpenedHandle*"
269275
ctest --verbose -E "not_impl"

docs/config/api.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,26 @@ IPC API allows retrieving IPC handles for the memory buffers allocated from
168168
UMF memory pools. The memory provider used by the pool should support IPC
169169
operations for this API to work. Otherwise IPC APIs return an error.
170170

171+
IPC caching
172+
------------------------------------------
173+
174+
UMF employs IPC caching to avoid multiple IPC handles being created for the same
175+
coarse-grain memory region allocated by the memory provider. UMF guarantees that
176+
for each coarse-grain memory region allocated by the memory provider, only one
177+
IPC handle is created when the :any:`umfGetIPCHandle` function is called. All
178+
subsequent calls to the :any:`umfGetIPCHandle` function for the pointer to the
179+
same memory region will return the entry from the cache.
180+
181+
The same is true for the :any:`umfOpenIPCHandle` function. The actual mapping
182+
of the IPC handle to the virtual address space is created only once, and all
183+
subsequent calls to open the same IPC handle will return the entry from the cache.
184+
The size of the cache for opened IPC handles is controlled by the ``UMF_MAX_OPENED_IPC_HANDLES``
185+
environment variable. By default, the cache size is unlimited. However, if the environment
186+
variable is set and the cache size exceeds the limit, old items will be evicted. UMF tracks
187+
the ref count for each entry in the cache and can evict only items with the ref count equal to 0.
188+
The ref count is increased when the :any:`umfOpenIPCHandle` function is called and decreased
189+
when the :any:`umfCloseIPCHandle` function is called for the corresponding IPC handle.
190+
171191
.. _ipc-api:
172192

173193
IPC API

src/ipc.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,19 +146,15 @@ umf_result_t umfOpenIPCHandle(umf_ipc_handler_handle_t hIPCHandler,
146146
}
147147

148148
umf_result_t umfCloseIPCHandle(void *ptr) {
149-
umf_alloc_info_t allocInfo;
150-
umf_result_t ret = umfMemoryTrackerGetAllocInfo(ptr, &allocInfo);
149+
umf_ipc_info_t ipcInfo;
150+
umf_result_t ret = umfMemoryTrackerGetIpcInfo(ptr, &ipcInfo);
151151
if (ret != UMF_RESULT_SUCCESS) {
152-
LOG_ERR("cannot get alloc info for ptr = %p.", ptr);
152+
LOG_ERR("cannot get IPC info for ptr = %p.", ptr);
153153
return ret;
154154
}
155155

156-
// We cannot use umfPoolGetMemoryProvider function because it returns
157-
// upstream provider but we need tracking one
158-
umf_memory_provider_handle_t hProvider = allocInfo.pool->provider;
159-
160-
return umfMemoryProviderCloseIPCHandle(hProvider, allocInfo.base,
161-
allocInfo.baseSize);
156+
return umfMemoryProviderCloseIPCHandle(ipcInfo.provider, ipcInfo.base,
157+
ipcInfo.baseSize);
162158
}
163159

164160
umf_result_t umfPoolGetIPCHandler(umf_memory_pool_handle_t hPool,

src/ipc_cache.c

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,22 @@ typedef struct ipc_opened_cache_t {
5454

5555
ipc_opened_cache_global_t *IPC_OPENED_CACHE_GLOBAL = NULL;
5656

57+
// Returns value of the UMF_MAX_OPENED_IPC_HANDLES environment variable
58+
// or 0 if it is not set.
59+
static size_t umfIpcCacheGlobalInitMaxOpenedHandles(void) {
60+
const char *max_size_str = getenv("UMF_MAX_OPENED_IPC_HANDLES");
61+
if (max_size_str) {
62+
char *endptr;
63+
size_t max_size = strtoul(max_size_str, &endptr, 10);
64+
if (*endptr == '\0') {
65+
return max_size;
66+
}
67+
LOG_ERR("Invalid value of UMF_MAX_OPENED_IPC_HANDLES: %s",
68+
max_size_str);
69+
}
70+
return 0;
71+
}
72+
5773
umf_result_t umfIpcCacheGlobalInit(void) {
5874
umf_result_t ret = UMF_RESULT_SUCCESS;
5975
ipc_opened_cache_global_t *cache_global =
@@ -78,8 +94,7 @@ umf_result_t umfIpcCacheGlobalInit(void) {
7894
goto err_mutex_destroy;
7995
}
8096

81-
// TODO: make max_size configurable via environment variable
82-
cache_global->max_size = 0;
97+
cache_global->max_size = umfIpcCacheGlobalInitMaxOpenedHandles();
8398
cache_global->cur_size = 0;
8499
cache_global->lru_list = NULL;
85100

@@ -191,7 +206,19 @@ umf_result_t umfIpcOpenedCacheGet(ipc_opened_cache_handle_t cache,
191206
if (entry == NULL && cache->global->max_size != 0 &&
192207
cache->global->cur_size >= cache->global->max_size) {
193208
// If max_size is set and the cache is full, evict the least recently used entry.
194-
entry = cache->global->lru_list->prev;
209+
// we need to search for the least recently used entry with ref_count == 0
210+
// The utlist implementation of the doubly-linked list keeps a tail pointer in head->prev
211+
ipc_opened_cache_entry_t *candidate = cache->global->lru_list->prev;
212+
do {
213+
uint64_t ref_count = 0;
214+
utils_atomic_load_acquire_u64(&candidate->ref_count,
215+
&ref_count);
216+
if (ref_count == 0) {
217+
entry = candidate;
218+
break;
219+
}
220+
candidate = candidate->prev;
221+
} while (candidate != cache->global->lru_list->prev);
195222
}
196223

197224
if (entry) { // we have eviction candidate
@@ -244,3 +271,20 @@ umf_result_t umfIpcOpenedCacheGet(ipc_opened_cache_handle_t cache,
244271

245272
return ret;
246273
}
274+
275+
umf_result_t
276+
umfIpcHandleMappedCacheRelease(ipc_opened_cache_value_t *cacheValue) {
277+
if (!cacheValue) {
278+
LOG_ERR("cacheValue is NULL");
279+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
280+
}
281+
282+
// get pointer to the entry
283+
ipc_opened_cache_entry_t *entry =
284+
(ipc_opened_cache_entry_t *)((char *)cacheValue -
285+
offsetof(ipc_opened_cache_entry_t, value));
286+
// decrement the ref count
287+
utils_atomic_decrement_u64(&entry->ref_count);
288+
289+
return UMF_RESULT_SUCCESS;
290+
}

src/ipc_cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,6 @@ umf_result_t umfIpcOpenedCacheGet(ipc_opened_cache_handle_t cache,
4747
uint64_t handle_id,
4848
ipc_opened_cache_value_t **retEntry);
4949

50+
umf_result_t
51+
umfIpcHandleMappedCacheRelease(ipc_opened_cache_value_t *cacheValue);
5052
#endif /* UMF_IPC_CACHE_H */

0 commit comments

Comments
 (0)