1 /*
2 * Copyright (c) 2023-2024 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 "trace_decorator.h"
17
18 #include "file_util.h"
19
20 namespace OHOS {
21 namespace HiviewDFX {
22 namespace UCollectUtil {
23 const std::string TRACE_COLLECTOR_NAME = "TraceCollector";
24 const std::string UC_HITRACE_API_STAT_TITLE = "Hitrace API detail statistics:";
25 const std::string UC_HITRACE_API_STAT_ITEM =
26 "Caller FailCall OverCall TotalCall AvgLatency(us) MaxLatency(us) TotalTimeSpent(us)";
27 const std::string UC_HITRACE_COMPRESS_RATIO = "Hitrace Traffic Compress Ratio:";
28 const std::string UC_HITRACE_TRAFFIC_STAT_TITLE = "Hitrace Traffic statistics:";
29 const std::string UC_HITRACE_TRAFFIC_STAT_ITEM =
30 "Caller TraceFile TimeSpent(us) RawSize(b) UsedSize(b) TimeStamp(us)";
31
32 StatInfoWrapper TraceDecorator::statInfoWrapper_;
33 TraceStatWrapper TraceDecorator::traceStatWrapper_;
34
DumpTrace(UCollect::TraceCaller & caller)35 CollectResult<std::vector<std::string>> TraceDecorator::DumpTrace(UCollect::TraceCaller &caller)
36 {
37 auto task = [this, &caller] { return traceCollector_->DumpTrace(caller); };
38 return Invoke(task, traceStatWrapper_, caller);
39 }
40
DumpTraceWithDuration(UCollect::TraceCaller & caller,uint32_t timeLimit)41 CollectResult<std::vector<std::string>> TraceDecorator::DumpTraceWithDuration(UCollect::TraceCaller &caller,
42 uint32_t timeLimit)
43 {
44 auto task = [this, &caller, &timeLimit] { return traceCollector_->DumpTraceWithDuration(caller, timeLimit); };
45 return Invoke(task, traceStatWrapper_, caller);
46 }
47
TraceOn()48 CollectResult<int32_t> TraceDecorator::TraceOn()
49 {
50 auto task = [this] { return traceCollector_->TraceOn(); };
51 return UCDecorator::Invoke(task, statInfoWrapper_, TRACE_COLLECTOR_NAME + UC_SEPARATOR + __func__);
52 }
53
TraceOff()54 CollectResult<std::vector<std::string>> TraceDecorator::TraceOff()
55 {
56 auto task = [this] { return traceCollector_->TraceOff(); };
57 return UCDecorator::Invoke(task, statInfoWrapper_, TRACE_COLLECTOR_NAME + UC_SEPARATOR + __func__);
58 }
59
SaveStatSpecialInfo()60 void TraceDecorator::SaveStatSpecialInfo()
61 {
62 WriteLinesToFile({""}, false); // a blank line after common stat info
63 std::map<std::string, TraceStatInfo> traceStatInfo = traceStatWrapper_.GetTraceStatInfo();
64 std::vector<std::string> traceFormattedStatInfo = {UC_HITRACE_API_STAT_TITLE, UC_HITRACE_API_STAT_ITEM};
65 for (const auto& record : traceStatInfo) {
66 traceFormattedStatInfo.push_back(record.second.ToString());
67 }
68 WriteLinesToFile(traceFormattedStatInfo, true);
69
70 std::vector<std::string> compressRatio = {UC_HITRACE_COMPRESS_RATIO, std::to_string(TRACE_COMPRESS_RATIO)};
71 WriteLinesToFile(compressRatio, true);
72
73 std::map<std::string, std::vector<std::string>> traceTrafficInfo = traceStatWrapper_.GetTrafficStatInfo();
74 std::vector<std::string> trafficFormattedInfo = {UC_HITRACE_TRAFFIC_STAT_TITLE, UC_HITRACE_TRAFFIC_STAT_ITEM};
75 for (const auto& record : traceTrafficInfo) {
76 trafficFormattedInfo.insert(trafficFormattedInfo.end(), record.second.begin(), record.second.end());
77 }
78 WriteLinesToFile(trafficFormattedInfo, false);
79 }
80
SaveStatCommonInfo()81 void TraceDecorator::SaveStatCommonInfo()
82 {
83 std::map<std::string, StatInfo> statInfo = statInfoWrapper_.GetStatInfo();
84 std::vector<std::string> formattedStatInfo;
85 for (const auto& record : statInfo) {
86 formattedStatInfo.push_back(record.second.ToString());
87 }
88 WriteLinesToFile(formattedStatInfo, false);
89 }
90
ResetStatInfo()91 void TraceDecorator::ResetStatInfo()
92 {
93 statInfoWrapper_.ResetStatInfo();
94 traceStatWrapper_.ResetStatInfo();
95 }
96
UpdateTraceStatInfo(uint64_t startTime,uint64_t endTime,UCollect::TraceCaller & caller,const CollectResult<std::vector<std::string>> & result)97 void TraceStatWrapper::UpdateTraceStatInfo(uint64_t startTime, uint64_t endTime, UCollect::TraceCaller& caller,
98 const CollectResult<std::vector<std::string>>& result)
99 {
100 bool isCallSucc = (result.retCode == UCollect::UcError::SUCCESS);
101 bool isOverCall = (result.retCode == UCollect::UcError::TRACE_OVER_FLOW);
102 uint64_t latency = (endTime - startTime > 0) ? (endTime - startTime) : 0;
103 std::string callerStr;
104 if (CallerMap.find(caller) != CallerMap.end()) {
105 callerStr = CallerMap.at(caller);
106 } else {
107 callerStr = "UNKNOWN";
108 }
109 TraceStatItem item = {.caller = callerStr, .isCallSucc = isCallSucc,
110 .isOverCall = isOverCall, .latency = latency};
111 UpdateAPIStatInfo(item);
112 UpdateTrafficInfo(callerStr, latency, result);
113 }
114
UpdateAPIStatInfo(const TraceStatItem & item)115 void TraceStatWrapper::UpdateAPIStatInfo(const TraceStatItem& item)
116 {
117 std::lock_guard<std::mutex> lock(traceMutex_);
118 if (traceStatInfos_.find(item.caller) == traceStatInfos_.end()) {
119 TraceStatInfo statInfo = {
120 .caller = item.caller,
121 .failCall = (item.isCallSucc || item.isOverCall) ? 0 : 1,
122 .overCall = item.isOverCall ? 1 : 0,
123 .totalCall = 1,
124 .avgLatency = item.latency,
125 .maxLatency = item.latency,
126 .totalTimeSpend = item.latency,
127 };
128 traceStatInfos_.insert(std::make_pair(item.caller, statInfo));
129 return;
130 }
131
132 TraceStatInfo& statInfo = traceStatInfos_[item.caller];
133 statInfo.totalCall += 1;
134 statInfo.failCall += ((item.isCallSucc || item.isOverCall) ? 0 : 1);
135 statInfo.overCall += (item.isOverCall ? 1 : 0);
136 statInfo.totalTimeSpend += item.latency;
137 if (statInfo.maxLatency < item.latency) {
138 statInfo.maxLatency = item.latency;
139 }
140 uint32_t succCall = statInfo.totalCall;
141 if (succCall > 0) {
142 statInfo.avgLatency = statInfo.totalTimeSpend / succCall;
143 }
144 }
145
UpdateTrafficInfo(const std::string & caller,uint64_t latency,const CollectResult<std::vector<std::string>> & result)146 void TraceStatWrapper::UpdateTrafficInfo(const std::string& caller, uint64_t latency,
147 const CollectResult<std::vector<std::string>>& result)
148 {
149 std::lock_guard<std::mutex> lock(traceMutex_);
150 std::vector<std::string> traceFiles = result.data;
151 if (latency <= 0 || traceFiles.empty()) { // dumptrace fail, no need to update traffic
152 return;
153 }
154
155 uint64_t timeStamp = TimeUtil::GenerateTimestamp();
156 uint64_t avgLatency = latency / traceFiles.size();
157 for (const auto& file : traceFiles) {
158 uint64_t fileSize = FileUtil::GetFileSize(file);
159 TraceTrafficInfo statInfo;
160 statInfo.caller = caller;
161 statInfo.traceFile = file;
162 statInfo.timeSpent = avgLatency;
163 statInfo.rawSize = fileSize;
164 statInfo.usedSize = fileSize * TRACE_COMPRESS_RATIO;
165 statInfo.timeStamp = timeStamp;
166
167 if (trafficStatInfos_.find(caller) == trafficStatInfos_.end()) {
168 trafficStatInfos_[caller] = {statInfo.ToString()};
169 } else {
170 std::vector<std::string>& tmp = trafficStatInfos_[caller];
171 tmp.push_back(statInfo.ToString());
172 }
173 }
174 }
175
GetTraceStatInfo()176 std::map<std::string, TraceStatInfo> TraceStatWrapper::GetTraceStatInfo()
177 {
178 std::lock_guard<std::mutex> lock(traceMutex_);
179 return traceStatInfos_;
180 }
181
GetTrafficStatInfo()182 std::map<std::string, std::vector<std::string>> TraceStatWrapper::GetTrafficStatInfo()
183 {
184 std::lock_guard<std::mutex> lock(traceMutex_);
185 return trafficStatInfos_;
186 }
187
ResetStatInfo()188 void TraceStatWrapper::ResetStatInfo()
189 {
190 std::lock_guard<std::mutex> lock(traceMutex_);
191 traceStatInfos_.clear();
192 trafficStatInfos_.clear();
193 }
194 } // namespace UCollectUtil
195 } // namespace HiviewDFX
196 } // namespace OHOS
197