diff --git a/llvm/include/llvm/Support/TimeProfiler.h b/llvm/include/llvm/Support/TimeProfiler.h --- a/llvm/include/llvm/Support/TimeProfiler.h +++ b/llvm/include/llvm/Support/TimeProfiler.h @@ -98,6 +98,9 @@ /// Finish a time trace profiler running on a worker thread. void timeTraceProfilerFinishThread(); +/// Finish a time trace profiler running on a different thread. +void timeTraceProfilerFinishThreadExternal(llvm::TimeTraceProfiler *prof); + /// Is the time trace profiler enabled, i.e. initialized? inline bool timeTraceProfilerEnabled() { return getTimeTraceProfilerInstance() != nullptr; diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp --- a/llvm/lib/Support/TimeProfiler.cpp +++ b/llvm/lib/Support/TimeProfiler.cpp @@ -315,6 +315,14 @@ TimeTraceProfilerInstance = nullptr; } +// Finish TimeTraceProfilerInstance on a different thread +void llvm::timeTraceProfilerFinishThreadExternal( + llvm::TimeTraceProfiler *prof) { + auto &Instances = getTimeTraceProfilerInstances(); + std::lock_guard Lock(Instances.Lock); + Instances.List.push_back(prof); +} + void llvm::timeTraceProfilerWrite(raw_pwrite_stream &OS) { assert(TimeTraceProfilerInstance != nullptr && "Profiler object can't be null"); diff --git a/openmp/libomptarget/src/private.h b/openmp/libomptarget/src/private.h --- a/openmp/libomptarget/src/private.h +++ b/openmp/libomptarget/src/private.h @@ -189,12 +189,18 @@ } } +void checkTimeTraceInitThisThread(); + #include "llvm/Support/TimeProfiler.h" -#define TIMESCOPE() llvm::TimeTraceScope TimeScope(__FUNCTION__) +#define TIMESCOPE() \ + checkTimeTraceInitThisThread(); \ + llvm::TimeTraceScope TimeScope(__FUNCTION__) #define TIMESCOPE_WITH_IDENT(IDENT) \ + checkTimeTraceInitThisThread(); \ SourceInfo SI(IDENT); \ llvm::TimeTraceScope TimeScope(__FUNCTION__, SI.getProfileLocation()) #define TIMESCOPE_WITH_NAME_AND_IDENT(NAME, IDENT) \ + checkTimeTraceInitThisThread(); \ SourceInfo SI(IDENT); \ llvm::TimeTraceScope TimeScope(NAME, SI.getProfileLocation()) #else diff --git a/openmp/libomptarget/src/rtl.cpp b/openmp/libomptarget/src/rtl.cpp --- a/openmp/libomptarget/src/rtl.cpp +++ b/openmp/libomptarget/src/rtl.cpp @@ -43,6 +43,10 @@ static char *ProfileTraceFile = nullptr; +// List of TimeTraceProfiler instances on other threads +std::vector *profileInstancesOtherThreads = nullptr; +std::mutex profLock; + __attribute__((constructor(101))) void init() { DP("Init target library!\n"); @@ -62,8 +66,10 @@ ProfileTraceFile = getenv("LIBOMPTARGET_PROFILE"); // TODO: add a configuration option for time granularity - if (ProfileTraceFile) + if (ProfileTraceFile) { + profileInstancesOtherThreads = new std::vector; timeTraceProfilerInitialize(500 /* us */, "libomptarget"); + } } __attribute__((destructor(101))) void deinit() { @@ -71,11 +77,29 @@ delete PM; if (ProfileTraceFile) { + for (auto prof : *profileInstancesOtherThreads) + timeTraceProfilerFinishThreadExternal(prof); // TODO: add env var for file output if (auto E = timeTraceProfilerWrite(ProfileTraceFile, "-")) fprintf(stderr, "Error writing out the time trace\n"); timeTraceProfilerCleanup(); + delete profileInstancesOtherThreads; + } +} + +// Check if time trace profiler is already initialized on this thread. +// If not, initialize it and save a pointer to call finish before +// writing out the file. +void checkTimeTraceInitThisThread() { + if (ProfileTraceFile) { + if (llvm::getTimeTraceProfilerInstance() == nullptr) { + DP("initializing profiler on thread"); + llvm::timeTraceProfilerInitialize(500, "libomptarget"); + llvm::TimeTraceProfiler *prof = llvm::getTimeTraceProfilerInstance(); + std::lock_guard Lock(profLock); + profileInstancesOtherThreads->push_back(prof); + } } }