Skip to content

Commit 57b96f9

Browse files
committed
add IPC test with proxy lib
1 parent 0d64d11 commit 57b96f9

File tree

5 files changed

+305
-8
lines changed

5 files changed

+305
-8
lines changed

CMakeLists.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,8 +432,16 @@ if(WINDOWS)
432432
)
433433
endif()
434434
endif()
435+
435436
# set UMF_PROXY_LIB_ENABLED
436-
if(UMF_PROXY_LIB_BASED_ON_POOL STREQUAL SCALABLE)
437+
if(UMF_LINK_HWLOC_STATICALLY)
438+
message(
439+
STATUS
440+
"Disabling the proxy library, because HWLOC is set to link statically which is not supported"
441+
)
442+
elseif(UMF_DISABLE_HWLOC)
443+
message(STATUS "Disabling the proxy library, because HWLOC is disabled")
444+
elseif(UMF_PROXY_LIB_BASED_ON_POOL STREQUAL SCALABLE)
437445
if(UMF_POOL_SCALABLE_ENABLED)
438446
set(UMF_PROXY_LIB_ENABLED ON)
439447
set(PROXY_LIB_USES_SCALABLE_POOL ON)

src/CMakeLists.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,6 @@ install(TARGETS umf EXPORT ${PROJECT_NAME}-targets)
195195

196196
add_subdirectory(pool)
197197

198-
if(UMF_PROXY_LIB_ENABLED
199-
AND NOT UMF_LINK_HWLOC_STATICALLY
200-
AND NOT UMF_DISABLE_HWLOC)
198+
if(UMF_PROXY_LIB_ENABLED)
201199
add_subdirectory(proxy_lib)
202200
endif()

test/CMakeLists.txt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -408,10 +408,7 @@ add_umf_test(
408408
LIBS ${UMF_UTILS_FOR_TEST})
409409

410410
# tests for the proxy library
411-
if(UMF_PROXY_LIB_ENABLED
412-
AND UMF_BUILD_SHARED_LIBRARY
413-
AND NOT UMF_DISABLE_HWLOC
414-
AND NOT UMF_LINK_HWLOC_STATICALLY)
411+
if(UMF_PROXY_LIB_ENABLED AND UMF_BUILD_SHARED_LIBRARY)
415412
add_umf_test(
416413
NAME proxy_lib_basic
417414
SRCS ${BA_SOURCES_FOR_TEST} test_proxy_lib.cpp
@@ -486,6 +483,18 @@ if(LINUX)
486483
add_umf_ipc_test(TEST ipc_os_prov_anon_fd)
487484
add_umf_ipc_test(TEST ipc_os_prov_shm)
488485

486+
if(UMF_PROXY_LIB_ENABLED AND UMF_BUILD_SHARED_LIBRARY)
487+
build_umf_test(
488+
NAME
489+
ipc_os_prov_proxy
490+
SRCS
491+
ipc_os_prov_proxy.c
492+
common/ipc_common.c
493+
LIBS
494+
${UMF_UTILS_FOR_TEST})
495+
add_umf_ipc_test(TEST ipc_os_prov_proxy)
496+
endif()
497+
489498
build_umf_test(
490499
NAME
491500
ipc_devdax_prov_consumer

test/ipc_os_prov_proxy.c

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
/*
2+
* Copyright (C) 2024 Intel Corporation
3+
*
4+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
*/
7+
8+
#include <dlfcn.h>
9+
#include <fcntl.h>
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
#include <string.h>
13+
#include <sys/socket.h>
14+
#include <sys/stat.h>
15+
#include <sys/types.h>
16+
#include <unistd.h>
17+
18+
#include <umf/ipc.h>
19+
20+
#include "ipc_common.h"
21+
#include "utils_load_library.h"
22+
23+
umf_result_t (*pfnGetIPCHandle)(const void *ptr, umf_ipc_handle_t *umfIPCHandle,
24+
size_t *size);
25+
umf_result_t (*pfnPutIPCHandle)(umf_ipc_handle_t umfIPCHandle);
26+
27+
// This is a test for a scenario where a user process is started using the
28+
// LD_PRELOAD with the UMF Proxy Lib and this process uses UMF by loading
29+
// libumf.so at runtime.
30+
// In this test, we expect that all allocations made by the process will be
31+
// handled by UMF in the Proxy Lib and added to the UMF tracker so that they
32+
// can be used later in the UMF IPC API.
33+
int main(int argc, char *argv[]) {
34+
int ret = 0;
35+
umf_result_t umf_result = UMF_RESULT_ERROR_UNKNOWN;
36+
int producer_socket = -1;
37+
const size_t MSG_SIZE = 2048;
38+
char consumer_message[MSG_SIZE];
39+
40+
if (argc < 2) {
41+
fprintf(stderr, "usage: %s <port> [shm_name]\n", argv[0]);
42+
return -1;
43+
}
44+
45+
int port = atoi(argv[1]);
46+
47+
int fd = open("/proc/self/maps", O_RDONLY);
48+
if (fd == -1) {
49+
return -1;
50+
}
51+
52+
// read the "/proc/self/maps" file until the "libumf_proxy.so" of the maps
53+
// is found or EOF is reached.
54+
const size_t SIZE_BUF = 8192;
55+
char buf[SIZE_BUF];
56+
ssize_t nbytes = 1;
57+
char *found = NULL;
58+
while (nbytes > 0 && found == NULL) {
59+
memset(buf, 0, SIZE_BUF); // erase previous data
60+
nbytes = read(fd, buf, SIZE_BUF);
61+
if (nbytes <= 0) {
62+
break;
63+
}
64+
found = strstr(buf, "libumf_proxy.so");
65+
}
66+
(void)close(fd);
67+
68+
if (found == NULL) {
69+
fprintf(
70+
stderr,
71+
"test binary not run under LD_PRELOAD with \"libumf_proxy.so\"\n");
72+
return -1;
73+
}
74+
75+
// open the UMF library and get umfGetIPCHandle() function
76+
const char *umf_lib_name = "libumf.so";
77+
void *umf_lib_handle = utils_open_library(umf_lib_name, 0);
78+
if (umf_lib_handle == NULL) {
79+
fprintf(stderr, "utils_open_library: UMF library not found (%s)\n",
80+
umf_lib_name);
81+
return -1;
82+
}
83+
84+
*(void **)&pfnGetIPCHandle =
85+
utils_get_symbol_addr(umf_lib_handle, "umfGetIPCHandle", umf_lib_name);
86+
if (pfnGetIPCHandle == NULL) {
87+
ret = -1;
88+
goto err_close_lib;
89+
}
90+
91+
*(void **)&pfnPutIPCHandle =
92+
utils_get_symbol_addr(umf_lib_handle, "umfPutIPCHandle", umf_lib_name);
93+
if (pfnPutIPCHandle == NULL) {
94+
ret = -1;
95+
goto err_close_lib;
96+
}
97+
98+
// create simple allocation - it should be added to the UMF tracker if the
99+
// process was launched under UMF Proxy Lib
100+
size_t size = 2137;
101+
void *ptr = malloc(size);
102+
if (ptr == NULL) {
103+
fprintf(stderr, "malloc() failed!\n");
104+
ret = -1;
105+
goto err_close_lib;
106+
}
107+
108+
fprintf(stderr, "Allocated memory - %zu\n", size);
109+
size_t val = 144;
110+
size_t expected_val = val / 2;
111+
*(size_t *)ptr = val;
112+
113+
// get IPC handle of the allocation
114+
umf_ipc_handle_t ipc_handle = NULL;
115+
size_t ipc_handle_size = 0;
116+
umf_result_t res = pfnGetIPCHandle(ptr, &ipc_handle, &ipc_handle_size);
117+
if (res != UMF_RESULT_SUCCESS) {
118+
fprintf(stderr, "pfnGetIPCHandle() failed!\n");
119+
ret = -1;
120+
goto err_free_mem;
121+
}
122+
123+
// check if we got valid data
124+
if (ipc_handle == NULL || ipc_handle_size == 0) {
125+
fprintf(stderr, "pfnGetIPCHandle() couldn't find the handle data!\n");
126+
ret = -1;
127+
goto err_free_mem;
128+
}
129+
130+
fprintf(stderr, "Got IPCHandle for memory - %p | size - %zu\n",
131+
(void *)ipc_handle, ipc_handle_size);
132+
133+
producer_socket = producer_connect(port);
134+
if (producer_socket < 0) {
135+
goto err_PutIPCHandle;
136+
}
137+
138+
// send the ipc_handle_size to the consumer
139+
ssize_t len =
140+
send(producer_socket, &ipc_handle_size, sizeof(ipc_handle_size), 0);
141+
if (len < 0) {
142+
fprintf(stderr, "[producer] ERROR: unable to send the ipc_handle_size "
143+
"to the consumer\n");
144+
goto err_close_producer_socket;
145+
}
146+
147+
fprintf(stderr,
148+
"[producer] Sent the size of the IPC handle (%zu) to the consumer "
149+
"(sent %zu bytes)\n",
150+
ipc_handle_size, len);
151+
152+
// zero the consumer_message buffer
153+
memset(consumer_message, 0, sizeof(consumer_message));
154+
155+
// receive the consumer's confirmation - IPC handle size
156+
len = recv(producer_socket, consumer_message, sizeof(consumer_message), 0);
157+
if (len < 0) {
158+
fprintf(stderr, "[producer] ERROR: error while receiving the "
159+
"confirmation from the consumer\n");
160+
goto err_close_producer_socket;
161+
}
162+
163+
size_t conf_IPC_handle_size = *(size_t *)consumer_message;
164+
if (conf_IPC_handle_size == ipc_handle_size) {
165+
fprintf(stderr,
166+
"[producer] Received the correct confirmation (%zu) from the "
167+
"consumer (%zu bytes)\n",
168+
conf_IPC_handle_size, len);
169+
} else {
170+
fprintf(stderr,
171+
"[producer] Received an INCORRECT confirmation (%zu) from the "
172+
"consumer (%zu bytes)\n",
173+
conf_IPC_handle_size, len);
174+
goto err_close_producer_socket;
175+
}
176+
177+
// send the ipc_handle of ipc_handle_size to the consumer
178+
if (send(producer_socket, ipc_handle, ipc_handle_size, 0) < 0) {
179+
fprintf(stderr, "[producer] ERROR: unable to send the ipc_handle to "
180+
"the consumer\n");
181+
goto err_close_producer_socket;
182+
}
183+
184+
fprintf(stderr,
185+
"[producer] Sent the IPC handle to the consumer (%zu bytes)\n",
186+
ipc_handle_size);
187+
188+
// zero the consumer_message buffer
189+
memset(consumer_message, 0, sizeof(consumer_message));
190+
191+
// receive the consumer's response
192+
if (recv(producer_socket, consumer_message, sizeof(consumer_message) - 1,
193+
0) < 0) {
194+
fprintf(
195+
stderr,
196+
"[producer] ERROR: error while receiving the consumer's message\n");
197+
goto err_close_producer_socket;
198+
}
199+
200+
fprintf(stderr, "[producer] Received the consumer's response: \"%s\"\n",
201+
consumer_message);
202+
203+
if (strncmp(consumer_message, "SKIP", 5 /* length of "SKIP" + 1 */) == 0) {
204+
fprintf(stderr, "[producer] SKIP: received the 'SKIP' response from "
205+
"consumer, skipping ...\n");
206+
ret = 1;
207+
goto err_close_producer_socket;
208+
}
209+
210+
// read a new value - the expected correct value val / 2
211+
volatile unsigned long long new_val = *(unsigned long long *)ptr;
212+
if (new_val == expected_val) {
213+
ret = 0; // got the correct value - success!
214+
fprintf(
215+
stderr,
216+
"[producer] The consumer wrote the correct value (the old one / 2) "
217+
"to my shared memory: %llu\n",
218+
new_val);
219+
} else {
220+
fprintf(
221+
stderr,
222+
"[producer] ERROR: The consumer did NOT write the correct value "
223+
"(the old one / 2 = %llu) to my shared memory: %llu\n",
224+
expected_val, new_val);
225+
}
226+
227+
err_close_producer_socket:
228+
close(producer_socket);
229+
230+
err_PutIPCHandle:
231+
umf_result = pfnPutIPCHandle(ipc_handle);
232+
if (umf_result != UMF_RESULT_SUCCESS) {
233+
fprintf(stderr, "[producer] ERROR: putting the IPC handle failed\n");
234+
}
235+
236+
fprintf(stderr, "[producer] Put the IPC handle\n");
237+
238+
if (ret == 0) {
239+
fprintf(stderr, "[producer] Shutting down (status OK) ...\n");
240+
} else if (ret == 1) {
241+
fprintf(stderr, "[producer] Shutting down (status SKIP) ...\n");
242+
ret = 0;
243+
} else {
244+
fprintf(stderr, "[producer] Shutting down (status ERROR) ...\n");
245+
}
246+
247+
return ret;
248+
249+
err_free_mem:
250+
free(ptr);
251+
252+
err_close_lib:
253+
utils_close_library(umf_lib_handle);
254+
255+
return ret;
256+
}

test/ipc_os_prov_proxy.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#
2+
# Copyright (C) 2024 Intel Corporation
3+
#
4+
# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
#
7+
8+
#!/bin/bash
9+
10+
set -e
11+
12+
UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes"
13+
UMF_PROXY_VAL="page.disposition=shared-shm"
14+
LD_PRELOAD_VAL="../lib/libumf_proxy.so"
15+
16+
# port should be a number from the range <1024, 65535>
17+
PORT=$(( 1024 + ( $$ % ( 65535 - 1024 ))))
18+
19+
echo "Starting CONSUMER on port $PORT ..."
20+
UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_os_prov_consumer $PORT &
21+
22+
echo "Waiting 1 sec ..."
23+
sleep 1
24+
25+
echo "Starting ipc_os_prov_proxy PRODUCER on port $PORT ..."
26+
LD_PRELOAD=$LD_PRELOAD_VAL UMF_LOG=$UMF_LOG_VAL UMF_PROXY=$UMF_PROXY_VAL ./umf_test-ipc_os_prov_proxy $PORT

0 commit comments

Comments
 (0)