blob: e7168e43f63e8ab72f9d98ff49f5095d570495d4 [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001/*
Isabella Gottardic64f5062022-01-21 15:27:13 +00002 * Copyright (c) 2022 Arm Limited. All rights reserved.
alexander3c798932021-03-26 21:42:19 +00003 * 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"
alexander31ae9f02022-02-10 16:15:54 +000018#include "log_macros.h"
alexander3c798932021-03-26 21:42:19 +000019
20#include <cstring>
alexander3c798932021-03-26 21:42:19 +000021
22namespace arm {
23namespace app {
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010024 Profiler::Profiler()
25 : Profiler("Unknown")
26 {}
27
28 Profiler::Profiler(const char* name)
29 : m_name(name)
30 {}
alexander3c798932021-03-26 21:42:19 +000031
32 bool Profiler::StartProfiling(const char* name)
33 {
34 if (name) {
35 this->SetName(name);
36 }
Richard Burton2c2cacd2022-05-13 09:46:57 +010037
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010038 if (!this->m_started) {
39 hal_pmu_reset();
40 this->m_tstampSt.initialised = false;
41 hal_pmu_get_counters(&this->m_tstampSt);
42 if (this->m_tstampSt.initialised) {
Richard Burton2c2cacd2022-05-13 09:46:57 +010043 if (this->m_profStats.count(this->m_name) == 0) {
44 this->m_profStats.insert(
45 std::pair<std::string, std::vector<Statistics>>(
46 this->m_name, std::vector<Statistics>(this->m_tstampSt.num_counters))
47 );
48 }
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010049 this->m_started = true;
50 return true;
51 }
alexander3c798932021-03-26 21:42:19 +000052 }
Isabella Gottardi56ee6202021-05-12 08:27:15 +010053 printf_err("Failed to start profiler %s\n", this->m_name.c_str());
alexander3c798932021-03-26 21:42:19 +000054 return false;
55 }
56
57 bool Profiler::StopProfiling()
58 {
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010059 if (this->m_started) {
60 this->m_tstampEnd.initialised = false;
61 hal_pmu_get_counters(&this->m_tstampEnd);
Isabella Gottardi56ee6202021-05-12 08:27:15 +010062 this->m_started = false;
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010063 if (this->m_tstampEnd.initialised) {
Richard Burton2c2cacd2022-05-13 09:46:57 +010064 this->UpdateRunningStats(
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010065 this->m_tstampSt,
66 this->m_tstampEnd,
67 this->m_name);
68 return true;
69 }
alexander3c798932021-03-26 21:42:19 +000070 }
Isabella Gottardi56ee6202021-05-12 08:27:15 +010071 printf_err("Failed to stop profiler %s\n", this->m_name.c_str());
alexander3c798932021-03-26 21:42:19 +000072 return false;
73 }
74
75 bool Profiler::StopProfilingAndReset()
76 {
77 if (this->StopProfiling()) {
78 this->Reset();
79 return true;
80 }
Isabella Gottardi56ee6202021-05-12 08:27:15 +010081 printf_err("Failed to stop profiler %s\n", this->m_name.c_str());
alexander3c798932021-03-26 21:42:19 +000082 return false;
83 }
84
85 void Profiler::Reset()
86 {
Isabella Gottardi56ee6202021-05-12 08:27:15 +010087 this->m_started = false;
Richard Burton2c2cacd2022-05-13 09:46:57 +010088 this->m_profStats.clear();
Isabella Gottardi56ee6202021-05-12 08:27:15 +010089 memset(&this->m_tstampSt, 0, sizeof(this->m_tstampSt));
90 memset(&this->m_tstampEnd, 0, sizeof(this->m_tstampEnd));
alexander3c798932021-03-26 21:42:19 +000091 }
92
Isabella Gottardi8df12f32021-04-07 17:15:31 +010093 void calcProfilingStat(uint64_t currentValue,
Richard Burton2c2cacd2022-05-13 09:46:57 +010094 Statistics& data)
alexander3c798932021-03-26 21:42:19 +000095 {
Isabella Gottardi8df12f32021-04-07 17:15:31 +010096 data.total += currentValue;
97 data.min = std::min(data.min, currentValue);
98 data.max = std::max(data.max, currentValue);
Richard Burton2c2cacd2022-05-13 09:46:57 +010099 data.avrg = (static_cast<double>(data.total) / data.samplesNum);
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100100 }
alexander3c798932021-03-26 21:42:19 +0000101
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100102 void Profiler::GetAllResultsAndReset(std::vector<ProfileResult>& results)
103 {
Richard Burton2c2cacd2022-05-13 09:46:57 +0100104 for (const auto& item: this->m_profStats) {
alexander3c798932021-03-26 21:42:19 +0000105 auto name = item.first;
Richard Burton2c2cacd2022-05-13 09:46:57 +0100106 std::vector<Statistics> series = item.second;
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100107 ProfileResult result{};
108 result.name = item.first;
alexander3c798932021-03-26 21:42:19 +0000109
Richard Burton2c2cacd2022-05-13 09:46:57 +0100110 for (Statistics& stat : series) {
111 result.samplesNum = stat.samplesNum;
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100112 result.data.emplace_back(stat);
113 }
114
115 results.emplace_back(result);
alexander3c798932021-03-26 21:42:19 +0000116 }
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100117
alexander3c798932021-03-26 21:42:19 +0000118 this->Reset();
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100119 }
120
121 void printStatisticsHeader(uint32_t samplesNum) {
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100122 info("Number of samples: %" PRIu32 "\n", samplesNum);
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100123 info("%s\n", "Total / Avg./ Min / Max");
124 }
125
126 void Profiler::PrintProfilingResult(bool printFullStat) {
127 std::vector<ProfileResult> results{};
128 GetAllResultsAndReset(results);
129 for(ProfileResult& result: results) {
Richard Burton2c2cacd2022-05-13 09:46:57 +0100130 if (!result.data.empty()) {
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100131 info("Profile for %s:\n", result.name.c_str());
132 if (printFullStat) {
133 printStatisticsHeader(result.samplesNum);
134 }
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100135 }
136
137 for (Statistics &stat: result.data) {
138 if (printFullStat) {
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100139 info("%s %s: %" PRIu64 "/ %.0f / %" PRIu64 " / %" PRIu64 " \n",
140 stat.name.c_str(), stat.unit.c_str(),
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100141 stat.total, stat.avrg, stat.min, stat.max);
142 } else {
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100143 info("%s: %.0f %s\n", stat.name.c_str(), stat.avrg, stat.unit.c_str());
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100144 }
145 }
146 }
alexander3c798932021-03-26 21:42:19 +0000147 }
148
149 void Profiler::SetName(const char* str)
150 {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100151 this->m_name = std::string(str);
alexander3c798932021-03-26 21:42:19 +0000152 }
153
Richard Burton2c2cacd2022-05-13 09:46:57 +0100154 void Profiler::UpdateRunningStats(pmu_counters start, pmu_counters end,
155 const std::string& name)
alexander3c798932021-03-26 21:42:19 +0000156 {
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100157 struct ProfilingUnit unit = {
158 .counters = end
159 };
alexander3c798932021-03-26 21:42:19 +0000160
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100161 if (end.num_counters != start.num_counters ||
Richard Burton2c2cacd2022-05-13 09:46:57 +0100162 !end.initialised || !start.initialised) {
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100163 printf_err("Invalid start or end counters\n");
164 return;
165 }
alexander3c798932021-03-26 21:42:19 +0000166
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100167 for (size_t i = 0; i < unit.counters.num_counters; ++i) {
168 if (unit.counters.counters[i].value < start.counters[i].value) {
169 warn("Overflow detected for %s\n", unit.counters.counters[i].name);
170 unit.counters.counters[i].value = 0;
171 } else {
172 unit.counters.counters[i].value -= start.counters[i].value;
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100173 }
alexander3c798932021-03-26 21:42:19 +0000174 }
175
Richard Burton2c2cacd2022-05-13 09:46:57 +0100176 for (size_t i = 0; i < this->m_profStats[name].size(); ++i) {
177 this->m_profStats[name][i].name = unit.counters.counters[i].name;
178 this->m_profStats[name][i].unit = unit.counters.counters[i].unit;
179 ++this->m_profStats[name][i].samplesNum;
180 calcProfilingStat(
181 unit.counters.counters[i].value,
182 this->m_profStats[name][i]);
183 }
184
185 ProfileResult result{};
186 result.name = this->m_name;
187 result.samplesNum = this->m_profStats[name][0].samplesNum;
188
189 for (Statistics& stat : this->m_profStats[name]) {
190 result.data.emplace_back(stat);
191 }
alexander3c798932021-03-26 21:42:19 +0000192 }
193
194} /* namespace app */
Kshitij Sisodia14ab8d42021-10-22 17:35:01 +0100195} /* namespace arm */