Compare commits

..

1 Commits

Author SHA1 Message Date
d98f270cb6 perf(functests): speedup — profrc pre-baking, pty-close shutdown, parallel port pools
All checks were successful
CI Code / Check spelling (pull_request) Successful in 18s
CI Code / Check coding style (pull_request) Successful in 31s
CI Code / Code Coverage (pull_request) Successful in 3m2s
CI Code / Linux (debian) (pull_request) Successful in 4m31s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m32s
CI Code / Linux (arch) (pull_request) Successful in 4m48s
Replace 16 interactive UI setup commands with pre-written profrc file
containing [ui] and [notifications] sections (~1800ms saved per test).

Replace sleep(1) + blocking waitpid with close(pty fd) → SIGHUP →
polling waitpid(WNOHANG) → SIGTERM/SIGKILL fallback chain (~4900ms
saved per test).

Remove post-stbbr_start() and post-stbbr_stop() sleeps — bind+listen
completes synchronously before stbbr_start() returns, and
pthread_join() in stbbr_stop() guarantees socket cleanup (~200ms saved).

Add PORTS_PER_GROUP=50 isolated port ranges per test group to enable
safe parallel execution of 4 groups without port conflicts.
2026-03-12 17:35:25 +03:00

View File

@@ -21,6 +21,14 @@
/* Number of parallel test groups for CI builds */
#define TEST_GROUPS 4
/* Number of ports reserved per test group; allows skipping TIME_WAIT ports */
#define PORTS_PER_GROUP 50
/* Shutdown polling: interval and maximum attempts before escalating signals */
#define SHUTDOWN_POLL_MS 50
#define SHUTDOWN_POLL_MAX 100 /* 100 x 50ms = 5s */
#define SIGTERM_POLL_MAX 20 /* 20 x 50ms = 1s */
char *config_orig;
char *data_orig;
@@ -247,10 +255,12 @@ init_prof_test(void **state)
const char *build_env = getenv("PROF_BUILD_INDEX");
int build_idx = build_env ? atoi(build_env) : 0;
/* Calculate port base: each build uses a separate block of
* TEST_GROUPS * PORTS_PER_GROUP ports so parallel CI builds don't collide.
* Build 0/1: 5230, Build 2: 5430, Build 3: 5630, etc. */
#define PORTS_PER_GROUP 50
/* Calculate port base: each build uses a different range of
* TEST_GROUPS * PORTS_PER_GROUP ports.
* Build 0 (local/default): 5230-5429, Full: 5230-5429, Minimal: 5430-5629, etc.
* Build 0 and Full share the same range because build 0 is for local runs
* or sequential run (no parallel builds), while Full/Minimal/NoEncrypt/Default
* are used in CI where they run in parallel. */
int port_base = 5230 + ((build_idx > 0 ? build_idx - 1 : 0) * TEST_GROUPS * PORTS_PER_GROUP);
/* Each group gets a dedicated range of ports for parallel execution.
@@ -317,18 +327,14 @@ init_prof_test(void **state)
_create_chatlogs_dir();
_create_logs_dir();
/* Pre-write profrc with all UI settings that were previously set via
* 16 interactive commands (each costing ~115ms of input+regex polling).
* This eliminates ~1800ms from init_prof_test. */
const char* flatfile_env = getenv("PROF_FLATFILE");
/* Pre-write profrc with UI/notification defaults to ensure consistent,
* deterministic output across tests (no timestamps, no roster/occupants
* panels, low input-blocking delay for fast command processing). */
char profrc_path[512];
snprintf(profrc_path, sizeof(profrc_path),
"%s/profanity/profrc", xdg_config_home);
FILE* prc = fopen(profrc_path, "w");
if (prc) {
if (flatfile_env && strcmp(flatfile_env, "1") == 0) {
fprintf(prc, "[logging]\ndblog=flatfile\n\n");
}
fprintf(prc,
"[ui]\n"
"inpblock=5\n"
@@ -352,7 +358,6 @@ init_prof_test(void **state)
int prof_started = prof_output_regex("CProof\\. Type /help for help information\\.");
assert_true(prof_started);
/* UI settings are pre-baked in profrc — no interactive commands needed. */
return 0;
}
@@ -367,20 +372,19 @@ close_prof_test(void **state)
usleep(100000); /* 100ms grace for /quit to be read from pty buffer */
close(fd);
fd = 0;
/* Poll for exit — typically completes in <100ms */
int exited = 0;
for (int i = 0; i < 100; i++) { /* 100 × 50ms = 5s max */
for (int i = 0; i < SHUTDOWN_POLL_MAX; i++) {
if (waitpid(child_pid, NULL, WNOHANG) != 0) {
exited = 1;
break;
}
usleep(50000); /* 50ms */
usleep(SHUTDOWN_POLL_MS * 1000);
}
if (!exited) {
kill(child_pid, SIGTERM);
for (int i = 0; i < 20; i++) { /* 1s grace */
for (int i = 0; i < SIGTERM_POLL_MAX; i++) {
if (waitpid(child_pid, NULL, WNOHANG) != 0) { exited = 1; break; }
usleep(50000);
usleep(SHUTDOWN_POLL_MS * 1000);
}
if (!exited) {
kill(child_pid, SIGKILL);
@@ -398,9 +402,6 @@ close_prof_test(void **state)
}
stbbr_stop();
/* No sleep needed: stbbr_stop() calls pthread_join() which blocks until
* the server thread completes _shutdown() (close listen_socket).
* SO_REUSEADDR is set, so the port is immediately available for rebind. */
return 0;
}