blob: 88a7adff7c87ab1292930b1b4a9aaeb306c22179 [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
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#if ARMNN_PROFILING_ENABLED
8
9#include "armnn/ArmNN.hpp"
10
11#include <chrono>
12#include <iosfwd>
13#include <ctime>
14#include <vector>
15#include <stack>
16#include <map>
17
18namespace armnn
19{
20
21// Clock class that uses the same timestamp function as the Mali DDK
22class monotonic_clock {
23public:
24 using duration = std::chrono::nanoseconds;
25 using time_point = std::chrono::time_point<monotonic_clock, duration>;
26
27 static std::chrono::time_point<monotonic_clock, std::chrono::nanoseconds> now() noexcept
28 {
29 timespec ts;
30#if defined(CLOCK_MONOTONIC_RAW)
31 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
32#else
33 clock_gettime(CLOCK_MONOTONIC, &ts);
34#endif
35 return time_point(std::chrono::nanoseconds(ts.tv_sec*1000000000 + ts.tv_nsec));
36 }
37};
38
39// Simple single-threaded profiler.
40// Tracks events reported by BeginEvent()/EndEvent() and outputs detailed information and stats when
41// Profiler::AnalyzeEventsAndWriteResults() is called.
42class Profiler
43{
44public:
45 // Marks the beginning of a user-defined event.
46 // No attempt will be made to copy the name string: It must be known at compile time.
47 void BeginEvent(Compute compute, const std::string name);
48
49 // Marks the end of a user-defined event.
50 void EndEvent(Compute compute);
51
52 // Increments the event tag, allowing grouping of events in a user-defined manner (e.g. per inference).
53 void UpdateEventTag() { ++m_EventTag; m_EventTagUpdated = true; }
54
55 // Analyzes the tracked events and writes the results to the given output stream.
56 // Please refer to the configuration variables in Profiling.cpp to customize the information written.
57 void AnalyzeEventsAndWriteResults(std::ostream& outStream) const;
58
59 // Accesses the singleton
60 static Profiler& Get() { return s_Instance; }
61
62 // Gets a string name for a given Compute device enum
63 const char* GetEventComputeDevice(Compute compute) const;
64
65 // Gets the color to render an event with, based on which device it denotes
66 std::uint32_t GetEventColor(Compute compute) const;
67
68 typedef monotonic_clock Clock;
69 typedef std::chrono::time_point<Clock> TimePoint;
70
71private:
72
73 struct Marker
74 {
75 std::size_t m_Id;
76 const std::string m_EventName;
77 TimePoint m_TimeStamp;
78 Compute m_ComputeDevice;
79 std::uint32_t m_Tag;
80 };
81
82 struct ProfilingEvent
83 {
84 std::string m_Label;
85 TimePoint m_StartTime;
86 TimePoint m_StopTime;
87 Compute m_Device;
88 std::uint32_t m_Tag;
89
90 double DurationMs() const
91 {
92 return std::chrono::duration<double>(m_StopTime - m_StartTime).count()*1000.0;
93 }
94 };
95
96 struct ProfilingEventStats
97 {
98 double m_TotalMs;
99 double m_MinMs;
100 double m_MaxMs;
101 std::uint32_t m_Count;
102 };
103
104 Profiler();
105 ~Profiler();
106
107 // Waits for a compute device to finish working to guarantee correct timings.
108 // Currently used exclusively when emitting profiling events denoting GPU work.
109 void WaitForDevice(Compute compute) const;
110
111 void AnalyzeEventSequenceAndWriteResults(std::vector<ProfilingEvent>::const_iterator first,
112 std::vector<ProfilingEvent>::const_iterator last,
113 std::ostream& outStream) const;
114
115 std::map<std::string, ProfilingEventStats> CalculateProfilingEventStats() const;
116
117 std::stack<Marker> m_ObservedMarkers;
118 std::vector<ProfilingEvent> m_EventSequence;
119 std::uint32_t m_EventTag;
120 std::uint32_t m_NestingLevel;
121 bool m_EventTagUpdated;
122
123 static Profiler s_Instance;
124};
125
126// Helper to easily add event markers to the codebase
127class ScopedProfilingEvent
128{
129public:
130 ScopedProfilingEvent(Compute compute, const std::string name)
131 : m_Compute(compute)
132 {
133 Profiler::Get().BeginEvent(compute, name);
134 }
135
136 ~ScopedProfilingEvent()
137 {
138 Profiler::Get().EndEvent(m_Compute);
139 }
140
141private:
142 armnn::Compute m_Compute;
143};
144
145} // namespace armnn
146
147// Allows grouping events in an user-defined manner (e.g. per inference)
148#define ARMNN_UPDATE_PROFILING_EVENT_TAG() armnn::Profiler::Get().UpdateEventTag();
149
150// The event name must be known at compile time
151#define ARMNN_SCOPED_PROFILING_EVENT(compute, name) armnn::ScopedProfilingEvent e_##__FILE__##__LINE__(compute, name);
152
153#else
154
155#define ARMNN_UPDATE_PROFILING_EVENT_TAG()
156#define ARMNN_SCOPED_PROFILING_EVENT(compute, name)
157
158#endif // ARMNN_PROFILING_ENABLED
159