| //===- GenericProfiler.h - GenericProfiler interface for use in Plugins ---===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // The GenericProfiler interface allows to implement profiler logic for various | |
| // backends, such as OMPT or other tracing mechanisms. | |
| // This enables the plugins to be agnostic of the actual high-level language | |
| // that is implemented. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef OFFLOAD_PLUGINS_NEXTGEN_COMMON_INCLUDE_GENERICPROFILER_H | |
| #define OFFLOAD_PLUGINS_NEXTGEN_COMMON_INCLUDE_GENERICPROFILER_H | |
| #include "Shared/APITypes.h" | |
| #include <cstdint> | |
| #include <functional> | |
| #include <tuple> | |
| namespace llvm { | |
| namespace omp { | |
| namespace target { | |
| namespace plugin { | |
| struct GenericDeviceTy; | |
| class GenericProfilerTy; | |
| /// Helper function to unpack a tuple of arguments and call a function with | |
| /// them. | |
| template <typename FunT, typename... ArgsT, size_t... IdxSequence> | |
| void callViaIndexSeq(FunT F, GenericProfilerTy *P, uint64_t StartNanos, | |
| uint64_t EndNanos, std::tuple<ArgsT...> Args, | |
| std::index_sequence<IdxSequence...>) { | |
| F(P, StartNanos, EndNanos, std::get<IdxSequence>(Args)...); | |
| } | |
| /// Helper function to unpack a tuple of arguments and call a function with | |
| /// them. | |
| template <typename FunT, typename... ArgsT> | |
| void callViaUnpack(FunT F, GenericProfilerTy *P, uint64_t StartNanos, | |
| uint64_t EndNanos, std::tuple<ArgsT...> Tup) { | |
| callViaIndexSeq(F, P, StartNanos, EndNanos, Tup, | |
| std::index_sequence_for<ArgsT...>{}); | |
| } | |
| /// Abstraction layer to implement different profiler backends. | |
| /// | |
| /// The plugins call into the GenericProfilerTy to handle the specific events | |
| /// with whatever specific backend was instantiated. For now, the supported | |
| /// backends are limited to an OMPT implementation. | |
| class GenericProfilerTy { | |
| public: | |
| GenericProfilerTy() = default; | |
| virtual ~GenericProfilerTy() = default; | |
| /// Returns true if profiling is enabled, false otherwise. | |
| virtual bool isProfilingEnabled() { return false; } | |
| /// Set the factors which are used to interpolate the device clock compared to | |
| /// the host clock. This follows a simple linear interpolation: Slope * <time> | |
| /// + Offset. | |
| void setTimeConversionFactors(double Slope, double Offset) { | |
| HostToDeviceSlope = Slope; | |
| HostToDeviceOffset = Offset; | |
| setTimeConversionFactorsImpl(HostToDeviceSlope, HostToDeviceOffset); | |
| } | |
| /// Hook that is called when memory is allocated on the device. | |
| virtual void handleDataAlloc(uint64_t StartNanos, uint64_t EndNanos, | |
| void *HostPtr, uint64_t Size, void *Data) {} | |
| /// Hook that is called when memory is freed on the device. | |
| virtual void handleDataDelete(uint64_t StartNanos, uint64_t EndNanos, | |
| void *TgtPtr, void *Data) {} | |
| /// Hook that is called before launching a kernel. | |
| virtual void handlePreKernelLaunch(GenericDeviceTy *Device, | |
| uint32_t NumBlocks[3], | |
| __tgt_async_info *AI) {} | |
| /// Hook that is called when the kernel is finished to extract the specific | |
| /// timing info for that kernel execution. | |
| virtual void handleKernelCompletion(uint64_t StartNanos, uint64_t EndNanos, | |
| void *Data) {} | |
| /// Hook that is called when a data transfer happens to extract timing info | |
| /// for that transfer. | |
| virtual void handleDataTransfer(uint64_t StartNanos, uint64_t EndNanos, | |
| void *Data) {} | |
| /// Allow factors for time conversion between host and device. | |
| virtual void setTimeConversionFactorsImpl(double Slope, double Offset) {} | |
| /// RAII style timer that measures the elapsed time between construction and | |
| /// destruction, then invokes a callback with the profiler, start/end times, | |
| /// and any captured arguments. It wraps an existing GenericProfiler instance | |
| /// to delay the call of the ProfilerFunction (F) until this object's dtor is | |
| /// called. | |
| template <typename ProfilerFuncTy, typename... ProfilerFuncArgsTy> | |
| class ProfTimerTy { | |
| public: | |
| /// On creation, saves the timestamp from the profiler and device, and | |
| /// stores the callback function and its arguments. | |
| ProfTimerTy(ProfilerFuncTy &&F, GenericProfilerTy *P, GenericDeviceTy *D, | |
| ProfilerFuncArgsTy... As) | |
| : ProfilerFunction(F), ProfilerInstance(P), Device(D), | |
| ProfilerFuncArgs(As...) { | |
| assert(ProfilerInstance && "GenericProfilerTy is null"); | |
| assert(Device && "GenericDeviceTy is null"); | |
| if (ProfilerInstance) | |
| StartTime = ProfilerInstance->getDeviceTimeStamp(Device); | |
| } | |
| /// On destruction, saves the end timestamp and invokes the callback | |
| /// function with the profiler, start/end times, and captured arguments. | |
| ~ProfTimerTy() { | |
| assert(ProfilerInstance && "GenericProfilerTy is null"); | |
| assert(Device && "GenericDeviceTy is null"); | |
| if (ProfilerInstance) { | |
| uint64_t EndTime = ProfilerInstance->getDeviceTimeStamp(Device); | |
| callViaUnpack(ProfilerFunction, ProfilerInstance, StartTime, EndTime, | |
| ProfilerFuncArgs); | |
| } | |
| } | |
| private: | |
| /// The callback function to be invoked on destruction, which takes the | |
| /// profiler, start/end times, and captured arguments. | |
| ProfilerFuncTy ProfilerFunction; | |
| /// The profiler instance to be used for timing and invoking the callback | |
| /// function. | |
| GenericProfilerTy *ProfilerInstance; | |
| /// The device instance to be used for timing and invoking the callback | |
| /// function. | |
| GenericDeviceTy *Device; | |
| /// The start time of the timer, captured at construction. | |
| uint64_t StartTime = 0; | |
| /// The captured arguments to be passed to the callback function on | |
| /// destruction. | |
| std::tuple<ProfilerFuncArgsTy...> ProfilerFuncArgs; | |
| }; | |
| template <typename ProfilerFuncTy, typename... ProfilerFuncArgsTy> | |
| [[maybe_unused]] | |
| ProfTimerTy(ProfilerFuncTy &&, GenericProfilerTy *, ProfilerFuncArgsTy...) | |
| -> ProfTimerTy<ProfilerFuncTy, ProfilerFuncArgsTy...>; | |
| template <typename ProfilerFuncTy, typename... ProfilerFuncArgsTy> | |
| friend class ProfTimerTy; | |
| /// Returns an RAII style timer, which handles data allocation timing. | |
| [[nodiscard]] auto getScopedDataAllocTimer(GenericDeviceTy *Dev, | |
| void *HostPtr, uint64_t Size, | |
| void *ProfData = nullptr) { | |
| return ProfTimerTy( | |
| [](GenericProfilerTy *P, auto... args) { | |
| assert(P && "P was null"); | |
| P->handleDataAlloc(args...); | |
| }, | |
| this, Dev, HostPtr, Size, ProfData); | |
| } | |
| /// Returns an RAII style timer, which handles data deletion timing. | |
| [[nodiscard]] auto getScopedDataDeleteTimer(GenericDeviceTy *Dev, | |
| void *TgtPtr, | |
| void *ProfData = nullptr) { | |
| return ProfTimerTy( | |
| [](GenericProfilerTy *P, auto... args) { | |
| assert(P && "P was null"); | |
| P->handleDataDelete(args...); | |
| }, | |
| this, Dev, TgtPtr, ProfData); | |
| } | |
| protected: | |
| /// Factors to convert host time to device time. The default values are | |
| /// Computed in a way Slope * Time + Offset (inspired by Score-P). | |
| double HostToDeviceSlope = 1.0; | |
| double HostToDeviceOffset = .0; | |
| private: | |
| /// Vendor-specific implementation to obtain device time. | |
| uint64_t getDeviceTimeStamp(GenericDeviceTy *D); | |
| }; | |
| /// Null-object used to normalize an absent profiler. Callers that do not have a | |
| /// profiler pass none, and the receiving method resolves to this instance, so | |
| /// profiling logic never has to test for a null pointer. | |
| GenericProfilerTy &getNoOpProfiler(); | |
| } // namespace plugin | |
| } // namespace target | |
| } // namespace omp | |
| } // namespace llvm | |
| #endif // OFFLOAD_PLUGINS_NEXTGEN_COMMON_INCLUDE_GENERICPROFILER_H |