blob: d134425b6c77d00a1a38c4ece7e80b4dc3da0549 [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.
Francis Murtagh33199c22021-02-15 10:11:28 +000027class ProfilerImpl
telsoa014fcda012018-03-09 14:13:49 +000028{
29public:
Francis Murtagh33199c22021-02-15 10:11:28 +000030 ProfilerImpl();
31 ~ProfilerImpl();
telsoa01c577f2c2018-08-31 09:22:23 +010032 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.
Francis Murtagh33199c22021-02-15 10:11:28 +000036 Event* BeginEvent(armnn::IProfiler* profiler,
37 const BackendId& backendId,
38 const std::string& name,
39 std::vector<InstrumentPtr>&& instruments);
telsoa014fcda012018-03-09 14:13:49 +000040
41 // Marks the end of a user-defined event.
telsoa01c577f2c2018-08-31 09:22:23 +010042 void EndEvent(Event* event);
43
44 // Enables/disables profiling.
Francis Murtagh33199c22021-02-15 10:11:28 +000045 void EnableProfiling(bool enableProfiling);
telsoa01c577f2c2018-08-31 09:22:23 +010046
47 // Checks if profiling is enabled.
Francis Murtagh33199c22021-02-15 10:11:28 +000048 bool IsProfilingEnabled();
telsoa014fcda012018-03-09 14:13:49 +000049
50 // Increments the event tag, allowing grouping of events in a user-defined manner (e.g. per inference).
telsoa01c577f2c2018-08-31 09:22:23 +010051 void UpdateEventTag();
telsoa014fcda012018-03-09 14:13:49 +000052
53 // Analyzes the tracked events and writes the results to the given output stream.
54 // Please refer to the configuration variables in Profiling.cpp to customize the information written.
Francis Murtagh33199c22021-02-15 10:11:28 +000055 void AnalyzeEventsAndWriteResults(std::ostream& outStream) const;
telsoa014fcda012018-03-09 14:13:49 +000056
telsoa01c577f2c2018-08-31 09:22:23 +010057 // Print stats for events in JSON Format to the given output stream.
Francis Murtagh33199c22021-02-15 10:11:28 +000058 void Print(std::ostream& outStream) const;
telsoa014fcda012018-03-09 14:13:49 +000059
telsoa01c577f2c2018-08-31 09:22:23 +010060 // Gets the color to render an event with, based on which device it denotes.
Matthew Bentham1b63d6c2019-04-05 09:35:15 +010061 uint32_t GetEventColor(const BackendId& backendId) const;
telsoa014fcda012018-03-09 14:13:49 +000062
telsoa01c577f2c2018-08-31 09:22:23 +010063 using EventPtr = std::unique_ptr<Event>;
telsoa014fcda012018-03-09 14:13:49 +000064 struct Marker
65 {
66 std::size_t m_Id;
telsoa014fcda012018-03-09 14:13:49 +000067 };
68
69 struct ProfilingEventStats
70 {
71 double m_TotalMs;
72 double m_MinMs;
73 double m_MaxMs;
telsoa01c577f2c2018-08-31 09:22:23 +010074 uint32_t m_Count;
telsoa014fcda012018-03-09 14:13:49 +000075 };
76
telsoa01c577f2c2018-08-31 09:22:23 +010077 template<typename EventIterType>
78 void AnalyzeEventSequenceAndWriteResults(EventIterType first, EventIterType last, std::ostream& outStream) const;
telsoa014fcda012018-03-09 14:13:49 +000079
80 std::map<std::string, ProfilingEventStats> CalculateProfilingEventStats() const;
telsoa01c577f2c2018-08-31 09:22:23 +010081 void PopulateInferences(std::vector<const Event*>& outInferences, int& outBaseLevel) const;
82 void PopulateDescendants(std::map<const Event*, std::vector<const Event*>>& outDescendantsMap) const;
telsoa014fcda012018-03-09 14:13:49 +000083
telsoa01c577f2c2018-08-31 09:22:23 +010084 std::stack<Event*> m_Parents;
85 std::vector<EventPtr> m_EventSequence;
86 bool m_ProfilingEnabled;
telsoa014fcda012018-03-09 14:13:49 +000087};
88
telsoa01c577f2c2018-08-31 09:22:23 +010089// Singleton profiler manager.
90// Keeps track of all the running profiler instances.
91class ProfilerManager
92{
93public:
94 // Register the given profiler as a thread local pointer.
Francis Murtagh33199c22021-02-15 10:11:28 +000095 void RegisterProfiler(IProfiler* profiler);
telsoa01c577f2c2018-08-31 09:22:23 +010096
97 // Gets the thread local pointer to the profiler.
Francis Murtagh33199c22021-02-15 10:11:28 +000098 IProfiler* GetProfiler();
telsoa01c577f2c2018-08-31 09:22:23 +010099
100 // Accesses the singleton.
101 static ProfilerManager& GetInstance();
102
103private:
104 // The constructor is kept private so that other instances of this class (other that the singleton's)
105 // can't be allocated.
106 ProfilerManager() {}
107};
108
109// Helper to easily add event markers to the codebase.
telsoa014fcda012018-03-09 14:13:49 +0000110class ScopedProfilingEvent
111{
112public:
telsoa01c577f2c2018-08-31 09:22:23 +0100113 using InstrumentPtr = std::unique_ptr<Instrument>;
114
115 template<typename... Args>
Derek Lambertia08d29b2020-06-19 14:33:05 +0100116 ScopedProfilingEvent(const BackendId& backendId, const std::string& name, Args&&... args)
telsoa01c577f2c2018-08-31 09:22:23 +0100117 : m_Event(nullptr)
118 , m_Profiler(ProfilerManager::GetInstance().GetProfiler())
telsoa014fcda012018-03-09 14:13:49 +0000119 {
telsoa01c577f2c2018-08-31 09:22:23 +0100120 if (m_Profiler && m_Profiler->IsProfilingEnabled())
121 {
122 std::vector<InstrumentPtr> instruments(0);
123 instruments.reserve(sizeof...(args)); //One allocation
Derek Lambertia08d29b2020-06-19 14:33:05 +0100124 ConstructNextInVector(instruments, std::forward<Args>(args)...);
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000125 m_Event = m_Profiler->BeginEvent(backendId, name, std::move(instruments));
telsoa01c577f2c2018-08-31 09:22:23 +0100126 }
telsoa014fcda012018-03-09 14:13:49 +0000127 }
128
129 ~ScopedProfilingEvent()
130 {
telsoa01c577f2c2018-08-31 09:22:23 +0100131 if (m_Profiler && m_Event)
132 {
Francis Murtagh33199c22021-02-15 10:11:28 +0000133 m_Profiler->pProfilerImpl->EndEvent(m_Event);
telsoa01c577f2c2018-08-31 09:22:23 +0100134 }
telsoa014fcda012018-03-09 14:13:49 +0000135 }
136
137private:
telsoa01c577f2c2018-08-31 09:22:23 +0100138
139 void ConstructNextInVector(std::vector<InstrumentPtr>& instruments)
140 {
Jan Eilers8eb25602020-03-09 12:13:48 +0000141 IgnoreUnused(instruments);
telsoa01c577f2c2018-08-31 09:22:23 +0100142 }
143
144 template<typename Arg, typename... Args>
Derek Lambertia08d29b2020-06-19 14:33:05 +0100145 void ConstructNextInVector(std::vector<InstrumentPtr>& instruments, Arg&& arg, Args&&... args)
telsoa01c577f2c2018-08-31 09:22:23 +0100146 {
Derek Lambertia08d29b2020-06-19 14:33:05 +0100147 instruments.emplace_back(std::make_unique<Arg>(std::forward<Arg>(arg)));
148 ConstructNextInVector(instruments, std::forward<Args>(args)...);
telsoa01c577f2c2018-08-31 09:22:23 +0100149 }
150
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000151 Event* m_Event; ///< Event to track
Francis Murtagh33199c22021-02-15 10:11:28 +0000152 IProfiler* m_Profiler; ///< Profiler used
telsoa014fcda012018-03-09 14:13:49 +0000153};
154
155} // namespace armnn
156
Jim Flynnc456c312020-10-13 14:40:29 +0100157#define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC_INNER(lineNumber, backendId, /*name,*/ ...) \
158 armnn::ScopedProfilingEvent e_ ## lineNumber(backendId, /*name,*/ __VA_ARGS__);
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100159
Jim Flynnc456c312020-10-13 14:40:29 +0100160#define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC(lineNumber, backendId, /*name,*/ ...) \
161 ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC_INNER(lineNumber, backendId, /*name,*/ __VA_ARGS__)
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100162
Jim Flynnc456c312020-10-13 14:40:29 +0100163// The event name must be known at compile time i.e. if you are going to use this version of the macro
164// in code the first argument you supply after the backendId must be the name.
165// NOTE: need to pass the line number as an argument from here so by the time it gets to the UNIQUE_LOC_INNER
166// above it has expanded to a string and will concat (##) correctly with the 'e_' prefix to yield a
167// legal and unique variable name (so long as you don't use the macro twice on the same line).
168// The concat preprocessing operator (##) very unhelpfully will not expand macros see
169// https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html for the gory details.
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000170#define ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(backendId, /*name,*/ ...) \
Jim Flynnc456c312020-10-13 14:40:29 +0100171 ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS_UNIQUE_LOC(__LINE__,backendId, /*name,*/ __VA_ARGS__)
telsoa014fcda012018-03-09 14:13:49 +0000172
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000173#define ARMNN_SCOPED_PROFILING_EVENT(backendId, name) \
174 ARMNN_SCOPED_PROFILING_EVENT_WITH_INSTRUMENTS(backendId, name, armnn::WallClockTimer())