1*89c4ff92SAndroid Build Coastguard Worker //
2*89c4ff92SAndroid Build Coastguard Worker // Copyright © 2017 Arm Ltd. All rights reserved.
3*89c4ff92SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT
4*89c4ff92SAndroid Build Coastguard Worker //
5*89c4ff92SAndroid Build Coastguard Worker #pragma once
6*89c4ff92SAndroid Build Coastguard Worker
7*89c4ff92SAndroid Build Coastguard Worker #include <common/include/ProfilingGuid.hpp>
8*89c4ff92SAndroid Build Coastguard Worker #include "ProfilingEvent.hpp"
9*89c4ff92SAndroid Build Coastguard Worker #include "ProfilingDetails.hpp"
10*89c4ff92SAndroid Build Coastguard Worker #include "armnn/IProfiler.hpp"
11*89c4ff92SAndroid Build Coastguard Worker
12*89c4ff92SAndroid Build Coastguard Worker #include <armnn/Optional.hpp>
13*89c4ff92SAndroid Build Coastguard Worker #include <armnn/utility/IgnoreUnused.hpp>
14*89c4ff92SAndroid Build Coastguard Worker #include "WallClockTimer.hpp"
15*89c4ff92SAndroid Build Coastguard Worker
16*89c4ff92SAndroid Build Coastguard Worker #include <chrono>
17*89c4ff92SAndroid Build Coastguard Worker #include <iosfwd>
18*89c4ff92SAndroid Build Coastguard Worker #include <ctime>
19*89c4ff92SAndroid Build Coastguard Worker #include <vector>
20*89c4ff92SAndroid Build Coastguard Worker #include <stack>
21*89c4ff92SAndroid Build Coastguard Worker #include <map>
22*89c4ff92SAndroid Build Coastguard Worker
23*89c4ff92SAndroid Build Coastguard Worker namespace armnn
24*89c4ff92SAndroid Build Coastguard Worker {
25*89c4ff92SAndroid Build Coastguard Worker
26*89c4ff92SAndroid Build Coastguard Worker // Simple single-threaded profiler.
27*89c4ff92SAndroid Build Coastguard Worker // Tracks events reported by BeginEvent()/EndEvent() and outputs detailed information and stats when
28*89c4ff92SAndroid Build Coastguard Worker // Profiler::AnalyzeEventsAndWriteResults() is called.
29*89c4ff92SAndroid Build Coastguard Worker class ProfilerImpl
30*89c4ff92SAndroid Build Coastguard Worker {
31*89c4ff92SAndroid Build Coastguard Worker public:
32*89c4ff92SAndroid Build Coastguard Worker ProfilerImpl();
33*89c4ff92SAndroid Build Coastguard Worker ~ProfilerImpl();
34*89c4ff92SAndroid Build Coastguard Worker using InstrumentPtr = std::unique_ptr<Instrument>;
35*89c4ff92SAndroid Build Coastguard Worker
36*89c4ff92SAndroid Build Coastguard Worker // Marks the beginning of a user-defined event.
37*89c4ff92SAndroid Build Coastguard Worker // No attempt will be made to copy the name string: it must be known at compile time.
38*89c4ff92SAndroid Build Coastguard Worker Event* BeginEvent(armnn::IProfiler* profiler,
39*89c4ff92SAndroid Build Coastguard Worker const BackendId& backendId,
40*89c4ff92SAndroid Build Coastguard Worker const std::string& name,
41*89c4ff92SAndroid Build Coastguard Worker std::vector<InstrumentPtr>&& instruments,
42*89c4ff92SAndroid Build Coastguard Worker const Optional<arm::pipe::ProfilingGuid>& guid);
43*89c4ff92SAndroid Build Coastguard Worker
44*89c4ff92SAndroid Build Coastguard Worker template<typename DescriptorType>
AddLayerDetails(const std::string & label,const DescriptorType & desc,const WorkloadInfo & infos,const arm::pipe::ProfilingGuid guid)45*89c4ff92SAndroid Build Coastguard Worker void AddLayerDetails(const std::string& label,
46*89c4ff92SAndroid Build Coastguard Worker const DescriptorType& desc,
47*89c4ff92SAndroid Build Coastguard Worker const WorkloadInfo& infos,
48*89c4ff92SAndroid Build Coastguard Worker const arm::pipe::ProfilingGuid guid)
49*89c4ff92SAndroid Build Coastguard Worker {
50*89c4ff92SAndroid Build Coastguard Worker m_ProfilingDetails->AddDetailsToString(label, desc, infos, guid);
51*89c4ff92SAndroid Build Coastguard Worker }
52*89c4ff92SAndroid Build Coastguard Worker
53*89c4ff92SAndroid Build Coastguard Worker // Marks the end of a user-defined event.
54*89c4ff92SAndroid Build Coastguard Worker void EndEvent(Event* event);
55*89c4ff92SAndroid Build Coastguard Worker
56*89c4ff92SAndroid Build Coastguard Worker // Enables/disables profiling.
57*89c4ff92SAndroid Build Coastguard Worker void EnableProfiling(bool enableProfiling);
58*89c4ff92SAndroid Build Coastguard Worker
59*89c4ff92SAndroid Build Coastguard Worker // Checks if profiling is enabled.
60*89c4ff92SAndroid Build Coastguard Worker bool IsProfilingEnabled();
61*89c4ff92SAndroid Build Coastguard Worker
62*89c4ff92SAndroid Build Coastguard Worker // Enables outputting the layer descriptors and infos to stdout
63*89c4ff92SAndroid Build Coastguard Worker void EnableNetworkDetailsToStdOut(ProfilingDetailsMethod detailsMethod);
64*89c4ff92SAndroid Build Coastguard Worker
65*89c4ff92SAndroid Build Coastguard Worker // Increments the event tag, allowing grouping of events in a user-defined manner (e.g. per inference).
66*89c4ff92SAndroid Build Coastguard Worker void UpdateEventTag();
67*89c4ff92SAndroid Build Coastguard Worker
68*89c4ff92SAndroid Build Coastguard Worker // Analyzes the tracked events and writes the results to the given output stream.
69*89c4ff92SAndroid Build Coastguard Worker // Please refer to the configuration variables in Profiling.cpp to customize the information written.
70*89c4ff92SAndroid Build Coastguard Worker void AnalyzeEventsAndWriteResults(std::ostream& outStream) const;
71*89c4ff92SAndroid Build Coastguard Worker
72*89c4ff92SAndroid Build Coastguard Worker // Print stats for events in JSON Format to the given output stream.
73*89c4ff92SAndroid Build Coastguard Worker void Print(std::ostream& outStream) const;
74*89c4ff92SAndroid Build Coastguard Worker
75*89c4ff92SAndroid Build Coastguard Worker // Gets the color to render an event with, based on which device it denotes.
76*89c4ff92SAndroid Build Coastguard Worker uint32_t GetEventColor(const BackendId& backendId) const;
77*89c4ff92SAndroid Build Coastguard Worker
78*89c4ff92SAndroid Build Coastguard Worker using EventPtr = std::unique_ptr<Event>;
79*89c4ff92SAndroid Build Coastguard Worker using DescPtr = std::unique_ptr<ProfilingDetails>;
80*89c4ff92SAndroid Build Coastguard Worker
81*89c4ff92SAndroid Build Coastguard Worker struct Marker
82*89c4ff92SAndroid Build Coastguard Worker {
83*89c4ff92SAndroid Build Coastguard Worker std::size_t m_Id;
84*89c4ff92SAndroid Build Coastguard Worker };
85*89c4ff92SAndroid Build Coastguard Worker
86*89c4ff92SAndroid Build Coastguard Worker struct ProfilingEventStats
87*89c4ff92SAndroid Build Coastguard Worker {
88*89c4ff92SAndroid Build Coastguard Worker double m_TotalMs;
89*89c4ff92SAndroid Build Coastguard Worker double m_MinMs;
90*89c4ff92SAndroid Build Coastguard Worker double m_MaxMs;
91*89c4ff92SAndroid Build Coastguard Worker uint32_t m_Count;
92*89c4ff92SAndroid Build Coastguard Worker };
93*89c4ff92SAndroid Build Coastguard Worker
94*89c4ff92SAndroid Build Coastguard Worker template<typename EventIterType>
95*89c4ff92SAndroid Build Coastguard Worker void AnalyzeEventSequenceAndWriteResults(EventIterType first, EventIterType last, std::ostream& outStream) const;
96*89c4ff92SAndroid Build Coastguard Worker
97*89c4ff92SAndroid Build Coastguard Worker std::map<std::string, ProfilingEventStats> CalculateProfilingEventStats() const;
98*89c4ff92SAndroid Build Coastguard Worker void PopulateParent(std::vector<const Event*>& outEvents, int& outBaseLevel, std::string parentName) const;
99*89c4ff92SAndroid Build Coastguard Worker void PopulateDescendants(std::map<const Event*, std::vector<const Event*>>& outDescendantsMap) const;
100*89c4ff92SAndroid Build Coastguard Worker
101*89c4ff92SAndroid Build Coastguard Worker std::stack<Event*> m_Parents;
102*89c4ff92SAndroid Build Coastguard Worker std::vector<EventPtr> m_EventSequence;
103*89c4ff92SAndroid Build Coastguard Worker DescPtr m_ProfilingDetails = std::make_unique<ProfilingDetails>();
104*89c4ff92SAndroid Build Coastguard Worker bool m_ProfilingEnabled;
105*89c4ff92SAndroid Build Coastguard Worker ProfilingDetailsMethod m_DetailsToStdOutMethod;
106*89c4ff92SAndroid Build Coastguard Worker
107*89c4ff92SAndroid Build Coastguard Worker };
108*89c4ff92SAndroid Build Coastguard Worker
109*89c4ff92SAndroid Build Coastguard Worker // Singleton profiler manager.
110*89c4ff92SAndroid Build Coastguard Worker // Keeps track of all the running profiler instances.
111*89c4ff92SAndroid Build Coastguard Worker class ProfilerManager
112*89c4ff92SAndroid Build Coastguard Worker {
113*89c4ff92SAndroid Build Coastguard Worker public:
114*89c4ff92SAndroid Build Coastguard Worker // Register the given profiler as a thread local pointer.
115*89c4ff92SAndroid Build Coastguard Worker void RegisterProfiler(IProfiler* profiler);
116*89c4ff92SAndroid Build Coastguard Worker
117*89c4ff92SAndroid Build Coastguard Worker // Gets the thread local pointer to the profiler.
118*89c4ff92SAndroid Build Coastguard Worker IProfiler* GetProfiler();
119*89c4ff92SAndroid Build Coastguard Worker
120*89c4ff92SAndroid Build Coastguard Worker // Accesses the singleton.
121*89c4ff92SAndroid Build Coastguard Worker static ProfilerManager& GetInstance();
122*89c4ff92SAndroid Build Coastguard Worker
123*89c4ff92SAndroid Build Coastguard Worker private:
124*89c4ff92SAndroid Build Coastguard Worker // The constructor is kept private so that other instances of this class (other that the singleton's)
125*89c4ff92SAndroid Build Coastguard Worker // can't be allocated.
ProfilerManager()126*89c4ff92SAndroid Build Coastguard Worker ProfilerManager() {}
127*89c4ff92SAndroid Build Coastguard Worker };
128*89c4ff92SAndroid Build Coastguard Worker
129*89c4ff92SAndroid Build Coastguard Worker // Helper to easily add event markers to the codebase.
130*89c4ff92SAndroid Build Coastguard Worker class ScopedProfilingEvent
131*89c4ff92SAndroid Build Coastguard Worker {
132*89c4ff92SAndroid Build Coastguard Worker public:
133*89c4ff92SAndroid Build Coastguard Worker using InstrumentPtr = std::unique_ptr<Instrument>;
134*89c4ff92SAndroid Build Coastguard Worker
135*89c4ff92SAndroid Build Coastguard Worker template<typename... Args>
ScopedProfilingEvent(const BackendId & backendId,const Optional<arm::pipe::ProfilingGuid> & guid,const std::string & name,Args &&...args)136*89c4ff92SAndroid Build Coastguard Worker ScopedProfilingEvent(const BackendId& backendId,
137*89c4ff92SAndroid Build Coastguard Worker const Optional<arm::pipe::ProfilingGuid>& guid,
138*89c4ff92SAndroid Build Coastguard Worker const std::string& name,
139*89c4ff92SAndroid Build Coastguard Worker Args&& ... args)
140*89c4ff92SAndroid Build Coastguard Worker : m_Event(nullptr)
141*89c4ff92SAndroid Build Coastguard Worker , m_Profiler(ProfilerManager::GetInstance().GetProfiler())
142*89c4ff92SAndroid Build Coastguard Worker {
143*89c4ff92SAndroid Build Coastguard Worker if (m_Profiler && m_Profiler->IsProfilingEnabled())
144*89c4ff92SAndroid Build Coastguard Worker {
145*89c4ff92SAndroid Build Coastguard Worker std::vector<InstrumentPtr> instruments(0);
146*89c4ff92SAndroid Build Coastguard Worker instruments.reserve(sizeof...(args)); //One allocation
147*89c4ff92SAndroid Build Coastguard Worker ConstructNextInVector(instruments, std::forward<Args>(args)...);
148*89c4ff92SAndroid Build Coastguard Worker m_Event = m_Profiler->BeginEvent(backendId, name, std::move(instruments), guid);
149*89c4ff92SAndroid Build Coastguard Worker }
150*89c4ff92SAndroid Build Coastguard Worker }
151*89c4ff92SAndroid Build Coastguard Worker
~ScopedProfilingEvent()152*89c4ff92SAndroid Build Coastguard Worker ~ScopedProfilingEvent()
153*89c4ff92SAndroid Build Coastguard Worker {
154*89c4ff92SAndroid Build Coastguard Worker if (m_Profiler && m_Event)
155*89c4ff92SAndroid Build Coastguard Worker {
156*89c4ff92SAndroid Build Coastguard Worker m_Profiler->pProfilerImpl->EndEvent(m_Event);
157*89c4ff92SAndroid Build Coastguard Worker }
158*89c4ff92SAndroid Build Coastguard Worker }
159*89c4ff92SAndroid Build Coastguard Worker
160*89c4ff92SAndroid Build Coastguard Worker private:
161*89c4ff92SAndroid Build Coastguard Worker
ConstructNextInVector(std::vector<InstrumentPtr> & instruments)162*89c4ff92SAndroid Build Coastguard Worker void ConstructNextInVector(std::vector<InstrumentPtr>& instruments)
163*89c4ff92SAndroid Build Coastguard Worker {
164*89c4ff92SAndroid Build Coastguard Worker IgnoreUnused(instruments);
165*89c4ff92SAndroid Build Coastguard Worker }
166*89c4ff92SAndroid Build Coastguard Worker
167*89c4ff92SAndroid Build Coastguard Worker template<typename Arg, typename... Args>
ConstructNextInVector(std::vector<InstrumentPtr> & instruments,Arg && arg,Args &&...args)168*89c4ff92SAndroid Build Coastguard Worker void ConstructNextInVector(std::vector<InstrumentPtr>& instruments, Arg&& arg, Args&&... args)
169*89c4ff92SAndroid Build Coastguard Worker {
170*89c4ff92SAndroid Build Coastguard Worker instruments.emplace_back(std::make_unique<Arg>(std::forward<Arg>(arg)));
171*89c4ff92SAndroid Build Coastguard Worker ConstructNextInVector(instruments, std::forward<Args>(args)...);
172*89c4ff92SAndroid Build Coastguard Worker }
173*89c4ff92SAndroid Build Coastguard Worker
174*89c4ff92SAndroid Build Coastguard Worker Event* m_Event; ///< Event to track
175*89c4ff92SAndroid Build Coastguard Worker IProfiler* m_Profiler; ///< Profiler used
176*89c4ff92SAndroid Build Coastguard Worker };
177*89c4ff92SAndroid Build Coastguard Worker
178*89c4ff92SAndroid Build Coastguard Worker // Helper to easily add operator details during profiling.
179*89c4ff92SAndroid Build Coastguard Worker template<typename DescriptorType>
ProfilingUpdateDescriptions(const std::string & name,const DescriptorType & desc,const WorkloadInfo & infos,const arm::pipe::ProfilingGuid guid)180*89c4ff92SAndroid Build Coastguard Worker inline void ProfilingUpdateDescriptions(const std::string& name,
181*89c4ff92SAndroid Build Coastguard Worker const DescriptorType& desc,
182*89c4ff92SAndroid Build Coastguard Worker const WorkloadInfo& infos,
183*89c4ff92SAndroid Build Coastguard Worker const arm::pipe::ProfilingGuid guid)
184*89c4ff92SAndroid Build Coastguard Worker {
185*89c4ff92SAndroid Build Coastguard Worker IProfiler* profiler(ProfilerManager::GetInstance().GetProfiler()); ///< Profiler used
186*89c4ff92SAndroid Build Coastguard Worker if (profiler && profiler->IsProfilingEnabled())
187*89c4ff92SAndroid Build Coastguard Worker {
188*89c4ff92SAndroid Build Coastguard Worker profiler->AddLayerDetails(name, desc, infos, guid);
189*89c4ff92SAndroid Build Coastguard Worker }
190*89c4ff92SAndroid Build Coastguard Worker }
191*89c4ff92SAndroid Build Coastguard Worker
192*89c4ff92SAndroid Build Coastguard Worker template<typename DescriptorType>
AddLayerDetails(const std::string & name,const DescriptorType & desc,const WorkloadInfo & infos,const arm::pipe::ProfilingGuid guid)193*89c4ff92SAndroid Build Coastguard Worker void IProfiler::AddLayerDetails(const std::string& name,
194*89c4ff92SAndroid Build Coastguard Worker const DescriptorType& desc,
195*89c4ff92SAndroid Build Coastguard Worker const WorkloadInfo& infos,
196*89c4ff92SAndroid Build Coastguard Worker const arm::pipe::ProfilingGuid guid)
197*89c4ff92SAndroid Build Coastguard Worker {
198*89c4ff92SAndroid Build Coastguard Worker return pProfilerImpl->AddLayerDetails(name, desc, infos, guid);
199*89c4ff92SAndroid Build Coastguard Worker }
200*89c4ff92SAndroid Build Coastguard Worker
201*89c4ff92SAndroid Build Coastguard Worker } // namespace armnn
202*89c4ff92SAndroid Build Coastguard Worker
203*89c4ff92SAndroid Build Coastguard Worker // Event Definitions for profiling
204*89c4ff92SAndroid Build Coastguard Worker #define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC_INNER(lineNumber, backendId, guid, /*name,*/ ...) \
205*89c4ff92SAndroid Build Coastguard Worker armnn::ScopedProfilingEvent e_ ## lineNumber(backendId, guid, /*name,*/ __VA_ARGS__);
206*89c4ff92SAndroid Build Coastguard Worker
207*89c4ff92SAndroid Build Coastguard Worker #define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC(lineNumber, backendId, guid, /*name,*/ ...) \
208*89c4ff92SAndroid Build Coastguard Worker ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC_INNER(lineNumber, backendId, guid, /*name,*/ __VA_ARGS__)
209*89c4ff92SAndroid Build Coastguard Worker
210*89c4ff92SAndroid Build Coastguard Worker // The event name must be known at compile time i.e. if you are going to use this version of the macro
211*89c4ff92SAndroid Build Coastguard Worker // in code the first argument you supply after the backendId must be the name.
212*89c4ff92SAndroid Build Coastguard Worker // NOTE: need to pass the line number as an argument from here so by the time it gets to the UNIQUE_LOC_INNER
213*89c4ff92SAndroid Build Coastguard Worker // above it has expanded to a string and will concat (##) correctly with the 'e_' prefix to yield a
214*89c4ff92SAndroid Build Coastguard Worker // legal and unique variable name (so long as you don't use the macro twice on the same line).
215*89c4ff92SAndroid Build Coastguard Worker // The concat preprocessing operator (##) very unhelpfully will not expand macros see
216*89c4ff92SAndroid Build Coastguard Worker // https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html for the gory details.
217*89c4ff92SAndroid Build Coastguard Worker #define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(backendId, guid, /*name,*/ ...) \
218*89c4ff92SAndroid Build Coastguard Worker ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC(__LINE__,backendId, guid, /*name,*/ __VA_ARGS__)
219*89c4ff92SAndroid Build Coastguard Worker
220*89c4ff92SAndroid Build Coastguard Worker #define ARMNN_SCOPED_PROFILING_EVENT(backendId, name) \
221*89c4ff92SAndroid Build Coastguard Worker ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(backendId, armnn::EmptyOptional(), name, armnn::WallClockTimer())
222*89c4ff92SAndroid Build Coastguard Worker
223*89c4ff92SAndroid Build Coastguard Worker #define ARMNN_SCOPED_PROFILING_EVENT_GUID(backendId, name, guid) \
224*89c4ff92SAndroid Build Coastguard Worker ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(backendId, guid, name, armnn::WallClockTimer())
225*89c4ff92SAndroid Build Coastguard Worker
226*89c4ff92SAndroid Build Coastguard Worker // Workload Description definitons for profiling
227*89c4ff92SAndroid Build Coastguard Worker #define ARMNN_REPORT_PROFILING_WORKLOAD_DESC(name, desc, infos, guid) \
228*89c4ff92SAndroid Build Coastguard Worker armnn::ProfilingUpdateDescriptions(name, desc, infos, guid);
229