• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "performance_data_manager.h"
17 
18 #include <algorithm>
19 #include <chrono>
20 #include <cinttypes>
21 #include <cstdint>
22 #include <map>
23 #include <mutex>
24 
25 #include <base/containers/fixed_string.h>
26 #include <base/containers/string.h>
27 #include <base/containers/string_view.h>
28 #include <base/containers/type_traits.h>
29 #include <base/containers/unique_ptr.h>
30 #include <base/containers/unordered_map.h>
31 #include <base/containers/vector.h>
32 #include <base/math/mathf.h>
33 #include <base/namespace.h>
34 #include <base/util/uid.h>
35 #include <core/log.h>
36 #include <core/namespace.h>
37 #include <core/perf/intf_performance_data_manager.h>
38 #include <core/perf/intf_performance_trace.h>
39 
40 CORE_BEGIN_NAMESPACE()
41 using BASE_NS::make_unique;
42 using BASE_NS::pair;
43 using BASE_NS::string_view;
44 using BASE_NS::Uid;
45 using BASE_NS::vector;
46 
47 struct PerformanceDataManager::InternalData {
48     NameToPerformanceMap data;
49 };
50 
51 namespace {
52 #if (CORE_PERF_ENABLED == 1)
UpdateTimingData(const string_view subCategory,const string_view name,const int64_t microSeconds,const PerformanceDataManager::PerformanceTimingData::DataType type,PerformanceDataManager::TypeDataSet & dataSet)53 void UpdateTimingData(const string_view subCategory, const string_view name, const int64_t microSeconds,
54     const PerformanceDataManager::PerformanceTimingData::DataType type, PerformanceDataManager::TypeDataSet& dataSet)
55 {
56     auto iter = dataSet.find(subCategory);
57     if (iter != dataSet.end()) {
58         auto dataIter = iter->second.data.find(name);
59         if (dataIter != iter->second.data.end()) {
60             auto& ref = dataIter->second;
61             const int64_t arrayIndex = ref.counter % IPerformanceDataManager::TIMING_DATA_POOL_SIZE;
62             ref.counter++;
63             ref.currentTime = microSeconds;
64             if (microSeconds > ref.maxTime) {
65                 ref.maxTime = microSeconds;
66             }
67             if (microSeconds < ref.minTime) {
68                 ref.minTime = microSeconds;
69             }
70             ref.timings[arrayIndex] = microSeconds;
71             int64_t frameAverage = 0;
72             for (const auto& timingsRef : ref.timings) {
73                 frameAverage += timingsRef;
74             }
75             ref.averageTime = frameAverage / IPerformanceDataManager::TIMING_DATA_POOL_SIZE;
76             ref.averageTimings[arrayIndex] = ref.averageTime;
77             ref.totalTime += ref.currentTime;
78             if (ref.totalTime > ref.maxTotalTime) {
79                 ref.maxTotalTime = ref.totalTime;
80             }
81             ref.type = type;
82         } else {
83             // new value
84             auto& ref = iter->second.data[name];
85             ref = {
86                 microSeconds, // currentTime
87                 microSeconds, // maxTime
88                 microSeconds, // minTime
89                 microSeconds, // averageTime
90                 microSeconds, // totalTime
91                 1,            // counter
92             };
93             ref.type = type;
94             std::fill_n(ref.timings, IPerformanceDataManager::TIMING_DATA_POOL_SIZE, microSeconds);
95             std::fill_n(ref.averageTimings, IPerformanceDataManager::TIMING_DATA_POOL_SIZE, microSeconds);
96         }
97     } else {
98         // new subcategory and new value
99         auto& ref = dataSet[subCategory].data[name];
100         ref = {
101             microSeconds, // currentTime
102             microSeconds, // maxTime
103             microSeconds, // minTime
104             microSeconds, // averageTime
105             microSeconds, // totalTime
106             1,            // counter
107         };
108         ref.type = type;
109         std::fill_n(ref.timings, IPerformanceDataManager::TIMING_DATA_POOL_SIZE, microSeconds);
110         std::fill_n(ref.averageTimings, IPerformanceDataManager::TIMING_DATA_POOL_SIZE, microSeconds);
111     }
112 }
113 
GetTimingData(const PerformanceDataManager::TypeDataSet & typeData)114 vector<IPerformanceDataManager::PerformanceData> GetTimingData(const PerformanceDataManager::TypeDataSet& typeData)
115 {
116     vector<IPerformanceDataManager::PerformanceData> data;
117     data.reserve(typeData.size());
118     for (const auto& typeRef : typeData) {
119         IPerformanceDataManager::PerformanceData& pd = data.emplace_back();
120         pd.subCategory = typeRef.first;
121         for (const auto& perfRef : typeRef.second.data) {
122             pd.timings[perfRef.first] = perfRef.second;
123         }
124     }
125     return data;
126 }
127 #endif // CORE_PERF_ENABLED
128 } // namespace
129 
130 PerformanceDataManager::~PerformanceDataManager() = default;
131 
PerformanceDataManager(const string_view category,PerformanceDataManagerFactory & factory)132 PerformanceDataManager::PerformanceDataManager(const string_view category, PerformanceDataManagerFactory& factory)
133     : category_(category), factory_(factory)
134 {}
135 
GetCategory() const136 string_view PerformanceDataManager::GetCategory() const
137 {
138     return category_;
139 }
140 
141 using Clock = std::chrono::steady_clock;
142 
BeginTimer()143 IPerformanceDataManager::TimerHandle PerformanceDataManager::BeginTimer()
144 {
145     return static_cast<IPerformanceDataManager::TimerHandle>(Clock::now().time_since_epoch().count());
146 }
147 
EndTimer(IPerformanceDataManager::TimerHandle handle)148 int64_t PerformanceDataManager::EndTimer(IPerformanceDataManager::TimerHandle handle)
149 {
150     using std::chrono::duration_cast;
151     using std::chrono::microseconds;
152     const auto dt = Clock::now().time_since_epoch() - Clock::duration(handle);
153     return static_cast<int64_t>(duration_cast<microseconds>(dt).count());
154 }
155 
UpdateData(const string_view subCategory,const string_view name,const int64_t microSeconds)156 void PerformanceDataManager::UpdateData([[maybe_unused]] const string_view subCategory,
157     [[maybe_unused]] const string_view name, [[maybe_unused]] const int64_t microSeconds)
158 {
159 #if (CORE_PERF_ENABLED == 1)
160     std::lock_guard<std::mutex> lock(dataMutex_);
161     UpdateTimingData(subCategory, name, microSeconds, PerformanceTimingData::DataType::MICROSECONDS, data_);
162 #endif
163 }
164 
UpdateData(const string_view subCategory,const string_view name,const int64_t value,PerformanceTimingData::DataType type)165 void PerformanceDataManager::UpdateData([[maybe_unused]] const string_view subCategory,
166     [[maybe_unused]] const string_view name, [[maybe_unused]] const int64_t value,
167     [[maybe_unused]] PerformanceTimingData::DataType type)
168 {
169 #if (CORE_PERF_ENABLED == 1)
170     std::lock_guard<std::mutex> lock(dataMutex_);
171     UpdateTimingData(subCategory, name, value, type, data_);
172 #endif
173 }
174 
ResetData()175 void PerformanceDataManager::ResetData()
176 {
177 #if (CORE_PERF_ENABLED == 1)
178     std::lock_guard<std::mutex> lock(dataMutex_);
179     data_.clear();
180 #endif
181 }
182 
GetData() const183 vector<IPerformanceDataManager::PerformanceData> PerformanceDataManager::GetData() const
184 {
185 #if (CORE_PERF_ENABLED == 1)
186     std::lock_guard<std::mutex> lock(dataMutex_);
187     return GetTimingData(data_);
188 #else
189     return {};
190 #endif
191 }
192 
RemoveData(const string_view subCategory)193 void PerformanceDataManager::RemoveData([[maybe_unused]] const string_view subCategory)
194 {
195 #if (CORE_PERF_ENABLED == 1)
196     std::lock_guard<std::mutex> lock(dataMutex_);
197     data_.erase(subCategory);
198 #endif
199 }
200 
DumpToLog() const201 void PerformanceDataManager::DumpToLog() const
202 {
203 #if (CORE_PERF_ENABLED == 1)
204     std::lock_guard<std::mutex> lock(dataMutex_);
205 
206     constexpr const string_view formatLegend = "%8s %8s %8s %9s %8s (microseconds)";
207     constexpr const string_view formatData = "%8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %9" PRIu64 " %8" PRIu64 " %s::%s";
208 
209     CORE_LOG_I(formatLegend.data(), "avg", "min", "max", "total", "count");
210 
211     for (const auto& typeRef : data_) {
212         for (const auto& perfRef : typeRef.second.data) {
213             const int64_t counter = BASE_NS::Math::max(perfRef.second.counter, int64_t(1));
214             CORE_LOG_I(formatData.data(), perfRef.second.totalTime / counter, perfRef.second.minTime,
215                 perfRef.second.maxTime, perfRef.second.totalTime, perfRef.second.counter, typeRef.first.c_str(),
216                 perfRef.first.c_str());
217         }
218     }
219 #endif
220 }
221 
222 // IInterface
GetInterface(const Uid & uid) const223 const IInterface* PerformanceDataManager::GetInterface(const Uid& uid) const
224 {
225     if ((uid == IPerformanceDataManager::UID) || (uid == IInterface::UID)) {
226         return this;
227     }
228     return nullptr;
229 }
230 
GetInterface(const Uid & uid)231 IInterface* PerformanceDataManager::GetInterface(const Uid& uid)
232 {
233     if ((uid == IPerformanceDataManager::UID) || (uid == IInterface::UID)) {
234         return this;
235     }
236     return nullptr;
237 }
238 
Ref()239 void PerformanceDataManager::Ref() {}
240 
Unref()241 void PerformanceDataManager::Unref() {}
242 
PerformanceDataManagerFactory(IPluginRegister & registry)243 PerformanceDataManagerFactory::PerformanceDataManagerFactory(IPluginRegister& registry) {}
244 
SetPerformanceTrace(const Uid & uid,IPerformanceTrace::Ptr && trace)245 void PerformanceDataManagerFactory::SetPerformanceTrace(
246     [[maybe_unused]] const Uid& uid, [[maybe_unused]] IPerformanceTrace::Ptr&& trace)
247 {
248 #if (CORE_PERF_ENABLED == 1)
249     perfTraces_.push_back({ uid, BASE_NS::move(trace) });
250 #endif
251 }
252 
RemovePerformanceTrace(const BASE_NS::Uid & uid)253 void PerformanceDataManagerFactory::RemovePerformanceTrace([[maybe_unused]] const BASE_NS::Uid& uid)
254 {
255 #if (CORE_PERF_ENABLED == 1)
256     perfTraces_.erase(std::remove_if(perfTraces_.begin(), perfTraces_.end(),
257                                      [uid](const RegisteredPerformanceTrace &info) { return info.uid == uid; }),
258                       perfTraces_.cend());
259 #endif
260 }
261 
GetFirstPerformanceTrace() const262 IPerformanceTrace* PerformanceDataManagerFactory::GetFirstPerformanceTrace() const
263 {
264     return perfTraces_.size() > 0 ? perfTraces_.at(0).instance.get() : nullptr;
265 }
266 
267 PerformanceDataManagerFactory::~PerformanceDataManagerFactory() = default;
268 
Get(const string_view category)269 IPerformanceDataManager* PerformanceDataManagerFactory::Get([[maybe_unused]] const string_view category)
270 {
271 #if (CORE_PERF_ENABLED == 1)
272     std::lock_guard lock(mutex_);
273     if (auto pos = managers_.find(category); pos != managers_.end()) {
274         return pos->second.get();
275     }
276     auto inserted = managers_.insert({ category, make_unique<PerformanceDataManager>(category, *this) });
277     return inserted.first->second.get();
278 #else
279     return {};
280 #endif
281 }
282 
GetAllCategories() const283 vector<IPerformanceDataManager*> PerformanceDataManagerFactory::GetAllCategories() const
284 {
285     vector<IPerformanceDataManager*> categories;
286 #if (CORE_PERF_ENABLED == 1)
287     std::lock_guard lock(mutex_);
288     categories.reserve(managers_.size());
289     for (const auto& manager : managers_) {
290         if (auto* mgrPtr = manager.second.get(); mgrPtr) {
291             categories.push_back(mgrPtr);
292         }
293     }
294 #endif
295     return categories;
296 }
297 
298 // IInterface
GetInterface(const Uid & uid) const299 const IInterface* PerformanceDataManagerFactory::GetInterface(const Uid& uid) const
300 {
301     if ((uid == IPerformanceDataManagerFactory::UID) || (uid == IInterface::UID)) {
302         return this;
303     }
304     return nullptr;
305 }
306 
GetInterface(const Uid & uid)307 IInterface* PerformanceDataManagerFactory::GetInterface(const Uid& uid)
308 {
309     if ((uid == IPerformanceDataManagerFactory::UID) || (uid == IInterface::UID)) {
310         return this;
311     }
312     return nullptr;
313 }
314 
Ref()315 void PerformanceDataManagerFactory::Ref() {}
316 
Unref()317 void PerformanceDataManagerFactory::Unref() {}
318 
GetLogger()319 ILogger::IOutput::Ptr PerformanceDataManagerFactory::GetLogger()
320 {
321     return ILogger::IOutput::Ptr { new PerformanceTraceLogger(this) };
322 }
323 
324 BASE_NS::array_view<const PerformanceDataManagerFactory::RegisteredPerformanceTrace>
GetPerformanceTraces() const325 PerformanceDataManagerFactory::GetPerformanceTraces() const
326 {
327     return BASE_NS::array_view(perfTraces_.data(), perfTraces_.size());
328 }
329 
Write(ILogger::LogLevel logLevel,BASE_NS::string_view filename,int lineNumber,BASE_NS::string_view message)330 void PerformanceTraceLogger::Write(
331     ILogger::LogLevel logLevel, BASE_NS::string_view filename, int lineNumber, BASE_NS::string_view message)
332 {
333     if (auto trace = factory_->GetFirstPerformanceTrace()) {
334         trace->Message(message.data(), message.size(), 0);
335     }
336 }
337 CORE_END_NAMESPACE()
338