Skip to content

Commit 4ed4f1a

Browse files
lrstewartgoatgoose
andauthoredMar 5, 2025
tests: try to make s2n_mem_usage_test more useful (#5139)
Co-authored-by: Sam Clark <3758302+goatgoose@users.noreply.github.com>
1 parent af27eb7 commit 4ed4f1a

File tree

3 files changed

+90
-102
lines changed

3 files changed

+90
-102
lines changed
 

‎codebuild/spec/buildspec_generalbatch.yml

+18
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,21 @@ batch:
273273
privileged-mode: true
274274
compute-type: BUILD_GENERAL1_LARGE
275275
image: 024603541914.dkr.ecr.us-west-2.amazonaws.com/docker:ubuntu22codebuild
276+
- identifier: s2nMemUsageTest_awslc
277+
buildspec: codebuild/spec/buildspec_mem.yml
278+
env:
279+
compute-type: BUILD_GENERAL1_SMALL
280+
image: 024603541914.dkr.ecr.us-west-2.amazonaws.com/docker:ubuntu24
281+
privileged-mode: true
282+
variables:
283+
S2N_LIBCRYPTO: 'awslc'
284+
S2N_EXPECTED_CONNECTION_MEMORY_KB: 47
285+
- identifier: s2nMemUsageTest_awslcfips
286+
buildspec: codebuild/spec/buildspec_mem.yml
287+
env:
288+
compute-type: BUILD_GENERAL1_SMALL
289+
image: 024603541914.dkr.ecr.us-west-2.amazonaws.com/docker:ubuntu24
290+
privileged-mode: true
291+
variables:
292+
S2N_LIBCRYPTO: 'awslc-fips-2022'
293+
S2N_EXPECTED_CONNECTION_MEMORY_KB: 46

‎codebuild/spec/buildspec_mem.yml

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"). You may not use
5+
# this file except in compliance with the License. A copy of the License is
6+
# located at
7+
#
8+
# http://aws.amazon.com/apache2.0/
9+
#
10+
# or in the "license" file accompanying this file. This file is distributed on an
11+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
# implied. See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
version: 0.2
15+
16+
env:
17+
shell: bash
18+
variables:
19+
CTEST_OUTPUT_ON_FAILURE: 1
20+
S2N_TEST_NAME: s2n_mem_usage_test
21+
22+
phases:
23+
pre_build:
24+
commands:
25+
- |
26+
if [ -d "third-party-src" ]; then
27+
cd third-party-src;
28+
fi
29+
build:
30+
on-failure: ABORT
31+
commands:
32+
- export CTEST_PARALLEL_LEVEL=$(nproc)
33+
# Test for expected memory
34+
- |
35+
cmake . -Bbuild \
36+
-DCMAKE_PREFIX_PATH=/usr/local/$S2N_LIBCRYPTO
37+
- cmake --build build -j $(nproc) --target $S2N_TEST_NAME
38+
- echo ">>>> POSITIVE TEST - EXPECTED TO SUCCEED <<<<"
39+
- make -C build test -- ARGS="-R $S2N_TEST_NAME"
40+
# Test for unexpected memory to confirm failure possible
41+
# Use an unrealistically high number
42+
- cmake --build build -j $(nproc) --target $S2N_TEST_NAME
43+
- echo ">>>> NEGATIVE TESTS - EXPECTED TO FAIL <<<<"
44+
- |
45+
! S2N_EXPECTED_CONNECTION_MEMORY_KB=3 make -C build test -- ARGS="-R $S2N_TEST_NAME"
46+
! S2N_EXPECTED_CONNECTION_MEMORY_KB=500 make -C build test -- ARGS="-R $S2N_TEST_NAME"

‎tests/unit/s2n_mem_usage_test.c

+26-102
Original file line numberDiff line numberDiff line change
@@ -50,32 +50,8 @@
5050
* usage. The greater the value, the more accurate the end result. */
5151
#define MAX_CONNECTIONS 1000
5252

53-
/* This is roughly the current memory usage per connection, in KB */
54-
#ifdef __FreeBSD__
55-
#define MEM_PER_CONNECTION 57
56-
#elif defined(__OpenBSD__)
57-
#define MEM_PER_CONNECTION 61
58-
#else
59-
#define MEM_PER_CONNECTION 51
60-
#endif
61-
62-
/* This is the maximum memory per connection including 4KB of slack */
63-
#define TEST_SLACK 4
64-
#define MAX_MEM_PER_CONNECTION \
65-
((MEM_PER_CONNECTION + TEST_SLACK) * 1024)
66-
67-
/* This is the total maximum memory allowed */
68-
#define MAX_MEM_ALLOWED(num_connections) \
69-
(2 * (num_connections) *MAX_MEM_PER_CONNECTION)
70-
71-
/* This is the correct value of MEM_PER_CONNECTION based on test results.
72-
* Basically, this calculation should reverse MAX_MEM_ALLOWED */
73-
#define ACTUAL_MEM_PER_CONNECTION(num_connections, max_mem) \
74-
((((max_mem) / 2 / (num_connections)) / 1024) - TEST_SLACK)
75-
7653
ssize_t get_vm_data_size()
7754
{
78-
#ifdef __linux__
7955
long page_size = 0;
8056
ssize_t size = 0, resident = 0, share = 0, text = 0, lib = 0, data = 0, dt = 0;
8157

@@ -92,57 +68,6 @@ ssize_t get_vm_data_size()
9268
fclose(status_file);
9369

9470
return data * page_size;
95-
96-
#elif defined(__FreeBSD__)
97-
pid_t ppid = getpid();
98-
int pidinfo[4];
99-
pidinfo[0] = CTL_KERN;
100-
pidinfo[1] = KERN_PROC;
101-
pidinfo[2] = KERN_PROC_PID;
102-
pidinfo[3] = (int) ppid;
103-
104-
struct kinfo_proc procinfo = { 0 };
105-
106-
size_t len = sizeof(procinfo);
107-
108-
sysctl(pidinfo, nitems(pidinfo), &procinfo, &len, NULL, 0);
109-
110-
/* Taken from linprocfs implementation
111-
* https://github.com/freebsd/freebsd-src/blob/779fd05344662aeec79c29470258bf657318eab3/sys/compat/linprocfs/linprocfs.c#L1019 */
112-
segsz_t lsize = (procinfo.ki_size >> PAGE_SHIFT) - procinfo.ki_dsize - procinfo.ki_ssize - procinfo.ki_tsize - 1;
113-
114-
return lsize << PAGE_SHIFT;
115-
116-
#elif defined(__OpenBSD__)
117-
struct kinfo_proc *procinfo;
118-
kvm_t *kd;
119-
pid_t ppid;
120-
long page_size;
121-
ssize_t size;
122-
int nentries;
123-
124-
kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
125-
ppid = getpid();
126-
procinfo = kvm_getprocs(kd, KERN_PROC_PID, ppid, sizeof(*procinfo), &nentries);
127-
if (procinfo == NULL || nentries == 0) {
128-
return -1;
129-
}
130-
131-
/* Taken from ps(1)'s calculation of vsize
132-
* https://github.com/openbsd/src/blob/329e3480337617df4d195c9a400c3f186254b137/bin/ps/print.c#L603 */
133-
size = procinfo->p_vm_dsize + procinfo->p_vm_ssize + procinfo->p_vm_tsize;
134-
135-
page_size = sysconf(_SC_PAGESIZE);
136-
if (page_size < 0) {
137-
return -1;
138-
}
139-
kvm_close(kd);
140-
141-
return (size * page_size);
142-
#else
143-
/* Not implemented for other platforms */
144-
return 0;
145-
#endif
14671
}
14772

14873
int main(int argc, char **argv)
@@ -158,11 +83,16 @@ int main(int argc, char **argv)
15883
DEFER_CLEANUP(struct s2n_test_io_pair io_pair = { 0 }, s2n_io_pair_close);
15984
EXPECT_SUCCESS(s2n_io_pair_init_non_blocking(&io_pair));
16085

161-
/* Skip the test when running under valgrind or address sanitizer, as those tools
162-
* impact the memory usage. */
163-
if (getenv("S2N_VALGRIND") != NULL || getenv("S2N_ADDRESS_SANITIZER") != NULL) {
86+
/* Skip the test unless specifically enabled.
87+
* This test is too unreliable to run in all customer environments.
88+
* We should choose specific, known builds to run this test in.
89+
*/
90+
const char *env_var = getenv("S2N_EXPECTED_CONNECTION_MEMORY_KB");
91+
if (env_var == NULL) {
16492
END_TEST();
16593
}
94+
const int expected_kbs_per_conn = atoi(env_var);
95+
EXPECT_TRUE(expected_kbs_per_conn > 1);
16696

16797
struct rlimit file_limit;
16898
EXPECT_SUCCESS(getrlimit(RLIMIT_NOFILE, &file_limit));
@@ -172,9 +102,6 @@ int main(int argc, char **argv)
172102
connectionsToUse = MAX(1, (file_limit.rlim_cur - 16) / 4);
173103
}
174104

175-
const ssize_t maxAllowedMemDiff = MAX_MEM_ALLOWED(connectionsToUse);
176-
const ssize_t minAllowedMemDiff = maxAllowedMemDiff * 0.75;
177-
178105
struct s2n_connection **clients = calloc(connectionsToUse, sizeof(struct s2n_connection *));
179106
struct s2n_connection **servers = calloc(connectionsToUse, sizeof(struct s2n_connection *));
180107

@@ -253,34 +180,31 @@ int main(int argc, char **argv)
253180
free(clients);
254181
free(servers);
255182

256-
TEST_DEBUG_PRINT("\n");
257-
TEST_DEBUG_PRINT("VmData initial: %10zd\n", vm_data_initial);
258-
TEST_DEBUG_PRINT("VmData after allocations: %10zd\n", vm_data_after_allocation);
259-
TEST_DEBUG_PRINT("VmData after handshakes: %10zd\n", vm_data_after_handshakes);
260-
TEST_DEBUG_PRINT("VmData after free handshake: %10zd\n", vm_data_after_free_handshake);
261-
TEST_DEBUG_PRINT("VmData after release: %10zd\n", vm_data_after_release_buffers);
262-
TEST_DEBUG_PRINT("Max VmData diff allowed: %10zd\n", maxAllowedMemDiff);
263-
TEST_DEBUG_PRINT("Number of connections used: %10zu\n", connectionsToUse);
264-
265183
EXPECT_TRUE(vm_data_after_free_handshake <= vm_data_after_handshakes);
266184
EXPECT_TRUE(vm_data_after_release_buffers <= vm_data_after_free_handshake);
267185

268186
ssize_t handshake_diff = (vm_data_after_handshakes - vm_data_initial);
269187
ssize_t allocation_diff = (vm_data_after_allocation - vm_data_initial);
270-
271-
/*
272-
* get_vm_data_size is required for this test to succeed.
273-
* Any platform that doesn't implement get_vm_data_size should be excluded here.
274-
*/
275-
#ifndef __APPLE__
276-
if (allocation_diff > maxAllowedMemDiff
277-
|| handshake_diff > maxAllowedMemDiff
278-
|| handshake_diff < minAllowedMemDiff) {
279-
fprintf(stdout, "\nActual KB per connection: %i\n",
280-
(int) ACTUAL_MEM_PER_CONNECTION(connectionsToUse, handshake_diff));
188+
EXPECT_TRUE(allocation_diff <= handshake_diff);
189+
190+
ssize_t mem_per_conn = handshake_diff / (connectionsToUse * 2);
191+
ssize_t kbs_per_conn = mem_per_conn / 1024;
192+
193+
if (kbs_per_conn != expected_kbs_per_conn) {
194+
printf("\nExpected KB per connection: %i\n", expected_kbs_per_conn);
195+
printf("\nActual KB per connection: %li\n", kbs_per_conn);
196+
printf("This is a %.2f%% change\n",
197+
(kbs_per_conn - expected_kbs_per_conn) * 100.0 / expected_kbs_per_conn);
198+
199+
printf("\n");
200+
printf("VmData initial: %10zd\n", vm_data_initial);
201+
printf("VmData after allocations: %10zd\n", vm_data_after_allocation);
202+
printf("VmData after handshakes: %10zd\n", vm_data_after_handshakes);
203+
printf("VmData after free handshake: %10zd\n", vm_data_after_free_handshake);
204+
printf("VmData after release: %10zd\n", vm_data_after_release_buffers);
205+
printf("Number of connections used: %10zu\n", connectionsToUse);
281206
FAIL_MSG("Unexpected memory usage. If expected, update MEM_PER_CONNECTION.");
282207
}
283-
#endif
284208

285209
END_TEST();
286210
}

0 commit comments

Comments
 (0)
Failed to load comments.