12 #if ARMNN_STREAMLINE_ENABLED 13 #include <streamline_annotate.h> 23 #include <boost/algorithm/string.hpp> 48 BOOST_ASSERT(event !=
nullptr);
53 if (measurement.m_Name == name)
61 return Measurement{
"", 0.f, Measurement::Unit::TIME_MS };
66 BOOST_ASSERT(event !=
nullptr);
68 std::vector<Measurement> measurements;
73 if (measurement.m_Name.rfind(
"OpenClKernelTimer", 0) == 0
74 || measurement.m_Name.rfind(
"NeonKernelTimer", 0) == 0)
77 measurements.push_back(measurement);
84 std::map<std::string, Profiler::ProfilingEventStats> Profiler::CalculateProfilingEventStats()
const 86 std::map<std::string, ProfilingEventStats> nameToStatsMap;
88 for (
const auto& event : m_EventSequence)
92 double durationMs = measurement.
m_Value;
93 auto it = nameToStatsMap.find(event->GetName());
94 if (it != nameToStatsMap.end())
96 ProfilingEventStats& stats = it->second;
97 stats.m_TotalMs += durationMs;
98 stats.m_MinMs = std::min(stats.m_MinMs, durationMs);
99 stats.m_MaxMs = std::max(stats.m_MaxMs, durationMs);
104 nameToStatsMap.emplace(event->GetName(), ProfilingEventStats{ durationMs, durationMs, durationMs, 1 });
108 return nameToStatsMap;
114 template<
typename ItertType>
115 void Profiler::AnalyzeEventSequenceAndWriteResults(ItertType first, ItertType last, std::ostream& outStream)
const 118 if (g_WriteProfilingEventSequence)
121 std::streamsize oldPrecision = outStream.precision();
122 outStream.precision(6);
123 std::ios_base::fmtflags oldFlags = outStream.flags();
124 outStream.setf(std::ios::fixed);
126 outStream <<
"Event Sequence - Name | Duration (ms) | Start (ms) | Stop (ms) | Device" << std::endl;
127 for (
auto event = first;
event != last; ++event)
135 outStream << std::setw(50) << eventPtr->
GetName() <<
" " 136 << std::setw(20) << durationMs
137 << std::setw(20) << startTimeMs
138 << std::setw(20) << stopTimeMs
142 outStream << std::endl;
144 outStream.flags(oldFlags);
145 outStream.precision(oldPrecision);
149 std::map<std::string, ProfilingEventStats> nameToStatsMap = CalculateProfilingEventStats();
152 outStream <<
"Event Stats - Name | Avg (ms) | Min (ms) | Max (ms) | Total (ms) | Count" << std::endl;
153 for (
const auto& pair : nameToStatsMap)
155 const std::string& eventLabel = pair.first;
156 const ProfilingEventStats& eventStats = pair.second;
157 const double avgMs = eventStats.m_TotalMs / double(eventStats.m_Count);
159 outStream <<
"\t" << std::setw(50) << eventLabel <<
" " << std::setw(9) << avgMs <<
" " 160 << std::setw(9) << eventStats.m_MinMs <<
" " << std::setw(9) << eventStats.m_MaxMs <<
" " 161 << std::setw(9) << eventStats.m_TotalMs <<
" " << std::setw(9) << eventStats.m_Count << std::endl;
163 outStream << std::endl;
167 : m_ProfilingEnabled(
false)
169 m_EventSequence.reserve(g_ProfilingEventCountHint);
171 #if ARMNN_STREAMLINE_ENABLED 179 if (m_ProfilingEnabled)
181 if (g_WriteReportToStdOutOnProfilerDestruction)
193 return m_ProfilingEnabled;
198 m_ProfilingEnabled = enableProfiling;
202 const std::string& label,
203 std::vector<InstrumentPtr>&& instruments)
205 Event* parent = m_Parents.empty() ? nullptr : m_Parents.top();
206 m_EventSequence.push_back(std::make_unique<Event>(label,
this, parent, backendId, std::move(instruments)));
207 Event*
event = m_EventSequence.back().get();
210 #if ARMNN_STREAMLINE_ENABLED 211 ANNOTATE_CHANNEL_COLOR(uint32_t(m_Parents.size()),
GetEventColor(backendId), label.c_str());
214 m_Parents.push(event);
222 BOOST_ASSERT(!m_Parents.empty());
223 BOOST_ASSERT(event == m_Parents.top());
226 Event* parent = m_Parents.empty() ? nullptr : m_Parents.top();
230 #if ARMNN_STREAMLINE_ENABLED 231 ANNOTATE_CHANNEL_END(uint32_t(m_Parents.size()));
238 while (eventPtr !=
nullptr)
246 void Profiler::PopulateInferences(std::vector<const Event*>& outInferences,
int& outBaseLevel)
const 248 outInferences.reserve(m_EventSequence.size());
249 for (
const auto& event : m_EventSequence)
251 const Event* eventPtrRaw =
event.get();
252 if (eventPtrRaw->
GetName() ==
"EnqueueWorkload")
254 outBaseLevel = (outBaseLevel == -1) ?
CalcLevel(eventPtrRaw) : outBaseLevel;
255 outInferences.push_back(eventPtrRaw);
260 void Profiler::PopulateDescendants(std::map<
const Event*, std::vector<const Event*>>& outDescendantsMap)
const 262 for (
const auto& event : m_EventSequence)
264 const Event* eventPtrRaw =
event.get();
272 auto it = outDescendantsMap.find(parent);
273 if (it == outDescendantsMap.end())
275 outDescendantsMap.emplace(parent, std::vector<const Event*>({eventPtrRaw}));
279 it->second.push_back(eventPtrRaw);
286 const Event* parentEvent,
288 std::map<
const Event*, std::vector<const Event*>> descendantsMap)
290 BOOST_ASSERT(parentEvent);
291 std::vector<Measurement> instrumentMeasurements = parentEvent->
GetMeasurements();
292 unsigned int childIdx=0;
293 for(
size_t measurementIndex = 0; measurementIndex < instrumentMeasurements.size(); ++measurementIndex, ++childIdx)
295 if (inferenceIndex == 0)
298 JsonChildObject measurementObject{instrumentMeasurements[measurementIndex].m_Name};
299 measurementObject.
SetUnit(instrumentMeasurements[measurementIndex].m_Unit);
302 BOOST_ASSERT(parentObject.
NumChildren() == childIdx);
303 parentObject.
AddChild(measurementObject);
310 auto childEventsIt = descendantsMap.find(parentEvent);
311 if (childEventsIt != descendantsMap.end())
313 for (
auto childEvent : childEventsIt->second)
315 if (inferenceIndex == 0)
334 std::streamsize oldPrecision = outStream.precision();
335 outStream.precision(6);
336 std::ios_base::fmtflags oldFlags = outStream.flags();
337 outStream.setf(std::ios::fixed);
342 std::vector<const Event*> inferences;
343 PopulateInferences(inferences, baseLevel);
346 std::map<const Event*, std::vector<const Event*>> descendantsMap;
347 PopulateDescendants(descendantsMap);
351 std::vector<JsonChildObject> workloadObjects;
352 std::map<unsigned int, std::vector<JsonChildObject>> workloadToKernelObjects;
354 for (
unsigned int inferenceIndex = 0; inferenceIndex < inferences.size(); ++inferenceIndex)
356 auto inference = inferences[inferenceIndex];
377 outStream.flags(oldFlags);
378 outStream.precision(oldPrecision);
384 const bool saneMarkerSequence = m_Parents.empty();
388 if (!saneMarkerSequence)
390 outStream <<
"Cannot write profiling stats. " 391 "Unexpected errors were found when analyzing the sequence of logged events, which may lead to plainly " 392 "wrong stats. The profiling system may contain implementation issues or could have been used in an " 393 "unsafe manner." << std::endl;
398 AnalyzeEventSequenceAndWriteResults(m_EventSequence.cbegin(),
399 m_EventSequence.cend(),
403 if (g_AggregateProfilingEventsByInference)
405 outStream << std::endl;
406 outStream <<
"***" << std::endl;
407 outStream <<
"*** Per Inference Stats" << std::endl;
408 outStream <<
"***" << std::endl;
409 outStream << std::endl;
412 std::vector<const Event*> inferences;
413 PopulateInferences(inferences, baseLevel);
416 std::map<const Event*, std::vector<const Event*>> descendantsMap;
417 PopulateDescendants(descendantsMap);
419 std::function<void (const Event*, std::vector<const Event*>&)>
420 FindDescendantEvents = [&](
const Event* eventPtr,
421 std::vector<const Event*>& sequence)
423 sequence.push_back(eventPtr);
430 auto children = descendantsMap.find(eventPtr);
431 if (children == descendantsMap.end())
436 for (
const Event* child : children->second)
438 return FindDescendantEvents(child, sequence);
443 int inferenceIdx = 0;
444 for (
auto inference : inferences)
446 std::vector<const Event*> sequence;
449 FindDescendantEvents(inference, sequence);
451 outStream <<
"> Begin Inference: " << inferenceIdx << std::endl;
452 outStream << std::endl;
453 AnalyzeEventSequenceAndWriteResults(sequence.cbegin(),
456 outStream << std::endl;
457 outStream <<
"> End Inference: " << inferenceIdx << std::endl;
469 if (backendId == cpuRef) {
472 }
else if (backendId == cpuAcc) {
475 }
else if (backendId == gpuAcc) {
491 return s_ProfilerManager;
496 tl_Profiler = profiler;
JsonChildObject & GetChild(const unsigned int index)
void EndEvent(Event *event)
Event class records measurements reported by BeginEvent()/EndEvent() and returns measurements when Ev...
const Event * GetEventPtr(const Event *ptr)
constexpr bool g_WriteReportToStdOutOnProfilerDestruction
void AddChild(const JsonChildObject &childObject)
void RegisterProfiler(Profiler *profiler)
int CalcLevel(const Event *eventPtr)
static ProfilerManager & GetInstance()
Measurement FindMeasurement(const std::string &name, const Event *event)
std::vector< Measurement > FindKernelMeasurements(const Event *event)
void EnableProfiling(bool enableProfiling) override
Enables/disables profiling for this profiler.
const std::string & GetName() const
Get the name of the event.
Copyright (c) 2020 ARM Limited.
void IgnoreUnused(Ts &&...)
void AnalyzeEventsAndWriteResults(std::ostream &outStream) const override
Analyzes the tracked events and writes the results to the given output stream.
size_t NumChildren() const
BackendId GetBackendId() const
Get the backend id of the event.
bool IsProfilingEnabled() override
Checks whether profiling is enabled.
const std::vector< Measurement > GetMeasurements() const
Get the recorded measurements calculated between Start() and Stop()
void ExtractJsonObjects(unsigned int inferenceIndex, const Event *parentEvent, JsonChildObject &parentObject, std::map< const Event *, std::vector< const Event *>> descendantsMap)
static const std::string WALL_CLOCK_TIME_STOP
void SetType(JsonObjectType type)
Event * BeginEvent(const BackendId &backendId, const std::string &name, std::vector< InstrumentPtr > &&instruments)
static const std::string WALL_CLOCK_TIME_START
thread_local Profiler * tl_Profiler
constexpr std::size_t g_ProfilingEventCountHint
static const std::string WALL_CLOCK_TIME
void AddMeasurement(const double measurement)
void PrintJsonChildObject(const JsonChildObject &object, size_t &id)
constexpr bool g_WriteProfilingEventSequence
constexpr bool g_AggregateProfilingEventsByInference
const std::string & Get() const
void SetUnit(const Measurement::Unit unit)
const Event * GetParentEvent() const
Get the pointer of the parent event.
uint32_t GetEventColor(const BackendId &backendId) const
void Print(std::ostream &outStream) const override
Print stats for events in JSON Format to the given output stream.