Implement simple OpenMP breakdown view

This commit is contained in:
Rodrigo Arias 2024-11-18 09:58:46 +01:00
parent 9826879bcd
commit 5ca0fcaed3
10 changed files with 372 additions and 5 deletions

View File

@ -0,0 +1,44 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW CPU: OpenMP Runtime/Label breakdown >
################################################################################
window_name CPU: OpenMP Runtime/Label breakdown
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled false
window_flags_enabled false
window_noncolor_mode true
window_custom_color_enabled true
window_custom_color_palette {1.000000000000:0,70,0},{3.000000000000:99,131,0},{4.000000000000:53,121,221},{5.000000000000:223,108,0},{6.000000000000:75,127,82},{7.000000000000:242,110,162},{8.000000000000:255,190,0},{9.000000000000:153,114,0},{10.000000000000:156,12,231},{11.000000000000:177,25,229},{12.000000000000:255,72,50},{15.000000000000:0,171,255},{16.000000000000:124,213,228},{17.000000000000:242,239,141},{18.000000000000:80,80,80},{19.000000000000:94,0,0},{20.000000000000:128,165,214},{22.000000000000:222,101,128},{23.000000000000:110,148,255},{100.000000000000:0,100,0},{101.000000000000:100,100,177},{102.000000000000:150,150,0}
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 53
window_filter_module evt_type_label 1 "CPU: OpenMP Runtime/Label breakdown"

View File

@ -65,6 +65,7 @@ add_library(emu STATIC
kernel/event.c
openmp/setup.c
openmp/event.c
openmp/breakdown.c
)
target_link_libraries(emu ovni-static)

View File

@ -35,6 +35,7 @@ enum emu_prv_types {
PRV_OPENMP_SUBSYSTEM = 50,
PRV_OPENMP_LABEL = 51,
PRV_OPENMP_TASKID = 52,
PRV_OPENMP_BREAKDOWN = 53,
PRV_OVNI_MARK = 100,
/* User marks [100, 200) */
PRV_RESERVED = 200,

View File

@ -313,7 +313,7 @@ model_nanos6_create(struct emu *emu)
extend_set(&emu->ext, model_id, e);
if (model_nanos6_breakdown_create(emu) != 0) {
err("model_nanos6_breakdown_connect failed");
err("model_nanos6_breakdown_create failed");
return -1;
}

239
src/emu/openmp/breakdown.c Normal file
View File

@ -0,0 +1,239 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "breakdown.h"
#include <stdint.h>
#include <stdio.h>
#include "bay.h"
#include "chan.h"
#include "common.h"
#include "cpu.h"
#include "emu.h"
#include "emu_args.h"
#include "emu_prv.h"
#include "extend.h"
#include "model_cpu.h"
#include "mux.h"
#include "openmp_priv.h"
#include "proc.h"
#include "pv/pcf.h"
#include "pv/prf.h"
#include "pv/prv.h"
#include "pv/pvt.h"
#include "recorder.h"
#include "sort.h"
#include "system.h"
#include "task.h"
#include "track.h"
#include "value.h"
static int
create_cpu(struct bay *bay, struct breakdown_cpu *bcpu, int64_t gindex)
{
enum chan_type t = CHAN_SINGLE;
chan_init(&bcpu->tri, t, "openmp.cpu%"PRIi64".breakdown.tri", gindex);
if (bay_register(bay, &bcpu->tri) != 0) {
err("bay_register tri failed");
return -1;
}
return 0;
}
int
model_openmp_breakdown_create(struct emu *emu)
{
if (emu->args.breakdown == 0)
return 0;
struct openmp_emu *memu = EXT(emu, 'P');
struct breakdown_emu *bemu = &memu->breakdown;
/* Count phy cpus */
struct system *sys = &emu->system;
int64_t nphycpus = (int64_t) (sys->ncpus - sys->nlooms);
bemu->nphycpus = nphycpus;
/* Create a new Paraver trace */
struct recorder *rec = &emu->recorder;
bemu->pvt = recorder_add_pvt(rec, "openmp-breakdown", (long) nphycpus);
if (bemu->pvt == NULL) {
err("recorder_add_pvt failed");
return -1;
}
if (sort_init(&bemu->sort, &emu->bay, nphycpus, "openmp.breakdown.sort") != 0) {
err("sort_init failed");
return -1;
}
for (struct cpu *cpu = sys->cpus; cpu; cpu = cpu->next) {
if (cpu->is_virtual)
continue;
struct openmp_cpu *mcpu = EXT(cpu, 'P');
struct breakdown_cpu *bcpu = &mcpu->breakdown;
if (create_cpu(&emu->bay, bcpu, cpu->gindex) != 0) {
err("create_cpu failed");
return -1;
}
}
return 0;
}
static int
select_label(struct mux *mux, struct value value, struct mux_input **input)
{
dbg("selecting tri output for value %s", value_str(value));
if (value.type != VALUE_NULL) {
dbg("selecting input 0 (label)");
*input = mux_get_input(mux, 0);
} else {
dbg("selecting input 1 (subsystem)");
*input = mux_get_input(mux, 1);
}
return 0;
}
static int
connect_cpu(struct bay *bay, struct openmp_cpu *mcpu)
{
struct breakdown_cpu *bcpu = &mcpu->breakdown;
/* Channel aliases */
struct chan *subsystem = &mcpu->m.track[CH_SUBSYSTEM].ch;
struct chan *label = &mcpu->m.track[CH_LABEL].ch;
struct chan *tri = &bcpu->tri;
/* Connect mux using label as select */
if (mux_init(&bcpu->mux, bay, label, tri, select_label, 2) != 0) {
err("mux_init failed");
return -1;
}
if (mux_set_input(&bcpu->mux, 0, label) != 0) {
err("mux_set_input label failed");
return -1;
}
if (mux_set_input(&bcpu->mux, 1, subsystem) != 0) {
err("mux_set_input subsystem failed");
return -1;
}
/* Emit unknown subsystem on NULL */
//mux_set_default(&bcpu->mux, value_int64(ST_UNKNOWN_SS));
return 0;
}
int
model_openmp_breakdown_connect(struct emu *emu)
{
if (emu->args.breakdown == 0)
return 0;
struct openmp_emu *memu = EXT(emu, 'P');
struct breakdown_emu *bemu = &memu->breakdown;
struct bay *bay = &emu->bay;
struct system *sys = &emu->system;
int64_t i = 0;
for (struct cpu *cpu = sys->cpus; cpu; cpu = cpu->next) {
if (cpu->is_virtual)
continue;
struct openmp_cpu *mcpu = EXT(cpu, 'P');
struct breakdown_cpu *bcpu = &mcpu->breakdown;
/* Connect tri channels and muxes */
if (connect_cpu(bay, mcpu) != 0) {
err("connect_cpu failed");
return -1;
}
/* Connect tri to sort */
if (sort_set_input(&bemu->sort, i, &bcpu->tri) != 0) {
err("sort_set_input failed");
return -1;
}
/* Connect out to PRV */
struct prv *prv = pvt_get_prv(bemu->pvt);
long type = PRV_OPENMP_BREAKDOWN;
long flags = PRV_SKIPDUP;
/* We may emit zero at the start, when an input changes and all
* the other sort output channels write a zero in the output,
* before the last value is set in prv.c. */
flags |= PRV_ZERO;
struct chan *out = sort_get_output(&bemu->sort, i);
if (prv_register(prv, (long) i, type, bay, out, flags)) {
err("prv_register failed");
return -1;
}
i++;
}
return 0;
}
int
model_openmp_breakdown_finish(struct emu *emu,
const struct pcf_value_label **labels)
{
if (emu->args.breakdown == 0)
return 0;
struct openmp_emu *memu = EXT(emu, 'P');
struct breakdown_emu *bemu = &memu->breakdown;
struct pcf *pcf = pvt_get_pcf(bemu->pvt);
long typeid = PRV_OPENMP_BREAKDOWN;
char label[] = "CPU: OpenMP Runtime/Label breakdown";
struct pcf_type *pcftype = pcf_add_type(pcf, (int) typeid, label);
const struct pcf_value_label *v = NULL;
/* Emit subsystem values */
for (v = labels[CH_SUBSYSTEM]; v->label; v++) {
if (pcf_add_value(pcftype, v->value, v->label) == NULL) {
err("pcf_add_value ss failed");
return -1;
}
}
/* Emit label values */
struct system *sys = &emu->system;
for (struct proc *p = sys->procs; p; p = p->gnext) {
struct openmp_proc *proc = EXT(p, 'P');
struct task_info *info = &proc->task_info;
if (task_create_pcf_types(pcftype, info->types) != 0) {
err("task_create_pcf_types failed");
return -1;
}
}
/* Also populate the row labels */
struct prf *prf = pvt_get_prf(bemu->pvt);
for (int64_t row = 0; row < bemu->nphycpus; row++) {
char name[128];
if (snprintf(name, 128, "~CPU %4" PRIi64, bemu->nphycpus - row) >= 128) {
err("label too long");
return -1;
}
if (prf_add(prf, (long) row, name) != 0) {
err("prf_add failed for %s", name);
return -1;
}
}
return 0;
}

View File

@ -0,0 +1,48 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef BREAKDOWN_H
#define BREAKDOWN_H
/*
* The breakdown model is implemented on top of the CPU subsystem, task_type and
* idle channels. The first mux0 selects the task type when the subsystem
* matches "Task body" otherwise forwards the subsystem as-is to tr. The second
* mux1 selects tr only when the CPU is not Idle, otherwise sets the output tri
* as Idle.
*
* +--------+
* | |
* | v
* | +------+
* label -----+-->--| |
* | mux0 |
* subsystem ---->--| |-->-- tri
* +------+
* Then the sort module takes the output tri of each CPU and sorts the values
* which are propagated to the PRV directly.
*
* +------+ +-----+
* cpu0.tri --->---| |--->---| |
* ... | sort | ... | PRV |
* cpuN.tri --->---| |--->---| |
* +------+ +-----+
*/
#include <stdint.h>
#include "chan.h"
#include "mux.h"
#include "sort.h"
struct breakdown_cpu {
struct mux mux;
struct chan tri;
};
struct breakdown_emu {
int64_t nphycpus;
struct sort sort;
struct pvt *pvt;
};
#endif /* BREAKDOWN_H */

View File

@ -8,6 +8,7 @@
#include "task.h"
#include "model_cpu.h"
#include "model_thread.h"
#include "breakdown.h"
/* Private enums */
@ -63,6 +64,7 @@ struct openmp_thread {
struct openmp_cpu {
struct model_cpu m;
struct breakdown_cpu breakdown;
};
struct openmp_proc {
@ -70,10 +72,19 @@ struct openmp_proc {
struct task_info task_info;
};
struct openmp_emu {
struct breakdown_emu breakdown;
};
int model_openmp_probe(struct emu *emu);
int model_openmp_create(struct emu *emu);
int model_openmp_connect(struct emu *emu);
int model_openmp_event(struct emu *emu);
int model_openmp_finish(struct emu *emu);
int model_openmp_breakdown_create(struct emu *emu);
int model_openmp_breakdown_connect(struct emu *emu);
int model_openmp_breakdown_finish(struct emu *emu,
const struct pcf_value_label **labels);
#endif /* OPENMP_PRIV_H */

View File

@ -278,6 +278,19 @@ model_openmp_create(struct emu *emu)
}
}
struct openmp_emu *e = calloc(1, sizeof(struct openmp_emu));
if (e == NULL) {
err("calloc failed:");
return -1;
}
extend_set(&emu->ext, model_id, e);
if (model_openmp_breakdown_create(emu) != 0) {
err("model_openmp_breakdown_create failed");
return -1;
}
return 0;
}
@ -294,6 +307,11 @@ model_openmp_connect(struct emu *emu)
return -1;
}
if (model_openmp_breakdown_connect(emu) != 0) {
err("model_openmp_breakdown_connect failed");
return -1;
}
return 0;
}
@ -379,6 +397,11 @@ model_openmp_finish(struct emu *emu)
return -1;
}
if (model_openmp_breakdown_finish(emu, pcf_labels) != 0) {
err("model_openmp_breakdown_finish 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

@ -26,7 +26,7 @@ if(NOT NOSV_FOUND)
endif()
function(openmp_rt_test)
ovni_test(${ARGN})
ovni_test(${ARGN} SORT)
target_compile_options("${OVNI_TEST_NAME}" PUBLIC "-fopenmp=libompv"
"-no-pedantic")
target_link_options("${OVNI_TEST_NAME}" PUBLIC "-fopenmp=libompv")
@ -34,7 +34,7 @@ function(openmp_rt_test)
set_property(TEST "${OVNI_TEST_NAME}" APPEND PROPERTY
ENVIRONMENT "OMP_OVNI=1")
set_property(TEST "${OVNI_TEST_NAME}" APPEND PROPERTY
ENVIRONMENT "NOSV_CONFIG_OVERRIDE=instrumentation.version=ovni")
ENVIRONMENT "NOSV_CONFIG_OVERRIDE=instrumentation.version=ovni,ovni.level=3")
endfunction()
openmp_rt_test(barrier-explicit.c)
@ -53,7 +53,7 @@ openmp_rt_test(taskloop.c)
openmp_rt_test(taskwait.c)
openmp_rt_test(team-distribute.c)
openmp_rt_test(worksharing-and-tasks.c)
openmp_rt_test(worksharing-mix.c)
openmp_rt_test(worksharing-mix.c BREAKDOWN)
openmp_rt_test(worksharing-task.c)
openmp_rt_test(worksharing.c)
openmp_rt_test(worksharing01.c)

View File

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