• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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/math/mathf.h>
26 #include <core/log.h>
27 #include <core/namespace.h>
28 #include <core/plugin/intf_interface.h>
29 #include <core/plugin/intf_plugin_register.h>
30 
31 CORE_BEGIN_NAMESPACE()
32 using BASE_NS::make_unique;
33 using BASE_NS::pair;
34 using BASE_NS::string_view;
35 using BASE_NS::Uid;
36 using BASE_NS::vector;
37 
38 struct PerformanceDataManager::InternalData {
39     NameToPerformanceMap data;
40 };
41 
42 namespace {
43 #if (CORE_PERF_ENABLED == 1)
UpdateTimingData(const string_view subCategory,const string_view name,const int64_t microSeconds,PerformanceDataManager::TypeDataSet & dataSet)44 void UpdateTimingData(const string_view subCategory, const string_view name, const int64_t microSeconds,
45     PerformanceDataManager::TypeDataSet& dataSet)
46 {
47     auto iter = dataSet.find(subCategory);
48     if (iter != dataSet.end()) {
49         auto dataIter = iter->second.data.find(name);
50         if (dataIter != iter->second.data.end()) {
51             auto& ref = dataIter->second;
52             const int64_t arrayIndex = ref.counter % IPerformanceDataManager::TIMING_DATA_POOL_SIZE;
53             ref.counter++;
54             ref.currentTime = microSeconds;
55             if (microSeconds < ref.minTime) {
56                 ref.minTime = microSeconds;
57             }
58             if (microSeconds > ref.maxTime) {
59                 ref.maxTime = microSeconds;
60             }
61             ref.timings[arrayIndex] = microSeconds;
62             int64_t frameAverage = 0;
63             for (const auto& timingsRef : ref.timings) {
64                 frameAverage += timingsRef;
65             }
66             ref.averageTime = frameAverage / IPerformanceDataManager::TIMING_DATA_POOL_SIZE;
67             ref.totalTime += ref.currentTime;
68             if (ref.totalTime > ref.maxTotalTime) {
69                 ref.maxTotalTime = ref.totalTime;
70             }
71         } else {
72             // new value
73             auto& ref = iter->second.data[name];
74             ref = {
75                 microSeconds, // currentTime
76                 microSeconds, // maxTime
77                 microSeconds, // minTime
78                 microSeconds, // averageTime
79                 microSeconds, // totalTime
80                 1,            // counter
81             };
82             std::fill_n(ref.timings, IPerformanceDataManager::TIMING_DATA_POOL_SIZE, microSeconds);
83         }
84     } else {
85         // new subcategory and new value
86         auto& ref = dataSet[subCategory].data[name];
87         ref = {
88             microSeconds, // currentTime
89             microSeconds, // maxTime
90             microSeconds, // minTime
91             microSeconds, // averageTime
92             microSeconds, // totalTime
93             1,            // counter
94         };
95         std::fill_n(ref.timings, IPerformanceDataManager::TIMING_DATA_POOL_SIZE, microSeconds);
96     }
97 }
98 
GetTimingData(const PerformanceDataManager::TypeDataSet & typeData)99 vector<IPerformanceDataManager::PerformanceData> GetTimingData(const PerformanceDataManager::TypeDataSet& typeData)
100 {
101     vector<IPerformanceDataManager::PerformanceData> data;
102     data.reserve(typeData.size());
103     for (const auto& typeRef : typeData) {
104         IPerformanceDataManager::PerformanceData& pd = data.emplace_back();
105         pd.subCategory = typeRef.first;
106         for (const auto& perfRef : typeRef.second.data) {
107             pd.timings[perfRef.first] = perfRef.second;
108         }
109     }
110     return data;
111 }
112 #endif // CORE_PERF_ENABLED
113 } // namespace
114 
115 PerformanceDataManager::~PerformanceDataManager() = default;
116 
PerformanceDataManager(const string_view category)117 PerformanceDataManager::PerformanceDataManager(const string_view category) : category_(category) {}
118 
GetCategory() const119 string_view PerformanceDataManager::GetCategory() const
120 {
121     return category_;
122 }
123 
124 using Clock = std::chrono::system_clock;
125 
BeginTimer()126 IPerformanceDataManager::TimerHandle PerformanceDataManager::BeginTimer()
127 {
128     return static_cast<IPerformanceDataManager::TimerHandle>(Clock::now().time_since_epoch().count());
129 }
130 
EndTimer(IPerformanceDataManager::TimerHandle handle)131 int64_t PerformanceDataManager::EndTimer(IPerformanceDataManager::TimerHandle handle)
132 {
133     using std::chrono::duration_cast;
134     using std::chrono::microseconds;
135     const auto dt = Clock::now().time_since_epoch() - Clock::duration(handle);
136     return static_cast<int64_t>(duration_cast<microseconds>(dt).count());
137 }
138 
UpdateData(const string_view subCategory,const string_view name,const int64_t microSeconds)139 void PerformanceDataManager::UpdateData(
140     const string_view subCategory, const string_view name, const int64_t microSeconds)
141 {
142 #if (CORE_PERF_ENABLED == 1)
143     std::lock_guard<std::mutex> lock(dataMutex_);
144     UpdateTimingData(subCategory, name, microSeconds, data_);
145 #endif
146 }
147 
ResetData()148 void PerformanceDataManager::ResetData()
149 {
150 #if (CORE_PERF_ENABLED == 1)
151     std::lock_guard<std::mutex> lock(dataMutex_);
152     data_.clear();
153 #endif
154 }
155 
GetData() const156 vector<IPerformanceDataManager::PerformanceData> PerformanceDataManager::GetData() const
157 {
158 #if (CORE_PERF_ENABLED == 1)
159     std::lock_guard<std::mutex> lock(dataMutex_);
160     return GetTimingData(data_);
161 #else
162     return {};
163 #endif
164 }
165 
RemoveData(const string_view subCategory)166 void PerformanceDataManager::RemoveData(const string_view subCategory)
167 {
168 #if (CORE_PERF_ENABLED == 1)
169     std::lock_guard<std::mutex> lock(dataMutex_);
170     data_.erase(subCategory);
171 #endif
172 }
173 
DumpToLog() const174 void PerformanceDataManager::DumpToLog() const
175 {
176 #if (CORE_PERF_ENABLED == 1)
177     std::lock_guard<std::mutex> lock(dataMutex_);
178 
179     constexpr const string_view formatLegend = "%8s %8s %8s %9s %8s (microseconds)";
180     constexpr const string_view formatData = "%8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %9" PRIu64 " %8" PRIu64 " %s::%s";
181 
182     CORE_LOG_I(formatLegend.data(), "avg", "min", "max", "total", "count");
183 
184     for (const auto& typeRef : data_) {
185         for (const auto& perfRef : typeRef.second.data) {
186             const int64_t counter = BASE_NS::Math::max(perfRef.second.counter, int64_t(1));
187             CORE_LOG_I(formatData.data(), perfRef.second.totalTime / counter, perfRef.second.minTime,
188                 perfRef.second.maxTime, perfRef.second.totalTime, perfRef.second.counter, typeRef.first.c_str(),
189                 perfRef.first.c_str());
190         }
191     }
192 #endif
193 }
194 
195 // IInterface
GetInterface(const Uid & uid) const196 const IInterface* PerformanceDataManager::GetInterface(const Uid& uid) const
197 {
198     if (uid == IPerformanceDataManager::UID) {
199         return this;
200     }
201     return nullptr;
202 }
203 
GetInterface(const Uid & uid)204 IInterface* PerformanceDataManager::GetInterface(const Uid& uid)
205 {
206     if (uid == IPerformanceDataManager::UID) {
207         return this;
208     }
209     return nullptr;
210 }
211 
Ref()212 void PerformanceDataManager::Ref() {}
213 
Unref()214 void PerformanceDataManager::Unref() {}
215 
Get(const string_view category)216 IPerformanceDataManager* PerformanceDataManagerFactory::Get(const string_view category)
217 {
218 #if (CORE_PERF_ENABLED == 1)
219     std::lock_guard lock(mutex_);
220     if (auto pos = managers_.find(category); pos != managers_.end()) {
221         return pos->second.get();
222     } else {
223         auto inserted = managers_.insert({ category, make_unique<PerformanceDataManager>(category) });
224         return inserted.first->second.get();
225     }
226 #else
227     return {};
228 #endif
229 }
230 
GetAllCategories() const231 vector<IPerformanceDataManager*> PerformanceDataManagerFactory::GetAllCategories() const
232 {
233     vector<IPerformanceDataManager*> categories;
234 #if (CORE_PERF_ENABLED == 1)
235     std::lock_guard lock(mutex_);
236     categories.reserve(managers_.size());
237     for (const auto& manager : managers_) {
238         if (auto* mgrPtr = manager.second.get(); mgrPtr) {
239             categories.push_back(mgrPtr);
240         }
241     }
242 #endif
243     return categories;
244 }
245 
246 // IInterface
GetInterface(const Uid & uid) const247 const IInterface* PerformanceDataManagerFactory::GetInterface(const Uid& uid) const
248 {
249     if (uid == IPerformanceDataManagerFactory::UID) {
250         return this;
251     }
252     return nullptr;
253 }
254 
GetInterface(const Uid & uid)255 IInterface* PerformanceDataManagerFactory::GetInterface(const Uid& uid)
256 {
257     if (uid == IPerformanceDataManagerFactory::UID) {
258         return this;
259     }
260     return nullptr;
261 }
262 
Ref()263 void PerformanceDataManagerFactory::Ref() {}
264 
Unref()265 void PerformanceDataManagerFactory::Unref() {}
266 CORE_END_NAMESPACE()
267