summaryrefslogtreecommitdiff
path: root/source/application/main/Profiler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'source/application/main/Profiler.cc')
-rw-r--r--source/application/main/Profiler.cc219
1 files changed, 219 insertions, 0 deletions
diff --git a/source/application/main/Profiler.cc b/source/application/main/Profiler.cc
new file mode 100644
index 0000000..f364759
--- /dev/null
+++ b/source/application/main/Profiler.cc
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2021 Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "Profiler.hpp"
+
+#include <cstring>
+#include <string>
+#include <sstream>
+
+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)
+ {
+ if (platform && platform->inited) {
+ this->_m_pPlatform = platform;
+ this->Reset();
+ } else {
+ printf_err("Profiler %s initialised with invalid platform\n",
+ this->_m_name.c_str());
+ }
+ }
+
+ bool Profiler::StartProfiling(const char* name)
+ {
+ if (name) {
+ this->SetName(name);
+ }
+ if (this->_m_pPlatform && !this->_m_started) {
+ this->_m_pPlatform->timer->reset();
+ this->_m_tstampSt = this->_m_pPlatform->timer->start_profiling();
+ this->_m_started = true;
+ return true;
+ }
+ printf_err("Failed to start profiler %s\n", this->_m_name.c_str());
+ return false;
+ }
+
+ bool Profiler::StopProfiling()
+ {
+ if (this->_m_pPlatform && this->_m_started) {
+ this->_m_tstampEnd = this->_m_pPlatform->timer->stop_profiling();
+ this->_m_started = false;
+
+ this->_AddProfilingUnit(this->_m_tstampSt, this->_m_tstampEnd, this->_m_name);
+
+ return true;
+ }
+ printf_err("Failed to stop profiler %s\n", this->_m_name.c_str());
+ return false;
+ }
+
+ bool Profiler::StopProfilingAndReset()
+ {
+ if (this->StopProfiling()) {
+ this->Reset();
+ return true;
+ }
+ printf_err("Failed to stop profiler %s\n", this->_m_name.c_str());
+ return false;
+ }
+
+ void Profiler::Reset()
+ {
+ this->_m_started = false;
+ memset(&this->_m_tstampSt, 0, sizeof(this->_m_tstampSt));
+ memset(&this->_m_tstampEnd, 0, sizeof(this->_m_tstampEnd));
+ }
+
+ std::string Profiler::GetResultsAndReset()
+ {
+ std::ostringstream strResults;
+
+ 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;
+
+ 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;
+
+ if (samplesNum > 1) {
+ strResults << "\tSamples: " << samplesNum << std::endl;
+ strResults << "\t Total / Avg./ Min / Max"
+ << std::endl;
+
+ writeStatLine<uint64_t>(strResults, "Active NPU cycles: ",
+ totalActiveNpuCycles, samplesNum,
+ minActiveNpuCycles, maxActiveNpuCycles);
+
+ writeStatLine<uint64_t>(strResults, "Idle NPU cycles: ",
+ (totalNpuCycles - totalActiveNpuCycles),
+ samplesNum, minIdleNpuCycles, maxIdleNpuCycles);
+
+#if defined(CPU_PROFILE_ENABLED)
+ writeStatLine<uint64_t>(strResults, "Active CPU cycles (approx): ",
+ (totalCpuCycles - totalActiveNpuCycles),
+ samplesNum, minActiveCpuCycles,
+ maxActiveCpuCycles);
+
+ 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;
+#if defined(CPU_PROFILE_ENABLED)
+ strResults << "\tActive CPU cycles: "
+ << (totalCpuCycles - totalActiveNpuCycles)
+ << " (approx)" << std::endl;
+
+ strResults << "\tTime in ms: " << totalTimeMs << std::endl;
+#endif
+ }
+ }
+ this->Reset();
+ return strResults.str();
+ }
+
+ void Profiler::SetName(const char* str)
+ {
+ this->_m_name = std::string(str);
+ }
+
+ void Profiler::_AddProfilingUnit(time_counter start, time_counter end,
+ const std::string& name)
+ {
+ platform_timer * timer = this->_m_pPlatform->timer;
+
+ struct ProfilingUnit unit;
+
+ if (timer->cap.npu_cycles && timer->get_npu_total_cycle_diff &&
+ timer->get_npu_active_cycle_diff)
+ {
+ unit.npuCycles = timer->get_npu_total_cycle_diff(&start, &end);
+ unit.activeNpuCycles = timer->get_npu_active_cycle_diff(&start, &end);
+ }
+
+ if (timer->cap.cpu_cycles && timer->get_cpu_cycle_diff) {
+ unit.cpuCycles = timer->get_cpu_cycle_diff(&start, &end);
+ }
+
+ if (timer->cap.duration_ms && timer->get_duration_ms) {
+ unit.time = timer->get_duration_ms(&start, &end);
+ }
+
+ this->_m_series[name].emplace_back(unit);
+ }
+
+} /* namespace app */
+} /* namespace arm */ \ No newline at end of file