xref: /aosp_15_r20/external/armnn/src/armnn/Profiling.hpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
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