Add OpenMP support for labels and taskID views
Some checks failed
CI / build:rt (push) Failing after 15s
CI / build:debug (push) Successful in 13s
CI / build:asan (push) Failing after 13s
CI / build:nompi (push) Successful in 13s
CI / build:compilers (push) Successful in 13s
CI / build:local (push) Successful in 23s

Co-authored-by: Rodrigo Arias Mallo <rodrigo.arias@bsc.es>
This commit is contained in:
Raúl Peñacoba Veigas 2024-07-03 16:46:19 +02:00 committed by Rodrigo Arias
parent a7103f8510
commit 9826879bcd
25 changed files with 838 additions and 30 deletions

View File

@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Changed
- OpenMP model version increased to 1.2.0.
### Added
- Add support OpenMP label and task ID views.
## [1.11.0] - 2024-11-08
### Added

41
cfg/cpu/openmp/label.cfg Normal file
View File

@ -0,0 +1,41 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW CPU: OpenMP label of the RUNNING thread >
################################################################################
window_name CPU: OpenMP label of the RUNNING thread
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 51
window_filter_module evt_type_label 1 "CPU: OpenMP label of the RUNNING thread"

View File

@ -0,0 +1,41 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW CPU: OpenMP task id of the RUNNING thread >
################################################################################
window_name CPU: OpenMP task id of the RUNNING thread
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 52
window_filter_module evt_type_label 1 "CPU: OpenMP task id of the RUNNING thread"

View File

@ -0,0 +1,41 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW Thread: OpenMP label of the ACTIVE thread >
################################################################################
window_name Thread: OpenMP label of the ACTIVE thread
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 51
window_filter_module evt_type_label 1 "Thread: OpenMP label of the ACTIVE thread"

View File

@ -0,0 +1,41 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW Thread: OpenMP task id of the ACTIVE thread >
################################################################################
window_name Thread: OpenMP task id of the ACTIVE thread
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 52
window_filter_module evt_type_label 1 "Thread: OpenMP task id of the ACTIVE thread"

View File

@ -1,7 +1,7 @@
# Emulator events
This is a exhaustive list of the events recognized by the emulator.
Built on Jun 17 2024.
Built on Nov 13 2024.
## Model nanos6
@ -437,7 +437,7 @@ List of events for the model *ovni* with identifier **`O`** at version `1.1.0`:
## Model openmp
List of events for the model *openmp* with identifier **`P`** at version `1.1.0`:
List of events for the model *openmp* with identifier **`P`** at version `1.2.0`:
<dl>
<dt><a id="PBb" href="#PBb"><pre>PBb</pre></a></dt>
<dd>begins plain barrier</dd>
@ -563,6 +563,18 @@ List of events for the model *openmp* with identifier **`P`** at version `1.1.0`
<dd>begins initialization</dd>
<dt><a id="PCI" href="#PCI"><pre>PCI</pre></a></dt>
<dd>ceases initialization</dd>
<dt><a id="POc" href="#POc"><pre>POc+(u32 typeid, str label)</pre></a></dt>
<dd>creates a type %{typeid} with label &quot;%{label}&quot;</dd>
<dt><a id="PPc" href="#PPc"><pre>PPc(u32 taskid, u32 typeid)</pre></a></dt>
<dd>creates the task %{taskid} with type %{typeid}</dd>
<dt><a id="PPx" href="#PPx"><pre>PPx(u32 taskid)</pre></a></dt>
<dd>executes the task %{taskid}</dd>
<dt><a id="PPe" href="#PPe"><pre>PPe(u32 taskid)</pre></a></dt>
<dd>ends the task %{taskid}</dd>
<dt><a id="PQx" href="#PQx"><pre>PQx(u32 typeid)</pre></a></dt>
<dd>begins worksharing with type %{typeid}</dd>
<dt><a id="PQe" href="#PQe"><pre>PQe(u32 typeid)</pre></a></dt>
<dd>ends worksharing with type %{typeid}</dd>
</dl>
## Model tampi

View File

@ -8,21 +8,20 @@ refer to the
The [LLVM OpenMP Runtime](https://openmp.llvm.org/design/Runtimes.html) provides
an implementation of the OpenMP specification as a component of the LLVM
compiler infrastructure. We have modified the LLVM OpenMP runtime to run on top
compiler infrastructure. We have modified the LLVM OpenMP runtime (libomp) to run on top
of the [nOS-V](https://gitlab.bsc.es/nos-v/nos-v) runtime as part of the
[OmpSs-2 LLVM compiler](https://pm.bsc.es/llvm-ompss), named **OpenMP-V**.
[OmpSs-2 LLVM compiler](https://pm.bsc.es/llvm-ompss), named **libompv**.
We have added instrumentation events to OpenMP-V designed to be enabled along
We have added instrumentation events to libompv designed to be enabled along
the [nOS-V instrumentation](nosv.md). This document describes all the
instrumentation features included in our modified OpenMP-V runtime to identify
instrumentation features included in our modified libompv runtime to identify
what is happening. This data is useful for both users and developers of the
OpenMP runtime to analyze issues and undesired behaviors.
!!! Note
Instrumenting the original OpenMP runtime from the LLVM project is planned
but is not yet posible. For now you must use the modified OpenMP-V runtime
with nOS-V.
Instrumenting libomp is planned but is not yet posible.
For now you must use libompv.
## Enable the instrumentation
@ -33,25 +32,25 @@ To generate runtime traces, you will have to:
documentation](https://github.com/bsc-pm/nos-v/blob/master/docs/user/tracing.md).
Typically you should use the `--with-ovni` option at configure time to specify
where ovni is installed.
2. **Build OpenMP-V with ovni and nOS-V support:** Use the `PKG_CONFIG_PATH`
2. **Build libompv with ovni and nOS-V support:** Use the `PKG_CONFIG_PATH`
environment variable to specify the nOS-V and ovni installation
when configuring CMake.
3. **Enable the instrumentation in nOS-V at runtime:** Refer to the
[nOS-V documentation](https://github.com/bsc-pm/nos-v/blob/master/docs/user/tracing.md)
to find out how to enable the tracing at runtime. Typically you can just set
`NOSV_CONFIG_OVERRIDE="instrumentation.version=ovni"`.
4. **Enable the instrumentation of OpenMP-V at runtime:** Set the environment
4. **Enable the instrumentation of libompv at runtime:** Set the environment
variable `OMP_OVNI=1`.
Currently there is only support for the subsystem view, which is documented
below. The view is complemented with the information of [nOS-V views](nosv.md),
as OpenMP-V uses nOS-V tasks to run the workers.
Next sections describe each of the views included for analysis.
## Subsystem view
![Subsystem view example](fig/openmp-subsystem.png)
This view illustrates the activities of each thread with different states:
The view is complemented with the information of [nOS-V views](nosv.md),
as libompv uses nOS-V tasks to run the workers.
Subsystem illustrates the activities of each thread with different states:
- **Work-distribution subsystem**: Related to work-distribution constructs,
[in Chapter 11][workdis].
@ -135,9 +134,9 @@ This view illustrates the activities of each thread with different states:
- **Fork call**: Preparing a parallel section using the fork-join model.
Only called from the master thread.
- **Init**: Initializing the OpenMP-V runtime.
- **Init**: Initializing the libompv runtime.
- **Internal microtask**: Running a internal OpenMP-V function as a microtask.
- **Internal microtask**: Running a internal libompv function as a microtask.
- **User microtask**: Running user code as a microtask in a worker thread.
@ -156,9 +155,31 @@ This view illustrates the activities of each thread with different states:
[critical]: https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-5-2.pdf#section.15.2
[barrier]: https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-5-2.pdf#section.15.3
## Label view
The label view displays the text in the `label()` clause of OpenMP
tasks and work distribution constructs (static and dynamic for, single
and section). When the label is not provided, the source file and source
line location is used instead.
When nesting multiple tasks or work distribution constructs, only the
innermost label is shown.
Note that in this view, the numeric event value is a hash function of
the type label, so two distinct tasks (declared in different parts of
the code) with the same label will share the event value and have the
same color.
## Task ID view
The task ID view represents the numeric ID of the OpenMP task that is
currently running on each thread. The ID is a monotonically increasing
identifier assigned on task creation. Lower IDs correspond to tasks
created at an earlier point than higher IDs.
## Limitations
As the compiler generates the code that perform the calls to the OpenMP-V
As the compiler generates the code that perform the calls to the libompv
runtime, there are some parts of the execution that are complicated to
instrument by just placing a pair of events to delimite a function.

View File

@ -33,6 +33,8 @@ Track changes in emulator model versions.
## OpenMP
- openmp 1.2.0:
- Add support for labels and task ID views
- openmp 1.1.0: Initial version
## TAMPI

View File

@ -30,7 +30,7 @@
clangOmpss2Unwrapped = prev.clangOmpss2Unwrapped.override {
useGit = true;
gitBranch = "master";
gitCommit = "246e2df2eb10f52e48a57c8165074daecdb623f2";
gitCommit = "b7af30b36be3e7e90b33c5f01a3f7e3656df785f";
};
openmp = prev.openmp.overrideAttrs (old: {
# Newer version of LLVM OpenMP requires python3

View File

@ -33,6 +33,8 @@ enum emu_prv_types {
PRV_NANOS6_BREAKDOWN = 41,
PRV_KERNEL_CS = 45,
PRV_OPENMP_SUBSYSTEM = 50,
PRV_OPENMP_LABEL = 51,
PRV_OPENMP_TASKID = 52,
PRV_OVNI_MARK = 100,
/* User marks [100, 200) */
PRV_RESERVED = 200,

View File

@ -8,6 +8,9 @@
#include "emu_ev.h"
#include "extend.h"
#include "model_thread.h"
#include "ovni.h"
#include "proc.h"
#include "task.h"
#include "thread.h"
#include "value.h"
@ -95,7 +98,7 @@ static const int fn_table[256][256][3] = {
};
static int
process_ev(struct emu *emu)
simple(struct emu *emu)
{
if (!emu->thread->is_running) {
err("current thread %d not running", emu->thread->tid);
@ -122,6 +125,263 @@ process_ev(struct emu *emu)
return -1;
}
static int
create_task(struct emu *emu)
{
if (emu->ev->payload_size != 8) {
err("unexpected payload size");
return -1;
}
uint32_t taskid = emu->ev->payload->u32[0];
uint32_t typeid = emu->ev->payload->u32[1];
if (taskid == 0) {
err("taskid cannot be 0");
return -1;
}
if (typeid == 0) {
err("typeid cannot be 0");
return -1;
}
struct openmp_proc *proc = EXT(emu->proc, 'P');
struct task_info *info = &proc->task_info;
/* OpenMP submits inline tasks without pausing the previous
* task, so we relax the model to allow this for now. */
uint32_t flags = TASK_FLAG_RELAX_NESTING;
if (task_create(info, typeid, taskid, flags) != 0) {
err("task_create failed");
return -1;
}
dbg("task created with taskid %u", taskid);
return 0;
}
static int
update_task(struct emu *emu)
{
if (emu->ev->payload_size < 4) {
err("missing task id in payload");
return -1;
}
uint32_t taskid = emu->ev->payload->u32[0];
if (taskid == 0) {
err("taskid cannot be 0");
return -1;
}
struct openmp_thread *th = EXT(emu->thread, 'P');
struct openmp_proc *proc = EXT(emu->proc, 'P');
struct task_info *info = &proc->task_info;
struct task_stack *stack = &th->task_stack;
struct task *task = task_find(info->tasks, taskid);
if (task == NULL) {
err("cannot find task with id %u", taskid);
return -1;
}
/* OpenMP doesn't have parallel tasks */
uint32_t body_id = 1;
if (emu->ev->v == 'x') {
if (task_execute(stack, task, body_id) != 0) {
err("cannot change task state to running");
return -1;
}
if (chan_push(&th->m.ch[CH_TASKID], value_int64(task->id)) != 0) {
err("chan_push taskid failed");
return -1;
}
if (chan_push(&th->m.ch[CH_LABEL], value_int64(task->type->gid)) != 0) {
err("chan_push task label failed");
return -1;
}
} else if (emu->ev->v == 'e') {
if (task_end(stack, task, body_id) != 0) {
err("cannot change task state to end");
return -1;
}
if (chan_pop(&th->m.ch[CH_TASKID], value_int64(task->id)) != 0) {
err("chan_pop taskid failed");
return -1;
}
if (chan_pop(&th->m.ch[CH_LABEL], value_int64(task->type->gid)) != 0) {
err("chan_pop task label failed");
return -1;
}
} else {
err("unexpected task event %c", emu->ev->v);
return -1;
}
return 0;
}
static int
pre_task(struct emu *emu)
{
int ret = 0;
switch (emu->ev->v) {
case 'c':
ret = create_task(emu);
break;
case 'x':
case 'e':
ret = update_task(emu);
break;
default:
err("unexpected task event value");
return -1;
}
if (ret != 0) {
err("cannot update task state");
return -1;
}
return 0;
}
static int
pre_type(struct emu *emu)
{
uint8_t value = emu->ev->v;
if (value != 'c') {
err("unexpected event value %c", value);
return -1;
}
if (!emu->ev->is_jumbo) {
err("expecting a jumbo event");
return -1;
}
const uint8_t *data = &emu->ev->payload->jumbo.data[0];
uint32_t typeid;
memcpy(&typeid, data, 4); /* May be unaligned */
data += 4;
const char *label = (const char *) data;
struct openmp_proc *proc = EXT(emu->proc, 'P');
struct task_info *info = &proc->task_info;
/* It will be used for tasks and worksharings. */
if (task_type_create(info, typeid, label) != 0) {
err("task_type_create failed");
return -1;
}
return 0;
}
static int
update_ws_state(struct emu *emu, uint8_t action)
{
if (emu->ev->payload_size < 4) {
err("missing worksharing id in payload");
return -1;
}
uint32_t typeid = emu->ev->payload->u32[0];
if (typeid == 0) {
err("worksharing type id cannot be 0");
return -1;
}
struct openmp_thread *th = EXT(emu->thread, 'P');
struct openmp_proc *proc = EXT(emu->proc, 'P');
struct task_info *info = &proc->task_info;
/* Worksharings share the task type */
struct task_type *ttype = task_type_find(info->types, typeid);
if (ttype == NULL) {
err("cannot find ws with type %"PRIu32, typeid);
return -1;
}
if (action == 'x') {
if (chan_push(&th->m.ch[CH_LABEL], value_int64(ttype->gid)) != 0) {
err("chan_push worksharing label failed");
return -1;
}
} else {
if (chan_pop(&th->m.ch[CH_LABEL], value_int64(ttype->gid)) != 0) {
err("chan_pop worksharing label failed");
return -1;
}
}
return 0;
}
static int
pre_worksharing(struct emu *emu)
{
int ret = 0;
switch (emu->ev->v) {
case 'x':
case 'e':
ret = update_ws_state(emu, emu->ev->v);
break;
default:
err("unexpected ws event value %c", emu->ev->v);
return -1;
}
if (ret != 0) {
err("cannot update worksharing channels");
return -1;
}
return 0;
}
static int
process_ev(struct emu *emu)
{
if (!emu->thread->is_running) {
err("current thread %d not running", emu->thread->tid);
return -1;
}
switch (emu->ev->c) {
case 'B':
case 'I':
case 'W':
case 'T':
case 'A':
case 'M':
case 'H':
case 'C':
return simple(emu);
case 'P':
return pre_task(emu);
case 'O':
return pre_type(emu);
case 'Q':
return pre_worksharing(emu);
}
err("unknown event category");
return -1;
}
int
model_openmp_event(struct emu *emu)
{

View File

@ -5,6 +5,7 @@
#define OPENMP_PRIV_H
#include "emu.h"
#include "task.h"
#include "model_cpu.h"
#include "model_thread.h"
@ -12,6 +13,8 @@
enum openmp_chan {
CH_SUBSYSTEM = 0,
CH_LABEL,
CH_TASKID,
CH_MAX,
};
@ -55,12 +58,18 @@ enum openmp_function_values {
struct openmp_thread {
struct model_thread m;
struct task_stack task_stack;
};
struct openmp_cpu {
struct model_cpu m;
};
struct openmp_proc {
/* Shared among tasks and ws */
struct task_info task_info;
};
int model_openmp_probe(struct emu *emu);
int model_openmp_create(struct emu *emu);
int model_openmp_connect(struct emu *emu);

View File

@ -15,8 +15,10 @@
#include "model_cpu.h"
#include "model_pvt.h"
#include "model_thread.h"
#include "proc.h"
#include "pv/pcf.h"
#include "pv/prv.h"
#include "pv/pvt.h"
#include "system.h"
#include "thread.h"
#include "track.h"
@ -65,12 +67,22 @@ static struct ev_decl model_evlist[] = {
PAIR_B("PCf", "PCF", "fork call")
PAIR_B("PCi", "PCI", "initialization")
/* Task or worksharing type */
{ "POc+(u32 typeid, str label)", "creates a type %{typeid} with label \"%{label}\"" },
{ "PPc(u32 taskid, u32 typeid)", "creates the task %{taskid} with type %{typeid}" },
{ "PPx(u32 taskid)", "executes the task %{taskid}" },
{ "PPe(u32 taskid)", "ends the task %{taskid}" },
{ "PQx(u32 typeid)", "begins worksharing with type %{typeid}" },
{ "PQe(u32 typeid)", "ends worksharing with type %{typeid}" },
{ NULL, NULL },
};
struct model_spec model_openmp = {
.name = model_name,
.version = "1.1.0",
.version = "1.2.0",
.evlist = model_evlist,
.model = model_id,
.create = model_openmp_create,
@ -84,24 +96,34 @@ struct model_spec model_openmp = {
static const char *chan_name[CH_MAX] = {
[CH_SUBSYSTEM] = "subsystem",
[CH_LABEL] = "label",
[CH_TASKID] = "task ID",
};
static const int chan_stack[CH_MAX] = {
[CH_SUBSYSTEM] = 1,
[CH_LABEL] = 1,
[CH_TASKID] = 1,
};
static const int chan_dup[CH_MAX] = {
[CH_SUBSYSTEM] = 1,
[CH_LABEL] = 1, /* Two tasks nested with same type */
[CH_TASKID] = 1,
};
/* ----------------- pvt ------------------ */
static const int pvt_type[CH_MAX] = {
[CH_SUBSYSTEM] = PRV_OPENMP_SUBSYSTEM,
[CH_LABEL] = PRV_OPENMP_LABEL,
[CH_TASKID] = PRV_OPENMP_TASKID,
};
static const char *pcf_prefix[CH_MAX] = {
[CH_SUBSYSTEM] = "OpenMP subsystem",
[CH_LABEL] = "OpenMP label",
[CH_TASKID] = "OpenMP task ID",
};
static const struct pcf_value_label openmp_subsystem_values[] = {
@ -149,7 +171,9 @@ static const struct pcf_value_label *pcf_labels[CH_MAX] = {
};
static const long prv_flags[CH_MAX] = {
[CH_SUBSYSTEM] = PRV_EMITDUP,
[CH_SUBSYSTEM] = PRV_SKIPDUPNULL,
[CH_LABEL] = PRV_SKIPDUPNULL,
[CH_TASKID] = PRV_SKIPDUPNULL,
};
static const struct model_pvt_spec pvt_spec = {
@ -163,10 +187,14 @@ static const struct model_pvt_spec pvt_spec = {
static const int th_track[CH_MAX] = {
[CH_SUBSYSTEM] = TRACK_TH_ACT,
[CH_LABEL] = TRACK_TH_ACT,
[CH_TASKID] = TRACK_TH_ACT,
};
static const int cpu_track[CH_MAX] = {
[CH_SUBSYSTEM] = TRACK_TH_RUN,
[CH_LABEL] = TRACK_TH_RUN,
[CH_TASKID] = TRACK_TH_RUN,
};
/* ----------------- chan_spec ------------------ */
@ -213,9 +241,24 @@ model_openmp_probe(struct emu *emu)
return model_version_probe(&model_openmp, emu);
}
static int
init_proc(struct proc *sysproc)
{
struct openmp_proc *proc = calloc(1, sizeof(struct openmp_proc));
if (proc == NULL) {
err("calloc failed:");
return -1;
}
extend_set(&sysproc->ext, model_id, proc);
return 0;
}
int
model_openmp_create(struct emu *emu)
{
if (model_thread_create(emu, &th_spec) != 0) {
err("model_thread_init failed");
return -1;
@ -226,6 +269,15 @@ model_openmp_create(struct emu *emu)
return -1;
}
struct system *sys = &emu->system;
for (struct proc *p = sys->procs; p; p = p->gnext) {
if (init_proc(p) != 0) {
err("init_proc failed");
return -1;
}
}
return 0;
}
@ -245,6 +297,44 @@ model_openmp_connect(struct emu *emu)
return 0;
}
static int
create_pcf_type(struct system *sys, struct pcf *pcf, long typeid)
{
struct pcf_type *pcftype = pcf_find_type(pcf, (int) typeid);
for (struct proc *p = sys->procs; p; p = p->gnext) {
struct openmp_proc *proc = EXT(p, model_id);
struct task_info *info = &proc->task_info;
if (task_create_pcf_types(pcftype, info->types) != 0) {
err("task_create_pcf_types failed");
return -1;
}
}
return 0;
}
static int
finish_pvt(struct emu *emu, const char *name)
{
struct system *sys = &emu->system;
/* Emit task types for all channel types and processes */
struct pvt *pvt = recorder_find_pvt(&emu->recorder, name);
if (pvt == NULL) {
err("cannot find pvt with name '%s'", name);
return -1;
}
struct pcf *pcf = pvt_get_pcf(pvt);
if (create_pcf_type(sys, pcf, pvt_type[CH_LABEL]) != 0) {
err("create_pcf_type failed");
return -1;
}
return 0;
}
static int
end_lint(struct emu *emu)
{
@ -278,6 +368,17 @@ end_lint(struct emu *emu)
int
model_openmp_finish(struct emu *emu)
{
/* Fill task types */
if (finish_pvt(emu, "thread") != 0) {
err("finish_pvt thread failed");
return -1;
}
if (finish_pvt(emu, "cpu") != 0) {
err("finish_pvt cpu failed");
return -1;
}
/* When running in linter mode perform additional checks */
if (emu->args.linter_mode && end_lint(emu) != 0) {
err("end_lint failed");

View File

@ -1,4 +1,4 @@
# Copyright (c) 2022-2023 Barcelona Supercomputing Center (BSC)
# Copyright (c) 2022-2024 Barcelona Supercomputing Center (BSC)
# SPDX-License-Identifier: GPL-3.0-or-later
function(test_emu)
@ -13,3 +13,4 @@ add_subdirectory(nosv)
add_subdirectory(nanos6)
add_subdirectory(tampi)
add_subdirectory(mpi)
add_subdirectory(openmp)

View File

@ -0,0 +1,6 @@
# Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
# SPDX-License-Identifier: GPL-3.0-or-later
test_emu(nested-ws.c)
test_emu(nested-task.c)
test_emu(mix-task-ws.c)

View File

@ -0,0 +1,47 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef INSTR_OPENMP_H
#define INSTR_OPENMP_H
#include "instr.h"
#include "task.h"
static inline void
instr_openmp_init(void)
{
instr_require("openmp");
}
static inline uint32_t
instr_openmp_type_create(uint32_t typeid, const char *label)
{
struct ovni_ev ev = {0};
ovni_ev_set_mcv(&ev, "POc");
ovni_ev_set_clock(&ev, (uint64_t) get_clock());
char buf[256];
char *p = buf;
size_t nbytes = 0;
memcpy(buf, &typeid, sizeof(typeid));
p += sizeof(typeid);
nbytes += sizeof(typeid);
sprintf(p, "%s.%d", label, typeid);
nbytes += strlen(p) + 1;
ovni_ev_jumbo_emit(&ev, (uint8_t *) buf, (uint32_t) nbytes);
return task_get_type_gid(p);
}
INSTR_2ARG(instr_openmp_task_create, "PPc", uint32_t, taskid, uint32_t, typeid)
INSTR_1ARG(instr_openmp_task_execute, "PPx", uint32_t, taskid)
INSTR_1ARG(instr_openmp_task_end, "PPe", uint32_t, taskid)
INSTR_1ARG(instr_openmp_ws_enter, "PQx", uint32_t, typeid)
INSTR_1ARG(instr_openmp_ws_exit, "PQe", uint32_t, typeid)
#endif /* INSTR_OPENMP_H */

View File

@ -0,0 +1,47 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include <stdlib.h>
#include "compat.h"
#include "instr.h"
#include "instr_openmp.h"
int
main(void)
{
instr_start(0, 1);
instr_openmp_init();
enum { TASK=1, WS1=2, WS2=3 };
instr_openmp_type_create(TASK, "main task");
instr_openmp_type_create(WS1, "outer for");
instr_openmp_type_create(WS2, "inner for");
instr_openmp_task_create(1, TASK);
instr_openmp_task_execute(1);
sleep_us(100);
for (int i = 0; i < 3; i++) {
instr_openmp_ws_enter(WS1);
sleep_us(10);
{
instr_openmp_ws_enter(WS2);
sleep_us(10);
instr_openmp_ws_exit(WS2);
}
sleep_us(10);
instr_openmp_ws_exit(WS1);
sleep_us(10);
}
sleep_us(10);
instr_openmp_task_end(1);
sleep_us(10);
/* Another task from the same type */
instr_openmp_task_create(2, TASK);
instr_openmp_task_execute(2);
sleep_us(100);
instr_openmp_task_end(2);
instr_end();
return 0;
}

View File

@ -0,0 +1,32 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include <stdlib.h>
#include "compat.h"
#include "instr.h"
#include "instr_openmp.h"
int
main(void)
{
instr_start(0, 1);
instr_openmp_init();
enum { TYPE=1, A=1, B=2 };
instr_openmp_type_create(TYPE, "task");
instr_openmp_task_create(A, TYPE);
instr_openmp_task_create(B, TYPE);
instr_openmp_task_execute(A);
sleep_us(100);
instr_openmp_task_execute(B);
sleep_us(100);
instr_openmp_task_end(B);
sleep_us(100);
instr_openmp_task_end(A);
instr_end();
return 0;
}

View File

@ -0,0 +1,33 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include <stdlib.h>
#include "compat.h"
#include "instr.h"
#include "instr_openmp.h"
#define N 30
int
main(void)
{
instr_start(0, 1);
instr_openmp_init();
for (uint32_t type = 1; type <= N; type++)
instr_openmp_type_create(type, "ws");
for (uint32_t type = 1; type <= N; type++) {
instr_openmp_ws_enter(type);
sleep_us(100);
}
for (uint32_t type = N; type > 0; type--) {
instr_openmp_ws_exit(type);
sleep_us(100);
}
instr_end();
return 0;
}

View File

@ -14,12 +14,23 @@ if(NOT OPENMPV_COMPILER_FOUND OR NOT OPENMPV_LINKER_FOUND)
return()
endif()
find_package(Nosv)
if(NOT NOSV_FOUND)
if(ENABLE_ALL_TESTS)
message(FATAL_ERROR "nOS-V not found, cannot enable OpenMP-V RT tests")
else()
message(STATUS "nOS-V not found, disabling OpenMP-V RT tests")
endif()
return()
endif()
function(openmp_rt_test)
ovni_test(${ARGN})
target_compile_options("${OVNI_TEST_NAME}" PUBLIC "-fopenmp=libompv"
"-no-pedantic")
target_link_options("${OVNI_TEST_NAME}" PUBLIC "-fopenmp=libompv")
target_link_libraries("${OVNI_TEST_NAME}" PRIVATE "m")
target_link_libraries("${OVNI_TEST_NAME}" PRIVATE "m" PkgConfig::NOSV)
set_property(TEST "${OVNI_TEST_NAME}" APPEND PROPERTY
ENVIRONMENT "OMP_OVNI=1")
set_property(TEST "${OVNI_TEST_NAME}" APPEND PROPERTY
@ -48,3 +59,4 @@ openmp_rt_test(worksharing.c)
openmp_rt_test(worksharing01.c)
openmp_rt_test(worksharing02.c)
openmp_rt_test(worksharing03.c)
openmp_rt_test(worksharing-active-th.c DRIVER worksharing-active-th.driver.sh)

View File

@ -11,7 +11,7 @@ int main(void)
#pragma omp taskloop
for (int i = 0; i < 10000; i++)
{
#pragma omp task
#pragma omp task label("taskloop task")
sleep_us(1);
}
#pragma clang diagnostic pop

View File

@ -0,0 +1,22 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include <nosv.h>
#include "ovni.h"
/* Ensure that the thread is paused on nosv_waitfor(), so there is a hole in the
* OpenMP views, as they track the active thread (in the thread views) and the
* running thread (in the CPU views). */
int
main(void)
{
ovni_mark_type(0, OVNI_MARK_STACK, "tracker");
#pragma omp parallel for num_threads(1)
for (int i = 0; i < 100; ++i) {
ovni_mark_push(0, 123);
/* We should see a hole here */
nosv_waitfor(10, NULL);
ovni_mark_pop(0, 123);
}
}

View File

@ -0,0 +1,29 @@
target=$OVNI_TEST_BIN
export NOSV_APPID=1
export OMP_NUM_THREADS=1
$target
ovniemu -l ovni
# Mark API adds 100 to the type
prvtype="100"
row=$(grep '100:123$' ovni/thread.prv | head -1 | cut -d: -f 5)
t0=$(grep '100:123$' ovni/thread.prv | head -1 | cut -d: -f 6)
t1=$(grep '100:123$' ovni/thread.prv | tail -1 | cut -d: -f 6)
PRV_THREAD_STATE=4
TH_ST_PAUSED=2
# 2:0:1:1:1:15113228:100:123
count=$(grep "2:0:1:1:$row:.*:$PRV_THREAD_STATE:$TH_ST_PAUSED" ovni/thread.prv |\
awk -F: '$6 >= '$t0' && $6 <= '$t1' {n++} END {print n}')
if [ "$count" != 100 ]; then
echo "FAIL: expected 100 pause events"
exit 1
else
echo "OK: found 100 pause events"
fi

View File

@ -7,7 +7,7 @@ int main(void)
{
//#pragma omp single nowait
for (int i = 0; i < 100; i++) {
#pragma omp task
#pragma omp task label("minitask")
sleep_us(10);
}

View File

@ -9,7 +9,7 @@ int main(void)
{
#pragma omp parallel
{
#pragma omp for
#pragma omp for label("static-for-1")
for (int i = 0; i < 100; i++) {
sleep_us(1);
}
@ -26,7 +26,7 @@ int main(void)
{ sleep_us(104); printf("104\n"); }
}
#pragma omp for
#pragma omp for label("static-for-2")
for (int i = 0; i < 100; i++) {
sleep_us(1);
}
@ -46,11 +46,11 @@ int main(void)
#pragma omp barrier
#pragma omp for
#pragma omp for label("static-for-3")
for (int i = 0; i < 100; i++) {
sleep_us(1);
}
#pragma omp for schedule(dynamic, 1)
#pragma omp for schedule(dynamic, 1) label("dynamic-for")
for (int i = 0; i < 100; i++) {
sleep_us(i);
}