blob: e18bf475d17bb18c2db1a34d5134c598f3a862ad [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#include "Profiling.hpp"
Matthew Bentham1b63d6c2019-04-05 09:35:15 +01006
7#include <armnn/BackendId.hpp>
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01008#include <armnn/utility/Assert.hpp>
Matthew Bentham1b63d6c2019-04-05 09:35:15 +01009
telsoa01c577f2c2018-08-31 09:22:23 +010010#include "JsonPrinter.hpp"
telsoa014fcda012018-03-09 14:13:49 +000011
12#if ARMNN_STREAMLINE_ENABLED
13#include <streamline_annotate.h>
14#endif
15
telsoa014fcda012018-03-09 14:13:49 +000016#include <algorithm>
17#include <iomanip>
18#include <iostream>
telsoa01c577f2c2018-08-31 09:22:23 +010019#include <fstream>
telsoa014fcda012018-03-09 14:13:49 +000020#include <map>
21#include <stack>
telsoa014fcda012018-03-09 14:13:49 +000022
23namespace armnn
24{
25
26// Controls the amount of memory initially allocated to store profiling events.
27// If chosen carefully, the profiling system will not make any additional allocations, thus minimizing its impact on
28// measured times.
29constexpr std::size_t g_ProfilingEventCountHint = 1024;
30
31// Whether profiling reports should include the sequence of events together with their timings.
32constexpr bool g_WriteProfilingEventSequence = true;
33
telsoa01c577f2c2018-08-31 09:22:23 +010034// Whether profiling reports should also report detailed information on events grouped by inference.
35// This can spam the output stream, so use carefully (or adapt the code to just output information
36// of interest).
37constexpr bool g_AggregateProfilingEventsByInference = true;
telsoa014fcda012018-03-09 14:13:49 +000038
telsoa01c577f2c2018-08-31 09:22:23 +010039// Whether a call to Profiler::AnalyzeEventsAndWriteResults() will be made when the Profiler is destroyed.
40// It can be convenient for local tests.
41constexpr bool g_WriteReportToStdOutOnProfilerDestruction = false;
telsoa014fcda012018-03-09 14:13:49 +000042
telsoa01c577f2c2018-08-31 09:22:23 +010043Measurement FindMeasurement(const std::string& name, const Event* event)
44{
45
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010046 ARMNN_ASSERT(event != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +010047
48 // Search though the measurements.
49 for (const auto& measurement : event->GetMeasurements())
50 {
51 if (measurement.m_Name == name)
52 {
53 // Measurement found.
54 return measurement;
55 }
56 }
57
58 // Measurement not found.
59 return Measurement{ "", 0.f, Measurement::Unit::TIME_MS };
60}
61
62std::vector<Measurement> FindKernelMeasurements(const Event* event)
63{
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010064 ARMNN_ASSERT(event != nullptr);
telsoa01c577f2c2018-08-31 09:22:23 +010065
66 std::vector<Measurement> measurements;
67
68 // Search through the measurements.
69 for (const auto& measurement : event->GetMeasurements())
70 {
71 if (measurement.m_Name.rfind("OpenClKernelTimer", 0) == 0
72 || measurement.m_Name.rfind("NeonKernelTimer", 0) == 0)
73 {
74 // Measurement found.
75 measurements.push_back(measurement);
76 }
77 }
78
79 return measurements;
80}
telsoa014fcda012018-03-09 14:13:49 +000081
Francis Murtagh33199c22021-02-15 10:11:28 +000082std::map<std::string, ProfilerImpl::ProfilingEventStats> ProfilerImpl::CalculateProfilingEventStats() const
telsoa014fcda012018-03-09 14:13:49 +000083{
84 std::map<std::string, ProfilingEventStats> nameToStatsMap;
85
telsoa01c577f2c2018-08-31 09:22:23 +010086 for (const auto& event : m_EventSequence)
telsoa014fcda012018-03-09 14:13:49 +000087 {
telsoa01c577f2c2018-08-31 09:22:23 +010088 Measurement measurement = FindMeasurement(WallClockTimer::WALL_CLOCK_TIME, event.get());
89
90 double durationMs = measurement.m_Value;
91 auto it = nameToStatsMap.find(event->GetName());
92 if (it != nameToStatsMap.end())
telsoa014fcda012018-03-09 14:13:49 +000093 {
telsoa01c577f2c2018-08-31 09:22:23 +010094 ProfilingEventStats& stats = it->second;
95 stats.m_TotalMs += durationMs;
96 stats.m_MinMs = std::min(stats.m_MinMs, durationMs);
97 stats.m_MaxMs = std::max(stats.m_MaxMs, durationMs);
telsoa014fcda012018-03-09 14:13:49 +000098 ++stats.m_Count;
99 }
100 else
101 {
telsoa01c577f2c2018-08-31 09:22:23 +0100102 nameToStatsMap.emplace(event->GetName(), ProfilingEventStats{ durationMs, durationMs, durationMs, 1 });
telsoa014fcda012018-03-09 14:13:49 +0000103 }
104 }
105
106 return nameToStatsMap;
107}
108
telsoa01c577f2c2018-08-31 09:22:23 +0100109const Event* GetEventPtr(const Event* ptr) { return ptr;}
110const Event* GetEventPtr(const std::unique_ptr<Event>& ptr) {return ptr.get(); }
111
112template<typename ItertType>
Francis Murtagh33199c22021-02-15 10:11:28 +0000113void ProfilerImpl::AnalyzeEventSequenceAndWriteResults(ItertType first, ItertType last, std::ostream& outStream) const
telsoa014fcda012018-03-09 14:13:49 +0000114{
telsoa01c577f2c2018-08-31 09:22:23 +0100115 // Outputs event sequence, if needed.
telsoa014fcda012018-03-09 14:13:49 +0000116 if (g_WriteProfilingEventSequence)
117 {
telsoa01c577f2c2018-08-31 09:22:23 +0100118 // Makes sure timestamps are output with 6 decimals, and save old settings.
telsoa014fcda012018-03-09 14:13:49 +0000119 std::streamsize oldPrecision = outStream.precision();
120 outStream.precision(6);
121 std::ios_base::fmtflags oldFlags = outStream.flags();
122 outStream.setf(std::ios::fixed);
telsoa01c577f2c2018-08-31 09:22:23 +0100123 // Outputs fields.
telsoa014fcda012018-03-09 14:13:49 +0000124 outStream << "Event Sequence - Name | Duration (ms) | Start (ms) | Stop (ms) | Device" << std::endl;
125 for (auto event = first; event != last; ++event)
126 {
telsoa01c577f2c2018-08-31 09:22:23 +0100127 const Event* eventPtr = GetEventPtr((*event));
128 double startTimeMs = FindMeasurement(WallClockTimer::WALL_CLOCK_TIME_START, eventPtr).m_Value;
129 double stopTimeMs = FindMeasurement(WallClockTimer::WALL_CLOCK_TIME_STOP, eventPtr).m_Value;
telsoa014fcda012018-03-09 14:13:49 +0000130
telsoa01c577f2c2018-08-31 09:22:23 +0100131 // Find the WallClock measurement if there is one.
132 double durationMs = FindMeasurement(WallClockTimer::WALL_CLOCK_TIME, eventPtr).m_Value;
133 outStream << std::setw(50) << eventPtr->GetName() << " "
134 << std::setw(20) << durationMs
135 << std::setw(20) << startTimeMs
136 << std::setw(20) << stopTimeMs
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000137 << std::setw(20) << eventPtr->GetBackendId().Get()
telsoa01c577f2c2018-08-31 09:22:23 +0100138 << std::endl;
telsoa014fcda012018-03-09 14:13:49 +0000139 }
140 outStream << std::endl;
telsoa01c577f2c2018-08-31 09:22:23 +0100141 // Restores previous precision settings.
telsoa014fcda012018-03-09 14:13:49 +0000142 outStream.flags(oldFlags);
143 outStream.precision(oldPrecision);
144 }
145
telsoa01c577f2c2018-08-31 09:22:23 +0100146 // Aggregates results per event name.
telsoa014fcda012018-03-09 14:13:49 +0000147 std::map<std::string, ProfilingEventStats> nameToStatsMap = CalculateProfilingEventStats();
148
telsoa01c577f2c2018-08-31 09:22:23 +0100149 // Outputs aggregated stats.
telsoa014fcda012018-03-09 14:13:49 +0000150 outStream << "Event Stats - Name | Avg (ms) | Min (ms) | Max (ms) | Total (ms) | Count" << std::endl;
151 for (const auto& pair : nameToStatsMap)
152 {
153 const std::string& eventLabel = pair.first;
154 const ProfilingEventStats& eventStats = pair.second;
155 const double avgMs = eventStats.m_TotalMs / double(eventStats.m_Count);
156
157 outStream << "\t" << std::setw(50) << eventLabel << " " << std::setw(9) << avgMs << " "
Keith Davis5a64f222021-08-04 10:35:20 +0100158 << std::setw(9) << eventStats.m_MinMs << " " << std::setw(9) << eventStats.m_MaxMs << " "
159 << std::setw(9) << eventStats.m_TotalMs << " " << std::setw(9) << eventStats.m_Count << std::endl;
telsoa014fcda012018-03-09 14:13:49 +0000160 }
161 outStream << std::endl;
162}
163
Francis Murtagh33199c22021-02-15 10:11:28 +0000164ProfilerImpl::ProfilerImpl()
Sadik Armagan9f237112021-08-13 12:40:25 +0100165 : m_ProfilingEnabled(false),
Keith Davis4914d0c2021-08-18 17:14:05 +0100166 m_DetailsToStdOutMethod(ProfilingDetailsMethod::Undefined)
telsoa014fcda012018-03-09 14:13:49 +0000167{
168 m_EventSequence.reserve(g_ProfilingEventCountHint);
169
170#if ARMNN_STREAMLINE_ENABLED
telsoa01c577f2c2018-08-31 09:22:23 +0100171 // Initialises streamline annotations.
telsoa014fcda012018-03-09 14:13:49 +0000172 ANNOTATE_SETUP;
173#endif
174}
175
Francis Murtagh33199c22021-02-15 10:11:28 +0000176ProfilerImpl::~ProfilerImpl()
telsoa014fcda012018-03-09 14:13:49 +0000177{
telsoa01c577f2c2018-08-31 09:22:23 +0100178 if (m_ProfilingEnabled)
telsoa014fcda012018-03-09 14:13:49 +0000179 {
telsoa01c577f2c2018-08-31 09:22:23 +0100180 if (g_WriteReportToStdOutOnProfilerDestruction)
181 {
182 Print(std::cout);
183 }
telsoa014fcda012018-03-09 14:13:49 +0000184 }
telsoa01c577f2c2018-08-31 09:22:23 +0100185
186 // Un-register this profiler from the current thread.
187 ProfilerManager::GetInstance().RegisterProfiler(nullptr);
telsoa014fcda012018-03-09 14:13:49 +0000188}
189
Francis Murtagh33199c22021-02-15 10:11:28 +0000190bool ProfilerImpl::IsProfilingEnabled()
telsoa01c577f2c2018-08-31 09:22:23 +0100191{
192 return m_ProfilingEnabled;
193}
194
Francis Murtagh33199c22021-02-15 10:11:28 +0000195void ProfilerImpl::EnableProfiling(bool enableProfiling)
telsoa01c577f2c2018-08-31 09:22:23 +0100196{
197 m_ProfilingEnabled = enableProfiling;
198}
199
Keith Davis4914d0c2021-08-18 17:14:05 +0100200void ProfilerImpl::EnableNetworkDetailsToStdOut(ProfilingDetailsMethod details)
Keith Davisf4874862021-08-09 16:49:18 +0100201{
Keith Davis4914d0c2021-08-18 17:14:05 +0100202 m_DetailsToStdOutMethod = details;
Keith Davisf4874862021-08-09 16:49:18 +0100203}
204
Francis Murtagh33199c22021-02-15 10:11:28 +0000205Event* ProfilerImpl::BeginEvent(armnn::IProfiler* profiler,
Keith Davis5a64f222021-08-04 10:35:20 +0100206 const BackendId& backendId,
207 const std::string& label,
208 std::vector<InstrumentPtr>&& instruments,
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000209 const Optional<arm::pipe::ProfilingGuid>& guid)
telsoa014fcda012018-03-09 14:13:49 +0000210{
telsoa01c577f2c2018-08-31 09:22:23 +0100211 Event* parent = m_Parents.empty() ? nullptr : m_Parents.top();
Keith Davis5a64f222021-08-04 10:35:20 +0100212 m_EventSequence.push_back(std::make_unique<Event>(label,
213 profiler,
214 parent,
215 backendId,
216 std::move(instruments),
217 guid));
telsoa01c577f2c2018-08-31 09:22:23 +0100218 Event* event = m_EventSequence.back().get();
219 event->Start();
telsoa014fcda012018-03-09 14:13:49 +0000220
221#if ARMNN_STREAMLINE_ENABLED
Matthew Bentham1b63d6c2019-04-05 09:35:15 +0100222 ANNOTATE_CHANNEL_COLOR(uint32_t(m_Parents.size()), GetEventColor(backendId), label.c_str());
telsoa014fcda012018-03-09 14:13:49 +0000223#endif
224
telsoa01c577f2c2018-08-31 09:22:23 +0100225 m_Parents.push(event);
226 return event;
telsoa014fcda012018-03-09 14:13:49 +0000227}
228
Francis Murtagh33199c22021-02-15 10:11:28 +0000229void ProfilerImpl::EndEvent(Event* event)
telsoa014fcda012018-03-09 14:13:49 +0000230{
telsoa01c577f2c2018-08-31 09:22:23 +0100231 event->Stop();
telsoa014fcda012018-03-09 14:13:49 +0000232
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100233 ARMNN_ASSERT(!m_Parents.empty());
234 ARMNN_ASSERT(event == m_Parents.top());
telsoa01c577f2c2018-08-31 09:22:23 +0100235 m_Parents.pop();
telsoa014fcda012018-03-09 14:13:49 +0000236
telsoa01c577f2c2018-08-31 09:22:23 +0100237 Event* parent = m_Parents.empty() ? nullptr : m_Parents.top();
Jan Eilers8eb25602020-03-09 12:13:48 +0000238 IgnoreUnused(parent);
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100239 ARMNN_ASSERT(event->GetParentEvent() == parent);
telsoa014fcda012018-03-09 14:13:49 +0000240
241#if ARMNN_STREAMLINE_ENABLED
Matthew Bentham1b63d6c2019-04-05 09:35:15 +0100242 ANNOTATE_CHANNEL_END(uint32_t(m_Parents.size()));
telsoa014fcda012018-03-09 14:13:49 +0000243#endif
telsoa01c577f2c2018-08-31 09:22:23 +0100244}
telsoa014fcda012018-03-09 14:13:49 +0000245
telsoa01c577f2c2018-08-31 09:22:23 +0100246int CalcLevel(const Event* eventPtr)
247{
Keith Davis5a64f222021-08-04 10:35:20 +0100248 int level = 0;
telsoa01c577f2c2018-08-31 09:22:23 +0100249 while (eventPtr != nullptr)
250 {
251 eventPtr = eventPtr->GetParentEvent();
252 level++;
253 }
254 return level;
255}
256
Kevin May4692e112021-10-18 14:41:50 +0100257void ProfilerImpl::PopulateParent(std::vector<const Event*>& outEvents, int& outBaseLevel, std::string parentName) const
telsoa01c577f2c2018-08-31 09:22:23 +0100258{
Kevin May4692e112021-10-18 14:41:50 +0100259 outEvents.reserve(m_EventSequence.size());
telsoa01c577f2c2018-08-31 09:22:23 +0100260 for (const auto& event : m_EventSequence)
261 {
262 const Event* eventPtrRaw = event.get();
Kevin May4692e112021-10-18 14:41:50 +0100263 if (eventPtrRaw->GetName() == parentName)
telsoa01c577f2c2018-08-31 09:22:23 +0100264 {
265 outBaseLevel = (outBaseLevel == -1) ? CalcLevel(eventPtrRaw) : outBaseLevel;
Kevin May4692e112021-10-18 14:41:50 +0100266 outEvents.push_back(eventPtrRaw);
telsoa01c577f2c2018-08-31 09:22:23 +0100267 }
268 }
269}
270
Francis Murtagh33199c22021-02-15 10:11:28 +0000271void ProfilerImpl::PopulateDescendants(std::map<const Event*, std::vector<const Event*>>& outDescendantsMap) const
telsoa01c577f2c2018-08-31 09:22:23 +0100272{
273 for (const auto& event : m_EventSequence)
274 {
275 const Event* eventPtrRaw = event.get();
276 const Event* parent = eventPtrRaw->GetParentEvent();
277
278 if (!parent)
279 {
280 continue;
281 }
282
283 auto it = outDescendantsMap.find(parent);
284 if (it == outDescendantsMap.end())
285 {
Keith Davis5a64f222021-08-04 10:35:20 +0100286 outDescendantsMap.emplace(parent, std::vector<const Event*>({ eventPtrRaw }));
telsoa01c577f2c2018-08-31 09:22:23 +0100287 }
288 else
289 {
290 it->second.push_back(eventPtrRaw);
291 }
292 }
293}
294
Keith Davis554fa092021-07-20 11:25:22 +0100295void ConfigureDetailsObject(JsonChildObject& detailsObject,
296 std::string layerDetailsStr)
297{
298 detailsObject.SetType(JsonObjectType::ExecObjectDesc);
299 detailsObject.SetAndParseDetails(layerDetailsStr);
300
301}
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100302
303void ExtractJsonObjects(unsigned int inferenceIndex,
304 const Event* parentEvent,
305 JsonChildObject& parentObject,
306 std::map<const Event*, std::vector<const Event*>> descendantsMap)
307{
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100308 ARMNN_ASSERT(parentEvent);
Keith Davis5a64f222021-08-04 10:35:20 +0100309
310 // If profiling GUID is entered, process it
311 if (parentEvent->GetProfilingGuid().has_value())
312 {
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000313 arm::pipe::ProfilingGuid profilingGuid;
Keith Davis5a64f222021-08-04 10:35:20 +0100314 profilingGuid = parentEvent->GetProfilingGuid().value();
315 parentObject.SetGuid(profilingGuid);
316 }
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100317 std::vector<Measurement> instrumentMeasurements = parentEvent->GetMeasurements();
Keith Davis5a64f222021-08-04 10:35:20 +0100318 unsigned int childIdx = 0;
319 for (size_t measurementIndex = 0; measurementIndex < instrumentMeasurements.size(); ++measurementIndex, ++childIdx)
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100320 {
321 if (inferenceIndex == 0)
322 {
323 // Only add kernel measurement once, in case of multiple inferences
Keith Davis5a64f222021-08-04 10:35:20 +0100324 JsonChildObject measurementObject{ instrumentMeasurements[measurementIndex].m_Name };
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100325 measurementObject.SetUnit(instrumentMeasurements[measurementIndex].m_Unit);
326 measurementObject.SetType(JsonObjectType::Measurement);
327
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100328 ARMNN_ASSERT(parentObject.NumChildren() == childIdx);
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100329 parentObject.AddChild(measurementObject);
330 }
331
332 parentObject.GetChild(childIdx).AddMeasurement(instrumentMeasurements[measurementIndex].m_Value);
333 }
334
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100335 auto childEventsIt = descendantsMap.find(parentEvent);
336 if (childEventsIt != descendantsMap.end())
337 {
338 for (auto childEvent : childEventsIt->second)
339 {
340 if (inferenceIndex == 0)
341 {
342 // Only add second level once, in case of multiple inferences
Keith Davis5a64f222021-08-04 10:35:20 +0100343 JsonChildObject childObject{ childEvent->GetName() };
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100344 childObject.SetType(JsonObjectType::Event);
345 parentObject.AddChild(childObject);
346 }
347
348 // Recursively process children. In reality this won't be very deep recursion. ~4-6 levels deep.
349 ExtractJsonObjects(inferenceIndex, childEvent, parentObject.GetChild(childIdx), descendantsMap);
350
351 childIdx++;
352 }
353 }
354}
355
Francis Murtagh33199c22021-02-15 10:11:28 +0000356void ProfilerImpl::Print(std::ostream& outStream) const
telsoa01c577f2c2018-08-31 09:22:23 +0100357{
358 // Makes sure timestamps are output with 6 decimals, and save old settings.
359 std::streamsize oldPrecision = outStream.precision();
360 outStream.precision(6);
361 std::ios_base::fmtflags oldFlags = outStream.flags();
362 outStream.setf(std::ios::fixed);
363 JsonPrinter printer(outStream);
364
Kevin May4692e112021-10-18 14:41:50 +0100365 // First find all the parent Events and print out duration measurements.
telsoa01c577f2c2018-08-31 09:22:23 +0100366 int baseLevel = -1;
Kevin May4692e112021-10-18 14:41:50 +0100367
368 std::vector<const Event*> optimizations;
369 PopulateParent(optimizations, baseLevel, "Optimizer");
370
371 std::vector<const Event*> loadedNetworks;
372 PopulateParent(loadedNetworks, baseLevel, "LoadedNetwork");
373
telsoa01c577f2c2018-08-31 09:22:23 +0100374 std::vector<const Event*> inferences;
Kevin May4692e112021-10-18 14:41:50 +0100375 PopulateParent(inferences, baseLevel, "EnqueueWorkload");
telsoa01c577f2c2018-08-31 09:22:23 +0100376
377 // Second map out descendants hierarchy
378 std::map<const Event*, std::vector<const Event*>> descendantsMap;
379 PopulateDescendants(descendantsMap);
380
Kevin May4692e112021-10-18 14:41:50 +0100381 // Extract json objects for each parent event type
382 JsonChildObject optimizeObject{ "optimize_measurements" };
383
384 for (unsigned int optimizeIndex = 0; optimizeIndex < optimizations.size(); ++optimizeIndex)
385 {
386 auto optimization = optimizations[optimizeIndex];
387 ExtractJsonObjects(optimizeIndex, optimization, optimizeObject, descendantsMap);
388 }
389
390 JsonChildObject loadedNetworkObject{ "loaded_network_measurements" };
391
392 for (unsigned int loadedNetworkIndex = 0; loadedNetworkIndex < loadedNetworks.size(); ++loadedNetworkIndex)
393 {
394 auto loadedNetwork = loadedNetworks[loadedNetworkIndex];
395 ExtractJsonObjects(loadedNetworkIndex, loadedNetwork, loadedNetworkObject, descendantsMap);
396 }
397
Keith Davis5a64f222021-08-04 10:35:20 +0100398 JsonChildObject inferenceObject{ "inference_measurements" };
telsoa01c577f2c2018-08-31 09:22:23 +0100399
400 for (unsigned int inferenceIndex = 0; inferenceIndex < inferences.size(); ++inferenceIndex)
401 {
402 auto inference = inferences[inferenceIndex];
Derek Lamberti6b4dfc22019-08-07 17:01:57 +0100403 ExtractJsonObjects(inferenceIndex, inference, inferenceObject, descendantsMap);
telsoa01c577f2c2018-08-31 09:22:23 +0100404 }
405
telsoa01c577f2c2018-08-31 09:22:23 +0100406 printer.PrintHeader();
407 printer.PrintArmNNHeader();
408
Keith Davis4914d0c2021-08-18 17:14:05 +0100409 if (m_ProfilingDetails.get()->DetailsExist() &&
410 (m_DetailsToStdOutMethod == ProfilingDetailsMethod::DetailsOnly
411 || m_DetailsToStdOutMethod == ProfilingDetailsMethod::DetailsWithEvents))
Keith Davis554fa092021-07-20 11:25:22 +0100412 {
Keith Davis5a64f222021-08-04 10:35:20 +0100413 JsonChildObject detailsObject{ "layer_details" };
Keith Davisec22ad22021-10-22 14:17:19 +0100414 if (m_DetailsToStdOutMethod == ProfilingDetailsMethod::DetailsOnly)
415 {
416 detailsObject.EnableDetailsOnly();
417 }
418 detailsObject.SetType(JsonObjectType::ExecObjectDesc);
419 detailsObject.SetAndParseDetails(m_ProfilingDetails.get()->GetProfilingDetails());
Keith Davis554fa092021-07-20 11:25:22 +0100420
Keith Davis5a64f222021-08-04 10:35:20 +0100421 size_t id = 0;
Keith Davis554fa092021-07-20 11:25:22 +0100422 printer.PrintJsonChildObject(detailsObject, id);
423 }
424
telsoa01c577f2c2018-08-31 09:22:23 +0100425 // print inference object, also prints child layer and kernel measurements
Keith Davis5a64f222021-08-04 10:35:20 +0100426 size_t id = 0;
Keith Davis4914d0c2021-08-18 17:14:05 +0100427 if (m_DetailsToStdOutMethod != ProfilingDetailsMethod::DetailsOnly)
428 {
Kevin May4692e112021-10-18 14:41:50 +0100429 printer.PrintJsonChildObject(optimizeObject, id);
430 printer.PrintSeparator();
431 printer.PrintNewLine();
432 printer.PrintJsonChildObject(loadedNetworkObject, id);
433 printer.PrintSeparator();
434 printer.PrintNewLine();
Keith Davis4914d0c2021-08-18 17:14:05 +0100435 printer.PrintJsonChildObject(inferenceObject, id);
Keith Davisec22ad22021-10-22 14:17:19 +0100436 printer.PrintNewLine();
Keith Davis4914d0c2021-08-18 17:14:05 +0100437 }
telsoa01c577f2c2018-08-31 09:22:23 +0100438 // end of ArmNN
telsoa01c577f2c2018-08-31 09:22:23 +0100439 printer.PrintFooter();
440
441 // end of main JSON object
442 printer.PrintNewLine();
443 printer.PrintFooter();
444 printer.PrintNewLine();
445
446 // Restores previous precision settings.
447 outStream.flags(oldFlags);
448 outStream.precision(oldPrecision);
Keith Davis4914d0c2021-08-18 17:14:05 +0100449
450 if (m_DetailsToStdOutMethod == ProfilingDetailsMethod::DetailsOnly)
451 {
452 exit(0);
453 }
telsoa014fcda012018-03-09 14:13:49 +0000454}
455
Francis Murtagh33199c22021-02-15 10:11:28 +0000456void ProfilerImpl::AnalyzeEventsAndWriteResults(std::ostream& outStream) const
telsoa014fcda012018-03-09 14:13:49 +0000457{
458 // Stack should be empty now.
telsoa01c577f2c2018-08-31 09:22:23 +0100459 const bool saneMarkerSequence = m_Parents.empty();
telsoa014fcda012018-03-09 14:13:49 +0000460
461 // Abort if the sequence of markers was found to have incorrect information:
462 // The stats cannot be trusted.
463 if (!saneMarkerSequence)
464 {
465 outStream << "Cannot write profiling stats. "
Keith Davis5a64f222021-08-04 10:35:20 +0100466 "Unexpected errors were found when analyzing the sequence of logged events, "
467 "which may lead to plainly wrong stats. The profiling system may contain implementation "
468 "issues or could have been used in an unsafe manner." << std::endl;
telsoa014fcda012018-03-09 14:13:49 +0000469 return;
470 }
471
telsoa01c577f2c2018-08-31 09:22:23 +0100472 // Analyzes the full sequence of events.
473 AnalyzeEventSequenceAndWriteResults(m_EventSequence.cbegin(),
474 m_EventSequence.cend(),
475 outStream);
telsoa014fcda012018-03-09 14:13:49 +0000476
telsoa01c577f2c2018-08-31 09:22:23 +0100477 // Aggregates events by tag if requested (spams the output stream if done for all tags).
478 if (g_AggregateProfilingEventsByInference)
telsoa014fcda012018-03-09 14:13:49 +0000479 {
480 outStream << std::endl;
481 outStream << "***" << std::endl;
telsoa01c577f2c2018-08-31 09:22:23 +0100482 outStream << "*** Per Inference Stats" << std::endl;
telsoa014fcda012018-03-09 14:13:49 +0000483 outStream << "***" << std::endl;
484 outStream << std::endl;
485
telsoa01c577f2c2018-08-31 09:22:23 +0100486 int baseLevel = -1;
487 std::vector<const Event*> inferences;
Kevin May4692e112021-10-18 14:41:50 +0100488 PopulateParent(inferences, baseLevel, "EnqueueWorkload");
telsoa014fcda012018-03-09 14:13:49 +0000489
telsoa01c577f2c2018-08-31 09:22:23 +0100490 // Second map out descendants hierarchy
491 std::map<const Event*, std::vector<const Event*>> descendantsMap;
492 PopulateDescendants(descendantsMap);
493
Keith Davis5a64f222021-08-04 10:35:20 +0100494 std::function<void(const Event*, std::vector<const Event*>&)>
495 FindDescendantEvents = [&](const Event* eventPtr, std::vector<const Event*>& sequence)
telsoa014fcda012018-03-09 14:13:49 +0000496 {
telsoa01c577f2c2018-08-31 09:22:23 +0100497 sequence.push_back(eventPtr);
498
499 if (CalcLevel(eventPtr) > baseLevel+2) //We only care about levels as deep as workload executions.
telsoa014fcda012018-03-09 14:13:49 +0000500 {
telsoa01c577f2c2018-08-31 09:22:23 +0100501 return;
telsoa014fcda012018-03-09 14:13:49 +0000502 }
telsoa014fcda012018-03-09 14:13:49 +0000503
telsoa01c577f2c2018-08-31 09:22:23 +0100504 auto children = descendantsMap.find(eventPtr);
505 if (children == descendantsMap.end())
506 {
507 return;
508 }
telsoa014fcda012018-03-09 14:13:49 +0000509
Sadik Armagan689c96c2021-02-16 10:44:05 +0000510 if (!(children->second.empty()))
telsoa01c577f2c2018-08-31 09:22:23 +0100511 {
Sadik Armagan689c96c2021-02-16 10:44:05 +0000512 return FindDescendantEvents(children->second[0], sequence);
telsoa01c577f2c2018-08-31 09:22:23 +0100513 }
514 };
515
516 // Third, find events belonging to each inference
517 int inferenceIdx = 0;
518 for (auto inference : inferences)
519 {
520 std::vector<const Event*> sequence;
521
522 //build sequence, depth first
523 FindDescendantEvents(inference, sequence);
524
525 outStream << "> Begin Inference: " << inferenceIdx << std::endl;
526 outStream << std::endl;
527 AnalyzeEventSequenceAndWriteResults(sequence.cbegin(),
528 sequence.cend(),
529 outStream);
530 outStream << std::endl;
531 outStream << "> End Inference: " << inferenceIdx << std::endl;
532
533 inferenceIdx++;
telsoa014fcda012018-03-09 14:13:49 +0000534 }
535 }
536}
537
Francis Murtagh33199c22021-02-15 10:11:28 +0000538std::uint32_t ProfilerImpl::GetEventColor(const BackendId& backendId) const
telsoa014fcda012018-03-09 14:13:49 +0000539{
Matthew Bentham1b63d6c2019-04-05 09:35:15 +0100540 static BackendId cpuRef("CpuRef");
541 static BackendId cpuAcc("CpuAcc");
542 static BackendId gpuAcc("GpuAcc");
Keith Davis5a64f222021-08-04 10:35:20 +0100543 if (backendId == cpuRef)
544 {
545 // Cyan
546 return 0xffff001b;
547 }
548 else if (backendId == cpuAcc)
549 {
550 // Green
551 return 0x00ff001b;
552 }
553 else if (backendId == gpuAcc)
554 {
555 // Purple
556 return 0xff007f1b;
557 }
558 else
559 {
560 // Dark gray
561 return 0x5555551b;
telsoa014fcda012018-03-09 14:13:49 +0000562 }
563}
564
telsoa01c577f2c2018-08-31 09:22:23 +0100565// The thread_local pointer to the profiler instance.
Francis Murtagh33199c22021-02-15 10:11:28 +0000566thread_local IProfiler* tl_Profiler = nullptr;
567
telsoa01c577f2c2018-08-31 09:22:23 +0100568ProfilerManager& ProfilerManager::GetInstance()
569{
570 // Global reference to the single ProfileManager instance allowed.
571 static ProfilerManager s_ProfilerManager;
572 return s_ProfilerManager;
573}
574
Francis Murtagh33199c22021-02-15 10:11:28 +0000575void ProfilerManager::RegisterProfiler(IProfiler* profiler)
telsoa01c577f2c2018-08-31 09:22:23 +0100576{
577 tl_Profiler = profiler;
578}
579
Francis Murtagh33199c22021-02-15 10:11:28 +0000580IProfiler* ProfilerManager::GetProfiler()
telsoa01c577f2c2018-08-31 09:22:23 +0100581{
582 return tl_Profiler;
583}
584
Francis Murtagh33199c22021-02-15 10:11:28 +0000585void IProfiler::EnableProfiling(bool enableProfiling)
586{
587 pProfilerImpl->EnableProfiling(enableProfiling);
588}
589
Keith Davis4914d0c2021-08-18 17:14:05 +0100590void IProfiler::EnableNetworkDetailsToStdOut(ProfilingDetailsMethod detailsMethod)
Keith Davisf4874862021-08-09 16:49:18 +0100591{
Keith Davis4914d0c2021-08-18 17:14:05 +0100592 pProfilerImpl->EnableNetworkDetailsToStdOut(detailsMethod);
Keith Davisf4874862021-08-09 16:49:18 +0100593}
594
Francis Murtagh33199c22021-02-15 10:11:28 +0000595bool IProfiler::IsProfilingEnabled()
596{
597 return pProfilerImpl->IsProfilingEnabled();
598}
599
600void IProfiler::AnalyzeEventsAndWriteResults(std::ostream& outStream) const
601{
602 pProfilerImpl->AnalyzeEventsAndWriteResults(outStream);
603}
604
605void IProfiler::Print(std::ostream& outStream) const
606{
607 pProfilerImpl->Print(outStream);
608}
609
610Event* IProfiler::BeginEvent(const BackendId& backendId,
Keith Davis554fa092021-07-20 11:25:22 +0100611 const std::string& label,
Keith Davis5a64f222021-08-04 10:35:20 +0100612 std::vector<InstrumentPtr>&& instruments,
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000613 const Optional<arm::pipe::ProfilingGuid>& guid)
Francis Murtagh33199c22021-02-15 10:11:28 +0000614{
Keith Davis5a64f222021-08-04 10:35:20 +0100615 return pProfilerImpl->BeginEvent(this, backendId, label, std::move(instruments), guid);
Francis Murtagh33199c22021-02-15 10:11:28 +0000616}
617
618IProfiler::~IProfiler() = default;
Keith Davis5a64f222021-08-04 10:35:20 +0100619IProfiler::IProfiler() : pProfilerImpl(new ProfilerImpl())
620{};
Francis Murtagh33199c22021-02-15 10:11:28 +0000621
telsoa014fcda012018-03-09 14:13:49 +0000622} // namespace armnn