Skip to content

Commit 4b246b2

Browse files
committed
Add proxy library for intercepting user allocation requests
UMF proxy library is a library for intercepting user allocation requests. It intercepts following APIs: - aligned_alloc() - calloc() - free() - malloc() - malloc_usable_size() - realloc() Signed-off-by: Lukasz Dorau <[email protected]>
1 parent a1d6b2c commit 4b246b2

File tree

15 files changed

+609
-20
lines changed

15 files changed

+609
-20
lines changed

.github/workflows/pr_push.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,6 @@ jobs:
9191
Benchmark:
9292
needs: [Build]
9393
uses: ./.github/workflows/benchmarks.yml
94+
Proxy_lib:
95+
needs: [Build]
96+
uses: ./.github/workflows/proxy_lib.yml

.github/workflows/proxy_lib.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Proxy library
2+
3+
on: workflow_call
4+
5+
permissions:
6+
contents: read
7+
8+
jobs:
9+
ubuntu-build:
10+
name: Build - Ubuntu
11+
12+
strategy:
13+
matrix:
14+
os: ['ubuntu-22.04']
15+
build_type: [Release, Debug]
16+
compiler: [{c: gcc, cxx: g++}]
17+
runs-on: ${{matrix.os}}
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
22+
23+
- name: Install apt packages
24+
run: |
25+
sudo apt-get update
26+
sudo apt-get install -y cmake libhwloc-dev libjemalloc-dev libtbb-dev
27+
28+
- name: Configure build
29+
run: >
30+
cmake
31+
-B ${{github.workspace}}/build
32+
-DCMAKE_BUILD_TYPE=${{matrix.build_type}}
33+
-DCMAKE_C_COMPILER=${{matrix.compiler.c}}
34+
-DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}}
35+
-DUMF_BUILD_SHARED_LIBRARY=ON
36+
-DUMF_BUILD_BENCHMARKS=ON
37+
-DUMF_BUILD_TESTS=ON
38+
-DUMF_FORMAT_CODE_STYLE=OFF
39+
-DUMF_DEVELOPER_MODE=OFF
40+
-DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON
41+
-DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON
42+
-DUMF_BUILD_LIBUMF_POOL_SCALABLE=ON
43+
-DUMF_ENABLE_POOL_TRACKING=OFF
44+
45+
- name: Build UMF
46+
run: cmake --build ${{github.workspace}}/build -j $(nproc)
47+
48+
- name: Run "ctest --output-on-failure" with proxy library
49+
working-directory: ${{github.workspace}}/build
50+
run: LD_PRELOAD=./lib/libumf_proxy.so ctest --output-on-failure
51+
52+
- name: Run "./test/umf_test-memoryPool" with proxy library
53+
working-directory: ${{github.workspace}}/build
54+
run: LD_PRELOAD=./lib/libumf_proxy.so ./test/umf_test-memoryPool
55+
56+
- name: Run "/usr/bin/ls" with proxy library
57+
working-directory: ${{github.workspace}}/build
58+
run: LD_PRELOAD=./lib/libumf_proxy.so /usr/bin/ls
59+
60+
- name: Run "/usr/bin/date" with proxy library
61+
working-directory: ${{github.workspace}}/build
62+
run: LD_PRELOAD=./lib/libumf_proxy.so /usr/bin/date

src/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,12 @@ install(TARGETS umf
103103
)
104104

105105
add_subdirectory(pool)
106+
107+
# TODO: enable proxy_lib on Windows
108+
if(LINUX)
109+
if(UMF_BUILD_LIBUMF_POOL_JEMALLOC)
110+
add_subdirectory(proxy_lib)
111+
else()
112+
message(STATUS "The proxy library is disabled, because UMF_BUILD_LIBUMF_POOL_JEMALLOC is OFF")
113+
endif()
114+
endif()

src/base_alloc/base_alloc.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ struct umf_ba_main_pool_meta_t {
3636
size_t chunk_size; // size of all memory chunks in this pool
3737
os_mutex_t free_lock; // lock of free_list
3838
umf_ba_chunk_t *free_list; // list of free chunks
39+
size_t n_allocs; // number of allocated chunks
3940
#ifndef NDEBUG
4041
size_t n_pools;
41-
size_t n_allocs;
4242
size_t n_chunks;
4343
#endif /* NDEBUG */
4444
};
@@ -135,9 +135,9 @@ umf_ba_pool_t *umf_ba_create(size_t size) {
135135
pool->metadata.pool_size = pool_size;
136136
pool->metadata.chunk_size = chunk_size;
137137
pool->next_pool = NULL; // this is the only pool now
138+
pool->metadata.n_allocs = 0;
138139
#ifndef NDEBUG
139140
pool->metadata.n_pools = 1;
140-
pool->metadata.n_allocs = 0;
141141
pool->metadata.n_chunks = 0;
142142
#endif /* NDEBUG */
143143

@@ -187,8 +187,8 @@ void *umf_ba_alloc(umf_ba_pool_t *pool) {
187187

188188
umf_ba_chunk_t *chunk = pool->metadata.free_list;
189189
pool->metadata.free_list = pool->metadata.free_list->next;
190-
#ifndef NDEBUG
191190
pool->metadata.n_allocs++;
191+
#ifndef NDEBUG
192192
ba_debug_checks(pool);
193193
#endif /* NDEBUG */
194194
util_mutex_unlock(&pool->metadata.free_lock);
@@ -230,18 +230,30 @@ void umf_ba_free(umf_ba_pool_t *pool, void *ptr) {
230230
assert(pool_contains_pointer(pool, ptr));
231231
chunk->next = pool->metadata.free_list;
232232
pool->metadata.free_list = chunk;
233-
#ifndef NDEBUG
234233
pool->metadata.n_allocs--;
234+
#ifndef NDEBUG
235235
ba_debug_checks(pool);
236236
#endif /* NDEBUG */
237237
util_mutex_unlock(&pool->metadata.free_lock);
238238
}
239239

240240
void umf_ba_destroy(umf_ba_pool_t *pool) {
241+
// Do not destroy if we are running in the proxy library,
242+
// because it may need those resources till
243+
// the very end of exiting the application.
244+
if (pool->metadata.n_allocs && is_running_in_proxy_lib()) {
245+
return;
246+
}
247+
241248
#ifndef NDEBUG
242-
assert(pool->metadata.n_allocs == 0);
243249
ba_debug_checks(pool);
250+
if (pool->metadata.n_allocs) {
251+
fprintf(stderr, "umf_ba_destroy(): pool->metadata.n_allocs = %zu\n",
252+
pool->metadata.n_allocs);
253+
assert(pool->metadata.n_allocs == 0);
254+
}
244255
#endif /* NDEBUG */
256+
245257
size_t size = pool->metadata.pool_size;
246258
umf_ba_next_pool_t *current_pool;
247259
umf_ba_next_pool_t *next_pool = pool->next_pool;

src/base_alloc/base_alloc_linear.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,17 @@ void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) {
161161
}
162162

163163
void umf_ba_linear_destroy(umf_ba_linear_pool_t *pool) {
164+
// Do not destroy if we are running in the proxy library,
165+
// because it may need those resources till
166+
// the very end of exiting the application.
167+
if (is_running_in_proxy_lib()) {
168+
return;
169+
}
170+
164171
#ifndef NDEBUG
165172
ba_debug_checks(pool);
166173
#endif /* NDEBUG */
174+
167175
umf_ba_next_linear_pool_t *current_pool;
168176
umf_ba_next_linear_pool_t *next_pool = pool->next_pool;
169177
while (next_pool) {

src/provider/provider_tracking.c

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "provider_tracking.h"
1111
#include "critnib.h"
12+
#include "utils_common.h"
1213
#include "utils_concurrency.h"
1314

1415
#include <umf/memory_pool.h>
@@ -358,18 +359,23 @@ static void check_if_tracker_is_empty(umf_memory_tracker_handle_t hTracker,
358359
}
359360

360361
if (n_items) {
361-
if (pool) {
362-
fprintf(stderr,
363-
"ASSERT: tracking provider of pool %p is not empty! (%zu "
364-
"items left)\n",
365-
(void *)pool, n_items);
366-
} else {
367-
fprintf(
368-
stderr,
369-
"ASSERT: tracking provider is not empty! (%zu items left)\n",
370-
n_items);
362+
// Do not assert if we are running in the proxy library,
363+
// because it may need those resources till
364+
// the very end of exiting the application.
365+
if (!is_running_in_proxy_lib()) {
366+
if (pool) {
367+
fprintf(stderr,
368+
"ASSERT: tracking provider of pool %p is not empty! "
369+
"(%zu items left)\n",
370+
(void *)pool, n_items);
371+
} else {
372+
fprintf(stderr,
373+
"ASSERT: tracking provider is not empty! (%zu items "
374+
"left)\n",
375+
n_items);
376+
}
377+
assert(n_items == 0);
371378
}
372-
assert(n_items == 0);
373379
}
374380
}
375381
#endif /* NDEBUG */
@@ -516,12 +522,26 @@ void umfMemoryTrackerDestroy(umf_memory_tracker_handle_t handle) {
516522
return;
517523
}
518524

525+
// Do not destroy if we are running in the proxy library,
526+
// because it may need those resources till
527+
// the very end of exiting the application.
528+
if (is_running_in_proxy_lib()) {
529+
return;
530+
}
531+
519532
#ifndef NDEBUG
520533
check_if_tracker_is_empty(handle, NULL);
521534
#endif /* NDEBUG */
522535

536+
// We have to zero all inner pointers,
537+
// because the tracker handle can be copied
538+
// and used in many places.
523539
critnib_delete(handle->map);
540+
handle->map = NULL;
524541
util_mutex_destroy_not_free(&handle->splitMergeMutex);
525542
umf_ba_destroy(handle->tracker_allocator);
526-
umf_ba_linear_destroy(handle->pool_linear);
543+
handle->tracker_allocator = NULL;
544+
umf_ba_linear_pool_t *pool_linear = handle->pool_linear;
545+
handle->pool_linear = NULL;
546+
umf_ba_linear_destroy(pool_linear);
527547
}

src/proxy_lib/CMakeLists.txt

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright (C) 2023-2024 Intel Corporation
2+
# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
3+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
include(${UMF_CMAKE_SOURCE_DIR}/cmake/helpers.cmake)
6+
7+
# set one of:
8+
# - PROXY_LIB_USES_JEMALLOC_POOL
9+
# - PROXY_LIB_USES_SCALABLE_POOL
10+
set(PROXY_LIB_USES_SCALABLE_POOL ON)
11+
12+
if(PROXY_LIB_USES_SCALABLE_POOL)
13+
set(PROXY_LIBS umf scalable_pool)
14+
elseif(PROXY_LIB_USES_JEMALLOC_POOL)
15+
set(PROXY_LIBS umf jemalloc_pool)
16+
else()
17+
message(FATAL_ERROR "Proxy library: pool manager not defined")
18+
endif()
19+
20+
set(PROXY_SOURCES
21+
proxy_lib.c
22+
)
23+
24+
set(PROXY_SOURCES_LINUX
25+
proxy_lib_linux.c
26+
)
27+
28+
set(PROXY_SOURCES_WINDOWS
29+
proxy_lib_windows.c
30+
)
31+
32+
set(PROXY_SOURCES_MACOSX
33+
proxy_lib_linux.c
34+
)
35+
36+
if(LINUX)
37+
set(PROXY_SOURCES ${PROXY_SOURCES} ${PROXY_SOURCES_LINUX})
38+
elseif(WINDOWS)
39+
set(PROXY_SOURCES ${PROXY_SOURCES} ${PROXY_SOURCES_WINDOWS})
40+
elseif(MACOSX)
41+
set(PROXY_SOURCES ${PROXY_SOURCES} ${PROXY_SOURCES_MACOSX})
42+
endif()
43+
44+
add_umf_library(NAME umf_proxy
45+
TYPE SHARED
46+
SRCS ${PROXY_SOURCES}
47+
LIBS ${PROXY_LIBS}
48+
LINUX_MAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/proxy_lib.map
49+
WINDOWS_DEF_FILE ${CMAKE_CURRENT_SOURCE_DIR}/proxy_lib.def)
50+
51+
add_library(${PROJECT_NAME}::proxy ALIAS umf_proxy)
52+
53+
if(PROXY_LIB_USES_SCALABLE_POOL)
54+
target_compile_definitions(umf_proxy PRIVATE PROXY_LIB_USES_SCALABLE_POOL=1)
55+
elseif(PROXY_LIB_USES_JEMALLOC_POOL)
56+
target_compile_definitions(umf_proxy PRIVATE PROXY_LIB_USES_JEMALLOC_POOL=1)
57+
endif()
58+
59+
target_include_directories(umf_proxy PUBLIC
60+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
61+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/utils>
62+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
63+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
64+
)
65+
66+
install(TARGETS umf_proxy
67+
EXPORT ${PROJECT_NAME}-targets)

0 commit comments

Comments
 (0)