Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

314 lines
12 KiB
C++

//===-- OmptTracing.cpp - Target independent OpenMP target RTL --- C++ -*--===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Implementation of OMPT tracing interfaces for PluginInterface
//
//===----------------------------------------------------------------------===//
#ifdef OMPT_SUPPORT
#include "Shared/Debug.h"
#include "OmptDeviceTracing.h"
#include "omp-tools.h"
#include "llvm/Support/DynamicLibrary.h"
#include <atomic>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <mutex>
#pragma push_macro("DEBUG_PREFIX")
#undef DEBUG_PREFIX
#define DEBUG_PREFIX "OMPT"
// Define OMPT device tracing function entry points
#define defineOmptTracingFn(Name) \
libomptarget_##Name##_t llvm::omp::target::ompt::Name##_fn = nullptr;
FOREACH_OMPT_DEVICE_TRACING_FN_IMPLEMENTAIONS(defineOmptTracingFn)
#undef defineOmptTracingFn
// Define OMPT device tracing function mutexes
#define defineOmptTracingFnMutex(Name) \
std::mutex llvm::omp::target::ompt::Name##_mutex;
FOREACH_OMPT_DEVICE_TRACING_FN_IMPLEMENTAIONS(defineOmptTracingFnMutex)
#undef defineOmptTracingFnMutex
std::mutex llvm::omp::target::ompt::DeviceIdWritingMutex;
using namespace llvm::omp::target::ompt;
using namespace llvm::omp::target::debug;
std::shared_ptr<llvm::sys::DynamicLibrary>
llvm::omp::target::ompt::ParentLibrary(nullptr);
double llvm::omp::target::ompt::HostToDeviceSlope = .0;
double llvm::omp::target::ompt::HostToDeviceOffset = .0;
std::map<ompt_device_t *, int32_t> llvm::omp::target::ompt::Devices;
std::shared_ptr<llvm::sys::DynamicLibrary>
llvm::omp::target::ompt::getParentLibrary() {
static bool ParentLibraryAssigned = false;
if (!ParentLibraryAssigned) {
setParentLibrary("libomptarget.so");
ParentLibraryAssigned = true;
}
return ParentLibrary;
}
void llvm::omp::target::ompt::setParentLibrary(const char *Filename) {
if (ParentLibrary)
return;
std::string ErrorMsg;
ParentLibrary = std::make_shared<llvm::sys::DynamicLibrary>(
llvm::sys::DynamicLibrary::getPermanentLibrary(Filename, &ErrorMsg));
if ((ParentLibrary == nullptr) || (!ParentLibrary->isValid()))
REPORT() << "Failed to set parent library: " << ErrorMsg.c_str();
}
int llvm::omp::target::ompt::getDeviceId(ompt_device_t *Device) {
// Block other threads, which might trigger an erase (for the same device)
std::unique_lock<std::mutex> Lock(DeviceIdWritingMutex);
auto DeviceIterator = Devices.find(Device);
if (Device == nullptr || DeviceIterator == Devices.end()) {
REPORT() << "Failed to get ID for Device=" << Device;
return -1;
}
return DeviceIterator->second;
}
void llvm::omp::target::ompt::setDeviceId(ompt_device_t *Device,
int32_t DeviceId) {
assert(Device && "Mapping device ID to nullptr is not allowed");
if (Device == nullptr || DeviceId < 0) {
REPORT() << "Failed to set ID=%d for Device=" << DeviceId << Device;
return;
}
std::unique_lock<std::mutex> Lock(DeviceIdWritingMutex);
auto DeviceIterator = Devices.find(Device);
if (DeviceIterator != Devices.end()) {
auto CurrentDeviceId = DeviceIterator->second;
if (DeviceId == CurrentDeviceId) {
REPORT() << "Tried to duplicate OMPT Device= " << Device << " ID=" << DeviceId;
} else {
REPORT() << "Tried to overwrite OMPT Device=" << Device << " (ID=" << CurrentDeviceId << " with new ID=" << DeviceId;
}
return;
}
Devices.emplace(Device, DeviceId);
}
void llvm::omp::target::ompt::removeDeviceId(ompt_device_t *Device) {
int DeviceId = getDeviceId(Device);
if (DeviceId < 0) {
REPORT() << "Tried to remove Device= " << Device << " ID=" << DeviceId;
return;
}
std::unique_lock<std::mutex> Lock(DeviceIdWritingMutex);
Devices.erase(Device);
TracedDevices.erase(DeviceId);
}
OMPT_API_ROUTINE ompt_set_result_t ompt_set_trace_ompt(ompt_device_t *Device,
unsigned int Enable,
unsigned int EventTy) {
ODBG(ODT_Tool) << "Executing ompt_set_trace_ompt";
int DeviceId = getDeviceId(Device);
if (DeviceId < 0) {
REPORT() << "Failed to set trace events for Device=" << Device <<
" (Unknown device) [Enable=" << Enable << " EventTy=" << EventTy;
return ompt_set_never;
}
std::unique_lock<std::mutex> Lock(ompt_set_trace_ompt_mutex);
ensureFuncPtrLoaded<libomptarget_ompt_set_trace_ompt_t>(
"libomptarget_ompt_set_trace_ompt", &ompt_set_trace_ompt_fn);
assert(ompt_set_trace_ompt_fn && "libomptarget_ompt_set_trace_ompt loaded");
return ompt_set_trace_ompt_fn(DeviceId, Enable, EventTy);
}
OMPT_API_ROUTINE int
ompt_start_trace(ompt_device_t *Device, ompt_callback_buffer_request_t Request,
ompt_callback_buffer_complete_t Complete) {
ODBG(ODT_Tool) << "Executing ompt_start_trace";
int DeviceId = getDeviceId(Device);
if (DeviceId < 0) {
REPORT() << "Failed to start trace for Device=" << Device << " (Unknown device";
// Indicate failure
return 0;
}
{
// Protect the function pointer
std::unique_lock<std::mutex> Lock(ompt_start_trace_mutex);
if (Request && Complete) {
llvm::omp::target::ompt::enableDeviceTracing(DeviceId);
// Enable asynchronous memory copy profiling
setOmptAsyncCopyProfile(/*Enable=*/true);
// Enable queue dispatch profiling
if (DeviceId >= 0)
setGlobalOmptKernelProfile(Device, /*Enable=*/1);
else
REPORT() << "May not enable kernel profiling for invalid device id=" <<
DeviceId;
}
// Call libomptarget specific function
ensureFuncPtrLoaded<libomptarget_ompt_start_trace_t>(
"libomptarget_ompt_start_trace", &ompt_start_trace_fn);
assert(ompt_start_trace_fn && "libomptarget_ompt_start_trace loaded");
}
return ompt_start_trace_fn(DeviceId, Request, Complete);
}
OMPT_API_ROUTINE int ompt_flush_trace(ompt_device_t *Device) {
ODBG(ODT_Tool) << "Executing ompt_flush_trace";
std::unique_lock<std::mutex> Lock(ompt_flush_trace_mutex);
ensureFuncPtrLoaded<libomptarget_ompt_flush_trace_t>(
"libomptarget_ompt_flush_trace", &ompt_flush_trace_fn);
assert(ompt_flush_trace_fn && "libomptarget_ompt_flush_trace loaded");
return ompt_flush_trace_fn(getDeviceId(Device));
}
OMPT_API_ROUTINE int ompt_stop_trace(ompt_device_t *Device) {
ODBG(ODT_Tool) << "Executing ompt_stop_trace";
int DeviceId = getDeviceId(Device);
if (DeviceId < 0) {
REPORT() << "Failed to stop trace for Device=" << Device << " (Unknown device)";
// Indicate failure
return 0;
}
{
// Protect the function pointer
std::unique_lock<std::mutex> Lock(ompt_stop_trace_mutex);
llvm::omp::target::ompt::disableDeviceTracing(DeviceId);
// Disable asynchronous memory copy profiling
setOmptAsyncCopyProfile(/*Enable=*/false);
// Disable queue dispatch profiling
if (DeviceId >= 0)
setGlobalOmptKernelProfile(Device, /*Enable=*/0);
else
REPORT() << "May not disable kernel profiling for invalid device id=" <<
DeviceId;
ensureFuncPtrLoaded<libomptarget_ompt_stop_trace_t>(
"libomptarget_ompt_stop_trace", &ompt_stop_trace_fn);
assert(ompt_stop_trace_fn && "libomptarget_ompt_stop_trace loaded");
}
return ompt_stop_trace_fn(DeviceId);
}
OMPT_API_ROUTINE ompt_record_ompt_t *
ompt_get_record_ompt(ompt_buffer_t *Buffer, ompt_buffer_cursor_t CurrentPos) {
// TODO In debug mode, get the metadata associated with this buffer
// and assert that there are enough bytes for the current record
// Currently, no synchronization required since a disjoint set of
// trace records is handed over to a thread.
// Note that CurrentPos can be nullptr. In that case, we return
// nullptr. The tool has to handle that properly.
return (ompt_record_ompt_t *)CurrentPos;
}
OMPT_API_ROUTINE int ompt_advance_buffer_cursor(ompt_device_t *Device,
ompt_buffer_t *Buffer,
size_t Size,
ompt_buffer_cursor_t CurrentPos,
ompt_buffer_cursor_t *NextPos) {
// Note: The input parameter size is unused here. It refers to the
// bytes returned in the corresponding callback.
// Advance can be called concurrently, so synchronize setting the
// function pointer. The actual libomptarget function does not need
// to be synchronized since it must be working on logically disjoint
// buffers.
std::unique_lock<std::mutex> Lock(ompt_advance_buffer_cursor_mutex);
ensureFuncPtrLoaded<libomptarget_ompt_advance_buffer_cursor_t>(
"libomptarget_ompt_advance_buffer_cursor",
&ompt_advance_buffer_cursor_fn);
assert(ompt_advance_buffer_cursor_fn &&
"libomptarget_ompt_advance_buffer_cursor loaded");
return ompt_advance_buffer_cursor_fn(Device, Buffer, Size, CurrentPos,
NextPos);
}
OMPT_API_ROUTINE ompt_record_t
ompt_get_record_type(ompt_buffer_t *Buffer, ompt_buffer_cursor_t CurrentPos) {
std::unique_lock<std::mutex> Lock(ompt_get_record_type_mutex);
ensureFuncPtrLoaded<libomptarget_ompt_get_record_type_t>(
"libomptarget_ompt_get_record_type", &ompt_get_record_type_fn);
assert(ompt_get_record_type_fn && "libomptarget_ompt_get_record_type loaded");
return ompt_get_record_type_fn(Buffer, CurrentPos);
}
OMPT_API_ROUTINE ompt_device_time_t
ompt_get_device_time(ompt_device_t *Device) {
ODBG(ODT_Tool) << "Executing ompt_get_device_time";
return getSystemTimestampInNs();
}
OMPT_API_ROUTINE double ompt_translate_time(ompt_device_t *Device,
ompt_device_time_t DeviceTime) {
// Translate a device time to a meaningful timepoint in host time
// We do not need to account for clock-skew / drift. So simple linear
// translation using the host to device rate we obtained.
double TranslatedTime = DeviceTime * HostToDeviceSlope + HostToDeviceOffset;
ODBG(ODT_Tool) << "D2H translated time: " << TranslatedTime;
return TranslatedTime;
}
void llvm::omp::target::ompt::setOmptTimestamp(uint64_t StartTime,
uint64_t EndTime) {
std::unique_lock<std::mutex> Lock(ompt_set_timestamp_mutex);
ensureFuncPtrLoaded<libomptarget_ompt_set_timestamp_t>(
"libomptarget_ompt_set_timestamp", &ompt_set_timestamp_fn);
// No need to hold a lock
ompt_set_timestamp_fn(StartTime, EndTime);
}
void llvm::omp::target::ompt::setOmptHostToDeviceRate(double Slope,
double Offset) {
HostToDeviceSlope = Slope;
HostToDeviceOffset = Offset;
}
void llvm::omp::target::ompt::setOmptGrantedNumTeams(uint64_t NumTeams) {
std::unique_lock<std::mutex> Lock(ompt_set_granted_teams_mutex);
ensureFuncPtrLoaded<libomptarget_ompt_set_granted_teams_t>(
"libomptarget_ompt_set_granted_teams", &ompt_set_granted_teams_fn);
// No need to hold a lock
ompt_set_granted_teams_fn(NumTeams);
}
ompt_interface_fn_t llvm::omp::target::ompt::lookupDeviceTracingFn(
const char *InterfaceFunctionName) {
#define compareAgainst(AvailableFunction) \
if (strcmp(InterfaceFunctionName, #AvailableFunction) == 0) \
return (ompt_interface_fn_t)AvailableFunction;
FOREACH_OMPT_DEVICE_TRACING_FN(compareAgainst);
#undef compareAgainst
ODBG(ODT_Tool) << "Warning: Could not find requested function "
<< InterfaceFunctionName;
return (ompt_interface_fn_t) nullptr;
}
#pragma pop_macro("DEBUG_PREFIX")
#endif // OMPT_SUPPORT