diff options
author | Isabella Gottardi <isabella.gottardi@arm.com> | 2021-04-07 17:15:31 +0100 |
---|---|---|
committer | Alexander Efremov <alexander.efremov@arm.com> | 2021-04-12 14:00:49 +0000 |
commit | 8df12f37531d57a10cba2f8b2e8b6a9065202dd5 (patch) | |
tree | ba833d15649c3b0f885d57b40d3916970b3fd2c8 /source/application/main | |
parent | 37ce22ebc9cf3e8529d9914c0eed0f718243d961 (diff) | |
download | ml-embedded-evaluation-kit-8df12f37531d57a10cba2f8b2e8b6a9065202dd5.tar.gz |
MLECO-1870: Cherry pick profiling changes from dev to open source repo
* Documentation update
Change-Id: If85e7ebc44498840b291c408f14e66a5a5faa424
Signed-off-by: Isabella Gottardi <isabella.gottardi@arm.com>
Diffstat (limited to 'source/application/main')
-rw-r--r-- | source/application/main/Profiler.cc | 238 | ||||
-rw-r--r-- | source/application/main/UseCaseCommonUtils.cc | 9 | ||||
-rw-r--r-- | source/application/main/include/Profiler.hpp | 35 | ||||
-rw-r--r-- | source/application/main/include/UseCaseCommonUtils.hpp | 4 |
4 files changed, 181 insertions, 105 deletions
diff --git a/source/application/main/Profiler.cc b/source/application/main/Profiler.cc index f364759..ce59d9c 100644 --- a/source/application/main/Profiler.cc +++ b/source/application/main/Profiler.cc @@ -17,25 +17,10 @@ #include "Profiler.hpp" #include <cstring> -#include <string> -#include <sstream> +#include <iomanip> namespace arm { namespace app { - - template<class T> - static void writeStatLine(std::ostringstream& s, - const char* desc, - T total, - uint32_t samples, - T min, - T max) - { - s << "\t" << desc << total << " / " - << ((double)total / samples) << " / " - << min << " / " << max << std::endl; - } - Profiler::Profiler(hal_platform* platform, const char* name = "Unknown") : _m_name(name) { @@ -90,99 +75,162 @@ namespace app { void Profiler::Reset() { this->_m_started = false; + this->_m_series.clear(); memset(&this->_m_tstampSt, 0, sizeof(this->_m_tstampSt)); memset(&this->_m_tstampEnd, 0, sizeof(this->_m_tstampEnd)); } - std::string Profiler::GetResultsAndReset() + void calcProfilingStat(uint64_t currentValue, + Statistics& data, + uint32_t samples) { - std::ostringstream strResults; + data.total += currentValue; + data.min = std::min(data.min, currentValue); + data.max = std::max(data.max, currentValue); + data.avrg = ((double)data.total / samples); + } + void Profiler::GetAllResultsAndReset(std::vector<ProfileResult>& results) + { for (const auto& item: this->_m_series) { auto name = item.first; ProfilingSeries series = item.second; - - uint32_t samplesNum = series.size(); - - uint64_t totalNpuCycles = 0; /* Total NPU cycles (idle + active). */ - uint64_t totalActiveNpuCycles = 0; /* Active NPU cycles. */ - uint64_t totalCpuCycles = 0; /* Total CPU cycles. */ - time_t totalTimeMs = 0; - - uint64_t minActiveNpuCycles = series[0].activeNpuCycles; - uint64_t minIdleNpuCycles = series[0].npuCycles - minActiveNpuCycles; - uint64_t minActiveCpuCycles = series[0].cpuCycles - minActiveNpuCycles; - time_t minTimeMs = series[0].time; - - uint64_t maxIdleNpuCycles = 0; - uint64_t maxActiveNpuCycles = 0; - uint64_t maxActiveCpuCycles = 0; - time_t maxTimeMs = 0; - + ProfileResult result{}; + result.name = item.first; + result.samplesNum = series.size(); + + Statistics AXI0_RD { + .name = "NPU AXI0_RD_DATA_BEAT_RECEIVED", + .unit = "cycles", + .total = 0, + .avrg = 0.0, + .min = series[0].axi0writes, + .max = 0 + }; + Statistics AXI0_WR { + .name = "NPU AXI0_WR_DATA_BEAT_WRITTEN", + .unit = "cycles", + .total = 0, + .avrg = 0.0, + .min = series[0].axi0reads, + .max = 0 + }; + Statistics AXI1_RD { + .name = "NPU AXI1_RD_DATA_BEAT_RECEIVED", + .unit = "cycles", + .total = 0, + .avrg = 0.0, + .min = series[0].axi1reads, + .max = 0 + }; + Statistics NPU_ACTIVE { + .name = "NPU ACTIVE", + .unit = "cycles", + .total = 0, + .avrg = 0.0, + .min = series[0].activeNpuCycles, + .max = 0 + }; + Statistics NPU_IDLE { + .name = "NPU IDLE", + .unit = "cycles", + .total = 0, + .avrg = 0.0, + .min = series[0].idleNpuCycles, + .max = 0 + }; + Statistics NPU_Total { + .name = "NPU total", + .unit = "cycles", + .total = 0, + .avrg = 0.0, + .min = series[0].npuCycles, + .max = 0, + }; +#if defined(CPU_PROFILE_ENABLED) + Statistics CPU_ACTIVE { + .name = "CPU ACTIVE", + .unit = "cycles (approx)", + .total = 0, + .avrg = 0.0, + .min = series[0].cpuCycles - NPU_ACTIVE.min, + .max = 0 + }; + Statistics TIME { + .name = "Time", + .unit = "ms", + .total = 0, + .avrg = 0.0, + .min = static_cast<uint64_t>(series[0].time), + .max = 0 + }; +#endif for(ProfilingUnit& unit: series){ - totalNpuCycles += unit.npuCycles; - totalActiveNpuCycles += unit.activeNpuCycles; - totalCpuCycles += unit.cpuCycles; - totalTimeMs += unit.time; - - maxActiveNpuCycles = std::max(maxActiveNpuCycles, - unit.activeNpuCycles); - maxIdleNpuCycles = std::max(maxIdleNpuCycles, - unit.npuCycles - maxActiveNpuCycles); - maxActiveCpuCycles = std::max(maxActiveCpuCycles, - unit.cpuCycles - maxActiveNpuCycles); - maxTimeMs = std::max(maxTimeMs, unit.time); - - minActiveNpuCycles = std::min(minActiveNpuCycles, - unit.activeNpuCycles); - minIdleNpuCycles = std::min(minIdleNpuCycles, - unit.npuCycles - minActiveNpuCycles); - minActiveCpuCycles = std::min(minActiveCpuCycles, - unit.cpuCycles - minActiveNpuCycles); - minTimeMs = std::min(minTimeMs, unit.time); - } - strResults << "Profile for " << name << ": " << std::endl; + calcProfilingStat(unit.npuCycles, + NPU_Total, result.samplesNum); - if (samplesNum > 1) { - strResults << "\tSamples: " << samplesNum << std::endl; - strResults << "\t Total / Avg./ Min / Max" - << std::endl; + calcProfilingStat(unit.activeNpuCycles, + NPU_ACTIVE, result.samplesNum); - writeStatLine<uint64_t>(strResults, "Active NPU cycles: ", - totalActiveNpuCycles, samplesNum, - minActiveNpuCycles, maxActiveNpuCycles); + calcProfilingStat(unit.idleNpuCycles, + NPU_IDLE, result.samplesNum); - writeStatLine<uint64_t>(strResults, "Idle NPU cycles: ", - (totalNpuCycles - totalActiveNpuCycles), - samplesNum, minIdleNpuCycles, maxIdleNpuCycles); + calcProfilingStat(unit.axi0writes, + AXI0_WR, result.samplesNum); -#if defined(CPU_PROFILE_ENABLED) - writeStatLine<uint64_t>(strResults, "Active CPU cycles (approx): ", - (totalCpuCycles - totalActiveNpuCycles), - samplesNum, minActiveCpuCycles, - maxActiveCpuCycles); + calcProfilingStat(unit.axi0reads, + AXI0_RD, result.samplesNum); - writeStatLine<time_t>(strResults, "Time in ms: ", - totalTimeMs, samplesNum, minTimeMs, maxTimeMs); -#endif - } else { - strResults << "\tActive NPU cycles: " << totalActiveNpuCycles - << std::endl; - strResults << "\tIdle NPU cycles: " - << (totalNpuCycles - totalActiveNpuCycles) - << std::endl; + calcProfilingStat(unit.axi1reads, + AXI1_RD, result.samplesNum); #if defined(CPU_PROFILE_ENABLED) - strResults << "\tActive CPU cycles: " - << (totalCpuCycles - totalActiveNpuCycles) - << " (approx)" << std::endl; + calcProfilingStat(static_cast<uint64_t>(unit.time), + TIME, result.samplesNum); - strResults << "\tTime in ms: " << totalTimeMs << std::endl; + calcProfilingStat(unit.cpuCycles - unit.activeNpuCycles, + CPU_ACTIVE, result.samplesNum); #endif } + result.data.emplace_back(AXI0_RD); + result.data.emplace_back(AXI0_WR); + result.data.emplace_back(AXI1_RD); + result.data.emplace_back(NPU_ACTIVE); + result.data.emplace_back(NPU_IDLE); + result.data.emplace_back(NPU_Total); +#if defined(CPU_PROFILE_ENABLED) + result.data.emplace_back(CPU_ACTIVE); + result.data.emplace_back(TIME); +#endif + results.emplace_back(result); } this->Reset(); - return strResults.str(); + } + + void printStatisticsHeader(uint32_t samplesNum) { + info("Number of samples: %i\n", samplesNum); + info("%s\n", "Total / Avg./ Min / Max"); + } + + void Profiler::PrintProfilingResult(bool printFullStat) { + std::vector<ProfileResult> results{}; + GetAllResultsAndReset(results); + for(ProfileResult& result: results) { + info("Profile for %s:\n", result.name.c_str()); + + if (printFullStat) { + printStatisticsHeader(result.samplesNum); + } + + for (Statistics &stat: result.data) { + if (printFullStat) { + info("%s %s: %llu / %.0f / %llu / %llu \n", stat.name.c_str(), stat.unit.c_str(), + stat.total, stat.avrg, stat.min, stat.max); + } else { + info("%s %s: %.0f\n", stat.name.c_str(), stat.unit.c_str(), stat.avrg); + } + } + } } void Profiler::SetName(const char* str) @@ -197,11 +245,19 @@ namespace app { struct ProfilingUnit unit; - if (timer->cap.npu_cycles && timer->get_npu_total_cycle_diff && - timer->get_npu_active_cycle_diff) + if (timer->cap.npu_cycles && timer->get_npu_cycles_diff) { - unit.npuCycles = timer->get_npu_total_cycle_diff(&start, &end); - unit.activeNpuCycles = timer->get_npu_active_cycle_diff(&start, &end); + const size_t size = 6; + uint64_t pmuCounters[size] = {0}; + /* 6 values: total cc, active cc, idle cc, axi0 read, axi0 write, axi1 read*/ + if (0 == timer->get_npu_cycles_diff(&start, &end, pmuCounters, size)) { + unit.npuCycles = pmuCounters[0]; + unit.activeNpuCycles = pmuCounters[1]; + unit.idleNpuCycles = pmuCounters[2]; + unit.axi0reads = pmuCounters[3]; + unit.axi0writes = pmuCounters[4]; + unit.axi1reads = pmuCounters[5]; + } } if (timer->cap.cpu_cycles && timer->get_cpu_cycle_diff) { diff --git a/source/application/main/UseCaseCommonUtils.cc b/source/application/main/UseCaseCommonUtils.cc index 4ea5e4d..3acf53f 100644 --- a/source/application/main/UseCaseCommonUtils.cc +++ b/source/application/main/UseCaseCommonUtils.cc @@ -21,16 +21,11 @@ namespace arm { namespace app { - bool RunInference(hal_platform& platform, arm::app::Model& model) + bool RunInference(arm::app::Model& model, Profiler& profiler) { - Profiler profiler{&platform, "Inference"}; - profiler.StartProfiling(); - + profiler.StartProfiling("Inference"); bool runInf = model.RunInference(); - profiler.StopProfiling(); - std::string profileResults = profiler.GetResultsAndReset(); - info("%s\n", profileResults.c_str()); return runInf; } diff --git a/source/application/main/include/Profiler.hpp b/source/application/main/include/Profiler.hpp index b16a63b..d93b257 100644 --- a/source/application/main/include/Profiler.hpp +++ b/source/application/main/include/Profiler.hpp @@ -26,10 +26,31 @@ namespace arm { namespace app { + /** Statistics for a profiling metric. */ + struct Statistics { + std::string name; + std::string unit; + std::uint64_t total; + double avrg; + std::uint64_t min; + std::uint64_t max; + }; + + /** Profiling results with calculated statistics. */ + struct ProfileResult { + std::string name; + std::uint32_t samplesNum; + std::vector<Statistics> data; + }; + /** A single profiling unit definition. */ struct ProfilingUnit { uint64_t npuCycles = 0; uint64_t activeNpuCycles = 0; + uint64_t idleNpuCycles = 0; + uint64_t axi0writes = 0; + uint64_t axi0reads = 0; + uint64_t axi1reads = 0; uint64_t cpuCycles = 0; time_t time = 0; }; @@ -73,18 +94,22 @@ namespace app { void Reset(); /** - * @brief Gets the results as string and resets the profiler. - * @returns Result string. + * @brief Collects profiling results statistics and resets the profiler. + **/ + void GetAllResultsAndReset(std::vector<ProfileResult>& results); + + /** + * @brief Prints collected profiling results and resets the profiler. **/ - std::string GetResultsAndReset(); + void PrintProfilingResult(bool printFullStat = false); /** @brief Set the profiler name. */ void SetName(const char* str); private: ProfilingMap _m_series; /* Profiling series map. */ - time_counter _m_tstampSt; /* Container for a current starting timestamp. */ - time_counter _m_tstampEnd; /* Container for a current ending timestamp. */ + time_counter _m_tstampSt{}; /* Container for a current starting timestamp. */ + time_counter _m_tstampEnd{}; /* Container for a current ending timestamp. */ hal_platform * _m_pPlatform = nullptr; /* Platform pointer - to get the timer. */ bool _m_started = false; /* Indicates profiler has been started. */ diff --git a/source/application/main/include/UseCaseCommonUtils.hpp b/source/application/main/include/UseCaseCommonUtils.hpp index 02200e8..7887aea 100644 --- a/source/application/main/include/UseCaseCommonUtils.hpp +++ b/source/application/main/include/UseCaseCommonUtils.hpp @@ -38,11 +38,11 @@ namespace app { * @brief Run inference using given model * object. If profiling is enabled, it will log the * statistics too. - * @param[in] platform Reference to the hal platform object. * @param[in] model Reference to the initialised model. + * @param[in] profiler Reference to the initialised profiler. * @return true if inference succeeds, false otherwise. **/ - bool RunInference(hal_platform& platform, arm::app::Model& model); + bool RunInference(arm::app::Model& mode, Profiler& profiler); /** * @brief Read input and return as an integer. |