1 /*
2 * Copyright (c) 2021 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 #include "performance_analysis.h"
16
17 #include <climits>
18
19 #include "db_errno.h"
20 #include "log_print.h"
21 #include "macro_utils.h"
22 #include "platform_specific.h"
23 #include "time_helper.h"
24
25 namespace DistributedDB {
26 const std::string PerformanceAnalysis::STATISTICAL_DATA_FILE_NAME_HEADER = "/data/log/statistic";
27 const std::string PerformanceAnalysis::CSV_FILE_EXTENSION = ".csv";
28 const std::string PerformanceAnalysis::DEFAULT_FILE_NAME = "default00";
29 std::once_flag PerformanceAnalysis::initFlag_;
30
GetInstance(int stepNum)31 PerformanceAnalysis *PerformanceAnalysis::GetInstance(int stepNum)
32 {
33 static PerformanceAnalysis inst(stepNum);
34 std::call_once(initFlag_, [] { inst.Initialization(); });
35 return &inst;
36 }
37
PerformanceAnalysis(uint32_t inStepNum)38 PerformanceAnalysis::PerformanceAnalysis(uint32_t inStepNum)
39 : isOpen_(false)
40 {
41 stepNum_ = inStepNum;
42 fileNumber_ = 0;
43 fileName_ = std::string(DEFAULT_FILE_NAME) + std::to_string(fileNumber_);
44 }
45
Initialization()46 void PerformanceAnalysis::Initialization()
47 {
48 counts_.resize(stepNum_);
49 timeRecordData_.timeInfo.resize(stepNum_);
50 stepTimeRecordInfo_.resize(stepNum_);
51 for (auto &stepIter : stepTimeRecordInfo_) {
52 stepIter.max = 0;
53 stepIter.min = ULLONG_MAX;
54 stepIter.average = 0;
55 }
56 for (auto iter = counts_.begin(); iter != counts_.end(); ++iter) {
57 *iter = 0;
58 }
59 }
60
~PerformanceAnalysis()61 PerformanceAnalysis::~PerformanceAnalysis() {};
62
IsStepValid(uint32_t step) const63 bool PerformanceAnalysis::IsStepValid(uint32_t step) const
64 {
65 return (stepNum_ < MAX_TIMERECORD_STEP_NUM && step < stepNum_);
66 }
67
IsOpen() const68 bool PerformanceAnalysis::IsOpen() const
69 {
70 return isOpen_;
71 }
72
OpenPerformanceAnalysis()73 void PerformanceAnalysis::OpenPerformanceAnalysis()
74 {
75 isOpen_ = true;
76 }
77
ClosePerformanceAnalysis()78 void PerformanceAnalysis::ClosePerformanceAnalysis()
79 {
80 isOpen_ = false;
81 }
82
InsertTimeRecord(const TimePair & timePair,uint32_t step)83 bool PerformanceAnalysis::InsertTimeRecord(const TimePair &timePair, uint32_t step)
84 {
85 if (!IsStepValid(step)) { // LCOV_EXCL_BR_LINE
86 return false;
87 }
88 timeRecordData_.timeInfo[step] = timePair;
89 return true;
90 }
91
GetTimeRecord(uint32_t step,TimePair & timePair) const92 bool PerformanceAnalysis::GetTimeRecord(uint32_t step, TimePair &timePair) const
93 {
94 if (!IsStepValid(step)) { // LCOV_EXCL_BR_LINE
95 return false;
96 }
97 timePair = timeRecordData_.timeInfo[step];
98 return true;
99 }
100
TimeRecordStart()101 void PerformanceAnalysis::TimeRecordStart()
102 {
103 if (!IsOpen()) { // LCOV_EXCL_BR_LINE
104 return;
105 }
106 StepTimeRecordStart(0);
107 }
108
TimeRecordEnd()109 void PerformanceAnalysis::TimeRecordEnd()
110 {
111 if (!IsOpen()) { // LCOV_EXCL_BR_LINE
112 return;
113 }
114 StepTimeRecordEnd(0);
115 }
116
StepTimeRecordStart(uint32_t step)117 void PerformanceAnalysis::StepTimeRecordStart(uint32_t step)
118 {
119 if (!IsOpen()) {
120 return;
121 }
122 if (!IsStepValid(step)) { // LCOV_EXCL_BR_LINE
123 return;
124 }
125 TimePair timePair = {0, 0};
126 uint64_t curTime = 0;
127 int errCode = OS::GetCurrentSysTimeInMicrosecond(curTime);
128 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
129 LOGE("[performance_analysis] GetCurrentSysTimeInMicrosecond fail");
130 } else {
131 timePair.startTime = curTime;
132 LOGD("[performance_analysis] StepTimeRecordStart step:%" PRIu32 ", curTime:%" PRIu64, step, curTime);
133 (void)InsertTimeRecord(timePair, step);
134 }
135 }
136
StepTimeRecordEnd(uint32_t step)137 void PerformanceAnalysis::StepTimeRecordEnd(uint32_t step)
138 {
139 if (!IsOpen()) {
140 return;
141 }
142 if (!IsStepValid(step)) { // LCOV_EXCL_BR_LINE
143 return;
144 }
145 TimePair timePair = {0, 0};
146 bool errCode = GetTimeRecord(step, timePair);
147 if (!errCode) { // LCOV_EXCL_BR_LINE
148 return;
149 }
150 (void)InsertTimeRecord({0, 0}, step);
151
152 uint64_t curTime = 0;
153 (void)OS::GetCurrentSysTimeInMicrosecond(curTime);
154 timePair.endTime = curTime;
155 LOGD("[performance_analysis] StepTimeRecordEnd step:%" PRIu32 ", curTime:%" PRIu64, step, curTime);
156
157 if ((timePair.endTime < timePair.startTime) || (timePair.startTime == 0)
158 || (timePair.endTime == 0)) { // LCOV_EXCL_BR_LINE
159 return;
160 }
161 Timestamp offset = timePair.endTime - timePair.startTime;
162 if (stepTimeRecordInfo_[step].max < offset) { // LCOV_EXCL_BR_LINE
163 stepTimeRecordInfo_[step].max = offset;
164 }
165 if (offset < stepTimeRecordInfo_[step].min) { // LCOV_EXCL_BR_LINE
166 stepTimeRecordInfo_[step].min = offset;
167 }
168 counts_[step]++;
169 if (counts_[step] == 0) { // LCOV_EXCL_BR_LINE
170 stepTimeRecordInfo_[step].average = 0;
171 return;
172 }
173 stepTimeRecordInfo_[step].average += (static_cast<float>(offset) -
174 stepTimeRecordInfo_[step].average) / counts_[step];
175 }
176
GetStatistics()177 std::string PerformanceAnalysis::GetStatistics()
178 {
179 std::string result;
180 for (size_t i = 0; i < stepTimeRecordInfo_.size(); i++) {
181 if (stepTimeRecordInfo_[i].max != 0) { // LCOV_EXCL_BR_LINE
182 result += "\nstep : " + std::to_string(i) + "\n";
183 result += "max: " + std::to_string(stepTimeRecordInfo_[i].max) + "\n";
184 result += "min: " + std::to_string(stepTimeRecordInfo_[i].min) + "\n";
185 result += "average: " +
186 std::to_string(static_cast<uint64_t>(stepTimeRecordInfo_[i].average)) + "\n";
187 result += "count: " + std::to_string(counts_[i]) + "\n";
188 }
189 }
190 OutStatistics();
191 Clear();
192 return result;
193 }
194
OutStatistics()195 void PerformanceAnalysis::OutStatistics()
196 {
197 std::string addrStatistics = STATISTICAL_DATA_FILE_NAME_HEADER + fileName_ + CSV_FILE_EXTENSION;
198 outFile.open(addrStatistics, std::ios_base::app);
199 if (!outFile.is_open()) {
200 return;
201 }
202 // This part filters the zeros data
203 outFile << "stepNum, maxTime(us), minTime(us), averageTime(us), count,\n";
204 for (size_t i = 0; i < stepTimeRecordInfo_.size(); i++) { // output to performance file
205 if (stepTimeRecordInfo_[i].max != 0) { // LCOV_EXCL_BR_LINE
206 outFile << i << "," << stepTimeRecordInfo_[i].max<< "," << stepTimeRecordInfo_[i].min
207 << "," << stepTimeRecordInfo_[i].average << "," << counts_[i] << "," << "\n";
208 }
209 }
210 LOGD("outFile success and exit!");
211 outFile.close();
212 }
213
Clear()214 void PerformanceAnalysis::Clear()
215 {
216 counts_.clear();
217 timeRecordData_.timeInfo.clear();
218 stepTimeRecordInfo_.clear();
219 counts_.resize(stepNum_);
220 timeRecordData_.timeInfo.resize(stepNum_);
221 stepTimeRecordInfo_.resize(stepNum_);
222 for (auto &iter : stepTimeRecordInfo_) {
223 iter.max = 0;
224 iter.min = ULLONG_MAX;
225 iter.average = 0;
226 }
227 fileName_ = std::string(DEFAULT_FILE_NAME) + std::to_string(fileNumber_);
228 }
229
SetFileName(const std::string & fileName)230 void PerformanceAnalysis::SetFileName(const std::string &fileName)
231 {
232 fileName_ = fileName;
233 }
234 } // namespace DistributedDB
235