Release 18.08
[platform/upstream/armnn.git] / src / armnn / Profiling.hpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // See LICENSE file in the project root for full license information.
4 //
5 #pragma once
6
7 #include "ProfilingEvent.hpp"
8
9 #include "armnn/ArmNN.hpp"
10 #include "armnn/IProfiler.hpp"
11
12 #include "WallClockTimer.hpp"
13
14 #include <chrono>
15 #include <iosfwd>
16 #include <ctime>
17 #include <vector>
18 #include <stack>
19 #include <map>
20
21 #include <boost/core/ignore_unused.hpp>
22
23 namespace armnn
24 {
25
26 // Simple single-threaded profiler.
27 // Tracks events reported by BeginEvent()/EndEvent() and outputs detailed information and stats when
28 // Profiler::AnalyzeEventsAndWriteResults() is called.
29 class Profiler final : public IProfiler
30 {
31 public:
32     Profiler();
33     ~Profiler();
34     using InstrumentPtr = std::unique_ptr<Instrument>;
35
36     // Marks the beginning of a user-defined event.
37     // No attempt will be made to copy the name string: it must be known at compile time.
38     Event* BeginEvent(Compute compute, const std::string& name, std::vector<InstrumentPtr>&& instruments);
39
40     // Marks the end of a user-defined event.
41     void EndEvent(Event* event);
42
43     // Enables/disables profiling.
44     void EnableProfiling(bool enableProfiling) override;
45
46     // Checks if profiling is enabled.
47     bool IsProfilingEnabled() override;
48
49     // Increments the event tag, allowing grouping of events in a user-defined manner (e.g. per inference).
50     void UpdateEventTag();
51
52     // Analyzes the tracked events and writes the results to the given output stream.
53     // Please refer to the configuration variables in Profiling.cpp to customize the information written.
54     void AnalyzeEventsAndWriteResults(std::ostream& outStream) const override;
55
56     // Print stats for events in JSON Format to the given output stream.
57     void Print(std::ostream& outStream) const override;
58
59     // Gets the color to render an event with, based on which device it denotes.
60     uint32_t GetEventColor(Compute compute) const;
61
62 private:
63     using EventPtr = std::unique_ptr<Event>;
64     struct Marker
65     {
66         std::size_t m_Id;
67     };
68
69     struct ProfilingEventStats
70     {
71         double m_TotalMs;
72         double m_MinMs;
73         double m_MaxMs;
74         uint32_t m_Count;
75     };
76
77     // Waits for a compute device to finish working to guarantee correct timings.
78     // Currently used exclusively when emitting profiling events denoting GPU work.
79     void WaitForDevice(Compute compute) const;
80
81     template<typename EventIterType>
82     void AnalyzeEventSequenceAndWriteResults(EventIterType first, EventIterType last, std::ostream& outStream) const;
83
84     std::map<std::string, ProfilingEventStats> CalculateProfilingEventStats() const;
85     void PopulateInferences(std::vector<const Event*>& outInferences, int& outBaseLevel) const;
86     void PopulateDescendants(std::map<const Event*, std::vector<const Event*>>& outDescendantsMap) const;
87
88     std::stack<Event*> m_Parents;
89     std::vector<EventPtr> m_EventSequence;
90     bool m_ProfilingEnabled;
91
92 private:
93     // Friend functions for unit testing, see ProfilerTests.cpp.
94     friend size_t GetProfilerEventSequenceSize(armnn::Profiler* profiler);
95 };
96
97 // Singleton profiler manager.
98 // Keeps track of all the running profiler instances.
99 class ProfilerManager
100 {
101 public:
102     // Register the given profiler as a thread local pointer.
103     void RegisterProfiler(Profiler* profiler);
104
105     // Gets the thread local pointer to the profiler.
106     Profiler* GetProfiler();
107
108     // Accesses the singleton.
109     static ProfilerManager& GetInstance();
110
111 private:
112     // The constructor is kept private so that other instances of this class (other that the singleton's)
113     // can't be allocated.
114     ProfilerManager() {}
115 };
116
117 // Helper to easily add event markers to the codebase.
118 class ScopedProfilingEvent
119 {
120 public:
121     using InstrumentPtr = std::unique_ptr<Instrument>;
122
123     template<typename... Args>
124     ScopedProfilingEvent(Compute compute, const std::string& name, Args... args)
125         : m_Event(nullptr)
126         , m_Profiler(ProfilerManager::GetInstance().GetProfiler())
127     {
128         if (m_Profiler && m_Profiler->IsProfilingEnabled())
129         {
130             std::vector<InstrumentPtr> instruments(0);
131             instruments.reserve(sizeof...(args)); //One allocation
132             ConstructNextInVector(instruments, args...);
133             m_Event = m_Profiler->BeginEvent(compute, name, std::move(instruments));
134         }
135     }
136
137     ~ScopedProfilingEvent()
138     {
139         if (m_Profiler && m_Event)
140         {
141             m_Profiler->EndEvent(m_Event);
142         }
143     }
144
145 private:
146
147     void ConstructNextInVector(std::vector<InstrumentPtr>& instruments)
148     {
149         boost::ignore_unused(instruments);
150     }
151
152     template<typename Arg, typename... Args>
153     void ConstructNextInVector(std::vector<InstrumentPtr>& instruments, Arg arg, Args... args)
154     {
155         instruments.emplace_back(std::make_unique<Arg>(arg));
156         ConstructNextInVector(instruments, args...);
157     }
158
159     Event* m_Event;                                 ///< Event to track
160     Profiler* m_Profiler;                           ///< Profiler used
161 };
162
163 } // namespace armnn
164
165 // The event name must be known at compile time
166 #define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(compute, /*name,*/ ...) \
167     armnn::ScopedProfilingEvent e_##__FILE__##__LINE__(compute, /*name,*/ __VA_ARGS__);
168
169 #define ARMNN_SCOPED_PROFILING_EVENT(compute, name) \
170     ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(compute, name, armnn::WallClockTimer())