Skip to content

Commit

Permalink
tests: try to make s2n_mem_usage_test more useful
Browse files Browse the repository at this point in the history
  • Loading branch information
lrstewart committed Feb 20, 2025
1 parent 493248b commit bd51014
Showing 1 changed file with 44 additions and 97 deletions.
141 changes: 44 additions & 97 deletions tests/unit/s2n_mem_usage_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,19 @@
* usage. The greater the value, the more accurate the end result. */
#define MAX_CONNECTIONS 1000

/* This is roughly the current memory usage per connection, in KB */
#ifdef __FreeBSD__
#define MEM_PER_CONNECTION 57
#elif defined(__OpenBSD__)
#define MEM_PER_CONNECTION 61
#else
#define MEM_PER_CONNECTION 51
#endif

/* This is the maximum memory per connection including 4KB of slack */
#define TEST_SLACK 4
#define MAX_MEM_PER_CONNECTION \
((MEM_PER_CONNECTION + TEST_SLACK) * 1024)

/* This is the total maximum memory allowed */
#define MAX_MEM_ALLOWED(num_connections) \
(2 * (num_connections) *MAX_MEM_PER_CONNECTION)
/* This is roughly the current memory usage per connection, in KB.
*
* Do not attempt to track platform-specific variants of this number.
* Just exclude environments that vary too much.
* This test is not intended to be perfect-- it's just an indicator.
*/
#define MEM_PER_CONNECTION 45
#define ALLOWED_VARIANCE .05

/* This is the correct value of MEM_PER_CONNECTION based on test results.
* Basically, this calculation should reverse MAX_MEM_ALLOWED */
#define ACTUAL_MEM_PER_CONNECTION(num_connections, max_mem) \
((((max_mem) / 2 / (num_connections)) / 1024) - TEST_SLACK)
#define ALLOWED_DIFF (MEM_PER_CONNECTION * ALLOWED_VARIANCE)

ssize_t get_vm_data_size()
{
#ifdef __linux__
long page_size = 0;
ssize_t size = 0, resident = 0, share = 0, text = 0, lib = 0, data = 0, dt = 0;

Expand All @@ -92,57 +79,6 @@ ssize_t get_vm_data_size()
fclose(status_file);

return data * page_size;

#elif defined(__FreeBSD__)
pid_t ppid = getpid();
int pidinfo[4];
pidinfo[0] = CTL_KERN;
pidinfo[1] = KERN_PROC;
pidinfo[2] = KERN_PROC_PID;
pidinfo[3] = (int) ppid;

struct kinfo_proc procinfo = { 0 };

size_t len = sizeof(procinfo);

sysctl(pidinfo, nitems(pidinfo), &procinfo, &len, NULL, 0);

/* Taken from linprocfs implementation
* https://github.com/freebsd/freebsd-src/blob/779fd05344662aeec79c29470258bf657318eab3/sys/compat/linprocfs/linprocfs.c#L1019 */
segsz_t lsize = (procinfo.ki_size >> PAGE_SHIFT) - procinfo.ki_dsize - procinfo.ki_ssize - procinfo.ki_tsize - 1;

return lsize << PAGE_SHIFT;

#elif defined(__OpenBSD__)
struct kinfo_proc *procinfo;
kvm_t *kd;
pid_t ppid;
long page_size;
ssize_t size;
int nentries;

kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
ppid = getpid();
procinfo = kvm_getprocs(kd, KERN_PROC_PID, ppid, sizeof(*procinfo), &nentries);
if (procinfo == NULL || nentries == 0) {
return -1;
}

/* Taken from ps(1)'s calculation of vsize
* https://github.com/openbsd/src/blob/329e3480337617df4d195c9a400c3f186254b137/bin/ps/print.c#L603 */
size = procinfo->p_vm_dsize + procinfo->p_vm_ssize + procinfo->p_vm_tsize;

page_size = sysconf(_SC_PAGESIZE);
if (page_size < 0) {
return -1;
}
kvm_close(kd);

return (size * page_size);
#else
/* Not implemented for other platforms */
return 0;
#endif
}

int main(int argc, char **argv)
Expand All @@ -158,6 +94,23 @@ int main(int argc, char **argv)
DEFER_CLEANUP(struct s2n_test_io_pair io_pair = { 0 }, s2n_io_pair_close);
EXPECT_SUCCESS(s2n_io_pair_init_non_blocking(&io_pair));

/* Skip the test when not running with Linux.
* Handling other environments is not worth the complication.
*/
#ifndef __linux__
END_TEST();
#endif

/* Skip the test outside of our owned CI.
* We can use S2N_LIBCRYPTO, which our CI uses to communicate information
* about the configured libcrypto, as an indicator.
*
* This test is too unreliable to run on all customer environments.
*/
if (getenv("S2N_LIBCRYPTO") == NULL) {
END_TEST();
}

/* Skip the test when running under valgrind or address sanitizer, as those tools
* impact the memory usage. */
if (getenv("S2N_VALGRIND") != NULL || getenv("S2N_ADDRESS_SANITIZER") != NULL) {
Expand All @@ -172,9 +125,6 @@ int main(int argc, char **argv)
connectionsToUse = MAX(1, (file_limit.rlim_cur - 16) / 4);
}

const ssize_t maxAllowedMemDiff = MAX_MEM_ALLOWED(connectionsToUse);
const ssize_t minAllowedMemDiff = maxAllowedMemDiff * 0.75;

struct s2n_connection **clients = calloc(connectionsToUse, sizeof(struct s2n_connection *));
struct s2n_connection **servers = calloc(connectionsToUse, sizeof(struct s2n_connection *));

Expand Down Expand Up @@ -253,34 +203,31 @@ int main(int argc, char **argv)
free(clients);
free(servers);

TEST_DEBUG_PRINT("\n");
TEST_DEBUG_PRINT("VmData initial: %10zd\n", vm_data_initial);
TEST_DEBUG_PRINT("VmData after allocations: %10zd\n", vm_data_after_allocation);
TEST_DEBUG_PRINT("VmData after handshakes: %10zd\n", vm_data_after_handshakes);
TEST_DEBUG_PRINT("VmData after free handshake: %10zd\n", vm_data_after_free_handshake);
TEST_DEBUG_PRINT("VmData after release: %10zd\n", vm_data_after_release_buffers);
TEST_DEBUG_PRINT("Max VmData diff allowed: %10zd\n", maxAllowedMemDiff);
TEST_DEBUG_PRINT("Number of connections used: %10zu\n", connectionsToUse);

EXPECT_TRUE(vm_data_after_free_handshake <= vm_data_after_handshakes);
EXPECT_TRUE(vm_data_after_release_buffers <= vm_data_after_free_handshake);

ssize_t handshake_diff = (vm_data_after_handshakes - vm_data_initial);
ssize_t allocation_diff = (vm_data_after_allocation - vm_data_initial);

/*
* get_vm_data_size is required for this test to succeed.
* Any platform that doesn't implement get_vm_data_size should be excluded here.
*/
#ifndef __APPLE__
if (allocation_diff > maxAllowedMemDiff
|| handshake_diff > maxAllowedMemDiff
|| handshake_diff < minAllowedMemDiff) {
fprintf(stdout, "\nActual KB per connection: %i\n",
(int) ACTUAL_MEM_PER_CONNECTION(connectionsToUse, handshake_diff));
EXPECT_TRUE(allocation_diff <= handshake_diff);

ssize_t mem_per_conn = handshake_diff / (connectionsToUse * 2);
ssize_t kbs_per_conn = mem_per_conn / 1024;

if (kbs_per_conn < MEM_PER_CONNECTION - ALLOWED_DIFF
|| kbs_per_conn > MEM_PER_CONNECTION + ALLOWED_DIFF) {
printf("\nActual KB per connection: %li\n", kbs_per_conn);
printf("This is a %.2f%% change\n",
(kbs_per_conn - MEM_PER_CONNECTION) * 100.0 / MEM_PER_CONNECTION);

printf("\n");
printf("VmData initial: %10zd\n", vm_data_initial);
printf("VmData after allocations: %10zd\n", vm_data_after_allocation);
printf("VmData after handshakes: %10zd\n", vm_data_after_handshakes);
printf("VmData after free handshake: %10zd\n", vm_data_after_free_handshake);
printf("VmData after release: %10zd\n", vm_data_after_release_buffers);
printf("Number of connections used: %10zu\n", connectionsToUse);
FAIL_MSG("Unexpected memory usage. If expected, update MEM_PER_CONNECTION.");
}
#endif

END_TEST();
}

0 comments on commit bd51014

Please sign in to comment.