diff options
Diffstat (limited to 'src/armnn/Profiling.hpp')
-rw-r--r-- | src/armnn/Profiling.hpp | 179 |
1 files changed, 95 insertions, 84 deletions
diff --git a/src/armnn/Profiling.hpp b/src/armnn/Profiling.hpp index 88a7adff7c..33c5f46886 100644 --- a/src/armnn/Profiling.hpp +++ b/src/armnn/Profiling.hpp @@ -4,9 +4,12 @@ // #pragma once -#if ARMNN_PROFILING_ENABLED +#include "ProfilingEvent.hpp" #include "armnn/ArmNN.hpp" +#include "armnn/IProfiler.hpp" + +#include "WallClockTimer.hpp" #include <chrono> #include <iosfwd> @@ -15,82 +18,52 @@ #include <stack> #include <map> +#include <boost/core/ignore_unused.hpp> + namespace armnn { -// Clock class that uses the same timestamp function as the Mali DDK -class monotonic_clock { -public: - using duration = std::chrono::nanoseconds; - using time_point = std::chrono::time_point<monotonic_clock, duration>; - - static std::chrono::time_point<monotonic_clock, std::chrono::nanoseconds> now() noexcept - { - timespec ts; -#if defined(CLOCK_MONOTONIC_RAW) - clock_gettime(CLOCK_MONOTONIC_RAW, &ts); -#else - clock_gettime(CLOCK_MONOTONIC, &ts); -#endif - return time_point(std::chrono::nanoseconds(ts.tv_sec*1000000000 + ts.tv_nsec)); - } -}; - // Simple single-threaded profiler. // Tracks events reported by BeginEvent()/EndEvent() and outputs detailed information and stats when // Profiler::AnalyzeEventsAndWriteResults() is called. -class Profiler +class Profiler final : public IProfiler { public: + Profiler(); + ~Profiler(); + using InstrumentPtr = std::unique_ptr<Instrument>; + // Marks the beginning of a user-defined event. - // No attempt will be made to copy the name string: It must be known at compile time. - void BeginEvent(Compute compute, const std::string name); + // No attempt will be made to copy the name string: it must be known at compile time. + Event* BeginEvent(Compute compute, const std::string& name, std::vector<InstrumentPtr>&& instruments); // Marks the end of a user-defined event. - void EndEvent(Compute compute); + void EndEvent(Event* event); + + // Enables/disables profiling. + void EnableProfiling(bool enableProfiling) override; + + // Checks if profiling is enabled. + bool IsProfilingEnabled() override; // Increments the event tag, allowing grouping of events in a user-defined manner (e.g. per inference). - void UpdateEventTag() { ++m_EventTag; m_EventTagUpdated = true; } + void UpdateEventTag(); // Analyzes the tracked events and writes the results to the given output stream. // Please refer to the configuration variables in Profiling.cpp to customize the information written. - void AnalyzeEventsAndWriteResults(std::ostream& outStream) const; + void AnalyzeEventsAndWriteResults(std::ostream& outStream) const override; - // Accesses the singleton - static Profiler& Get() { return s_Instance; } + // Print stats for events in JSON Format to the given output stream. + void Print(std::ostream& outStream) const override; - // Gets a string name for a given Compute device enum - const char* GetEventComputeDevice(Compute compute) const; - - // Gets the color to render an event with, based on which device it denotes - std::uint32_t GetEventColor(Compute compute) const; - - typedef monotonic_clock Clock; - typedef std::chrono::time_point<Clock> TimePoint; + // Gets the color to render an event with, based on which device it denotes. + uint32_t GetEventColor(Compute compute) const; private: - + using EventPtr = std::unique_ptr<Event>; struct Marker { std::size_t m_Id; - const std::string m_EventName; - TimePoint m_TimeStamp; - Compute m_ComputeDevice; - std::uint32_t m_Tag; - }; - - struct ProfilingEvent - { - std::string m_Label; - TimePoint m_StartTime; - TimePoint m_StopTime; - Compute m_Device; - std::uint32_t m_Tag; - - double DurationMs() const - { - return std::chrono::duration<double>(m_StopTime - m_StartTime).count()*1000.0; - } }; struct ProfilingEventStats @@ -98,62 +71,100 @@ private: double m_TotalMs; double m_MinMs; double m_MaxMs; - std::uint32_t m_Count; + uint32_t m_Count; }; - Profiler(); - ~Profiler(); - // Waits for a compute device to finish working to guarantee correct timings. // Currently used exclusively when emitting profiling events denoting GPU work. void WaitForDevice(Compute compute) const; - void AnalyzeEventSequenceAndWriteResults(std::vector<ProfilingEvent>::const_iterator first, - std::vector<ProfilingEvent>::const_iterator last, - std::ostream& outStream) const; + template<typename EventIterType> + void AnalyzeEventSequenceAndWriteResults(EventIterType first, EventIterType last, std::ostream& outStream) const; std::map<std::string, ProfilingEventStats> CalculateProfilingEventStats() const; + void PopulateInferences(std::vector<const Event*>& outInferences, int& outBaseLevel) const; + void PopulateDescendants(std::map<const Event*, std::vector<const Event*>>& outDescendantsMap) const; - std::stack<Marker> m_ObservedMarkers; - std::vector<ProfilingEvent> m_EventSequence; - std::uint32_t m_EventTag; - std::uint32_t m_NestingLevel; - bool m_EventTagUpdated; + std::stack<Event*> m_Parents; + std::vector<EventPtr> m_EventSequence; + bool m_ProfilingEnabled; - static Profiler s_Instance; +private: + // Friend functions for unit testing, see ProfilerTests.cpp. + friend size_t GetProfilerEventSequenceSize(armnn::Profiler* profiler); }; -// Helper to easily add event markers to the codebase +// Singleton profiler manager. +// Keeps track of all the running profiler instances. +class ProfilerManager +{ +public: + // Register the given profiler as a thread local pointer. + void RegisterProfiler(Profiler* profiler); + + // Gets the thread local pointer to the profiler. + Profiler* GetProfiler(); + + // Accesses the singleton. + static ProfilerManager& GetInstance(); + +private: + // The constructor is kept private so that other instances of this class (other that the singleton's) + // can't be allocated. + ProfilerManager() {} +}; + +// Helper to easily add event markers to the codebase. class ScopedProfilingEvent { public: - ScopedProfilingEvent(Compute compute, const std::string name) - : m_Compute(compute) + using InstrumentPtr = std::unique_ptr<Instrument>; + + template<typename... Args> + ScopedProfilingEvent(Compute compute, const std::string& name, Args... args) + : m_Event(nullptr) + , m_Profiler(ProfilerManager::GetInstance().GetProfiler()) { - Profiler::Get().BeginEvent(compute, name); + if (m_Profiler && m_Profiler->IsProfilingEnabled()) + { + std::vector<InstrumentPtr> instruments(0); + instruments.reserve(sizeof...(args)); //One allocation + ConstructNextInVector(instruments, args...); + m_Event = m_Profiler->BeginEvent(compute, name, std::move(instruments)); + } } ~ScopedProfilingEvent() { - Profiler::Get().EndEvent(m_Compute); + if (m_Profiler && m_Event) + { + m_Profiler->EndEvent(m_Event); + } } private: - armnn::Compute m_Compute; -}; - -} // namespace armnn -// Allows grouping events in an user-defined manner (e.g. per inference) -#define ARMNN_UPDATE_PROFILING_EVENT_TAG() armnn::Profiler::Get().UpdateEventTag(); + void ConstructNextInVector(std::vector<InstrumentPtr>& instruments) + { + boost::ignore_unused(instruments); + } -// The event name must be known at compile time -#define ARMNN_SCOPED_PROFILING_EVENT(compute, name) armnn::ScopedProfilingEvent e_##__FILE__##__LINE__(compute, name); + template<typename Arg, typename... Args> + void ConstructNextInVector(std::vector<InstrumentPtr>& instruments, Arg arg, Args... args) + { + instruments.emplace_back(std::make_unique<Arg>(arg)); + ConstructNextInVector(instruments, args...); + } -#else + Event* m_Event; ///< Event to track + Profiler* m_Profiler; ///< Profiler used +}; -#define ARMNN_UPDATE_PROFILING_EVENT_TAG() -#define ARMNN_SCOPED_PROFILING_EVENT(compute, name) +} // namespace armnn -#endif // ARMNN_PROFILING_ENABLED +// The event name must be known at compile time +#define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(compute, /*name,*/ ...) \ + armnn::ScopedProfilingEvent e_##__FILE__##__LINE__(compute, /*name,*/ __VA_ARGS__); +#define ARMNN_SCOPED_PROFILING_EVENT(compute, name) \ + ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(compute, name, armnn::WallClockTimer()) |