From 2ff311e6c9e48bedc751071d05d51dbf8ea7a5ca Mon Sep 17 00:00:00 2001 From: Joachim Jenke Date: Tue, 17 Mar 2026 11:59:02 +0100 Subject: [PATCH] Add support for metrics that might consist of multiple values --- CMakeLists.txt | 1 - README.md | 3 +- critical-core.cpp | 136 ++---- criticalPath.h | 393 +++++++++++++----- debug.cpp | 14 + external/backward-cpp/backward.hpp | 11 +- handle-data.h | 85 ++-- ipc-data.h | 20 + mpi-critical.cpp | 42 +- mpi-critical.h | 96 ++--- ompt-critical.cpp | 4 +- tests/CMakeLists.txt | 10 +- tests/fortran/CMakeLists.txt | 4 +- .../{mpi-balanced.f90 => mpi-balanced.F90} | 0 .../{mpi-imbalance.f90 => mpi-imbalance.F90} | 0 tests/omp-only/omp-serialization.c | 4 +- tracking.cpp | 45 +- 17 files changed, 506 insertions(+), 362 deletions(-) create mode 100644 ipc-data.h rename tests/fortran/{mpi-balanced.f90 => mpi-balanced.F90} (100%) rename tests/fortran/{mpi-imbalance.f90 => mpi-imbalance.F90} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2afd6aa..44f823f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,7 +196,6 @@ if (OTFCPT_USE_GNU_LIBCPP) set(STDCPLUS_COMPILE_FLAGS "") set(STDCPLUS_LINK_FLAGS "") endif() - set(LINK_EXTERNAL_LIBRARIES Backward::Interface) add_compile_definitions(-DUSE_STL) if (OTFCPT_USE_BACKWARD) add_compile_definitions(-DUSE_BACKWARD) diff --git a/README.md b/README.md index 89e567e..3d88d38 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,6 @@ MPI_Pcontrol(1); // start // region of interest MPI_Pcontrol(0); // stop ``` - or alternatively for OpenMP applications: ``` omp_control_tool(omp_control_tool_start, 0, NULL); // start @@ -197,4 +196,4 @@ external/wrap/wrap.py -s -n gen-wrappers.w -o gen-wrappers.cpp ## Publications - **Joachim Protze, Fabian Orland, Kingshuk Haldar, Thore Koritzius, Christian Terboven**: *On-the-Fly Calculation of Model Factors for Multi-paradigm Applications*. Euro-Par 2022 -- **Joachim Jenke, Michael Knobloch, Marc-André Hermanns, Simon Schwitanski**: *A Shim Layer for Transparently Adding Meta Data to MPI Handles*. EuroMPI 2023 \ No newline at end of file +- **Joachim Jenke, Michael Knobloch, Marc-André Hermanns, Simon Schwitanski**: *A Shim Layer for Transparently Adding Meta Data to MPI Handles*. EuroMPI 2023 diff --git a/critical-core.cpp b/critical-core.cpp index 50d3dfa..f316e13 100644 --- a/critical-core.cpp +++ b/critical-core.cpp @@ -94,6 +94,11 @@ uint64_t my_next_id() { return ret; } +// Specializations that determine whether a metric class needs locking in +// SyncClock +template <> UniqLock::UniqLock(std::mutex &m) : u(m) {} +template <> UniqLock::UniqLock(std::mutex &m) : u() {} + double totalProgrammTime = 0; double startProgrammTime = getTime(), endProgrammTime; double crit_path_useful_time = 0; @@ -149,6 +154,17 @@ void startMeasurement(double time) { void stopMeasurement(double time) { endProgrammTime = time; } +template <> +double atomic_add(std::atomic &operand, double value_to_add) { + double old = operand.load(std::memory_order_consume); + double desired = old + value_to_add; + while (!operand.compare_exchange_weak(old, desired, std::memory_order_release, + std::memory_order_consume)) + desired = old + value_to_add; + + return desired; +} + #define NUM_SHARED_METRICS 7 void finishMeasurement() { @@ -188,8 +204,8 @@ void finishMeasurement() { if (tclock->getState() != STATE_INIT) tclock->setState(endProgrammTime, STATE_INIT, __func__); proc_counts.add(*tclock); - double curr_uc = tclock->clocks[CLOCK_USEFUL].thread.load(); - double curr_oot = tclock->clocks[CLOCK_OOMP].thread.load(); + double curr_uc = tclock->clocks[CLOCK_USEFUL].thread.getTime(); + double curr_oot = tclock->clocks[CLOCK_OOMP].thread.getTime(); if (curr_uc > uc_max[0]) { uc_max[0] = curr_uc; } @@ -205,14 +221,15 @@ void finishMeasurement() { } else { num_threads = 1; uc_max[0] = uc_avg[0] = - thread_local_clock->clocks[CLOCK_USEFUL].thread.load(); + thread_local_clock->clocks[CLOCK_USEFUL].thread.getTime(); uc_max[2] = uc_avg[2] = - thread_local_clock->clocks[CLOCK_OOMP].thread.load(); + thread_local_clock->clocks[CLOCK_OOMP].thread.getTime(); proc_counts.add(*thread_local_clock); } - uc_max[1] = uc_avg[1] = thread_local_clock->clocks[CLOCK_OMPI].proc.load(); - uc_max[3] = uc_avg[3] = thread_local_clock->clocks[CLOCK_USEFUL].proc.load(); - uc_max[4] = uc_avg[4] = thread_local_clock->clocks[CLOCK_OOMP].proc.load(); + uc_max[1] = uc_avg[1] = thread_local_clock->clocks[CLOCK_OMPI].proc.getTime(); + uc_max[3] = uc_avg[3] = + thread_local_clock->clocks[CLOCK_USEFUL].proc.getTime(); + uc_max[4] = uc_avg[4] = thread_local_clock->clocks[CLOCK_OOMP].proc.getTime(); uc_max[5] = uc_avg[5] = uc_avg[3] - uc_avg[4]; uc_avg[5] = uc_avg[5] * num_threads; uc_max[6] = uc_max[0]; @@ -256,11 +273,11 @@ void finishMeasurement() { if (myProcId == 0) { // display results on master thread // calculate pop metrics double totalRuntimeIdeal = - thread_local_clock->clocks[CLOCK_USEFUL].critical.load(); + thread_local_clock->clocks[CLOCK_USEFUL].critical.getTime(); double totalOutsideMPIIdeal = - thread_local_clock->clocks[CLOCK_OMPI].critical.load(); + thread_local_clock->clocks[CLOCK_OMPI].critical.getTime(); double totalOutsideOMPIdeal = - thread_local_clock->clocks[CLOCK_OOMP].critical.load(); + thread_local_clock->clocks[CLOCK_OOMP].critical.getTime(); avgComputation[5] = avgComputation[5] + totalRuntimeReal; maxComputation[5] = maxComputation[5] + totalRuntimeReal; @@ -434,101 +451,20 @@ inline int my_get_tid() { return thread_local_clock ? thread_local_clock->thread_id : 0; } -void SYNC_CLOCK::CheckArc(const char *loc, THREAD_CLOCK *tc_arg) { - CheckArc(loc, "", tc_arg); -} - -void SYNC_CLOCK::CheckArc(const char *loc, const char *fileline, - THREAD_CLOCK *tc_arg) { - if (sync_state == STATE_INIT) { - sync_state = tc_arg->getState(); - init_loc = loc; - init_fileline = fileline; - } else { - DCHECK_EQ_VA(tc_arg->getState(), sync_state, "\nInit location: ", init_loc, - "@", init_fileline, "\nCurrent location: ", loc, "@", fileline, - "\n"); - } -} - -void SYNC_CLOCK::OmpHBefore(const char *loc, THREAD_CLOCK *tc_arg) { - OmpHBefore(loc, 0, tc_arg); -} - -void SYNC_CLOCK::OmpHBefore(const char *loc, const char *fileline, - THREAD_CLOCK *tc_arg) { - if (!analysis_flags->running) - return; -#ifdef DEBUG_HB - printf("%s @%s: %p <- %p\n", __PRETTY_FUNCTION__, loc, this, tc_arg); -#endif - this->CheckArc(loc, fileline, tc_arg); - clocks[CLOCK_USEFUL].OmpHBefore(tc_arg->clocks[CLOCK_USEFUL]); - clocks[CLOCK_OOMP].OmpHBefore(tc_arg->clocks[CLOCK_OOMP]); - clocks[CLOCK_OMPI].OmpHBefore(tc_arg->clocks[CLOCK_OMPI]); -} - -void SYNC_CLOCK::OmpHAfter(const char *loc, THREAD_CLOCK *tc_arg) { - OmpHAfter(loc, "", tc_arg); -} - -void SYNC_CLOCK::OmpHAfter(const char *loc, const char *fileline, - THREAD_CLOCK *tc_arg) { - if (!analysis_flags->running) - return; -#ifdef DEBUG_HB - printf("%s @%s: %p -> %p\n", __PRETTY_FUNCTION__, loc, this, tc_arg); -#endif - this->CheckArc(loc, fileline, tc_arg); - clocks[CLOCK_USEFUL].OmpHAfter(tc_arg->clocks[CLOCK_USEFUL]); - clocks[CLOCK_OOMP].OmpHAfter(tc_arg->clocks[CLOCK_OOMP]); - clocks[CLOCK_OMPI].OmpHAfter(tc_arg->clocks[CLOCK_OMPI]); -} - -// Copy constructor for THREAD_CLOCK -// assigns unique id and copies atomic values correctly -THREAD_CLOCK::THREAD_CLOCK(const THREAD_CLOCK &other) - : THREAD_CLOCK(my_next_id(), 0) { - if (other.getState() != STATE_INIT) - clock_state_stack.PushBack(other.getState()); - clocks[CLOCK_USEFUL] = other.clocks[CLOCK_USEFUL]; - clocks[CLOCK_OMPI] = other.clocks[CLOCK_OMPI]; - clocks[CLOCK_OOMP] = other.clocks[CLOCK_OOMP]; -} - -void OmpClockReset(THREAD_CLOCK *cv) { - if (!cv || cv->openmp_thread) - return; - OmpClockReset(static_cast(cv)); -} - -void OmpClockReset(SYNC_CLOCK *cv) { - if (!analysis_flags->running) - return; - if (cv == nullptr) - DCHECK_VA(0, "Unexpected NULL arg"); - else { - cv->clocks[CLOCK_USEFUL].Reset(-1e50); - cv->clocks[CLOCK_OMPI].Reset(-1e50); - cv->clocks[CLOCK_OOMP].Reset(-1e50); - cv->sync_state = STATE_INIT; - } -} - void startTool(bool toolControl, ClockState cs) { if (analysis_flags->stopped && !toolControl) return; if (!analysis_flags->running) { DCHECK_EQ(thread_local_clock->getState(), STATE_INIT); - DCHECK_EQ(thread_local_clock->clocks[CLOCK_USEFUL].thread, 0); - DCHECK_EQ(thread_local_clock->clocks[CLOCK_USEFUL].proc, 0); - DCHECK_EQ(thread_local_clock->clocks[CLOCK_USEFUL].critical, 0); - DCHECK_EQ(thread_local_clock->clocks[CLOCK_OMPI].proc, 0); - DCHECK_EQ(thread_local_clock->clocks[CLOCK_OMPI].thread, 0); - DCHECK_EQ(thread_local_clock->clocks[CLOCK_OMPI].critical, 0); - DCHECK_EQ(thread_local_clock->clocks[CLOCK_OOMP].thread, 0); - DCHECK_EQ(thread_local_clock->clocks[CLOCK_OOMP].critical, 0); - DCHECK_EQ(thread_local_clock->clocks[CLOCK_OOMP].proc, 0); + DCHECK_EQ(thread_local_clock->clocks[CLOCK_USEFUL].thread.getTime(), 0); + DCHECK_EQ(thread_local_clock->clocks[CLOCK_USEFUL].proc.getTime(), 0); + DCHECK_EQ(thread_local_clock->clocks[CLOCK_USEFUL].critical.getTime(), 0); + DCHECK_EQ(thread_local_clock->clocks[CLOCK_OMPI].proc.getTime(), 0); + DCHECK_EQ(thread_local_clock->clocks[CLOCK_OMPI].thread.getTime(), 0); + DCHECK_EQ(thread_local_clock->clocks[CLOCK_OMPI].critical.getTime(), 0); + DCHECK_EQ(thread_local_clock->clocks[CLOCK_OOMP].thread.getTime(), 0); + DCHECK_EQ(thread_local_clock->clocks[CLOCK_OOMP].critical.getTime(), 0); + DCHECK_EQ(thread_local_clock->clocks[CLOCK_OOMP].proc.getTime(), 0); #if 0 && defined(USE_MPI) if (useMpi) { diff --git a/criticalPath.h b/criticalPath.h index 1dec816..16dfa0c 100644 --- a/criticalPath.h +++ b/criticalPath.h @@ -9,25 +9,32 @@ #include #include #include +#include +#include +#include #include #include -#include "containers.h" -#include "debug.h" -#include "parse_flags.h" - #if (defined __APPLE__ && defined __MACH__) #include #endif -using namespace __otfcpt; - -#include -#include - #include #include +#include "containers.h" +#include "debug.h" +#include "handle-data.h" +#include "parse_flags.h" + +using namespace __otfcpt; + +#ifdef DEBUG_CLOCKS +#define BUILD_DEBUG_CLOCKS(c) c +#else +#define BUILD_DEBUG_CLOCKS(c) +#endif + #define LINESTR1(file, line) file ":" #line #define LINESTR(file, line) LINESTR1(file, line) #define GET_FILELINE LINESTR(__FILE__, __LINE__) @@ -41,21 +48,55 @@ using namespace __otfcpt; #endif #endif -#ifdef DEBUG_CLOCKS -inline std::mutex debugClockMutex; -#endif +enum ClockState { + STATE_UNINIT = -1, + STATE_INIT = 0, + STATE_NONE = 1, + STATE_USEFUL = 2, + STATE_MPI = 3, + STATE_OMP = 4, + STATE_GPU = 5, + STATE_LAST = 6 +}; + +enum ClockType { + CLOCK_USEFUL = 0, + CLOCK_OMPI = 1, + CLOCK_OOMP = 2, + CLOCK_OGPU = 3, + CLOCK_LAST = 4 +}; + +enum ClockContext { + CLOCK_OMP, + CLOCK_OMP_ONLY, + CLOCK_MPI, + CLOCK_MPI_ONLY, + CLOCK_ALL +}; + +extern const char *debug_clock_state_string[]; + +#define STRING_CLOCK_STATE(a) debug_clock_state_string[((int)(a) + 1)] + +static const bool State[STATE_LAST][CLOCK_LAST] = { + {false, false, false, false}, // INIT + {false, true, true, true}, // NONE + {true, true, true, true}, // USEFUL + {false, false, true, true}, // MPI + {false, true, false, true}, // OMP + {false, true, true, false} // GPU +}; // USEFUL, OMPI, OOMP, OGPU extern int myProcId; extern bool useMpi; extern double localTimeOffset; extern long long startTimeOffset; +extern double startProgrammTime; +extern double crit_path_useful_time; double getTime(); - -struct THREAD_CLOCK; -extern thread_local THREAD_CLOCK *thread_local_clock; -extern ompt_finalize_tool_t critical_ompt_finalize_tool; - +uint64_t my_next_id(); int my_get_tid(); template @@ -69,41 +110,116 @@ static void update_maximum(std::atomic &maximum_value, template value_type atomic_add(std::atomic &operand, - value_type value_to_add) { - value_type old = operand.load(std::memory_order_consume); - value_type desired = old + value_to_add; - while (!operand.compare_exchange_weak(old, desired, std::memory_order_release, - std::memory_order_consume)) - desired = old + value_to_add; + value_type value_to_add); + +template <> +double atomic_add(std::atomic &operand, double value_to_add); - return desired; +template +value_type atomic_add(std::atomic &operand, + value_type value_to_add) { + return operand += value_to_add; } -enum ClockState { - STATE_UNINIT = -1, - STATE_INIT = 0, - STATE_NONE = 1, - STATE_USEFUL = 2, - STATE_MPI = 3, - STATE_OMP = 4, - STATE_GPU = 5, - STATE_LAST = 6 +template class UniqLock { + std::unique_lock u; + +public: + UniqLock(std::mutex &m); + ~UniqLock() {} }; -enum ClockType { - CLOCK_USEFUL = 0, - CLOCK_OMPI = 1, - CLOCK_OOMP = 2, - CLOCK_OGPU = 3, - CLOCK_LAST = 4 +class TimeMetric { +protected: + std::atomic value{0}; + +public: + void maxUpdate(const TimeMetric &other) { + update_maximum(value, other.value.load()); + } + void add(double time) { atomic_add(value, time); } + void Reset(double t = 0) { value.store(t); } + TimeMetric(double t) : value(t) {} + TimeMetric() {} + TimeMetric(int index, const double *values) : value(values[index]) {} + TimeMetric(int index, const depMetric *values) + : value(values[index].fvalues[0]) {} + TimeMetric &operator=(const TimeMetric &other) { + if (this != &other) { + value.store(other.value.load()); + } + return *this; + } + TimeMetric &operator=(double time) { + value.store(time); + return *this; + } + void loadValues(double &values) { values = value.load(); } + void loadValues(depMetric &values) { values.fvalues[0] = value.load(); } + double getTime() { return value.load(); } }; -extern const char *debug_clock_state_string[]; +class DependentMetric { +protected: + double refValue{0}; // time? + uint64_t depValue{0}; // energy? -#define STRING_CLOCK_STATE(a) debug_clock_state_string[((int)(a) + 1)] +public: + void maxUpdate(const DependentMetric &other) { + if (refValue < other.refValue) { + refValue = other.refValue; + depValue = other.depValue; + } + } + void add(const DependentMetric &ref) { + refValue += ref.refValue; + depValue += ref.depValue; + } + void Reset(double t = 0) { + refValue = t; + depValue = 0; + } + DependentMetric() {} + DependentMetric(double t) : refValue(t) {} + DependentMetric(const depMetric &values) + : refValue(values.fvalues[0]), depValue(values.ivalues[0]) {} + DependentMetric &operator=(const DependentMetric &other) { + if (this != &other) { + refValue = other.refValue; + depValue = other.depValue; + } + return *this; + } + void loadValues(depMetric &values) { + values.fvalues[0] = refValue; + values.ivalues[0] = depValue; + } + double getTime() { return refValue; } +}; + +#if NUM_UC_INT64 > 0 +using BaseMetric = DependentMetric; +#else +using BaseMetric = TimeMetric; +#endif + +template struct syncClock; +using SYNC_CLOCK = syncClock; + +template struct threadClock; +using THREAD_CLOCK = threadClock; + +template struct cpClocks; +using CP_CLOCKS = cpClocks; + +typedef SYNC_CLOCK ompt_tsan_clockid; + +extern thread_local THREAD_CLOCK *thread_local_clock; #ifdef DEBUG_CLOCKS #define CLOCK_DEBUG(a, b, c) DebugClocksRAII dcr = DebugClocksRAII(a, b, c) +inline std::mutex debugClockMutex; + class DebugClocksRAII { THREAD_CLOCK *tc; const char *loc; @@ -117,57 +233,65 @@ class DebugClocksRAII { #define CLOCK_DEBUG(a, b, c) #endif -struct CP_CLOCKS { - std::atomic thread{0}; - std::atomic proc{0}; - std::atomic critical{0}; +template struct cpClocks { + T thread{0}; + T proc{0}; + T critical{0}; + + cpClocks() : thread(0), proc(0), critical(0) {} - CP_CLOCKS &operator=(const CP_CLOCKS &other) { + cpClocks(double time) : thread(time), proc(time), critical(time) {} + + cpClocks &operator=(const cpClocks &other) { if (this != &other) { - thread.store(other.thread.load()); - proc.store(other.proc.load()); - critical.store(other.critical.load()); + thread = other.thread; + proc = other.proc; + critical = other.critical; } return *this; } void Reset(double time) { - thread = time; - proc = time; - critical = time; + thread.Reset(time); + proc.Reset(time); + critical.Reset(time); } void AddAll(double time) { - atomic_add(critical, time); - atomic_add(thread, time); - atomic_add(proc, time); + thread.add(time); + proc.add(time); + critical.add(time); } - void OmpHBefore(CP_CLOCKS &cc) { - update_maximum(proc, cc.proc.load()); - update_maximum(critical, cc.critical.load()); + void OmpHBefore(cpClocks &cc) { + proc.maxUpdate(cc.proc); + critical.maxUpdate(cc.critical); } - void OmpHAfter(CP_CLOCKS &cc) { - update_maximum(cc.proc, proc.load()); - update_maximum(cc.critical, critical.load()); + void OmpHAfter(cpClocks &cc) { + cc.proc.maxUpdate(proc); + cc.critical.maxUpdate(critical); } }; -struct SYNC_CLOCK { - CP_CLOCKS clocks[CLOCK_LAST]{}; +template struct syncClock { +protected: + cpClocks clocks[CLOCK_LAST]{}; ClockState sync_state{STATE_INIT}; const char *init_loc{nullptr}; const char *init_fileline{nullptr}; - SYNC_CLOCK(double _useful_computation) { + std::mutex scMutex; + +public: + syncClock(double _useful_computation) { clocks[CLOCK_USEFUL].critical = _useful_computation; } - SYNC_CLOCK(double _useful_computation, double _mpi_start_time) { + syncClock(double _useful_computation, double _mpi_start_time) { clocks[CLOCK_USEFUL].critical = _useful_computation; clocks[CLOCK_OMPI].proc = _mpi_start_time; clocks[CLOCK_OMPI].thread = _mpi_start_time; clocks[CLOCK_OMPI].critical = _mpi_start_time; } - SYNC_CLOCK() {} + syncClock() {} void CheckArc(const char *loc, THREAD_CLOCK *tc = thread_local_clock); void CheckArc(const char *loc, const char *fileline, THREAD_CLOCK *tc = thread_local_clock); @@ -177,6 +301,7 @@ struct SYNC_CLOCK { void OmpHAfter(const char *loc, THREAD_CLOCK *tc = thread_local_clock); void OmpHAfter(const char *loc, const char *fileline, THREAD_CLOCK *tc = thread_local_clock); + void OmpCReset(); void Print(const char *prefix1, const char *prefix2 = "", const char *prefix3 = "") { fprintf( @@ -187,35 +312,23 @@ struct SYNC_CLOCK { "omt=%lf, omp=%lf, omc=%lf, " "oot=%lf, oop=%lf, ooc=%lf\n", my_get_tid(), prefix1, this, prefix2, prefix3, - clocks[CLOCK_USEFUL].thread.load(), clocks[CLOCK_USEFUL].proc.load(), - clocks[CLOCK_USEFUL].critical.load(), clocks[CLOCK_OMPI].thread.load(), - clocks[CLOCK_OMPI].proc.load(), clocks[CLOCK_OMPI].critical.load(), - clocks[CLOCK_OOMP].thread.load(), clocks[CLOCK_OOMP].proc.load(), - clocks[CLOCK_OOMP].critical.load()); + clocks[CLOCK_USEFUL].thread.getTime(), + clocks[CLOCK_USEFUL].proc.getTime(), + clocks[CLOCK_USEFUL].critical.getTime(), + clocks[CLOCK_OMPI].thread.getTime(), clocks[CLOCK_OMPI].proc.getTime(), + clocks[CLOCK_OMPI].critical.getTime(), + clocks[CLOCK_OOMP].thread.getTime(), clocks[CLOCK_OOMP].proc.getTime(), + clocks[CLOCK_OOMP].critical.getTime()); } - void *operator new(size_t size) { return malloc(size); } - void operator delete(void *p) { free(p); } + friend void MpiHappensAfter(ipcData *uc, int remote); + friend void MpiHappensAfter(ipcData &uc, int remote); + friend ipcMetric *MpiHappensBefore(ipcData *uc, int remote); + friend ipcMetric *MpiHappensBefore(ipcData &uc, int remote); + friend void finishMeasurement(); }; -enum ClockContext { - CLOCK_OMP, - CLOCK_OMP_ONLY, - CLOCK_MPI, - CLOCK_MPI_ONLY, - CLOCK_ALL -}; - -static const bool State[STATE_LAST][CLOCK_LAST] = { - {false, false, false, false}, // INIT - {false, true, true, true}, // NONE - {true, true, true, true}, // USEFUL - {false, false, true, true}, // MPI - {false, true, false, true}, // OMP - {false, true, true, false} // GPU -}; // USEFUL, OMPI, OOMP, OGPU - struct MPI_COUNTS { uint64_t send{0}, recv{0}, isend{0}, irecv{0}, coll{0}, icoll{0}, test{0}, wait{0}, pers{0}, probe{0}; @@ -260,20 +373,27 @@ struct omptCounts { void operator delete(void *p) { free(p); } }; -struct THREAD_CLOCK : public SYNC_CLOCK, MPI_COUNTS { +template struct threadClock : public syncClock, MPI_COUNTS { int thread_id{-1}; bool openmp_thread{false}; Vector clock_state_stack; + using syncClock::clocks; - THREAD_CLOCK(int threadid, double _useful_computation, - bool _openmp_thread = false) + threadClock(int threadid, double _useful_computation, + bool _openmp_thread = false) : SYNC_CLOCK(_useful_computation, (!analysis_flags->running) ? 0 : -getTime()), thread_id(threadid), openmp_thread(_openmp_thread) { clock_state_stack.PushBack(STATE_INIT); } - THREAD_CLOCK() {} - THREAD_CLOCK(const THREAD_CLOCK &other); + threadClock() {} + threadClock(const threadClock &other) : threadClock(my_next_id(), 0) { + if (other.getState() != STATE_INIT) + clock_state_stack.PushBack(other.getState()); + clocks[CLOCK_USEFUL] = other.clocks[CLOCK_USEFUL]; + clocks[CLOCK_OMPI] = other.clocks[CLOCK_OMPI]; + clocks[CLOCK_OOMP] = other.clocks[CLOCK_OOMP]; + } void SwitchState(ClockState old_cs, ClockState new_cs, double time = 0, const char *loc = NULL) { @@ -296,8 +416,7 @@ struct THREAD_CLOCK : public SYNC_CLOCK, MPI_COUNTS { #ifdef DEBUG_CLOCKS void inline printStateStack(const char *loc = "", const char *prefix = "") { fprintf(analysis_flags->output, - "Thread %i: Clock State Stack at %s%s: ", my_get_tid(), loc, - prefix); + "Thread %i: Clock State Stack at %s%s: ", thread_id, loc, prefix); for (auto elem : clock_state_stack) { fprintf(analysis_flags->output, "%s ", STRING_CLOCK_STATE(elem)); } @@ -372,14 +491,9 @@ struct THREAD_CLOCK : public SYNC_CLOCK, MPI_COUNTS { void operator delete(void *p) { free(p); } }; -typedef SYNC_CLOCK ompt_tsan_clockid; -extern thread_local THREAD_CLOCK *thread_local_clock; extern Vector *thread_clocks; extern Vector *thread_counts; -extern double startProgrammTime; -extern double crit_path_useful_time; - -uint64_t my_next_id(); +extern ompt_finalize_tool_t critical_ompt_finalize_tool; void resetMpiClock(THREAD_CLOCK *thread_clock); @@ -390,15 +504,82 @@ void stopTool(); (cv)->OmpHBefore(__PRETTY_FUNCTION__, GET_FILELINE, ##__VA_ARGS__) #define OmpHappensAfter(cv, ...) \ (cv)->OmpHAfter(__PRETTY_FUNCTION__, GET_FILELINE, ##__VA_ARGS__) - -void OmpClockReset(THREAD_CLOCK *cv); -void OmpClockReset(SYNC_CLOCK *cv); +#define OmpClockReset(cv) (cv)->OmpCReset() void startMeasurement(double time = getTime()); void stopMeasurement(double time = getTime()); void finishMeasurement(); +template +void syncClock::CheckArc(const char *loc, THREAD_CLOCK *tc_arg) { + CheckArc(loc, "", tc_arg); +} + +template +void syncClock::CheckArc(const char *loc, const char *fileline, + THREAD_CLOCK *tc_arg) { + if (sync_state == STATE_INIT) { + sync_state = tc_arg->getState(); + init_loc = loc; + init_fileline = fileline; + } else { + DCHECK_EQ_VA(tc_arg->getState(), sync_state, "\nInit location: ", init_loc, + "@", init_fileline, "\nCurrent location: ", loc, "@", fileline, + "\n"); + } +} + +template +void syncClock::OmpHBefore(const char *loc, THREAD_CLOCK *tc_arg) { + OmpHBefore(loc, 0, tc_arg); +} + +template +void syncClock::OmpHBefore(const char *loc, const char *fileline, + THREAD_CLOCK *tc_arg) { + if (!analysis_flags->running) + return; +#ifdef DEBUG_HB + printf("%s @%s: %p <- %p\n", __PRETTY_FUNCTION__, loc, this, tc_arg); +#endif + UniqLock lock(scMutex); + this->CheckArc(loc, fileline, tc_arg); + clocks[CLOCK_USEFUL].OmpHBefore(tc_arg->clocks[CLOCK_USEFUL]); + clocks[CLOCK_OOMP].OmpHBefore(tc_arg->clocks[CLOCK_OOMP]); + clocks[CLOCK_OMPI].OmpHBefore(tc_arg->clocks[CLOCK_OMPI]); +} + +template +void syncClock::OmpHAfter(const char *loc, THREAD_CLOCK *tc_arg) { + OmpHAfter(loc, "", tc_arg); +} + +template +void syncClock::OmpHAfter(const char *loc, const char *fileline, + THREAD_CLOCK *tc_arg) { + if (!analysis_flags->running) + return; +#ifdef DEBUG_HB + printf("%s @%s: %p -> %p\n", __PRETTY_FUNCTION__, loc, this, tc_arg); +#endif + UniqLock lock(scMutex); + this->CheckArc(loc, fileline, tc_arg); + clocks[CLOCK_USEFUL].OmpHAfter(tc_arg->clocks[CLOCK_USEFUL]); + clocks[CLOCK_OOMP].OmpHAfter(tc_arg->clocks[CLOCK_OOMP]); + clocks[CLOCK_OMPI].OmpHAfter(tc_arg->clocks[CLOCK_OMPI]); +} + +template void syncClock::OmpCReset() { + if (!analysis_flags->running) + return; + UniqLock lock(scMutex); + clocks[CLOCK_USEFUL].Reset(-1e50); + clocks[CLOCK_OMPI].Reset(-1e50); + clocks[CLOCK_OOMP].Reset(-1e50); + sync_state = STATE_INIT; +} + extern "C" void enterOpenMP(const char *loc); extern "C" void exitOpenMP(const char *loc); diff --git a/debug.cpp b/debug.cpp index df0f3b1..70b6dc2 100644 --- a/debug.cpp +++ b/debug.cpp @@ -74,3 +74,17 @@ void CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2, Die(); } } + +// std::atomic needs this function in debug config +#ifndef USE_STL +namespace std { +extern "C++" _GLIBCXX_NORETURN __attribute__((__cold__)) void + __glibcxx_assert_fail /* Called when a precondition violation is detected. + */ + (const char *__file, int __line, const char *__function, + const char *__condition) _GLIBCXX_NOEXCEPT { + CheckFailed(__file, __line, __condition, 0, 0, {__function}); + abort(); // this function should be noreturn +} +} // namespace std +#endif \ No newline at end of file diff --git a/external/backward-cpp/backward.hpp b/external/backward-cpp/backward.hpp index 8875c54..be354ee 100644 --- a/external/backward-cpp/backward.hpp +++ b/external/backward-cpp/backward.hpp @@ -4336,8 +4336,7 @@ class SignalHandling { #ifdef __GNUC__ __attribute__((noreturn)) #endif - static void - sig_handler(int signo, siginfo_t *info, void *_ctx) { + static void sig_handler(int signo, siginfo_t *info, void *_ctx) { handleSignal(signo, info, _ctx); // try to forward the signal. @@ -4462,11 +4461,9 @@ class SignalHandling { abort(); } - static inline void __cdecl invalid_parameter_handler(const wchar_t *, - const wchar_t *, - const wchar_t *, - unsigned int, - uintptr_t) { + static inline void __cdecl + invalid_parameter_handler(const wchar_t *, const wchar_t *, const wchar_t *, + unsigned int, uintptr_t) { crash_handler(signal_skip_recs); abort(); } diff --git a/handle-data.h b/handle-data.h index 5a7f4e7..8dd0121 100644 --- a/handle-data.h +++ b/handle-data.h @@ -1,7 +1,13 @@ +#ifndef HANDLE_DATA_H +#define HANDLE_DATA_H 1 + +#include #include #include #include +#include "ipc-data.h" + enum nbFunction { nbf_unknown = -1, nbf_MPI_Isend, @@ -89,9 +95,6 @@ enum nbFunction { nbf_MPI_Neighbor_scatterv_init }; -#define NUM_UC_DOUBLE 3 -#define NUM_UC_INT64 0 - template class alignas(64) HandleData { protected: public: @@ -213,90 +216,58 @@ typedef enum { class ipcData { public: - double uc_double[NUM_UC_DOUBLE]; - int64_t uc_int64[NUM_UC_INT64]; + ipcMetric values[NUM_UC_VALUES]; static int num_uc_double; static int num_uc_int64; static MPI_Datatype ipcMpiType; + static MPI_Op ipcMpiOp; static void initIpcData(); static void finiIpcData(); /* NOTE: See copy-assignment constructor of RequestData why this is explictly * defined. */ ipcData &operator=(const ipcData &rhs) { - for (int i = 0; i < NUM_UC_DOUBLE; ++i) - uc_double[i] = rhs.uc_double[i]; - for (int i = 0; i < NUM_UC_INT64; ++i) - uc_int64[i] = rhs.uc_int64[i]; + for (int i = 0; i < NUM_UC_VALUES; ++i) + values[i] = rhs.values[i]; return *this; } void IBcast(int root, CommData *cData, MPI_Request *reqs) { - PMPI_Ibcast(uc_double, 1, ipcData::ipcMpiType, root, cData->getDupComm(), + PMPI_Ibcast(values, NUM_UC_VALUES, ipcMpiType, root, cData->getDupComm(), reqs); } void IAllreduce(CommData *cData, MPI_Request *reqs) { - if (num_uc_double > 0) - PMPI_Iallreduce(MPI_IN_PLACE, uc_double, num_uc_double, MPI_DOUBLE, - MPI_MAX, cData->getDupComm(), reqs); - if (num_uc_int64 > 0) - PMPI_Iallreduce(MPI_IN_PLACE, uc_int64, num_uc_int64, MPI_INT64_T, - MPI_MAX, cData->getDupComm(), reqs + 1); + PMPI_Iallreduce(MPI_IN_PLACE, values, NUM_UC_VALUES, ipcMpiType, ipcMpiOp, + cData->getDupComm(), reqs); } void Allreduce(CommData *cData) { - if (num_uc_double > 0) - PMPI_Allreduce(MPI_IN_PLACE, uc_double, num_uc_double, MPI_DOUBLE, - MPI_MAX, cData->getDupComm()); - if (num_uc_int64 > 0) - PMPI_Allreduce(MPI_IN_PLACE, uc_int64, num_uc_int64, MPI_INT64_T, MPI_MAX, - cData->getDupComm()); + PMPI_Allreduce(MPI_IN_PLACE, values, NUM_UC_VALUES, ipcMpiType, ipcMpiOp, + cData->getDupComm()); } void IReduce(int root, CommData *cData, MPI_Request *reqs) { if (root == cData->getRank()) { - if (num_uc_double > 0) - PMPI_Ireduce(MPI_IN_PLACE, uc_double, num_uc_double, MPI_DOUBLE, - MPI_MAX, root, cData->getDupComm(), reqs); - if (num_uc_int64 > 0) - PMPI_Ireduce(MPI_IN_PLACE, uc_int64, num_uc_int64, MPI_INT64_T, MPI_MAX, - root, cData->getDupComm(), reqs + 1); + PMPI_Ireduce(MPI_IN_PLACE, values, NUM_UC_VALUES, ipcMpiType, ipcMpiOp, + root, cData->getDupComm(), reqs); } else { - if (num_uc_double > 0) - PMPI_Ireduce(uc_double, NULL, num_uc_double, MPI_DOUBLE, MPI_MAX, root, - cData->getDupComm(), reqs); - if (num_uc_int64 > 0) - PMPI_Ireduce(uc_int64, NULL, num_uc_int64, MPI_INT64_T, MPI_MAX, root, - cData->getDupComm(), reqs + 1); + PMPI_Ireduce(values, NULL, NUM_UC_VALUES, ipcMpiType, ipcMpiOp, root, + cData->getDupComm(), reqs); } } #ifdef HAVE_PCOLL void BcastInit(int root, CommData *cData, MPI_Request *reqs) { - PMPI_Bcast_init(uc_double, 1, ipcData::ipcMpiType, root, + PMPI_Bcast_init(values, NUM_UC_VALUES, ipcMpiType, root, cData->getDupComm(), MPI_INFO_NULL, reqs); } void AllreduceInit(CommData *cData, MPI_Request *reqs) { - if (num_uc_double > 0) - PMPI_Allreduce_init(MPI_IN_PLACE, uc_double, num_uc_double, MPI_DOUBLE, - MPI_MAX, cData->getDupComm(), MPI_INFO_NULL, reqs); - if (num_uc_int64 > 0) - PMPI_Allreduce_init(MPI_IN_PLACE, uc_int64, num_uc_int64, MPI_INT64_T, - MPI_MAX, cData->getDupComm(), MPI_INFO_NULL, - reqs + 1); + PMPI_Allreduce_init(MPI_IN_PLACE, values, NUM_UC_VALUES, ipcMpiType, + ipcMpiOp, cData->getDupComm(), MPI_INFO_NULL, reqs); } void ReduceInit(int root, CommData *cData, MPI_Request *reqs) { if (root == cData->getRank()) { - if (num_uc_double > 0) - PMPI_Reduce_init(MPI_IN_PLACE, uc_double, num_uc_double, MPI_DOUBLE, - MPI_MAX, root, cData->getDupComm(), MPI_INFO_NULL, - reqs); - if (num_uc_int64 > 0) - PMPI_Reduce_init(MPI_IN_PLACE, uc_int64, num_uc_int64, MPI_INT64_T, - MPI_MAX, root, cData->getDupComm(), MPI_INFO_NULL, - reqs + 1); + PMPI_Reduce_init(MPI_IN_PLACE, values, NUM_UC_VALUES, ipcMpiType, + ipcMpiOp, root, cData->getDupComm(), MPI_INFO_NULL, + reqs); } else { - if (num_uc_double > 0) - PMPI_Reduce_init(uc_double, NULL, num_uc_double, MPI_DOUBLE, MPI_MAX, - root, cData->getDupComm(), MPI_INFO_NULL, reqs); - if (num_uc_int64 > 0) - PMPI_Reduce_init(uc_int64, NULL, num_uc_int64, MPI_INT64_T, MPI_MAX, - root, cData->getDupComm(), MPI_INFO_NULL, reqs + 1); + PMPI_Reduce_init(values, NULL, NUM_UC_VALUES, ipcMpiType, ipcMpiOp, root, + cData->getDupComm(), MPI_INFO_NULL, reqs); } } #endif @@ -450,3 +421,5 @@ class alignas(64) RequestData : public ipcData { completionCallback = cc; } }; + +#endif diff --git a/ipc-data.h b/ipc-data.h new file mode 100644 index 0000000..f669a43 --- /dev/null +++ b/ipc-data.h @@ -0,0 +1,20 @@ +#ifndef IPC_DATA_H +#define IPC_DATA_H 1 + +#include +#define NUM_UC_VALUES 4 +#define NUM_UC_DOUBLE 1 +#define NUM_UC_INT64 0 + +struct depMetric { + double fvalues[NUM_UC_DOUBLE]; + int64_t ivalues[NUM_UC_INT64]; +}; + +#if NUM_UC_INT64 > 0 +using ipcMetric = depMetric; +#else +using ipcMetric = double; +#endif + +#endif \ No newline at end of file diff --git a/mpi-critical.cpp b/mpi-critical.cpp index ac91bdb..7fe8134 100644 --- a/mpi-critical.cpp +++ b/mpi-critical.cpp @@ -8,6 +8,8 @@ #include #include +#include "handle-data.h" +#include "ipc-data.h" #include "mpi-critical.h" Vector timeOffsets; @@ -17,23 +19,24 @@ void MpiHappensAfter(ipcData *uc, int remote) { if (!analysis_flags->running) return; DCHECK_EQ(thread_local_clock->getState(), STATE_MPI); - update_maximum(thread_local_clock->clocks[CLOCK_USEFUL].critical, - uc->uc_double[0]); - update_maximum(thread_local_clock->clocks[CLOCK_OMPI].critical, - uc->uc_double[1]); - update_maximum(thread_local_clock->clocks[CLOCK_OOMP].critical, - uc->uc_double[2]); + DCHECK(remote >= -1); + thread_local_clock->clocks[CLOCK_USEFUL].critical.maxUpdate( + BaseMetric{uc->values[0]}); + thread_local_clock->clocks[CLOCK_OMPI].critical.maxUpdate( + BaseMetric{uc->values[1]}); + thread_local_clock->clocks[CLOCK_OOMP].critical.maxUpdate( + BaseMetric{uc->values[2]}); } -double *loadThreadTimers(ipcData &uc, int remote) { - return loadThreadTimers(&uc, remote); +ipcMetric *MpiHappensBefore(ipcData &uc, int remote) { + return MpiHappensBefore(&uc, remote); } -double *loadThreadTimers(ipcData *uc, int remote) { - uc->uc_double[0] = thread_local_clock->clocks[CLOCK_USEFUL].critical.load(); - uc->uc_double[1] = thread_local_clock->clocks[CLOCK_OMPI].critical.load(); - uc->uc_double[2] = thread_local_clock->clocks[CLOCK_OOMP].critical.load(); - return uc->uc_double; +ipcMetric *MpiHappensBefore(ipcData *uc, int remote) { + thread_local_clock->clocks[CLOCK_USEFUL].critical.loadValues(uc->values[0]); + thread_local_clock->clocks[CLOCK_OMPI].critical.loadValues(uc->values[1]); + thread_local_clock->clocks[CLOCK_OOMP].critical.loadValues(uc->values[2]); + return uc->values; } // completion callback function for wild-card recv @@ -46,7 +49,7 @@ void completePBWC(RequestData *uc, MPI_Status *status) { DCHECK(uc->comm->getDupComm() != MPI_COMM_NULL); if (uc->remote == MPI_ANY_SOURCE) uc->remote = status->MPI_SOURCE; - PMPI_Recv(uc->uc_double, 1, ipcData::ipcMpiType, status->MPI_SOURCE, + PMPI_Recv(uc->values, NUM_UC_VALUES, ipcData::ipcMpiType, status->MPI_SOURCE, status->MPI_TAG, uc->comm->getDupComm(), MPI_STATUS_IGNORE); MpiHappensAfter(uc, uc->remote); } @@ -111,7 +114,7 @@ void startPersPBHB(RequestData *uc) { if (!analysis_flags->running) return; #endif - loadThreadTimers(uc); + MpiHappensBefore(uc); if (uc->pb_reqs[1] == MPI_REQUEST_NULL) PMPI_Start(uc->pb_reqs); else @@ -209,9 +212,14 @@ int MPI_Finalize(void) { else DCHECK_EQ(thread_local_clock->getState(), STATE_INIT); ipcData max_uc; - loadThreadTimers(max_uc, REF_RANK); + MpiHappensBefore(max_uc, REF_RANK); max_uc.Allreduce(cf.findData(MPI_COMM_WORLD)); - MpiHappensAfter(max_uc, 0); + thread_local_clock->clocks[CLOCK_USEFUL].critical.maxUpdate( + BaseMetric{max_uc.values[0]}); + thread_local_clock->clocks[CLOCK_OMPI].critical.maxUpdate( + BaseMetric{max_uc.values[1]}); + thread_local_clock->clocks[CLOCK_OOMP].critical.maxUpdate( + BaseMetric{max_uc.values[2]}); finishMeasurement(); analysis_flags->running = false; diff --git a/mpi-critical.h b/mpi-critical.h index f6ffc8f..48a5a68 100644 --- a/mpi-critical.h +++ b/mpi-critical.h @@ -1,4 +1,6 @@ #include + +#include "ipc-data.h" #ifndef MPI_CRITICAL_H #define MPI_CRITICAL_H 1 @@ -10,8 +12,8 @@ void MpiHappensAfter(ipcData *uc, int remote = 0); void MpiHappensAfter(ipcData &uc, int remote = 0); -double *loadThreadTimers(ipcData *uc, int remote = -1); -double *loadThreadTimers(ipcData &uc, int remote = -1); +ipcMetric *MpiHappensBefore(ipcData *uc, int remote = -1); +ipcMetric *MpiHappensBefore(ipcData &uc, int remote = -1); void completePBWC(RequestData *uc, MPI_Status *status); void completePBHB(RequestData *uc, MPI_Status *status); @@ -63,7 +65,7 @@ struct mpiIcollBcastPBImpl { rank = cData->getRank(); if (root == rank) - loadThreadTimers(rData, REF_RANK); + MpiHappensBefore(rData, REF_RANK); rData->IBcast(root, cData, rData->pb_reqs); } ~mpiIcollBcastPBImpl() { @@ -116,7 +118,7 @@ struct mpiCollBcastPBImpl { auto cData = cf.findData(comm); rank = cData->getRank(); if (root == rank) - loadThreadTimers(rData, REF_RANK); + MpiHappensBefore(rData, REF_RANK); rData.IBcast(root, cData, rData.pb_reqs); } ~mpiCollBcastPBImpl() { @@ -143,7 +145,7 @@ struct mpiIcollAllreducePBImpl { #endif auto cData = cf.findData(comm); rank = cData->getRank(); - loadThreadTimers(rData, REF_RANK); + MpiHappensBefore(rData, REF_RANK); rData->IAllreduce(cData, rData->pb_reqs); } ~mpiIcollAllreducePBImpl() { @@ -192,7 +194,7 @@ struct mpiCollAllreducePBImpl { #endif auto cData = cf.findData(comm); rank = cData->getRank(); - loadThreadTimers(rData, REF_RANK); + MpiHappensBefore(rData, REF_RANK); rData.IAllreduce(cData, rData.pb_reqs); } ~mpiCollAllreducePBImpl() { @@ -221,7 +223,7 @@ struct mpiIcollReducePBImpl { #endif auto cData = cf.findData(comm); rank = cData->getRank(); - loadThreadTimers(rData, REF_RANK); + MpiHappensBefore(rData, REF_RANK); rData->IReduce(root, cData, rData->pb_reqs); if (root == rank) { rData->setCompletionCallback(completePBHB); @@ -279,7 +281,7 @@ struct mpiCollReducePBImpl { #endif auto cData = cf.findData(comm); rank = cData->getRank(); - loadThreadTimers(rData, REF_RANK); + MpiHappensBefore(rData, REF_RANK); rData.IReduce(root, cData, rData.pb_reqs); } ~mpiCollReducePBImpl() { @@ -323,7 +325,7 @@ typedef mpiCollBcastInitPBImpl mpiCollBcastInitPB; #endif struct mpiIsendPB { - double *uc{nullptr}; + ipcMetric *uc{nullptr}; RequestData *rData; MPI_Request *send_req; int dest; @@ -341,9 +343,9 @@ struct mpiIsendPB { return; auto cData = cf.findData(comm); rank = cData->getRank(); - uc = loadThreadTimers(rData); - PMPI_Isend(uc, 1, ipcData::ipcMpiType, dest, tag, cData->getDupComm(), - rData->pb_reqs); + uc = MpiHappensBefore(rData); + PMPI_Isend(uc, NUM_UC_VALUES, ipcData::ipcMpiType, dest, tag, + cData->getDupComm(), rData->pb_reqs); } ~mpiIsendPB() { #if OnlyActivePB @@ -361,7 +363,7 @@ struct mpiIsendPB { }; struct mpiSendInitPB { - double *uc{nullptr}; + ipcMetric *uc{nullptr}; RequestData *rData; MPI_Request *send_req; int dest; @@ -374,12 +376,12 @@ struct mpiSendInitPB { if (dest == MPI_PROC_NULL) return; auto cData = cf.findData(comm); - uc = rData->uc_double; + uc = rData->values; rank = cData->getRank(); rData->setStartCallback(startPersPBHB); rData->setCompletionCallback(completePersPBnoHB); - PMPI_Send_init(uc, 1, ipcData::ipcMpiType, dest, tag, cData->getDupComm(), - rData->pb_reqs); + PMPI_Send_init(uc, NUM_UC_VALUES, ipcData::ipcMpiType, dest, tag, + cData->getDupComm(), rData->pb_reqs); } ~mpiSendInitPB() { if (dest != MPI_PROC_NULL) { @@ -391,7 +393,7 @@ struct mpiSendInitPB { }; struct mpiSendPB { - double *uc{nullptr}; + ipcMetric *uc{nullptr}; RequestData rData{}; int dest; int rank; @@ -405,9 +407,9 @@ struct mpiSendPB { return; auto cData = cf.findData(comm); rank = cData->getRank(); - uc = loadThreadTimers(rData); - PMPI_Isend(uc, 1, ipcData::ipcMpiType, dest, tag, cData->getDupComm(), - rData.pb_reqs); + uc = MpiHappensBefore(rData); + PMPI_Isend(uc, NUM_UC_VALUES, ipcData::ipcMpiType, dest, tag, + cData->getDupComm(), rData.pb_reqs); } ~mpiSendPB() { #if OnlyActivePB @@ -421,7 +423,7 @@ struct mpiSendPB { }; struct mpiMprobePB { - double *uc{nullptr}; + ipcMetric *uc{nullptr}; MPI_Comm comm; MPI_Message *message; CommData *cData; @@ -458,7 +460,7 @@ struct mpiMprobePB { auto rData = rf.newData(); cData = cf.findData(comm); rank = cData->getRank(); - uc = rData->uc_double; + uc = rData->values; if (src == MPI_ANY_SOURCE || tag == MPI_ANY_TAG) { src = pStatus->MPI_SOURCE; tag = pStatus->MPI_TAG; @@ -469,13 +471,13 @@ struct mpiMprobePB { if (!analysis_flags->running) return; #endif - PMPI_Irecv(uc, 1, ipcData::ipcMpiType, src, tag, cData->getDupComm(), - rData->pb_reqs); + PMPI_Irecv(uc, NUM_UC_VALUES, ipcData::ipcMpiType, src, tag, + cData->getDupComm(), rData->pb_reqs); } }; struct mpiRecvPB { - double *uc{nullptr}; + ipcMetric *uc{nullptr}; RequestData rData; CommData *cData; MPI_Status tStatus; @@ -509,10 +511,10 @@ struct mpiRecvPB { return; cData = cf.findData(comm); rank = cData->getRank(); - uc = rData.uc_double; + uc = rData.values; if (src != MPI_ANY_SOURCE && tag != MPI_ANY_TAG) { - PMPI_Irecv(uc, 1, ipcData::ipcMpiType, src, tag, cData->getDupComm(), - rData.pb_reqs); + PMPI_Irecv(uc, NUM_UC_VALUES, ipcData::ipcMpiType, src, tag, + cData->getDupComm(), rData.pb_reqs); } else { if (*status == MPI_STATUS_IGNORE) { pStatus = *status = &tStatus; @@ -529,8 +531,8 @@ struct mpiRecvPB { if (src == MPI_ANY_SOURCE || tag == MPI_ANY_TAG) { src = pStatus->MPI_SOURCE; tag = pStatus->MPI_TAG; - PMPI_Recv(uc, 1, ipcData::ipcMpiType, src, tag, cData->getDupComm(), - MPI_STATUS_IGNORE); + PMPI_Recv(uc, NUM_UC_VALUES, ipcData::ipcMpiType, src, tag, + cData->getDupComm(), MPI_STATUS_IGNORE); } else { PMPI_Waitall(2, rData.pb_reqs, MPI_STATUSES_IGNORE); } @@ -539,7 +541,7 @@ struct mpiRecvPB { }; struct mpiIrecvPB { - double *uc{nullptr}; + ipcMetric *uc{nullptr}; RequestData *rData; CommData *cData; MPI_Request *send_req; @@ -567,10 +569,10 @@ struct mpiIrecvPB { return; cData = cf.findData(comm); rank = cData->getRank(); - uc = rData->uc_double; + uc = rData->values; if (src != MPI_ANY_SOURCE && tag != MPI_ANY_TAG) { - PMPI_Irecv(uc, 1, ipcData::ipcMpiType, src, tag, cData->getDupComm(), - rData->pb_reqs); + PMPI_Irecv(uc, NUM_UC_VALUES, ipcData::ipcMpiType, src, tag, + cData->getDupComm(), rData->pb_reqs); } } ~mpiIrecvPB() { @@ -596,7 +598,7 @@ struct mpiIrecvPB { }; struct mpiRecvInitPB { - double *uc{nullptr}; + ipcMetric *uc{nullptr}; RequestData *rData; CommData *cData; MPI_Request *send_req; @@ -612,17 +614,15 @@ struct mpiRecvInitPB { return; cData = cf.findData(comm); rank = cData->getRank(); - uc = rData->uc_double; + uc = rData->values; if (src == MPI_ANY_SOURCE || tag == MPI_ANY_TAG) { rData->setCompletionCallback(completePBWC); } else { rData->setStartCallback(startPersPBnoHB); rData->setCompletionCallback(completePersPBHB); rData->setCancelCallback(cancelPB); - PMPI_Recv_init(uc, 1, ipcData::ipcMpiType, src, tag, cData->getDupComm(), - rData->pb_reqs); - } - if (src != MPI_ANY_SOURCE && tag != MPI_ANY_TAG) { + PMPI_Recv_init(uc, NUM_UC_VALUES, ipcData::ipcMpiType, src, tag, + cData->getDupComm(), rData->pb_reqs); } } ~mpiRecvInitPB() { @@ -641,7 +641,7 @@ struct mpiRecvInitPB { #ifdef HAVE_ISRR struct mpiSendrecvPB { - double *uc{nullptr}; + ipcMetric *uc{nullptr}; RequestData rData{}; CommData *cData; MPI_Status tStatus; @@ -663,9 +663,9 @@ struct mpiSendrecvPB { return; cData = cf.findData(comm); rank = cData->getRank(); - uc = loadThreadTimers(rData); - PMPI_Isendrecv_replace(uc, 1, ipcData::ipcMpiType, dest, stag, src, rtag, - cData->getDupComm(), rData.pb_reqs); + uc = MpiHappensBefore(rData); + PMPI_Isendrecv_replace(uc, NUM_UC_VALUES, ipcData::ipcMpiType, dest, stag, + src, rtag, cData->getDupComm(), rData.pb_reqs); } ~mpiSendrecvPB() { #if OnlyActivePB @@ -682,7 +682,7 @@ struct mpiSendrecvPB { }; struct mpiIsendrecvPB { - double *uc{nullptr}; + ipcMetric *uc{nullptr}; RequestData *rData; CommData *cData; MPI_Request *send_req; @@ -706,9 +706,9 @@ struct mpiIsendrecvPB { return; cData = cf.findData(comm); rank = cData->getRank(); - uc = loadThreadTimers(rData); - PMPI_Isendrecv_replace(uc, 1, ipcData::ipcMpiType, dest, stag, src, rtag, - cData->getDupComm(), rData->pb_reqs); + uc = MpiHappensBefore(rData); + PMPI_Isendrecv_replace(uc, NUM_UC_VALUES, ipcData::ipcMpiType, dest, stag, + src, rtag, cData->getDupComm(), rData->pb_reqs); } ~mpiIsendrecvPB() { #if OnlyActivePB diff --git a/ompt-critical.cpp b/ompt-critical.cpp index 5b35c6d..3dba727 100644 --- a/ompt-critical.cpp +++ b/ompt-critical.cpp @@ -698,7 +698,6 @@ static void ompt_tsan_sync_region_wait(ompt_sync_region_t kind, static int ompt_tsan_control_tool(uint64_t command, uint64_t modifier, void *arg, const void *codeptr_ra) { if (command == omp_control_tool_start) { - // TODO start with no arguments = USEFUL startTool(); } else if (command == omp_control_tool_pause) { return 1; @@ -863,7 +862,8 @@ static void ompt_tsan_task_schedule(ompt_data_t *first_task_data, // For late fulfill of detached task, there is no task to schedule to if (prior_task_status == ompt_task_late_fulfill) { - OmpClockReset(thread_local_clock); + if (!thread_local_clock->openmp_thread) + OmpClockReset(thread_local_clock); return; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d4c0bb9..e11f69b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -57,7 +57,10 @@ add_custom_target(build-tests) add_custom_target(build-mpi-only-tests) add_custom_target(build-omp-only-tests) add_custom_target(build-hybrid-tests) -add_dependencies(build-tests build-mpi-only-tests build-omp-only-tests build-hybrid-tests OTFCPT OTFCPT_omp) +add_dependencies(build-omp-only-tests OTFCPT OTFCPT_omp) +add_dependencies(build-mpi-only-tests OTFCPT OTFCPT_omp) +add_dependencies(build-hybrid-tests OTFCPT OTFCPT_omp) +add_dependencies(build-tests build-mpi-only-tests build-omp-only-tests build-hybrid-tests) if (TARGET FileCheck_Standalone AND BUILD_FILECHECK) add_dependencies(build-tests FileCheck_Standalone) endif() @@ -101,10 +104,7 @@ file(GENERATE INPUT "${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.configured" ) -if (TARGET FileCheck_Standalone AND MUST_BUILD_FILECHECK) - add_dependencies(build-test FileCheck_Standalone) -endif() - add_check_target(NAME check SUITES . COMMENT "Run all OTF-CPT tests" DEPENDS build-tests) +add_check_target(NAME check-omp SUITES omp-only COMMENT "Run omp-tests tests" DEPENDS build-omp-only-tests) diff --git a/tests/fortran/CMakeLists.txt b/tests/fortran/CMakeLists.txt index 3a3fc3b..8aace74 100644 --- a/tests/fortran/CMakeLists.txt +++ b/tests/fortran/CMakeLists.txt @@ -23,8 +23,8 @@ set(fortranTests add_library(m_time OBJECT m_time.f90) FOREACH(tests ${fortranTests}) - set_source_files_properties(${tests}.f90 PROPERTIES Fortran_PREPROCESS ON) - add_executable(${tests}.f90.tmp ${tests}.f90 ../expected-metrics.c) + set_source_files_properties(${tests}.F90 PROPERTIES Fortran_PREPROCESS ON) + add_executable(${tests}.f90.tmp ${tests}.F90 ../expected-metrics.c) target_link_libraries(${tests}.f90.tmp PRIVATE OTFCPT) target_link_libraries(${tests}.f90.tmp PUBLIC MPI::MPI_Fortran) target_link_libraries(${tests}.f90.tmp PRIVATE m_time) diff --git a/tests/fortran/mpi-balanced.f90 b/tests/fortran/mpi-balanced.F90 similarity index 100% rename from tests/fortran/mpi-balanced.f90 rename to tests/fortran/mpi-balanced.F90 diff --git a/tests/fortran/mpi-imbalance.f90 b/tests/fortran/mpi-imbalance.F90 similarity index 100% rename from tests/fortran/mpi-imbalance.f90 rename to tests/fortran/mpi-imbalance.F90 diff --git a/tests/omp-only/omp-serialization.c b/tests/omp-only/omp-serialization.c index 08d3c37..a678a58 100644 --- a/tests/omp-only/omp-serialization.c +++ b/tests/omp-only/omp-serialization.c @@ -21,9 +21,9 @@ int main(int argc, char **argv) { int sum = 0, nt = omp_get_max_threads(); metrics m = {1000, 1000 / nt, 1000, 1000, 1000, 1000}; - printMetrics(m); #pragma omp parallel - {} +#pragma omp master + printMetrics(m); omp_control_tool(omp_control_tool_start, 0, NULL); #pragma omp parallel for ordered schedule(static, 1) for (int i = 0; i < nt; i++) { diff --git a/tracking.cpp b/tracking.cpp index a39da8f..d56c471 100644 --- a/tracking.cpp +++ b/tracking.cpp @@ -150,31 +150,48 @@ SessionFactory sf; int ipcData::num_uc_double{NUM_UC_DOUBLE}; int ipcData::num_uc_int64{NUM_UC_INT64}; MPI_Datatype ipcData::ipcMpiType{MPI_DATATYPE_NULL}; +MPI_Op ipcData::ipcMpiOp{MPI_OP_NULL}; + +void maxloc(depMetric *, depMetric *, int *, MPI_Datatype *); + +void maxloc(depMetric *invec, depMetric *inoutvec, int *len, + MPI_Datatype *dtype) { + DCHECK_EQ(ipcData::ipcMpiType, *dtype); + for (int i = 0; i < *len; i++) { + if (inoutvec[i].fvalues[0] < invec[i].fvalues[0]) { + for (int j = 0; j < ipcData::num_uc_double; j++) + inoutvec[i].fvalues[j] = invec[i].fvalues[j]; + for (int j = 0; j < ipcData::num_uc_int64; j++) + inoutvec[i].ivalues[j] = invec[i].ivalues[j]; + } + } +} void ipcData::initIpcData() { if (num_uc_int64 > 0) { - ipcData tempData{}; - RequestData tempRData{}; - MPI_Aint displs[2], rdispls[2]; - PMPI_Get_address(tempData.uc_double, displs); - PMPI_Get_address(tempData.uc_int64, displs + 1); - PMPI_Get_address(tempRData.uc_double, rdispls); - PMPI_Get_address(tempRData.uc_int64, rdispls + 1); + depMetric tempData{}; + MPI_Aint displs[2]; + PMPI_Get_address(tempData.fvalues, displs); + PMPI_Get_address(tempData.ivalues, displs + 1); + MPI_Datatype struType = MPI_DATATYPE_NULL; displs[1] -= displs[0]; displs[0] = 0; - rdispls[1] -= rdispls[0]; - rdispls[0] = 0; - DCHECK_EQ(displs[1], rdispls[1]); MPI_Datatype types[] = {MPI_DOUBLE, MPI_INT64_T}; int blengths[] = {num_uc_double, num_uc_int64}; - PMPI_Type_create_struct(2, blengths, displs, types, &ipcMpiType); + PMPI_Type_create_struct(2, blengths, displs, types, &struType); + PMPI_Type_create_resized(struType, 0, sizeof(depMetric), &ipcMpiType); + PMPI_Type_commit(&ipcMpiType); + PMPI_Type_free(&struType); + PMPI_Op_create((MPI_User_function *)maxloc, 1, &ipcMpiOp); } else { - PMPI_Type_contiguous(num_uc_double, MPI_DOUBLE, &ipcMpiType); + ipcMpiType = MPI_DOUBLE; + ipcMpiOp = MPI_MAX; } - PMPI_Type_commit(&ipcMpiType); } void ipcData::finiIpcData() { - if (ipcMpiType != MPI_DATATYPE_NULL) + if (ipcMpiType != MPI_DATATYPE_NULL && ipcMpiType != MPI_DOUBLE) PMPI_Type_free(&ipcMpiType); + if (ipcMpiOp != MPI_MAX) + PMPI_Op_free(&ipcMpiOp); } #endif // USE_MPI