blob: c0d37dc13ee5901a2851a20cc644028c591011a6 [file] [log] [blame]
Laurent Carlier749294b2020-06-01 09:03:17 +01001//
telsoa014fcda012018-03-09 14:13:49 +00002// Copyright © 2017 Arm Ltd. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
5#pragma once
6
telsoa01c577f2c2018-08-31 09:22:23 +01007#include "ProfilingEvent.hpp"
telsoa014fcda012018-03-09 14:13:49 +00008
Jan Eilers8eb25602020-03-09 12:13:48 +00009#include <armnn/utility/IgnoreUnused.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010010#include "armnn/IProfiler.hpp"
11
12#include "WallClockTimer.hpp"
telsoa014fcda012018-03-09 14:13:49 +000013
14#include <chrono>
15#include <iosfwd>
16#include <ctime>
17#include <vector>
18#include <stack>
19#include <map>
20
21namespace armnn
22{
23
telsoa014fcda012018-03-09 14:13:49 +000024// Simple single-threaded profiler.
25// Tracks events reported by BeginEvent()/EndEvent() and outputs detailed information and stats when
26// Profiler::AnalyzeEventsAndWriteResults() is called.
telsoa01c577f2c2018-08-31 09:22:23 +010027class Profiler final : public IProfiler
telsoa014fcda012018-03-09 14:13:49 +000028{
29public:
telsoa01c577f2c2018-08-31 09:22:23 +010030 Profiler();
31 ~Profiler();
32 using InstrumentPtr = std::unique_ptr<Instrument>;
33
telsoa014fcda012018-03-09 14:13:49 +000034 // Marks the beginning of a user-defined event.
telsoa01c577f2c2018-08-31 09:22:23 +010035 // No attempt will be made to copy the name string: it must be known at compile time.
Matteo Martincigh992d6dc2019-01-10 17:34:20 +000036 Event* BeginEvent(const BackendId& backendId, const std::string& name, std::vector<InstrumentPtr>&& instruments);
telsoa014fcda012018-03-09 14:13:49 +000037
38 // Marks the end of a user-defined event.
telsoa01c577f2c2018-08-31 09:22:23 +010039 void EndEvent(Event* event);
40
41 // Enables/disables profiling.
42 void EnableProfiling(bool enableProfiling) override;
43
44 // Checks if profiling is enabled.
45 bool IsProfilingEnabled() override;
telsoa014fcda012018-03-09 14:13:49 +000046
47 // Increments the event tag, allowing grouping of events in a user-defined manner (e.g. per inference).
telsoa01c577f2c2018-08-31 09:22:23 +010048 void UpdateEventTag();
telsoa014fcda012018-03-09 14:13:49 +000049
50 // Analyzes the tracked events and writes the results to the given output stream.
51 // Please refer to the configuration variables in Profiling.cpp to customize the information written.
telsoa01c577f2c2018-08-31 09:22:23 +010052 void AnalyzeEventsAndWriteResults(std::ostream& outStream) const override;
telsoa014fcda012018-03-09 14:13:49 +000053
telsoa01c577f2c2018-08-31 09:22:23 +010054 // Print stats for events in JSON Format to the given output stream.
55 void Print(std::ostream& outStream) const override;
telsoa014fcda012018-03-09 14:13:49 +000056
telsoa01c577f2c2018-08-31 09:22:23 +010057 // Gets the color to render an event with, based on which device it denotes.
Matthew Bentham1b63d6c2019-04-05 09:35:15 +010058 uint32_t GetEventColor(const BackendId& backendId) const;
telsoa014fcda012018-03-09 14:13:49 +000059
60private:
telsoa01c577f2c2018-08-31 09:22:23 +010061 using EventPtr = std::unique_ptr<Event>;
telsoa014fcda012018-03-09 14:13:49 +000062 struct Marker
63 {
64 std::size_t m_Id;
telsoa014fcda012018-03-09 14:13:49 +000065 };
66
67 struct ProfilingEventStats
68 {
69 double m_TotalMs;
70 double m_MinMs;
71 double m_MaxMs;
telsoa01c577f2c2018-08-31 09:22:23 +010072 uint32_t m_Count;
telsoa014fcda012018-03-09 14:13:49 +000073 };
74
telsoa01c577f2c2018-08-31 09:22:23 +010075 template<typename EventIterType>
76 void AnalyzeEventSequenceAndWriteResults(EventIterType first, EventIterType last, std::ostream& outStream) const;
telsoa014fcda012018-03-09 14:13:49 +000077
78 std::map<std::string, ProfilingEventStats> CalculateProfilingEventStats() const;
telsoa01c577f2c2018-08-31 09:22:23 +010079 void PopulateInferences(std::vector<const Event*>& outInferences, int& outBaseLevel) const;
80 void PopulateDescendants(std::map<const Event*, std::vector<const Event*>>& outDescendantsMap) const;
telsoa014fcda012018-03-09 14:13:49 +000081
telsoa01c577f2c2018-08-31 09:22:23 +010082 std::stack<Event*> m_Parents;
83 std::vector<EventPtr> m_EventSequence;
84 bool m_ProfilingEnabled;
telsoa014fcda012018-03-09 14:13:49 +000085
telsoa01c577f2c2018-08-31 09:22:23 +010086private:
87 // Friend functions for unit testing, see ProfilerTests.cpp.
88 friend size_t GetProfilerEventSequenceSize(armnn::Profiler* profiler);
telsoa014fcda012018-03-09 14:13:49 +000089};
90
telsoa01c577f2c2018-08-31 09:22:23 +010091// Singleton profiler manager.
92// Keeps track of all the running profiler instances.
93class ProfilerManager
94{
95public:
96 // Register the given profiler as a thread local pointer.
97 void RegisterProfiler(Profiler* profiler);
98
99 // Gets the thread local pointer to the profiler.
100 Profiler* GetProfiler();
101
102 // Accesses the singleton.
103 static ProfilerManager& GetInstance();
104
105private:
106 // The constructor is kept private so that other instances of this class (other that the singleton's)
107 // can't be allocated.
108 ProfilerManager() {}
109};
110
111// Helper to easily add event markers to the codebase.
telsoa014fcda012018-03-09 14:13:49 +0000112class ScopedProfilingEvent
113{
114public:
telsoa01c577f2c2018-08-31 09:22:23 +0100115 using InstrumentPtr = std::unique_ptr<Instrument>;
116
117 template<typename... Args>
Derek Lambertia08d29b2020-06-19 14:33:05 +0100118 ScopedProfilingEvent(const BackendId& backendId, const std::string& name, Args&&... args)
telsoa01c577f2c2018-08-31 09:22:23 +0100119 : m_Event(nullptr)
120 , m_Profiler(ProfilerManager::GetInstance().GetProfiler())
telsoa014fcda012018-03-09 14:13:49 +0000121 {
telsoa01c577f2c2018-08-31 09:22:23 +0100122 if (m_Profiler && m_Profiler->IsProfilingEnabled())
123 {
124 std::vector<InstrumentPtr> instruments(0);
125 instruments.reserve(sizeof...(args)); //One allocation
Derek Lambertia08d29b2020-06-19 14:33:05 +0100126 ConstructNextInVector(instruments, std::forward<Args>(args)...);
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000127 m_Event = m_Profiler->BeginEvent(backendId, name, std::move(instruments));
telsoa01c577f2c2018-08-31 09:22:23 +0100128 }
telsoa014fcda012018-03-09 14:13:49 +0000129 }
130
131 ~ScopedProfilingEvent()
132 {
telsoa01c577f2c2018-08-31 09:22:23 +0100133 if (m_Profiler && m_Event)
134 {
135 m_Profiler->EndEvent(m_Event);
136 }
telsoa014fcda012018-03-09 14:13:49 +0000137 }
138
139private:
telsoa01c577f2c2018-08-31 09:22:23 +0100140
141 void ConstructNextInVector(std::vector<InstrumentPtr>& instruments)
142 {
Jan Eilers8eb25602020-03-09 12:13:48 +0000143 IgnoreUnused(instruments);
telsoa01c577f2c2018-08-31 09:22:23 +0100144 }
145
146 template<typename Arg, typename... Args>
Derek Lambertia08d29b2020-06-19 14:33:05 +0100147 void ConstructNextInVector(std::vector<InstrumentPtr>& instruments, Arg&& arg, Args&&... args)
telsoa01c577f2c2018-08-31 09:22:23 +0100148 {
Derek Lambertia08d29b2020-06-19 14:33:05 +0100149 instruments.emplace_back(std::make_unique<Arg>(std::forward<Arg>(arg)));
150 ConstructNextInVector(instruments, std::forward<Args>(args)...);
telsoa01c577f2c2018-08-31 09:22:23 +0100151 }
152
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000153 Event* m_Event; ///< Event to track
154 Profiler* m_Profiler; ///< Profiler used
telsoa014fcda012018-03-09 14:13:49 +0000155};
156
157} // namespace armnn
158
Jim Flynnc456c312020-10-13 14:40:29 +0100159#define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC_INNER(lineNumber, backendId, /*name,*/ ...) \
160 armnn::ScopedProfilingEvent e_ ## lineNumber(backendId, /*name,*/ __VA_ARGS__);
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100161
Jim Flynnc456c312020-10-13 14:40:29 +0100162#define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC(lineNumber, backendId, /*name,*/ ...) \
163 ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC_INNER(lineNumber, backendId, /*name,*/ __VA_ARGS__)
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100164
Jim Flynnc456c312020-10-13 14:40:29 +0100165// The event name must be known at compile time i.e. if you are going to use this version of the macro
166// in code the first argument you supply after the backendId must be the name.
167// NOTE: need to pass the line number as an argument from here so by the time it gets to the UNIQUE_LOC_INNER
168// above it has expanded to a string and will concat (##) correctly with the 'e_' prefix to yield a
169// legal and unique variable name (so long as you don't use the macro twice on the same line).
170// The concat preprocessing operator (##) very unhelpfully will not expand macros see
171// https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html for the gory details.
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000172#define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(backendId, /*name,*/ ...) \
Jim Flynnc456c312020-10-13 14:40:29 +0100173 ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC(__LINE__,backendId, /*name,*/ __VA_ARGS__)
telsoa014fcda012018-03-09 14:13:49 +0000174
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000175#define ARMNN_SCOPED_PROFILING_EVENT(backendId, name) \
176 ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(backendId, name, armnn::WallClockTimer())