Skip to content

Commit e331e55

Browse files
authored
Merge pull request #417 from ldorau/Add_proxy_lib_new_delete.h
Enable tests of proxy library on Windows Debug
2 parents 05fef91 + 56d93ed commit e331e55

File tree

8 files changed

+262
-22
lines changed

8 files changed

+262
-22
lines changed

.cmake-format

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ with section("parse"):
2626
'kwargs': {
2727
'NAME': '*',
2828
'SRCS': '*',
29-
'LIBS': '*',
30-
'CFGS': '*'}},
29+
'LIBS': '*'}},
3130
'add_umf_library': {
3231
"pargs": 0,
3332
"flags": [],

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,26 @@ using umfMemspaceHostAllGet.
199199
Memspace backed by all available NUMA nodes discovered on the platform sorted by capacity.
200200
Can be retrieved using umfMemspaceHighestCapacityGet.
201201

202+
### Proxy library
203+
204+
UMF provides the UMF proxy library (`umf_proxy`) that makes it possible
205+
to override the default allocator in other programs in both Linux and Windows.
206+
207+
#### Linux
208+
209+
In case of Linux it can be done without any code changes using the `LD_PRELOAD` environment variable:
210+
211+
```sh
212+
$ LD_PRELOAD=/usr/lib/libumf_proxy.so myprogram
213+
```
214+
215+
#### Windows
216+
217+
In case of Windows it requires:
218+
1) explicitly linking your program dynamically with the `umf_proxy.dll` library
219+
2) (C++ code only) including `proxy_lib_new_delete.h` in a single(!) source file in your project
220+
to override also the `new`/`delete` operations.
221+
202222
## Contributions
203223

204224
All contributions to the UMF project are most welcome! Before submitting

include/umf/proxy_lib_new_delete.h

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/* ----------------------------------------------------------------------------
2+
Copyright (c) 2018-2020 Microsoft Research, Daan Leijen
3+
Copyright (C) 2024 Intel Corporation
4+
5+
This is free software; you can redistribute it and/or modify it under the
6+
terms of the MIT license:
7+
8+
MIT License
9+
10+
Permission is hereby granted, free of charge, to any person obtaining a copy
11+
of this software and associated documentation files (the "Software"), to deal
12+
in the Software without restriction, including without limitation the rights
13+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14+
copies of the Software, and to permit persons to whom the Software is
15+
furnished to do so, subject to the following conditions:
16+
17+
The above copyright notice and this permission notice shall be included in all
18+
copies or substantial portions of the Software.
19+
20+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26+
SOFTWARE.
27+
28+
-----------------------------------------------------------------------------*/
29+
30+
#ifndef UMF_PROXY_LIB_NEW_DELETE_H
31+
#define UMF_PROXY_LIB_NEW_DELETE_H
32+
33+
// ----------------------------------------------------------------------------
34+
// This header provides convenient overrides for the new and
35+
// delete operations in C++.
36+
//
37+
// This header should be included in only one source file!
38+
//
39+
// On Windows, or when linking dynamically with UMF, these
40+
// can be more performant than the standard new-delete operations.
41+
// See <https://en.cppreference.com/w/cpp/memory/new/operator_new>
42+
// ---------------------------------------------------------------------------
43+
44+
#if defined(__cplusplus)
45+
#include <new>
46+
47+
#ifndef _WIN32
48+
#include <stdlib.h>
49+
#endif // _WIN32
50+
51+
static inline void *internal_aligned_alloc(size_t alignment, size_t size) {
52+
#ifdef _WIN32
53+
return _aligned_malloc(size, alignment);
54+
#else
55+
return aligned_alloc(alignment, size);
56+
#endif // _WIN32
57+
}
58+
59+
#if defined(_MSC_VER) && defined(_Ret_notnull_) && \
60+
defined(_Post_writable_byte_size_)
61+
// stay consistent with VCRT definitions
62+
#define decl_new(n) [[nodiscard]] _Ret_notnull_ _Post_writable_byte_size_(n)
63+
#define decl_new_nothrow(n) \
64+
[[nodiscard]] _Ret_maybenull_ _Success_(return != NULL) \
65+
_Post_writable_byte_size_(n)
66+
#else
67+
#define decl_new(n) [[nodiscard]]
68+
#define decl_new_nothrow(n) [[nodiscard]]
69+
#endif // defined(_MSC_VER) && defined(_Ret_notnull_) && defined(_Post_writable_byte_size_)
70+
71+
void operator delete(void *p) noexcept { free(p); };
72+
void operator delete[](void *p) noexcept { free(p); };
73+
74+
void operator delete(void *p, const std::nothrow_t &) noexcept { free(p); }
75+
void operator delete[](void *p, const std::nothrow_t &) noexcept { free(p); }
76+
77+
decl_new(n) void *operator new(std::size_t n) noexcept(false) {
78+
return malloc(n);
79+
}
80+
decl_new(n) void *operator new[](std::size_t n) noexcept(false) {
81+
return malloc(n);
82+
}
83+
84+
decl_new_nothrow(n) void *operator new(std::size_t n,
85+
const std::nothrow_t &tag) noexcept {
86+
(void)(tag);
87+
return malloc(n);
88+
}
89+
decl_new_nothrow(n) void *operator new[](std::size_t n,
90+
const std::nothrow_t &tag) noexcept {
91+
(void)(tag);
92+
return malloc(n);
93+
}
94+
95+
#if (__cplusplus >= 201402L || _MSC_VER >= 1916)
96+
void operator delete(void *p, std::size_t n) noexcept {
97+
(void)(n);
98+
free(p);
99+
};
100+
void operator delete[](void *p, std::size_t n) noexcept {
101+
(void)(n);
102+
free(p);
103+
};
104+
#endif // (__cplusplus >= 201402L || _MSC_VER >= 1916)
105+
106+
#if (__cplusplus > 201402L || defined(__cpp_aligned_new))
107+
void operator delete(void *p, std::align_val_t al) noexcept {
108+
(void)(al);
109+
free(p);
110+
}
111+
void operator delete[](void *p, std::align_val_t al) noexcept {
112+
(void)(al);
113+
free(p);
114+
}
115+
void operator delete(void *p, std::size_t n, std::align_val_t al) noexcept {
116+
(void)(n);
117+
(void)(al);
118+
free(p);
119+
};
120+
void operator delete[](void *p, std::size_t n, std::align_val_t al) noexcept {
121+
(void)(n);
122+
(void)(al);
123+
free(p);
124+
};
125+
void operator delete(void *p, std::align_val_t al,
126+
const std::nothrow_t &) noexcept {
127+
(void)(al);
128+
free(p);
129+
}
130+
void operator delete[](void *p, std::align_val_t al,
131+
const std::nothrow_t &) noexcept {
132+
(void)(al);
133+
free(p);
134+
}
135+
136+
void *operator new(std::size_t n, std::align_val_t al) noexcept(false) {
137+
return internal_aligned_alloc(static_cast<size_t>(al), n);
138+
}
139+
void *operator new[](std::size_t n, std::align_val_t al) noexcept(false) {
140+
return internal_aligned_alloc(static_cast<size_t>(al), n);
141+
}
142+
void *operator new(std::size_t n, std::align_val_t al,
143+
const std::nothrow_t &) noexcept {
144+
return internal_aligned_alloc(static_cast<size_t>(al), n);
145+
}
146+
void *operator new[](std::size_t n, std::align_val_t al,
147+
const std::nothrow_t &) noexcept {
148+
return internal_aligned_alloc(static_cast<size_t>(al), n);
149+
}
150+
#endif // (__cplusplus > 201402L || defined(__cpp_aligned_new))
151+
#endif // defined(__cplusplus)
152+
153+
#endif // UMF_PROXY_LIB_NEW_DELETE_H

src/proxy_lib/proxy_lib.c

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,18 @@
1313
* - calloc()
1414
* - free()
1515
* - malloc()
16-
* - malloc_usable_size()
16+
* - malloc_usable_size() for Linux or _msize() for Windows
1717
* - realloc()
18+
*
19+
* Additionally for Windows only:
20+
* - _aligned_malloc()
21+
* - _aligned_realloc()
22+
* - _aligned_recalloc()
23+
* - _aligned_msize()
24+
* - _aligned_free()
25+
* - _aligned_offset_malloc()
26+
* - _aligned_offset_realloc()
27+
* - _aligned_offset_recalloc()
1828
*/
1929

2030
#if (defined PROXY_LIB_USES_JEMALLOC_POOL)
@@ -254,13 +264,6 @@ void free(void *ptr) {
254264
return;
255265
}
256266

257-
#ifdef _WIN32
258-
void _free_dbg(void *userData, int blockType) {
259-
(void)blockType; // unused
260-
free(userData);
261-
}
262-
#endif
263-
264267
void *realloc(void *ptr, size_t size) {
265268
if (ptr == NULL) {
266269
return malloc(size);
@@ -318,3 +321,60 @@ size_t malloc_usable_size(void *ptr) {
318321

319322
return 0; // unsupported in this case
320323
}
324+
325+
// Add Microsoft aligned variants
326+
#ifdef _WIN32
327+
328+
void *_aligned_malloc(size_t size, size_t alignment) {
329+
return aligned_alloc(alignment, size);
330+
}
331+
332+
void *_aligned_realloc(void *ptr, size_t size, size_t alignment) {
333+
if (alignment == 0) {
334+
return realloc(ptr, size);
335+
}
336+
return NULL; // not supported in this case
337+
}
338+
339+
void *_aligned_recalloc(void *ptr, size_t num, size_t size, size_t alignment) {
340+
(void)ptr; // unused
341+
(void)num; // unused
342+
(void)size; // unused
343+
(void)alignment; // unused
344+
return NULL; // not supported
345+
}
346+
347+
size_t _aligned_msize(void *ptr, size_t alignment, size_t offset) {
348+
(void)alignment; // unused
349+
(void)offset; // unused
350+
return _msize(ptr);
351+
}
352+
353+
void _aligned_free(void *ptr) { free(ptr); }
354+
355+
void *_aligned_offset_malloc(size_t size, size_t alignment, size_t offset) {
356+
if (offset == 0) {
357+
return aligned_alloc(alignment, size);
358+
}
359+
return NULL; // not supported in this case
360+
}
361+
362+
void *_aligned_offset_realloc(void *ptr, size_t size, size_t alignment,
363+
size_t offset) {
364+
if (alignment == 0 && offset == 0) {
365+
return realloc(ptr, size);
366+
}
367+
return NULL; // not supported in this case
368+
}
369+
370+
void *_aligned_offset_recalloc(void *ptr, size_t num, size_t size,
371+
size_t alignment, size_t offset) {
372+
(void)ptr; // unused
373+
(void)num; // unused
374+
(void)size; // unused
375+
(void)alignment; // unused
376+
(void)offset; // unused
377+
return NULL; // not supported
378+
}
379+
380+
#endif

src/proxy_lib/proxy_lib.def

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@ EXPORTS
99
DllMain
1010
aligned_alloc
1111
calloc
12-
_free_dbg
1312
free
1413
malloc
1514
_msize
1615
realloc
16+
_aligned_malloc
17+
_aligned_realloc
18+
_aligned_recalloc
19+
_aligned_msize
20+
_aligned_free
21+
_aligned_offset_malloc
22+
_aligned_offset_realloc
23+
_aligned_offset_recalloc

test/CMakeLists.txt

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function(add_umf_test)
3030
# * SRCS - source files
3131
# * LIBS - libraries to be linked with
3232
set(oneValueArgs NAME)
33-
set(multiValueArgs SRCS LIBS CFGS)
33+
set(multiValueArgs SRCS LIBS)
3434
cmake_parse_arguments(
3535
ARG
3636
""
@@ -73,7 +73,6 @@ function(add_umf_test)
7373
add_test(
7474
NAME ${TEST_NAME}
7575
COMMAND ${TEST_TARGET_NAME}
76-
CONFIGURATIONS ${ARG_CFGS}
7776
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
7877

7978
set_tests_properties(${TEST_NAME} PROPERTIES LABELS "umf")
@@ -224,22 +223,18 @@ add_umf_test(
224223

225224
# tests for the proxy library
226225
if(UMF_PROXY_LIB_ENABLED AND UMF_BUILD_SHARED_LIBRARY)
227-
# The CFGS variable can be removed when the issue of running the proxy
228-
# library on Windows with Debug configuration is fixed.
229-
if(WINDOWS)
230-
set(CONFIGS Release RelWithDebInfo MinSizeRel)
231-
endif()
232226
add_umf_test(
233227
NAME proxy_lib_basic
234228
SRCS test_proxy_lib.cpp
235-
LIBS umf_proxy
236-
CFGS ${CONFIGS})
229+
LIBS umf_proxy)
230+
237231
# the memoryPool test run with the proxy library
238232
add_umf_test(
239233
NAME proxy_lib_memoryPool
240234
SRCS memoryPoolAPI.cpp malloc_compliance_tests.cpp
241-
LIBS umf_proxy
242-
CFGS ${CONFIGS})
235+
LIBS umf_proxy)
236+
target_compile_definitions(umf_test-proxy_lib_memoryPool
237+
PUBLIC UMF_PROXY_LIB_ENABLED=1)
243238
endif()
244239

245240
if(UMF_ENABLE_POOL_TRACKING)

test/memoryPoolAPI.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
#include <umf/memory_provider.h>
1515
#include <umf/pools/pool_proxy.h>
1616

17+
#ifdef UMF_PROXY_LIB_ENABLED
18+
#include <umf/proxy_lib_new_delete.h>
19+
#endif
20+
1721
#include <array>
1822
#include <string>
1923
#include <thread>

test/test_proxy_lib.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <malloc.h>
1212
#endif
1313

14+
#include <umf/proxy_lib_new_delete.h>
15+
1416
#include "base.hpp"
1517
#include "test_helpers.h"
1618

0 commit comments

Comments
 (0)