blob: 64edcf2ff3e56959606eebbc121524a3dc4d9ce1 [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 }
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010037 if (!this->m_started) {
38 hal_pmu_reset();
39 this->m_tstampSt.initialised = false;
40 hal_pmu_get_counters(&this->m_tstampSt);
41 if (this->m_tstampSt.initialised) {
42 this->m_started = true;
43 return true;
44 }
alexander3c798932021-03-26 21:42:19 +000045 }
Isabella Gottardi56ee6202021-05-12 08:27:15 +010046 printf_err("Failed to start profiler %s\n", this->m_name.c_str());
alexander3c798932021-03-26 21:42:19 +000047 return false;
48 }
49
50 bool Profiler::StopProfiling()
51 {
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010052 if (this->m_started) {
53 this->m_tstampEnd.initialised = false;
54 hal_pmu_get_counters(&this->m_tstampEnd);
Isabella Gottardi56ee6202021-05-12 08:27:15 +010055 this->m_started = false;
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010056 if (this->m_tstampEnd.initialised) {
57 this->AddProfilingUnit(
58 this->m_tstampSt,
59 this->m_tstampEnd,
60 this->m_name);
61 return true;
62 }
alexander3c798932021-03-26 21:42:19 +000063 }
Isabella Gottardi56ee6202021-05-12 08:27:15 +010064 printf_err("Failed to stop profiler %s\n", this->m_name.c_str());
alexander3c798932021-03-26 21:42:19 +000065 return false;
66 }
67
68 bool Profiler::StopProfilingAndReset()
69 {
70 if (this->StopProfiling()) {
71 this->Reset();
72 return true;
73 }
Isabella Gottardi56ee6202021-05-12 08:27:15 +010074 printf_err("Failed to stop profiler %s\n", this->m_name.c_str());
alexander3c798932021-03-26 21:42:19 +000075 return false;
76 }
77
78 void Profiler::Reset()
79 {
Isabella Gottardi56ee6202021-05-12 08:27:15 +010080 this->m_started = false;
81 this->m_series.clear();
82 memset(&this->m_tstampSt, 0, sizeof(this->m_tstampSt));
83 memset(&this->m_tstampEnd, 0, sizeof(this->m_tstampEnd));
alexander3c798932021-03-26 21:42:19 +000084 }
85
Isabella Gottardi8df12f32021-04-07 17:15:31 +010086 void calcProfilingStat(uint64_t currentValue,
87 Statistics& data,
88 uint32_t samples)
alexander3c798932021-03-26 21:42:19 +000089 {
Isabella Gottardi8df12f32021-04-07 17:15:31 +010090 data.total += currentValue;
91 data.min = std::min(data.min, currentValue);
92 data.max = std::max(data.max, currentValue);
93 data.avrg = ((double)data.total / samples);
94 }
alexander3c798932021-03-26 21:42:19 +000095
Isabella Gottardi8df12f32021-04-07 17:15:31 +010096 void Profiler::GetAllResultsAndReset(std::vector<ProfileResult>& results)
97 {
Isabella Gottardi56ee6202021-05-12 08:27:15 +010098 for (const auto& item: this->m_series) {
alexander3c798932021-03-26 21:42:19 +000099 auto name = item.first;
100 ProfilingSeries series = item.second;
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100101 ProfileResult result{};
102 result.name = item.first;
103 result.samplesNum = series.size();
alexander3c798932021-03-26 21:42:19 +0000104
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100105 std::vector<Statistics> stats(series[0].counters.num_counters);
106 for (size_t i = 0; i < stats.size(); ++i) {
107 stats[i].name = series[0].counters.counters[i].name;
108 stats[i].unit = series[0].counters.counters[i].unit;
alexander3c798932021-03-26 21:42:19 +0000109 }
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100110
111 for(ProfilingUnit& unit: series) {
112 for (size_t i = 0; i < stats.size(); ++i) {
113 calcProfilingStat(
114 unit.counters.counters[i].value,
115 stats[i],
116 result.samplesNum);
117 }
118 }
119
120 for (Statistics& stat : stats) {
121 result.data.emplace_back(stat);
122 }
123
124 results.emplace_back(result);
alexander3c798932021-03-26 21:42:19 +0000125 }
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100126
alexander3c798932021-03-26 21:42:19 +0000127 this->Reset();
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100128 }
129
130 void printStatisticsHeader(uint32_t samplesNum) {
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100131 info("Number of samples: %" PRIu32 "\n", samplesNum);
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100132 info("%s\n", "Total / Avg./ Min / Max");
133 }
134
135 void Profiler::PrintProfilingResult(bool printFullStat) {
136 std::vector<ProfileResult> results{};
137 GetAllResultsAndReset(results);
138 for(ProfileResult& result: results) {
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100139 if (result.data.size()) {
140 info("Profile for %s:\n", result.name.c_str());
141 if (printFullStat) {
142 printStatisticsHeader(result.samplesNum);
143 }
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100144 }
145
146 for (Statistics &stat: result.data) {
147 if (printFullStat) {
Kshitij Sisodiaf9c19ea2021-05-07 16:08:14 +0100148 info("%s %s: %" PRIu64 "/ %.0f / %" PRIu64 " / %" PRIu64 " \n",
149 stat.name.c_str(), stat.unit.c_str(),
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100150 stat.total, stat.avrg, stat.min, stat.max);
151 } else {
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100152 info("%s: %.0f %s\n", stat.name.c_str(), stat.avrg, stat.unit.c_str());
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100153 }
154 }
155 }
alexander3c798932021-03-26 21:42:19 +0000156 }
157
158 void Profiler::SetName(const char* str)
159 {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100160 this->m_name = std::string(str);
alexander3c798932021-03-26 21:42:19 +0000161 }
162
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100163 void Profiler::AddProfilingUnit(pmu_counters start, pmu_counters end,
alexanderc350cdc2021-04-29 20:36:09 +0100164 const std::string& name)
alexander3c798932021-03-26 21:42:19 +0000165 {
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100166 struct ProfilingUnit unit = {
167 .counters = end
168 };
alexander3c798932021-03-26 21:42:19 +0000169
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100170 if (end.num_counters != start.num_counters ||
171 true != end.initialised || true != start.initialised) {
172 printf_err("Invalid start or end counters\n");
173 return;
174 }
alexander3c798932021-03-26 21:42:19 +0000175
Kshitij Sisodiada2ec062022-04-01 14:43:53 +0100176 for (size_t i = 0; i < unit.counters.num_counters; ++i) {
177 if (unit.counters.counters[i].value < start.counters[i].value) {
178 warn("Overflow detected for %s\n", unit.counters.counters[i].name);
179 unit.counters.counters[i].value = 0;
180 } else {
181 unit.counters.counters[i].value -= start.counters[i].value;
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100182 }
alexander3c798932021-03-26 21:42:19 +0000183 }
184
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100185 this->m_series[name].emplace_back(unit);
alexander3c798932021-03-26 21:42:19 +0000186 }
187
188} /* namespace app */
Kshitij Sisodia14ab8d42021-10-22 17:35:01 +0100189} /* namespace arm */