blob: 10a828af40dcbc0a95c713b8bcb1df77f821b043 [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001/*
2 * Copyright (c) 2021 Arm Limited. All rights reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17#include "Profiler.hpp"
18
19#include <cstring>
Isabella Gottardi8df12f32021-04-07 17:15:31 +010020#include <iomanip>
alexander3c798932021-03-26 21:42:19 +000021
22namespace arm {
23namespace app {
alexander3c798932021-03-26 21:42:19 +000024 Profiler::Profiler(hal_platform* platform, const char* name = "Unknown")
25 : _m_name(name)
26 {
27 if (platform && platform->inited) {
28 this->_m_pPlatform = platform;
29 this->Reset();
30 } else {
31 printf_err("Profiler %s initialised with invalid platform\n",
32 this->_m_name.c_str());
33 }
34 }
35
36 bool Profiler::StartProfiling(const char* name)
37 {
38 if (name) {
39 this->SetName(name);
40 }
41 if (this->_m_pPlatform && !this->_m_started) {
42 this->_m_pPlatform->timer->reset();
43 this->_m_tstampSt = this->_m_pPlatform->timer->start_profiling();
44 this->_m_started = true;
45 return true;
46 }
47 printf_err("Failed to start profiler %s\n", this->_m_name.c_str());
48 return false;
49 }
50
51 bool Profiler::StopProfiling()
52 {
53 if (this->_m_pPlatform && this->_m_started) {
54 this->_m_tstampEnd = this->_m_pPlatform->timer->stop_profiling();
55 this->_m_started = false;
56
alexanderc350cdc2021-04-29 20:36:09 +010057 this->AddProfilingUnit(this->_m_tstampSt, this->_m_tstampEnd, this->_m_name);
alexander3c798932021-03-26 21:42:19 +000058
59 return true;
60 }
61 printf_err("Failed to stop profiler %s\n", this->_m_name.c_str());
62 return false;
63 }
64
65 bool Profiler::StopProfilingAndReset()
66 {
67 if (this->StopProfiling()) {
68 this->Reset();
69 return true;
70 }
71 printf_err("Failed to stop profiler %s\n", this->_m_name.c_str());
72 return false;
73 }
74
75 void Profiler::Reset()
76 {
77 this->_m_started = false;
Isabella Gottardi8df12f32021-04-07 17:15:31 +010078 this->_m_series.clear();
alexander3c798932021-03-26 21:42:19 +000079 memset(&this->_m_tstampSt, 0, sizeof(this->_m_tstampSt));
80 memset(&this->_m_tstampEnd, 0, sizeof(this->_m_tstampEnd));
81 }
82
Isabella Gottardi8df12f32021-04-07 17:15:31 +010083 void calcProfilingStat(uint64_t currentValue,
84 Statistics& data,
85 uint32_t samples)
alexander3c798932021-03-26 21:42:19 +000086 {
Isabella Gottardi8df12f32021-04-07 17:15:31 +010087 data.total += currentValue;
88 data.min = std::min(data.min, currentValue);
89 data.max = std::max(data.max, currentValue);
90 data.avrg = ((double)data.total / samples);
91 }
alexander3c798932021-03-26 21:42:19 +000092
Isabella Gottardi8df12f32021-04-07 17:15:31 +010093 void Profiler::GetAllResultsAndReset(std::vector<ProfileResult>& results)
94 {
alexander3c798932021-03-26 21:42:19 +000095 for (const auto& item: this->_m_series) {
96 auto name = item.first;
97 ProfilingSeries series = item.second;
Isabella Gottardi8df12f32021-04-07 17:15:31 +010098 ProfileResult result{};
99 result.name = item.first;
100 result.samplesNum = series.size();
alexander3c798932021-03-26 21:42:19 +0000101
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100102 Statistics AXI0_RD {
103 .name = "NPU AXI0_RD_DATA_BEAT_RECEIVED",
alexanderdc8f3c82021-04-14 16:19:07 +0100104 .unit = "beats",
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100105 .total = 0,
106 .avrg = 0.0,
107 .min = series[0].axi0writes,
108 .max = 0
109 };
110 Statistics AXI0_WR {
111 .name = "NPU AXI0_WR_DATA_BEAT_WRITTEN",
alexanderdc8f3c82021-04-14 16:19:07 +0100112 .unit = "beats",
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100113 .total = 0,
114 .avrg = 0.0,
115 .min = series[0].axi0reads,
116 .max = 0
117 };
118 Statistics AXI1_RD {
119 .name = "NPU AXI1_RD_DATA_BEAT_RECEIVED",
alexanderdc8f3c82021-04-14 16:19:07 +0100120 .unit = "beats",
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100121 .total = 0,
122 .avrg = 0.0,
123 .min = series[0].axi1reads,
124 .max = 0
125 };
126 Statistics NPU_ACTIVE {
127 .name = "NPU ACTIVE",
128 .unit = "cycles",
129 .total = 0,
130 .avrg = 0.0,
131 .min = series[0].activeNpuCycles,
132 .max = 0
133 };
134 Statistics NPU_IDLE {
135 .name = "NPU IDLE",
136 .unit = "cycles",
137 .total = 0,
138 .avrg = 0.0,
139 .min = series[0].idleNpuCycles,
140 .max = 0
141 };
142 Statistics NPU_Total {
143 .name = "NPU total",
144 .unit = "cycles",
145 .total = 0,
146 .avrg = 0.0,
147 .min = series[0].npuCycles,
148 .max = 0,
149 };
150#if defined(CPU_PROFILE_ENABLED)
151 Statistics CPU_ACTIVE {
152 .name = "CPU ACTIVE",
153 .unit = "cycles (approx)",
154 .total = 0,
155 .avrg = 0.0,
156 .min = series[0].cpuCycles - NPU_ACTIVE.min,
157 .max = 0
158 };
159 Statistics TIME {
160 .name = "Time",
161 .unit = "ms",
162 .total = 0,
163 .avrg = 0.0,
164 .min = static_cast<uint64_t>(series[0].time),
165 .max = 0
166 };
167#endif
alexander3c798932021-03-26 21:42:19 +0000168 for(ProfilingUnit& unit: series){
alexander3c798932021-03-26 21:42:19 +0000169
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100170 calcProfilingStat(unit.npuCycles,
171 NPU_Total, result.samplesNum);
alexander3c798932021-03-26 21:42:19 +0000172
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100173 calcProfilingStat(unit.activeNpuCycles,
174 NPU_ACTIVE, result.samplesNum);
alexander3c798932021-03-26 21:42:19 +0000175
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100176 calcProfilingStat(unit.idleNpuCycles,
177 NPU_IDLE, result.samplesNum);
alexander3c798932021-03-26 21:42:19 +0000178
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100179 calcProfilingStat(unit.axi0writes,
180 AXI0_WR, result.samplesNum);
alexander3c798932021-03-26 21:42:19 +0000181
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100182 calcProfilingStat(unit.axi0reads,
183 AXI0_RD, result.samplesNum);
alexander3c798932021-03-26 21:42:19 +0000184
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100185 calcProfilingStat(unit.axi1reads,
186 AXI1_RD, result.samplesNum);
alexander3c798932021-03-26 21:42:19 +0000187#if defined(CPU_PROFILE_ENABLED)
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100188 calcProfilingStat(static_cast<uint64_t>(unit.time),
189 TIME, result.samplesNum);
alexander3c798932021-03-26 21:42:19 +0000190
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100191 calcProfilingStat(unit.cpuCycles - unit.activeNpuCycles,
192 CPU_ACTIVE, result.samplesNum);
alexander3c798932021-03-26 21:42:19 +0000193#endif
194 }
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100195 result.data.emplace_back(AXI0_RD);
196 result.data.emplace_back(AXI0_WR);
197 result.data.emplace_back(AXI1_RD);
198 result.data.emplace_back(NPU_ACTIVE);
199 result.data.emplace_back(NPU_IDLE);
200 result.data.emplace_back(NPU_Total);
201#if defined(CPU_PROFILE_ENABLED)
202 result.data.emplace_back(CPU_ACTIVE);
203 result.data.emplace_back(TIME);
204#endif
205 results.emplace_back(result);
alexander3c798932021-03-26 21:42:19 +0000206 }
207 this->Reset();
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100208 }
209
210 void printStatisticsHeader(uint32_t samplesNum) {
211 info("Number of samples: %i\n", samplesNum);
212 info("%s\n", "Total / Avg./ Min / Max");
213 }
214
215 void Profiler::PrintProfilingResult(bool printFullStat) {
216 std::vector<ProfileResult> results{};
217 GetAllResultsAndReset(results);
218 for(ProfileResult& result: results) {
219 info("Profile for %s:\n", result.name.c_str());
220
221 if (printFullStat) {
222 printStatisticsHeader(result.samplesNum);
223 }
224
225 for (Statistics &stat: result.data) {
226 if (printFullStat) {
227 info("%s %s: %llu / %.0f / %llu / %llu \n", stat.name.c_str(), stat.unit.c_str(),
228 stat.total, stat.avrg, stat.min, stat.max);
229 } else {
230 info("%s %s: %.0f\n", stat.name.c_str(), stat.unit.c_str(), stat.avrg);
231 }
232 }
233 }
alexander3c798932021-03-26 21:42:19 +0000234 }
235
236 void Profiler::SetName(const char* str)
237 {
238 this->_m_name = std::string(str);
239 }
240
alexanderc350cdc2021-04-29 20:36:09 +0100241 void Profiler::AddProfilingUnit(time_counter start, time_counter end,
242 const std::string& name)
alexander3c798932021-03-26 21:42:19 +0000243 {
244 platform_timer * timer = this->_m_pPlatform->timer;
245
246 struct ProfilingUnit unit;
247
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100248 if (timer->cap.npu_cycles && timer->get_npu_cycles_diff)
alexander3c798932021-03-26 21:42:19 +0000249 {
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100250 const size_t size = 6;
251 uint64_t pmuCounters[size] = {0};
252 /* 6 values: total cc, active cc, idle cc, axi0 read, axi0 write, axi1 read*/
253 if (0 == timer->get_npu_cycles_diff(&start, &end, pmuCounters, size)) {
254 unit.npuCycles = pmuCounters[0];
255 unit.activeNpuCycles = pmuCounters[1];
256 unit.idleNpuCycles = pmuCounters[2];
257 unit.axi0reads = pmuCounters[3];
258 unit.axi0writes = pmuCounters[4];
259 unit.axi1reads = pmuCounters[5];
260 }
alexander3c798932021-03-26 21:42:19 +0000261 }
262
263 if (timer->cap.cpu_cycles && timer->get_cpu_cycle_diff) {
264 unit.cpuCycles = timer->get_cpu_cycle_diff(&start, &end);
265 }
266
267 if (timer->cap.duration_ms && timer->get_duration_ms) {
268 unit.time = timer->get_duration_ms(&start, &end);
269 }
270
271 this->_m_series[name].emplace_back(unit);
272 }
273
274} /* namespace app */
275} /* namespace arm */