diff --git a/test/rt/nanos6/CMakeLists.txt b/test/rt/nanos6/CMakeLists.txt index f59dcb2..1b7d354 100644 --- a/test/rt/nanos6/CMakeLists.txt +++ b/test/rt/nanos6/CMakeLists.txt @@ -41,6 +41,10 @@ nanos6_rt_test(several-tasks.c) nanos6_rt_test(sched-add.c) nanos6_rt_test(if0.c) #nanos6_rt_test(taskfor.c) #Taskfor no longer supported +nanos6_rt_test(spawn-task.c) +nanos6_rt_test(spawn-task-external.c) +nanos6_rt_test(spawn-task-external-bad.c SHOULD_FAIL + REGEX "ovni_finish: thread [0-9]* is not dead") # Test multiple instrumentation levels nanos6_rt_test(simple-task.c NAME simple-task-level-1 LEVEL 1) diff --git a/test/rt/nanos6/spawn-task-external-bad.c b/test/rt/nanos6/spawn-task-external-bad.c new file mode 100644 index 0000000..e286d6d --- /dev/null +++ b/test/rt/nanos6/spawn-task-external-bad.c @@ -0,0 +1,71 @@ +/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +/* Spawn a task from an external thread that calls some nanos6 + * functions. The external thread must be paused when the task pauses + * the execution. This emulates the same behavior as TAMPI when using a + * polling task. */ + +#define _DEFAULT_SOURCE + +#include +#include +#include +#include + +#include "common.h" + +static double +get_time_ms(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (double) ts.tv_sec + (double) ts.tv_nsec * 1.0e-9; +} + +static void +dummy_work(double ms) +{ + double end = get_time_ms() + ms * 1e-3; + while (get_time_ms() < end); +} + +static void +polling_func(void *arg) +{ + double ms = *((double *) arg); + double end = get_time_ms() + ms * 1e-3; + while (get_time_ms() < end) { + dummy_work(1.0); /* 1 ms */ + nanos6_wait_for(1000UL); /* 1 ms */ + } +} + +/* Call the nanos6_spawn_function from an external thread */ +static void * +spawn(void *arg) +{ + double ms = *((double *) arg); + nanos6_spawn_function(polling_func, &ms, NULL, NULL, "polling_task"); + return NULL; +} + +int +main(void) +{ + pthread_t th; + double T = 100.0; + + if (pthread_create(&th, NULL, spawn, &T) != 0) + die("pthread_create failed:"); + + if (pthread_join(th, NULL) != 0) + die("pthread_join failed:"); + + #pragma oss task label("dummy_task") + dummy_work(T); + + #pragma oss taskwait + + return 0; +} diff --git a/test/rt/nanos6/spawn-task-external.c b/test/rt/nanos6/spawn-task-external.c new file mode 100644 index 0000000..7e28368 --- /dev/null +++ b/test/rt/nanos6/spawn-task-external.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +/* Spawn a task from an external thread that calls some nanos6 + * functions. The external thread must be paused when the task pauses + * the execution. This emulates the same behavior as TAMPI when using a + * polling task. */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include "common.h" +#include "compat.h" +#include "ovni.h" + +static double +get_time_ms(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (double) ts.tv_sec + (double) ts.tv_nsec * 1.0e-9; +} + +static void +dummy_work(double ms) +{ + double end = get_time_ms() + ms * 1e-3; + while (get_time_ms() < end); +} + +static void +polling_func(void *arg) +{ + double ms = *((double *) arg); + double end = get_time_ms() + ms * 1e-3; + while (get_time_ms() < end) { + dummy_work(1.0); /* 1 ms */ + nanos6_wait_for(1000UL); /* 1 ms */ + } +} + +static inline void +instr_thread_start(int32_t cpu, int32_t creator_tid, uint64_t tag) +{ + ovni_thread_init(gettid()); + + struct ovni_ev ev = {0}; + + ovni_ev_set_mcv(&ev, "OHx"); + ovni_ev_set_clock(&ev, ovni_clock_now()); + ovni_payload_add(&ev, (uint8_t *) &cpu, sizeof(cpu)); + ovni_payload_add(&ev, (uint8_t *) &creator_tid, sizeof(creator_tid)); + ovni_payload_add(&ev, (uint8_t *) &tag, sizeof(tag)); + ovni_ev_emit(&ev); + + /* Flush the events to disk before killing the thread */ + ovni_flush(); +} + +static inline void +instr_thread_end(void) +{ + struct ovni_ev ev = {0}; + + ovni_ev_set_mcv(&ev, "OHe"); + ovni_ev_set_clock(&ev, ovni_clock_now()); + ovni_ev_emit(&ev); + + /* Flush the events to disk before killing the thread */ + ovni_flush(); +} + +/* Call the nanos6_spawn_function from an external thread */ +static void * +spawn(void *arg) +{ + /* Inform ovni of this external thread */ + instr_thread_start(-1, -1, 0); + + double ms = *((double *) arg); + nanos6_spawn_function(polling_func, &ms, NULL, NULL, "polling_task"); + + /* Then inform that the thread finishes */ + instr_thread_end(); + + return NULL; +} + +int +main(void) +{ + pthread_t th; + double T = 100.0; + + if (pthread_create(&th, NULL, spawn, &T) != 0) + die("pthread_create failed:"); + + if (pthread_join(th, NULL) != 0) + die("pthread_join failed:"); + + #pragma oss task label("dummy_task") + dummy_work(T); + + #pragma oss taskwait + + return 0; +} diff --git a/test/rt/nanos6/spawn-task.c b/test/rt/nanos6/spawn-task.c new file mode 100644 index 0000000..4a687e0 --- /dev/null +++ b/test/rt/nanos6/spawn-task.c @@ -0,0 +1,54 @@ +/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +/* Spawn a task from the main thread that calls some nanos6 + * functions. */ + +#define _DEFAULT_SOURCE + +#include +#include +#include + +#include "common.h" + +static double +get_time_ms(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (double) ts.tv_sec + (double) ts.tv_nsec * 1.0e-9; +} + +static void +dummy_work(double ms) +{ + double end = get_time_ms() + ms * 1e-3; + while (get_time_ms() < end); +} + +static void +polling_func(void *arg) +{ + double ms = *((double *) arg); + double end = get_time_ms() + ms * 1e-3; + while (get_time_ms() < end) { + dummy_work(1.0); /* 1 ms */ + nanos6_wait_for(1000UL); /* 1 ms */ + } +} + +int +main(void) +{ + double T = 100.0; + + nanos6_spawn_function(polling_func, &T, NULL, NULL, "polling_task"); + + #pragma oss task label("dummy_task") + dummy_work(T); + + #pragma oss taskwait + + return 0; +}