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