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