diff --git a/openmp/tools/archer/ompt-tsan.cpp b/openmp/tools/archer/ompt-tsan.cpp index ac1c3783a8e1f..a40b29b664ca2 100644 --- a/openmp/tools/archer/ompt-tsan.cpp +++ b/openmp/tools/archer/ompt-tsan.cpp @@ -1,15 +1,14 @@ /* * ompt-tsan.cpp -- Archer runtime library, TSan annotations for Archer */ - - //===----------------------------------------------------------------------===// - // - // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. - // See https://llvm.org/LICENSE.txt for details. - // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - // - //===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for details. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS @@ -34,8 +33,8 @@ #include #endif -#include #include "omp-tools.h" +#include static int runOnTsan; static int hasReductionCallback; @@ -498,8 +497,7 @@ static void ompt_tsan_thread_end(ompt_data_t *thread_data) { static void ompt_tsan_parallel_begin(ompt_data_t *parent_task_data, const ompt_frame_t *parent_task_frame, ompt_data_t *parallel_data, - uint32_t requested_team_size, - int flag, + uint32_t requested_team_size, int flag, const void *codeptr_ra) { ParallelData *Data = new ParallelData(codeptr_ra); parallel_data->ptr = Data; @@ -508,8 +506,7 @@ static void ompt_tsan_parallel_begin(ompt_data_t *parent_task_data, } static void ompt_tsan_parallel_end(ompt_data_t *parallel_data, - ompt_data_t *task_data, - int flag, + ompt_data_t *task_data, int flag, const void *codeptr_ra) { ParallelData *Data = ToParallelData(parallel_data); TsanHappensAfter(Data->GetBarrierPtr(0)); @@ -523,15 +520,13 @@ static void ompt_tsan_parallel_end(ompt_data_t *parallel_data, __tsan_flush_memory(); } #endif - } static void ompt_tsan_implicit_task(ompt_scope_endpoint_t endpoint, ompt_data_t *parallel_data, ompt_data_t *task_data, unsigned int team_size, - unsigned int thread_num, - int type) { + unsigned int thread_num, int type) { switch (endpoint) { case ompt_scope_begin: if (type & ompt_task_initial) { @@ -563,86 +558,86 @@ static void ompt_tsan_sync_region(ompt_sync_region_t kind, case ompt_scope_begin: TsanFuncEntry(codeptr_ra); switch (kind) { - case ompt_sync_region_barrier_implementation: - case ompt_sync_region_barrier_implicit: - case ompt_sync_region_barrier_explicit: - case ompt_sync_region_barrier: { - char BarrierIndex = Data->BarrierIndex; - TsanHappensBefore(Data->Team->GetBarrierPtr(BarrierIndex)); - - if (hasReductionCallback < ompt_set_always) { - // We ignore writes inside the barrier. These would either occur during - // 1. reductions performed by the runtime which are guaranteed to be - // race-free. - // 2. execution of another task. - // For the latter case we will re-enable tracking in task_switch. - Data->InBarrier = true; - TsanIgnoreWritesBegin(); - } - - break; + case ompt_sync_region_barrier_implementation: + case ompt_sync_region_barrier_implicit: + case ompt_sync_region_barrier_explicit: + case ompt_sync_region_barrier: { + char BarrierIndex = Data->BarrierIndex; + TsanHappensBefore(Data->Team->GetBarrierPtr(BarrierIndex)); + + if (hasReductionCallback < ompt_set_always) { + // We ignore writes inside the barrier. These would either occur during + // 1. reductions performed by the runtime which are guaranteed to be + // race-free. + // 2. execution of another task. + // For the latter case we will re-enable tracking in task_switch. + Data->InBarrier = true; + TsanIgnoreWritesBegin(); } - case ompt_sync_region_taskwait: - break; + break; + } + + case ompt_sync_region_taskwait: + break; - case ompt_sync_region_taskgroup: - Data->TaskGroup = new Taskgroup(Data->TaskGroup); - break; + case ompt_sync_region_taskgroup: + Data->TaskGroup = new Taskgroup(Data->TaskGroup); + break; - default: - break; + default: + break; } break; case ompt_scope_end: TsanFuncExit(); switch (kind) { - case ompt_sync_region_barrier_implementation: - case ompt_sync_region_barrier_implicit: - case ompt_sync_region_barrier_explicit: - case ompt_sync_region_barrier: { - if (hasReductionCallback < ompt_set_always) { - // We want to track writes after the barrier again. - Data->InBarrier = false; - TsanIgnoreWritesEnd(); - } - - char BarrierIndex = Data->BarrierIndex; - // Barrier will end after it has been entered by all threads. - if (parallel_data) - TsanHappensAfter(Data->Team->GetBarrierPtr(BarrierIndex)); - - // It is not guaranteed that all threads have exited this barrier before - // we enter the next one. So we will use a different address. - // We are however guaranteed that this current barrier is finished - // by the time we exit the next one. So we can then reuse the first - // address. - Data->BarrierIndex = (BarrierIndex + 1) % 2; - break; + case ompt_sync_region_barrier_implementation: + case ompt_sync_region_barrier_implicit: + case ompt_sync_region_barrier_explicit: + case ompt_sync_region_barrier: { + if (hasReductionCallback < ompt_set_always) { + // We want to track writes after the barrier again. + Data->InBarrier = false; + TsanIgnoreWritesEnd(); } - case ompt_sync_region_taskwait: { - if (Data->execution > 1) - TsanHappensAfter(Data->GetTaskwaitPtr()); - break; - } + char BarrierIndex = Data->BarrierIndex; + // Barrier will end after it has been entered by all threads. + if (parallel_data) + TsanHappensAfter(Data->Team->GetBarrierPtr(BarrierIndex)); + + // It is not guaranteed that all threads have exited this barrier before + // we enter the next one. So we will use a different address. + // We are however guaranteed that this current barrier is finished + // by the time we exit the next one. So we can then reuse the first + // address. + Data->BarrierIndex = (BarrierIndex + 1) % 2; + break; + } - case ompt_sync_region_taskgroup: { - assert(Data->TaskGroup != nullptr && - "Should have at least one taskgroup!"); + case ompt_sync_region_taskwait: { + if (Data->execution > 1) + TsanHappensAfter(Data->GetTaskwaitPtr()); + break; + } - TsanHappensAfter(Data->TaskGroup->GetPtr()); + case ompt_sync_region_taskgroup: { + assert(Data->TaskGroup != nullptr && + "Should have at least one taskgroup!"); - // Delete this allocated taskgroup, all descendent task are finished by - // now. - Taskgroup *Parent = Data->TaskGroup->Parent; - delete Data->TaskGroup; - Data->TaskGroup = Parent; - break; - } + TsanHappensAfter(Data->TaskGroup->GetPtr()); - default: - break; + // Delete this allocated taskgroup, all descendent task are finished by + // now. + Taskgroup *Parent = Data->TaskGroup->Parent; + delete Data->TaskGroup; + Data->TaskGroup = Parent; + break; + } + + default: + break; } break; } @@ -656,20 +651,20 @@ static void ompt_tsan_reduction(ompt_sync_region_t kind, switch (endpoint) { case ompt_scope_begin: switch (kind) { - case ompt_sync_region_reduction: - TsanIgnoreWritesBegin(); - break; - default: - break; + case ompt_sync_region_reduction: + TsanIgnoreWritesBegin(); + break; + default: + break; } break; case ompt_scope_end: switch (kind) { - case ompt_sync_region_reduction: - TsanIgnoreWritesEnd(); - break; - default: - break; + case ompt_sync_region_reduction: + TsanIgnoreWritesEnd(); + break; + default: + break; } break; } @@ -678,9 +673,9 @@ static void ompt_tsan_reduction(ompt_sync_region_t kind, /// OMPT event callbacks for handling tasks. static void ompt_tsan_task_create( - ompt_data_t *parent_task_data, /* id of parent task */ + ompt_data_t *parent_task_data, /* id of parent task */ const ompt_frame_t *parent_frame, /* frame data for parent task */ - ompt_data_t *new_task_data, /* id of created task */ + ompt_data_t *new_task_data, /* id of created task */ int type, int has_dependences, const void *codeptr_ra) /* pointer to outlined function */ { @@ -791,7 +786,8 @@ static void ompt_tsan_task_schedule(ompt_data_t *first_task_data, // in dependencies block following inout and out dependencies! TsanHappensBefore(ToInAddr(Dependency->variable.ptr)); - if (Dependency->dependence_type == ompt_dependence_type_out || Dependency->dependence_type == ompt_dependence_type_inout) { + if (Dependency->dependence_type == ompt_dependence_type_out || + Dependency->dependence_type == ompt_dependence_type_inout) { TsanHappensBefore(Dependency->variable.ptr); } } @@ -842,14 +838,12 @@ static void ompt_tsan_task_schedule(ompt_data_t *first_task_data, } static void ompt_tsan_dependences(ompt_data_t *task_data, - const ompt_dependence_t *deps, - int ndeps) { + const ompt_dependence_t *deps, int ndeps) { if (ndeps > 0) { // Copy the data to use it in task_switch and task_end. TaskData *Data = ToTaskData(task_data); Data->Dependencies = new ompt_dependence_t[ndeps]; - std::memcpy(Data->Dependencies, deps, - sizeof(ompt_dependence_t) * ndeps); + std::memcpy(Data->Dependencies, deps, sizeof(ompt_dependence_t) * ndeps); Data->DependencyCount = ndeps; // This callback is executed before this task is first started. @@ -858,53 +852,51 @@ static void ompt_tsan_dependences(ompt_data_t *task_data, } /// OMPT event callbacks for handling locking. -static void ompt_tsan_mutex_acquired(ompt_mutex_t kind, - ompt_wait_id_t wait_id, +static void ompt_tsan_mutex_acquired(ompt_mutex_t kind, ompt_wait_id_t wait_id, const void *codeptr_ra) { // Acquire our own lock to make sure that // 1. the previous release has finished. // 2. the next acquire doesn't start before we have finished our release. - LocksMutex.lock(); - std::mutex &Lock = Locks[wait_id]; - LocksMutex.unlock(); + LocksMutex.lock(); + std::mutex &Lock = Locks[wait_id]; + LocksMutex.unlock(); - Lock.lock(); - TsanHappensAfter(&Lock); + Lock.lock(); + TsanHappensAfter(&Lock); } -static void ompt_tsan_mutex_released(ompt_mutex_t kind, - ompt_wait_id_t wait_id, +static void ompt_tsan_mutex_released(ompt_mutex_t kind, ompt_wait_id_t wait_id, const void *codeptr_ra) { - LocksMutex.lock(); - std::mutex &Lock = Locks[wait_id]; - LocksMutex.unlock(); - TsanHappensBefore(&Lock); + LocksMutex.lock(); + std::mutex &Lock = Locks[wait_id]; + LocksMutex.unlock(); + TsanHappensBefore(&Lock); - Lock.unlock(); + Lock.unlock(); } // callback , signature , variable to store result , required support level -#define SET_OPTIONAL_CALLBACK_T(event, type, result, level) \ - do { \ - ompt_callback_##type##_t tsan_##event = &ompt_tsan_##event; \ - result = ompt_set_callback(ompt_callback_##event, \ - (ompt_callback_t)tsan_##event); \ - if (result < level) \ - printf("Registered callback '" #event "' is not supported at " #level " (%i)\n", \ - result); \ +#define SET_OPTIONAL_CALLBACK_T(event, type, result, level) \ + do { \ + ompt_callback_##type##_t tsan_##event = &ompt_tsan_##event; \ + result = ompt_set_callback(ompt_callback_##event, \ + (ompt_callback_t)tsan_##event); \ + if (result < level) \ + printf("Registered callback '" #event "' is not supported at " #level \ + " (%i)\n", \ + result); \ } while (0) -#define SET_CALLBACK_T(event, type) \ - do { \ - int res; \ - SET_OPTIONAL_CALLBACK_T(event, type, res, ompt_set_always); \ +#define SET_CALLBACK_T(event, type) \ + do { \ + int res; \ + SET_OPTIONAL_CALLBACK_T(event, type, res, ompt_set_always); \ } while (0) #define SET_CALLBACK(event) SET_CALLBACK_T(event, event) -static int ompt_tsan_initialize(ompt_function_lookup_t lookup, - int device_num, +static int ompt_tsan_initialize(ompt_function_lookup_t lookup, int device_num, ompt_data_t *tool_data) { const char *options = getenv("TSAN_OPTIONS"); TsanFlags tsan_flags(options); @@ -938,13 +930,14 @@ static int ompt_tsan_initialize(ompt_function_lookup_t lookup, SET_CALLBACK_T(mutex_acquired, mutex); SET_CALLBACK_T(mutex_released, mutex); - SET_OPTIONAL_CALLBACK_T(reduction, sync_region, hasReductionCallback, ompt_set_never); + SET_OPTIONAL_CALLBACK_T(reduction, sync_region, hasReductionCallback, + ompt_set_never); if (!tsan_flags.ignore_noninstrumented_modules) - fprintf( - stderr, - "Warning: please export TSAN_OPTIONS='ignore_noninstrumented_modules=1' " - "to avoid false positive reports from the OpenMP runtime!\n"); + fprintf(stderr, + "Warning: please export " + "TSAN_OPTIONS='ignore_noninstrumented_modules=1' " + "to avoid false positive reports from the OpenMP runtime!\n"); return 1; // success } @@ -959,26 +952,23 @@ static void ompt_tsan_finalize(ompt_data_t *tool_data) { delete archer_flags; } -extern "C" -ompt_start_tool_result_t *ompt_start_tool(unsigned int omp_version, - const char *runtime_version) { +extern "C" ompt_start_tool_result_t * +ompt_start_tool(unsigned int omp_version, const char *runtime_version) { const char *options = getenv("ARCHER_OPTIONS"); archer_flags = new ArcherFlags(options); - if (!archer_flags->enabled) - { + if (!archer_flags->enabled) { if (archer_flags->verbose) - std::cout << "Archer disabled, stopping operation" - << std::endl; + std::cout << "Archer disabled, stopping operation" << std::endl; delete archer_flags; return NULL; } - + static ompt_start_tool_result_t ompt_start_tool_result = { &ompt_tsan_initialize, &ompt_tsan_finalize, {0}}; - runOnTsan=1; + runOnTsan = 1; RunningOnValgrind(); if (!runOnTsan) // if we are not running on TSAN, give a different tool the - // chance to be loaded + // chance to be loaded { if (archer_flags->verbose) std::cout << "Archer detected OpenMP application without TSan "