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