From 1f2e44c2ec28a1df11040cd56299fdddbfcd7452 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 21 Oct 2024 12:16:23 -0400 Subject: Add tests: * test_mp_fail_fast * test_mp_stop_continue --- tests/test_multiprocessing.c | 82 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) (limited to 'tests/test_multiprocessing.c') diff --git a/tests/test_multiprocessing.c b/tests/test_multiprocessing.c index b9cd309..3377783 100644 --- a/tests/test_multiprocessing.c +++ b/tests/test_multiprocessing.c @@ -1,5 +1,6 @@ #include "testing.h" #include "multiprocessing.h" +#include static struct MultiProcessingPool *pool; char *commands[] = { @@ -12,6 +13,10 @@ char *commands[] = { }; void test_mp_pool_init() { + STASIS_ASSERT((pool = mp_pool_init(NULL, "mplogs")) == NULL, "Pool should not be initialized with invalid ident"); + STASIS_ASSERT((pool = mp_pool_init("mypool", NULL)) == NULL, "Pool should not be initialized with invalid logname"); + STASIS_ASSERT((pool = mp_pool_init(NULL, NULL)) == NULL, "Pool should not be initialized with invalid arguments"); + pool = NULL; STASIS_ASSERT((pool = mp_pool_init("mypool", "mplogs")) != NULL, "Pool initialization failed"); STASIS_ASSERT_FATAL(pool != NULL, "Should not be NULL"); STASIS_ASSERT(pool->num_alloc == MP_POOL_TASK_MAX, "Wrong number of default records"); @@ -56,6 +61,7 @@ void test_mp_task() { pool = mp_pool_init("mypool", "mplogs"); if (pool) { + pool->status_interval = 3; for (size_t i = 0; i < sizeof(commands) / sizeof(*commands); i++) { struct MultiProcessingTask *task; char task_name[100] = {0}; @@ -113,6 +119,80 @@ void test_mp_pool_workflow() { } } +void test_mp_fail_fast() { + char *commands_ff[] = { + "sleep 1; true", + "sleep 2; true", + "sleep 3; false", + "sleep 10; true", // these... + "sleep 10; true", // shouldn't... + "sleep 10; true", // execute... but need to be here to satisfy the signaled_by test below + }; + + struct MultiProcessingPool *p; + STASIS_ASSERT((p = mp_pool_init("failfast", "failfastlogs")) != NULL, "Failed to initialize pool"); + for (size_t i = 0; i < sizeof(commands_ff) / sizeof(*commands_ff); i++) { + struct MultiProcessingTask *task; + char *command = commands_ff[i]; + STASIS_ASSERT(mp_pool_task(p, "task", NULL, (char *) command) != NULL, "Failed to queue task"); + } + + STASIS_ASSERT(mp_pool_join(p, get_cpu_count(), MP_POOL_FAIL_FAST) < 0, "Unexpected result"); + + struct result { + int total_signaled; + int total_status; + int total_unused; + } result = { + .total_signaled = 0, + .total_status = 0, + .total_unused = 0, + }; + for (size_t i = 0; i < p->num_used; i++) { + struct MultiProcessingTask *task = &p->task[i]; + if (task->signaled_by) result.total_signaled++; + if (task->status) result.total_status++; + if (task->pid == MP_POOL_PID_UNUSED) result.total_unused++; + } + STASIS_ASSERT(result.total_status == 1, "Unexpected status count"); + STASIS_ASSERT(result.total_signaled == 3, "Unexpected signal count"); + STASIS_ASSERT(result.total_unused == 5, "Unexpected PID. Should be marked UNUSED."); + mp_pool_show_summary(p); + mp_pool_free(&p); +} + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static void *pool_container(void *data) { + char *commands_sc[] = { + "sleep 10; echo done sleeping" + }; + struct MultiProcessingPool **x = (struct MultiProcessingPool **) data; + struct MultiProcessingPool *p = (*x); + pthread_mutex_lock(&mutex); + mp_pool_task(p, "stop_resume_test", NULL, commands_sc[0]); + mp_pool_join(p, 1, 0); + mp_pool_show_summary(p); + mp_pool_free(&p); + pthread_mutex_unlock(&mutex); + return NULL; +} + +void test_mp_stop_continue() { + struct MultiProcessingPool *p = NULL; + STASIS_ASSERT((p = mp_pool_init("stopcontinue", "stopcontinuelogs")) != NULL, "Failed to initialize pool"); + pthread_t th; + pthread_create(&th, NULL, pool_container, &p); + sleep(2); + if (p->task[0].pid != MP_POOL_PID_UNUSED) { + STASIS_ASSERT(kill(p->task[0].pid, SIGSTOP) == 0, "SIGSTOP failed"); + sleep(2); + STASIS_ASSERT(kill(p->task[0].pid, SIGCONT) == 0, "SIGCONT failed"); + } else { + STASIS_ASSERT(false, "Task was marked as unused when it shouldn't have been"); + } + pthread_join(th, NULL); +} + int main(int argc, char *argv[]) { STASIS_TEST_BEGIN_MAIN(); STASIS_TEST_FUNC *tests[] = { @@ -121,6 +201,8 @@ int main(int argc, char *argv[]) { test_mp_pool_join, test_mp_pool_free, test_mp_pool_workflow, + test_mp_fail_fast, + test_mp_stop_continue }; STASIS_TEST_RUN(tests); STASIS_TEST_END_MAIN(); -- cgit From a27fb62977c7a3faf9032ffbc7e6531700e30441 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 21 Oct 2024 13:17:16 -0400 Subject: The CI internal clocks are off? I don't see why these failed. * Increasing sleep times might help. --- tests/test_multiprocessing.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'tests/test_multiprocessing.c') diff --git a/tests/test_multiprocessing.c b/tests/test_multiprocessing.c index 3377783..750a001 100644 --- a/tests/test_multiprocessing.c +++ b/tests/test_multiprocessing.c @@ -122,17 +122,16 @@ void test_mp_pool_workflow() { void test_mp_fail_fast() { char *commands_ff[] = { "sleep 1; true", - "sleep 2; true", - "sleep 3; false", - "sleep 10; true", // these... - "sleep 10; true", // shouldn't... - "sleep 10; true", // execute... but need to be here to satisfy the signaled_by test below + "sleep 3; true", + "sleep 5; false", + "sleep 30; true", // these... + "sleep 30; true", // shouldn't... + "sleep 30; true", // execute... but need to be here to satisfy the signaled_by test below }; struct MultiProcessingPool *p; STASIS_ASSERT((p = mp_pool_init("failfast", "failfastlogs")) != NULL, "Failed to initialize pool"); for (size_t i = 0; i < sizeof(commands_ff) / sizeof(*commands_ff); i++) { - struct MultiProcessingTask *task; char *command = commands_ff[i]; STASIS_ASSERT(mp_pool_task(p, "task", NULL, (char *) command) != NULL, "Failed to queue task"); } @@ -156,7 +155,7 @@ void test_mp_fail_fast() { } STASIS_ASSERT(result.total_status == 1, "Unexpected status count"); STASIS_ASSERT(result.total_signaled == 3, "Unexpected signal count"); - STASIS_ASSERT(result.total_unused == 5, "Unexpected PID. Should be marked UNUSED."); + STASIS_ASSERT(result.total_unused > 0, "Unexpected PIDs present. Should be marked UNUSED."); mp_pool_show_summary(p); mp_pool_free(&p); } -- cgit From b46552ef9e37e60f7913c9776f73637e17a1d9e6 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 22 Oct 2024 01:33:35 -0400 Subject: Update test_mp_fail_fast * Record status(s) and just verify they're non-zero. Checking for exact values is difficult when you don't know the hardware ahead of time. * Apply HOLD state --- tests/test_multiprocessing.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'tests/test_multiprocessing.c') diff --git a/tests/test_multiprocessing.c b/tests/test_multiprocessing.c index 750a001..13a343d 100644 --- a/tests/test_multiprocessing.c +++ b/tests/test_multiprocessing.c @@ -140,22 +140,28 @@ void test_mp_fail_fast() { struct result { int total_signaled; - int total_status; + int total_status_fail; + int total_status_success; int total_unused; } result = { .total_signaled = 0, - .total_status = 0, + .total_status_fail = 0, + .total_status_success = 0, .total_unused = 0, }; for (size_t i = 0; i < p->num_used; i++) { struct MultiProcessingTask *task = &p->task[i]; if (task->signaled_by) result.total_signaled++; - if (task->status) result.total_status++; - if (task->pid == MP_POOL_PID_UNUSED) result.total_unused++; + if (task->status > 0) result.total_status_fail++; + if (task->status == 0) result.total_status_success++; + if (task->pid == MP_POOL_PID_UNUSED && task->status == MP_POOL_TASK_STATUS_INITIAL) result.total_unused++; } - STASIS_ASSERT(result.total_status == 1, "Unexpected status count"); - STASIS_ASSERT(result.total_signaled == 3, "Unexpected signal count"); - STASIS_ASSERT(result.total_unused > 0, "Unexpected PIDs present. Should be marked UNUSED."); + fprintf(stderr, "total_status_fail = %d\ntotal_status_success = %d\ntotal_signaled = %d\ntotal_unused = %d\n", + result.total_status_fail, result.total_status_success, result.total_signaled, result.total_unused); + STASIS_ASSERT(result.total_status_fail, "Should have failures"); + STASIS_ASSERT(result.total_status_success, "Should have successes"); + STASIS_ASSERT(result.total_signaled, "Should have signaled PIDs"); + STASIS_ASSERT(result.total_unused, "Should have PIDs marked UNUSED."); mp_pool_show_summary(p); mp_pool_free(&p); } -- cgit From ebb75d08d5f680f13867f71528b83df62a9d27b0 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 22 Oct 2024 01:47:34 -0400 Subject: Update test_mp_fail_fast * Brute force the conditions required to make this work. Issue 128 jobs. --- tests/test_multiprocessing.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'tests/test_multiprocessing.c') diff --git a/tests/test_multiprocessing.c b/tests/test_multiprocessing.c index 13a343d..7cc8bc7 100644 --- a/tests/test_multiprocessing.c +++ b/tests/test_multiprocessing.c @@ -120,20 +120,26 @@ void test_mp_pool_workflow() { } void test_mp_fail_fast() { - char *commands_ff[] = { + char *commands_ff[128] = { "sleep 1; true", "sleep 3; true", "sleep 5; false", - "sleep 30; true", // these... - "sleep 30; true", // shouldn't... - "sleep 30; true", // execute... but need to be here to satisfy the signaled_by test below }; + // Pad the array with tasks. None of these should execute when + // the "fail fast" conditions are met + char *nopcmd = "sleep 30; true"; + for (size_t i = 3; i < sizeof(commands_ff) / sizeof(*commands_ff); i++) { + commands_ff[i] = nopcmd; + } + struct MultiProcessingPool *p; STASIS_ASSERT((p = mp_pool_init("failfast", "failfastlogs")) != NULL, "Failed to initialize pool"); for (size_t i = 0; i < sizeof(commands_ff) / sizeof(*commands_ff); i++) { char *command = commands_ff[i]; - STASIS_ASSERT(mp_pool_task(p, "task", NULL, (char *) command) != NULL, "Failed to queue task"); + char taskname[100] = {0}; + snprintf(taskname, sizeof(taskname) - 1, "task_%03zu", i); + STASIS_ASSERT(mp_pool_task(p, taskname, NULL, (char *) command) != NULL, "Failed to queue task"); } STASIS_ASSERT(mp_pool_join(p, get_cpu_count(), MP_POOL_FAIL_FAST) < 0, "Unexpected result"); -- cgit From 30f48145d1a1c747c40f94e2a7314d4bdf61cf55 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 22 Oct 2024 09:11:11 -0400 Subject: Update test_mp_fail_fast * macOS Actions runners have 3 vCPUs. No wonder this wasn't working. Reduce the success count to 1. --- tests/test_multiprocessing.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tests/test_multiprocessing.c') diff --git a/tests/test_multiprocessing.c b/tests/test_multiprocessing.c index 7cc8bc7..7c9d695 100644 --- a/tests/test_multiprocessing.c +++ b/tests/test_multiprocessing.c @@ -121,7 +121,6 @@ void test_mp_pool_workflow() { void test_mp_fail_fast() { char *commands_ff[128] = { - "sleep 1; true", "sleep 3; true", "sleep 5; false", }; @@ -129,7 +128,7 @@ void test_mp_fail_fast() { // Pad the array with tasks. None of these should execute when // the "fail fast" conditions are met char *nopcmd = "sleep 30; true"; - for (size_t i = 3; i < sizeof(commands_ff) / sizeof(*commands_ff); i++) { + for (size_t i = 2; i < sizeof(commands_ff) / sizeof(*commands_ff); i++) { commands_ff[i] = nopcmd; } -- cgit