#ifndef OMPT_SUPPORT
extern "C" {
void ompt_libomptarget_connect() {}
}
#else
#include <cstdlib>
#include <cstring>
#include <memory>
#include "Shared/Debug.h"
#include "OpenMP/OMPT/Callback.h"
#include "OpenMP/OMPT/Connector.h"
#include "OpenMP/OMPT/Interface.h"
#include "llvm/Support/DynamicLibrary.h"
#undef DEBUG_PREFIX
#define DEBUG_PREFIX "OMPT"
using namespace llvm::omp::target::ompt;
#define defineOmptCallback(Name, Type, Code) \
Name##_t llvm::omp::target::ompt::Name##_fn = nullptr;
FOREACH_OMPT_NOEMI_EVENT(defineOmptCallback)
FOREACH_OMPT_EMI_EVENT(defineOmptCallback)
#undef defineOmptCallback
class LibomptargetRtlFinalizer;
LibomptargetRtlFinalizer *LibraryFinalizer = nullptr;
thread_local Interface llvm::omp::target::ompt::RegionInterface;
thread_local void *llvm::omp::target::ompt::ReturnAddress = nullptr;
bool llvm::omp::target::ompt::Initialized = false;
ompt_get_callback_t llvm::omp::target::ompt::lookupCallbackByCode = nullptr;
ompt_function_lookup_t llvm::omp::target::ompt::lookupCallbackByName = nullptr;
ompt_get_target_task_data_t ompt_get_target_task_data_fn = nullptr;
ompt_get_task_data_t ompt_get_task_data_fn = nullptr;
static std::atomic<uint64_t> IdCounter(1);
static uint64_t createId() { return IdCounter.fetch_add(1); }
static uint64_t createOpId() {
uint64_t NewId = createId();
RegionInterface.setHostOpId(NewId);
return NewId;
}
static uint64_t createRegionId() {
uint64_t NewId = createId();
RegionInterface.setTargetDataValue(NewId);
return NewId;
}
void Interface::beginTargetDataAlloc(int64_t DeviceId, void *HstPtrBegin,
void **TgtPtrBegin, size_t Size,
void *Code) {
beginTargetDataOperation();
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_begin, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_alloc, HstPtrBegin,
omp_get_initial_device(), *TgtPtrBegin,
DeviceId, Size, Code);
} else if (ompt_callback_target_data_op_fn) {
HostOpId = createOpId();
ompt_callback_target_data_op_fn(
TargetData.value, HostOpId, ompt_target_data_alloc, HstPtrBegin,
omp_get_initial_device(), *TgtPtrBegin,
DeviceId, Size, Code);
}
}
void Interface::endTargetDataAlloc(int64_t DeviceId, void *HstPtrBegin,
void **TgtPtrBegin, size_t Size,
void *Code) {
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_end, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_alloc, HstPtrBegin,
omp_get_initial_device(), *TgtPtrBegin,
DeviceId, Size, Code);
}
endTargetDataOperation();
}
void Interface::beginTargetDataSubmit(int64_t SrcDeviceId, void *SrcPtrBegin,
int64_t DstDeviceId, void *DstPtrBegin,
size_t Size, void *Code) {
beginTargetDataOperation();
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_begin, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_transfer_to_device, SrcPtrBegin, SrcDeviceId,
DstPtrBegin, DstDeviceId, Size, Code);
} else if (ompt_callback_target_data_op_fn) {
HostOpId = createOpId();
ompt_callback_target_data_op_fn(
TargetData.value, HostOpId, ompt_target_data_transfer_to_device,
SrcPtrBegin, SrcDeviceId, DstPtrBegin, DstDeviceId, Size, Code);
}
}
void Interface::endTargetDataSubmit(int64_t SrcDeviceId, void *SrcPtrBegin,
int64_t DstDeviceId, void *DstPtrBegin,
size_t Size, void *Code) {
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_end, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_transfer_to_device, SrcPtrBegin, SrcDeviceId,
DstPtrBegin, DstDeviceId, Size, Code);
}
endTargetDataOperation();
}
void Interface::beginTargetDataDelete(int64_t DeviceId, void *TgtPtrBegin,
void *Code) {
beginTargetDataOperation();
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_begin, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_delete, TgtPtrBegin, DeviceId,
nullptr, -1, 0, Code);
} else if (ompt_callback_target_data_op_fn) {
HostOpId = createOpId();
ompt_callback_target_data_op_fn(TargetData.value, HostOpId,
ompt_target_data_delete, TgtPtrBegin,
DeviceId, nullptr,
-1, 0, Code);
}
}
void Interface::endTargetDataDelete(int64_t DeviceId, void *TgtPtrBegin,
void *Code) {
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_end, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_delete, TgtPtrBegin, DeviceId,
nullptr, -1, 0, Code);
}
endTargetDataOperation();
}
void Interface::beginTargetDataRetrieve(int64_t SrcDeviceId, void *SrcPtrBegin,
int64_t DstDeviceId, void *DstPtrBegin,
size_t Size, void *Code) {
beginTargetDataOperation();
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_begin, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_transfer_from_device, SrcPtrBegin, SrcDeviceId,
DstPtrBegin, DstDeviceId, Size, Code);
} else if (ompt_callback_target_data_op_fn) {
HostOpId = createOpId();
ompt_callback_target_data_op_fn(
TargetData.value, HostOpId, ompt_target_data_transfer_from_device,
SrcPtrBegin, SrcDeviceId, DstPtrBegin, DstDeviceId, Size, Code);
}
}
void Interface::endTargetDataRetrieve(int64_t SrcDeviceId, void *SrcPtrBegin,
int64_t DstDeviceId, void *DstPtrBegin,
size_t Size, void *Code) {
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_end, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_transfer_from_device, SrcPtrBegin, SrcDeviceId,
DstPtrBegin, DstDeviceId, Size, Code);
}
endTargetDataOperation();
}
void Interface::beginTargetSubmit(unsigned int numTeams) {
if (ompt_callback_target_submit_emi_fn) {
ompt_callback_target_submit_emi_fn(ompt_scope_begin, &TargetData, &HostOpId,
numTeams);
} else if (ompt_callback_target_submit_fn) {
HostOpId = createOpId();
ompt_callback_target_submit_fn(TargetData.value, HostOpId, numTeams);
}
}
void Interface::endTargetSubmit(unsigned int numTeams) {
if (ompt_callback_target_submit_emi_fn) {
ompt_callback_target_submit_emi_fn(ompt_scope_end, &TargetData, &HostOpId,
numTeams);
}
}
void Interface::beginTargetDataEnter(int64_t DeviceId, void *Code) {
beginTargetRegion();
if (ompt_callback_target_emi_fn) {
ompt_callback_target_emi_fn(ompt_target_enter_data, ompt_scope_begin,
DeviceId, TaskData, TargetTaskData, &TargetData,
Code);
} else if (ompt_callback_target_fn) {
ompt_callback_target_fn(ompt_target_enter_data, ompt_scope_begin, DeviceId,
TaskData, TargetData.value, Code);
}
}
void Interface::endTargetDataEnter(int64_t DeviceId, void *Code) {
if (ompt_callback_target_emi_fn) {
ompt_callback_target_emi_fn(ompt_target_enter_data, ompt_scope_end,
DeviceId, TaskData, TargetTaskData, &TargetData,
Code);
} else if (ompt_callback_target_fn) {
ompt_callback_target_fn(ompt_target_enter_data, ompt_scope_end, DeviceId,
TaskData, TargetData.value, Code);
}
endTargetRegion();
}
void Interface::beginTargetDataExit(int64_t DeviceId, void *Code) {
beginTargetRegion();
if (ompt_callback_target_emi_fn) {
ompt_callback_target_emi_fn(ompt_target_exit_data, ompt_scope_begin,
DeviceId, TaskData, TargetTaskData, &TargetData,
Code);
} else if (ompt_callback_target_fn) {
TargetData.value = createRegionId();
ompt_callback_target_fn(ompt_target_exit_data, ompt_scope_begin, DeviceId,
TaskData, TargetData.value, Code);
}
}
void Interface::endTargetDataExit(int64_t DeviceId, void *Code) {
if (ompt_callback_target_emi_fn) {
ompt_callback_target_emi_fn(ompt_target_exit_data, ompt_scope_end, DeviceId,
TaskData, TargetTaskData, &TargetData, Code);
} else if (ompt_callback_target_fn) {
ompt_callback_target_fn(ompt_target_exit_data, ompt_scope_end, DeviceId,
TaskData, TargetData.value, Code);
}
endTargetRegion();
}
void Interface::beginTargetUpdate(int64_t DeviceId, void *Code) {
beginTargetRegion();
if (ompt_callback_target_emi_fn) {
ompt_callback_target_emi_fn(ompt_target_update, ompt_scope_begin, DeviceId,
TaskData, TargetTaskData, &TargetData, Code);
} else if (ompt_callback_target_fn) {
TargetData.value = createRegionId();
ompt_callback_target_fn(ompt_target_update, ompt_scope_begin, DeviceId,
TaskData, TargetData.value, Code);
}
}
void Interface::endTargetUpdate(int64_t DeviceId, void *Code) {
if (ompt_callback_target_emi_fn) {
ompt_callback_target_emi_fn(ompt_target_update, ompt_scope_end, DeviceId,
TaskData, TargetTaskData, &TargetData, Code);
} else if (ompt_callback_target_fn) {
ompt_callback_target_fn(ompt_target_update, ompt_scope_end, DeviceId,
TaskData, TargetData.value, Code);
}
endTargetRegion();
}
void Interface::beginTargetAssociatePointer(int64_t DeviceId, void *HstPtrBegin,
void *TgtPtrBegin, size_t Size,
void *Code) {
beginTargetDataOperation();
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_begin, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_associate, HstPtrBegin, omp_get_initial_device(),
TgtPtrBegin, DeviceId, Size, Code);
} else if (ompt_callback_target_data_op_fn) {
HostOpId = createOpId();
ompt_callback_target_data_op_fn(
TargetData.value, HostOpId, ompt_target_data_associate, HstPtrBegin,
omp_get_initial_device(), TgtPtrBegin, DeviceId, Size, Code);
}
}
void Interface::endTargetAssociatePointer(int64_t DeviceId, void *HstPtrBegin,
void *TgtPtrBegin, size_t Size,
void *Code) {
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_end, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_associate, HstPtrBegin, omp_get_initial_device(),
TgtPtrBegin, DeviceId, Size, Code);
}
}
void Interface::beginTargetDisassociatePointer(int64_t DeviceId,
void *HstPtrBegin,
void *TgtPtrBegin, size_t Size,
void *Code) {
beginTargetDataOperation();
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_begin, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_disassociate, HstPtrBegin, omp_get_initial_device(),
TgtPtrBegin, DeviceId, Size, Code);
} else if (ompt_callback_target_data_op_fn) {
HostOpId = createOpId();
ompt_callback_target_data_op_fn(
TargetData.value, HostOpId, ompt_target_data_disassociate, HstPtrBegin,
omp_get_initial_device(), TgtPtrBegin, DeviceId, Size, Code);
}
}
void Interface::endTargetDisassociatePointer(int64_t DeviceId,
void *HstPtrBegin,
void *TgtPtrBegin, size_t Size,
void *Code) {
if (ompt_callback_target_data_op_emi_fn) {
ompt_callback_target_data_op_emi_fn(
ompt_scope_end, TargetTaskData, &TargetData, &HostOpId,
ompt_target_data_disassociate, HstPtrBegin, omp_get_initial_device(),
TgtPtrBegin, DeviceId, Size, Code);
}
}
void Interface::beginTarget(int64_t DeviceId, void *Code) {
beginTargetRegion();
if (ompt_callback_target_emi_fn) {
ompt_callback_target_emi_fn(ompt_target, ompt_scope_begin, DeviceId,
TaskData, TargetTaskData, &TargetData, Code);
} else if (ompt_callback_target_fn) {
TargetData.value = createRegionId();
ompt_callback_target_fn(ompt_target, ompt_scope_begin, DeviceId, TaskData,
TargetData.value, Code);
}
}
void Interface::endTarget(int64_t DeviceId, void *Code) {
if (ompt_callback_target_emi_fn) {
ompt_callback_target_emi_fn(ompt_target, ompt_scope_end, DeviceId, TaskData,
TargetTaskData, &TargetData, Code);
} else if (ompt_callback_target_fn) {
ompt_callback_target_fn(ompt_target, ompt_scope_end, DeviceId, TaskData,
TargetData.value, Code);
}
endTargetRegion();
}
void Interface::beginTargetDataOperation() {
DP("in ompt_target_region_begin (TargetRegionId = %lu)\n", TargetData.value);
}
void Interface::endTargetDataOperation() {
DP("in ompt_target_region_end (TargetRegionId = %lu)\n", TargetData.value);
}
void Interface::beginTargetRegion() {
assert(ompt_get_task_data_fn && "Calling a null task data function");
TaskData = ompt_get_task_data_fn();
assert(ompt_get_target_task_data_fn &&
"Calling a null target task data function");
TargetTaskData = ompt_get_target_task_data_fn();
TargetData = ompt_data_none;
}
void Interface::endTargetRegion() {
TaskData = 0;
TargetTaskData = 0;
TargetData = ompt_data_none;
}
class LibomptargetRtlFinalizer {
public:
LibomptargetRtlFinalizer() {}
void registerRtl(ompt_finalize_t FinalizationFunction) {
if (FinalizationFunction) {
RtlFinalizationFunctions.emplace_back(FinalizationFunction);
}
}
void finalize() {
for (auto FinalizationFunction : RtlFinalizationFunctions)
FinalizationFunction( nullptr);
RtlFinalizationFunctions.clear();
}
private:
llvm::SmallVector<ompt_finalize_t> RtlFinalizationFunctions;
};
int llvm::omp::target::ompt::initializeLibrary(ompt_function_lookup_t lookup,
int initial_device_num,
ompt_data_t *tool_data) {
DP("Executing initializeLibrary (libomp)\n");
#define bindOmptFunctionName(OmptFunction, DestinationFunction) \
DestinationFunction = (OmptFunction##_t)lookup(#OmptFunction); \
DP("initializeLibrary (libomp) bound %s=%p\n", #DestinationFunction, \
((void *)(uint64_t)DestinationFunction));
bindOmptFunctionName(ompt_get_callback, lookupCallbackByCode);
bindOmptFunctionName(ompt_get_task_data, ompt_get_task_data_fn);
bindOmptFunctionName(ompt_get_target_task_data, ompt_get_target_task_data_fn);
#undef bindOmptFunctionName
lookupCallbackByName = lookup;
assert(lookupCallbackByCode && "lookupCallbackByCode should be non-null");
assert(lookupCallbackByName && "lookupCallbackByName should be non-null");
assert(ompt_get_task_data_fn && "ompt_get_task_data_fn should be non-null");
assert(ompt_get_target_task_data_fn &&
"ompt_get_target_task_data_fn should be non-null");
assert(LibraryFinalizer == nullptr &&
"LibraryFinalizer should not be initialized yet");
LibraryFinalizer = new LibomptargetRtlFinalizer();
Initialized = true;
return 0;
}
void llvm::omp::target::ompt::finalizeLibrary(ompt_data_t *data) {
DP("Executing finalizeLibrary (libomp)\n");
LibraryFinalizer->finalize();
delete LibraryFinalizer;
Initialized = false;
}
void llvm::omp::target::ompt::connectLibrary() {
DP("Entering connectLibrary (libomp)\n");
static OmptLibraryConnectorTy LibompConnector("libomp");
static ompt_start_tool_result_t OmptResult;
OmptResult.initialize = ompt::initializeLibrary;
OmptResult.finalize = ompt::finalizeLibrary;
OmptResult.tool_data.value = 0;
LibompConnector.connect(&OmptResult);
#define bindOmptCallback(Name, Type, Code) \
if (lookupCallbackByCode) \
lookupCallbackByCode( \
(ompt_callbacks_t)(Code), \
(ompt_callback_t *)&(llvm::omp::target::ompt::Name##_fn));
FOREACH_OMPT_NOEMI_EVENT(bindOmptCallback)
FOREACH_OMPT_EMI_EVENT(bindOmptCallback)
#undef bindOmptCallback
DP("Exiting connectLibrary (libomp)\n");
}
extern "C" {
void ompt_libomptarget_connect(ompt_start_tool_result_t *result) {
DP("Enter ompt_libomptarget_connect\n");
if (Initialized && result && LibraryFinalizer) {
LibraryFinalizer->registerRtl(result->finalize);
result->initialize(lookupCallbackByName,
0, nullptr);
}
DP("Leave ompt_libomptarget_connect\n");
}
}
#endif