• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "htrace_parser.h"
17 #include <unistd.h>
18 #include "binder_filter.h"
19 #include "cpu_filter.h"
20 #include "ftrace_event.pb.h"
21 #include "log.h"
22 #include "memory_plugin_result.pb.h"
23 #include "services/common_types.pb.h"
24 #include "stat_filter.h"
25 #include "trace_plugin_config.pb.h"
26 #include "trace_plugin_result.pb.h"
27 namespace SysTuning {
28 namespace TraceStreamer {
HtraceParser(TraceDataCache * dataCache,const TraceStreamerFilters * filters)29 HtraceParser::HtraceParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters)
30     : ParserBase(filters),
31       htraceCpuDetailParser_(std::make_unique<HtraceCpuDetailParser>(dataCache, filters)),
32       htraceSymbolsDetailParser_(std::make_unique<HtraceSymbolsDetailParser>(dataCache, filters)),
33       htraceMemParser_(std::make_unique<HtraceMemParser>(dataCache, filters)),
34       htraceClockDetailParser_(std::make_unique<HtraceClockDetailParser>(dataCache, filters)),
35       htraceHiLogParser_(std::make_unique<HtraceHiLogParser>(dataCache, filters)),
36       dataSegArray(new HtraceDataSegment[MAX_SEG_ARRAY_SIZE])
37 {
38 }
39 
~HtraceParser()40 HtraceParser::~HtraceParser()
41 {
42     TS_LOGI("clockid 2 is for RealTime and 1 is for BootTime");
43 }
44 
WaitForParserEnd()45 void HtraceParser::WaitForParserEnd()
46 {
47     if (parseThreadStarted_ || filterThreadStarted_) {
48         toExit_ = true;
49         while (!exited_) {
50             usleep(sleepDur_ * sleepDur_);
51         }
52     }
53     streamFilters_->cpuFilter_->FinishCpuEvent();
54     streamFilters_->binderFilter_->FinishBinderEvent();
55     htraceHiLogParser_->Finish();
56     htraceMemParser_->Finish();
57 }
58 
ParseTraceDataItem(const std::string & buffer)59 void HtraceParser::ParseTraceDataItem(const std::string& buffer)
60 {
61     while (!toExit_) {
62         int head = rawDataHead_;
63         if (dataSegArray[head].status.load() != TS_PARSE_STATUS_INIT) {
64             usleep(sleepDur_);
65             continue;
66         }
67         dataSegArray[head].seg = std::move(buffer);
68         dataSegArray[head].status = TS_PARSE_STATUS_SEPRATED;
69         rawDataHead_ = (rawDataHead_ + 1) % MAX_SEG_ARRAY_SIZE;
70         break;
71     }
72     if (!parseThreadStarted_) {
73         parseThreadStarted_ = true;
74         int tmp = maxThread_;
75         while (tmp--) {
76             parserThreadCount_++;
77             std::thread ParseTypeThread(&HtraceParser::ParseThread, this);
78             ParseTypeThread.detach();
79             TS_LOGI("parser Thread:%d/%d start working ...\n", maxThread_ - tmp, maxThread_);
80         }
81     }
82 }
FilterThread()83 void HtraceParser::FilterThread()
84 {
85     while (1) {
86         HtraceDataSegment& seg = dataSegArray[filterHead_];
87         if (seg.status.load() == TS_PARSE_STATUS_INVALID) {
88             seg.status = TS_PARSE_STATUS_INIT;
89             filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE;
90             streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID);
91             TS_LOGD("seprateHead_d:\t%d, parseHead_:\t%d, filterHead_:\t%d\n", rawDataHead_, parseHead_, filterHead_);
92             continue;
93         }
94         if (seg.status.load() != TS_PARSE_STATUS_PARSED) {
95             if (toExit_ && !parserThreadCount_) {
96                 TS_LOGI("exiting ParseLine Thread");
97                 exited_ = true;
98                 filterThreadStarted_ = false;
99                 TS_LOGD("seprateHead:\t%d, parseHead_:\t%d, filterHead_:\t%d, status:%d\n", rawDataHead_, parseHead_,
100                         filterHead_, seg.status.load());
101                 return;
102             }
103             TS_LOGD("seprateHead:\t%d, parseHead_:\t%d, filterHead_:\t%d, status:%d\n", rawDataHead_, parseHead_,
104                     filterHead_, seg.status.load());
105             usleep(sleepDur_);
106             continue;
107         }
108         if (seg.dataType == DATA_SOURCE_TYPE_TRACE) {
109             if (seg.traceData.ftrace_cpu_detail_size()) {
110                 htraceCpuDetailParser_->Parse(seg.traceData, clock_); // has Event
111             }
112             if (seg.traceData.symbols_detail_size()) {
113                 htraceSymbolsDetailParser_->Parse(seg.traceData); // has Event
114             }
115             if (seg.traceData.clocks_detail_size()) {
116                 htraceClockDetailParser_->Parse(seg.traceData); // has Event
117             }
118         } else if (seg.dataType == DATA_SOURCE_TYPE_MEM) {
119             htraceMemParser_->Parse(seg.memData, seg.timeStamp, seg.clockId);
120         } else if (seg.dataType == DATA_SOURCE_TYPE_HILOG) {
121             htraceHiLogParser_->Parse(seg.logData);
122         }
123         filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE;
124         seg.status = TS_PARSE_STATUS_INIT;
125     }
126 }
127 
ParseThread()128 void HtraceParser::ParseThread()
129 {
130     while (1) {
131         if (!filterThreadStarted_) {
132             filterThreadStarted_ = true;
133             std::thread ParserThread(&HtraceParser::FilterThread, this);
134             ParserThread.detach();
135         }
136         int head = GetNextSegment();
137         if (head < 0) {
138             if (head == ERROR_CODE_EXIT) {
139                 return;
140             } else if (head == ERROR_CODE_NODATA) {
141                 continue;
142             }
143         }
144         HtraceDataSegment& dataSeg = dataSegArray[head];
145         ProfilerPluginData pluginData;
146         if (!pluginData.ParseFromArray(dataSeg.seg.data(), static_cast<int>(dataSeg.seg.length()))) {
147             TS_LOGW("ProfilerPluginData ParseFromArray failed\n");
148             dataSeg.status = TS_PARSE_STATUS_INVALID;
149             continue;
150         }
151         if (pluginData.name() == "memory-plugin") {
152             ParseMemory(pluginData, dataSeg);
153         } else if (pluginData.name() == "/data/local/tmp/libhilogplugin.z.so") {
154             ParseHilog(pluginData, dataSeg);
155         } else if (pluginData.name() == "/data/local/tmp/libftrace_plugin.z.so"){
156             ParseFtrace(pluginData, dataSeg);
157         } else {
158             TS_LOGW("unrecognized pluginData.name():%s", pluginData.name().c_str());
159         }
160     }
161 }
162 
ParseMemory(const ProfilerPluginData & pluginData,HtraceDataSegment & dataSeg)163 void HtraceParser::ParseMemory(const ProfilerPluginData& pluginData, HtraceDataSegment &dataSeg)
164 {
165     dataSeg.dataType = DATA_SOURCE_TYPE_MEM;
166     auto timeStamp = pluginData.tv_nsec() + pluginData.tv_sec() * SEC_TO_NS;
167     BuiltinClocks clockId = TS_CLOCK_REALTIME;
168     auto clockIdTemp = pluginData.clock_id();
169     if (clockIdTemp == ProfilerPluginData_ClockId_CLOCKID_REALTIME) {
170         clockId = TS_CLOCK_REALTIME;
171     }
172     dataSeg.memData.Clear();
173     if (!dataSeg.memData.ParseFromArray(pluginData.data().data(),
174         static_cast<int>(pluginData.data().size()))) {
175         TS_LOGW("tracePacketParseFromArray failed\n");
176         dataSeg.status = TS_PARSE_STATUS_INVALID;
177         return;
178     }
179     if (dataSeg.memData.processesinfo_size()) {
180         dataSeg.dataType = DATA_SOURCE_TYPE_MEM;
181         dataSeg.timeStamp = timeStamp;
182         dataSeg.clockId = clockId;
183         dataSeg.status = TS_PARSE_STATUS_PARSED;
184     } else if (dataSeg.memData.meminfo_size()) {
185         dataSeg.dataType = DATA_SOURCE_TYPE_MEM;
186         dataSeg.timeStamp = timeStamp;
187         dataSeg.clockId = clockId;
188         dataSeg.status = TS_PARSE_STATUS_PARSED;
189     } else if (dataSeg.memData.vmeminfo_size()) {
190         dataSeg.dataType = DATA_SOURCE_TYPE_MEM;
191         dataSeg.timeStamp = timeStamp;
192         dataSeg.clockId = clockId;
193         dataSeg.status = TS_PARSE_STATUS_PARSED;
194     } else {
195         dataSeg.status = TS_PARSE_STATUS_INVALID;
196     }
197 }
ParseHilog(const ProfilerPluginData & pluginData,HtraceDataSegment & dataSeg)198 void HtraceParser::ParseHilog(const ProfilerPluginData& pluginData, HtraceDataSegment &dataSeg)
199 {
200     dataSeg.dataType = DATA_SOURCE_TYPE_HILOG;
201     dataSeg.traceData.Clear();
202     if (!dataSeg.logData.ParseFromArray(pluginData.data().data(), static_cast<int>(pluginData.data().size()))) {
203         TS_LOGW("tracePacketParseFromArray failed\n");
204         dataSeg.status = TS_PARSE_STATUS_PARSED;
205         return;
206     }
207     if (dataSeg.logData.info_size()) {
208         dataSeg.status = TS_PARSE_STATUS_PARSED;
209         return;
210     }
211     dataSeg.status = TS_PARSE_STATUS_INVALID;
212 }
ParseFtrace(const ProfilerPluginData & pluginData,HtraceDataSegment & dataSeg)213 void HtraceParser::ParseFtrace(const ProfilerPluginData& pluginData, HtraceDataSegment &dataSeg)
214 {
215     dataSeg.dataType = DATA_SOURCE_TYPE_TRACE;
216     dataSeg.traceData.Clear();
217     if (!dataSeg.traceData.ParseFromArray(pluginData.data().data(), static_cast<int>(pluginData.data().size()))) {
218         TS_LOGW("tracePacketParseFromArray failed\n");
219         dataSeg.status = TS_PARSE_STATUS_INVALID;
220         return;
221     }
222     if (dataSeg.traceData.ftrace_cpu_stats_size()) {
223         auto cpuStats = dataSeg.traceData.ftrace_cpu_stats(0);
224         auto s = cpuStats.per_cpu_stats(0);
225         TS_LOGD("s.overrun():%lu", s.overrun());
226         TS_LOGD("s.dropped_events():%lu", s.dropped_events());
227         auto clock = cpuStats.trace_clock();
228         if (clock == "boot") {
229             clock_ = TS_CLOCK_BOOTTIME;
230         }
231         dataSeg.clockId = clock_;
232         dataSeg.status = TS_PARSE_STATUS_PARSED;
233         return;
234     }
235     if (dataSeg.traceData.clocks_detail_size() || dataSeg.traceData.ftrace_cpu_detail_size() ||
236         dataSeg.traceData.symbols_detail_size()) {
237         dataSeg.status = TS_PARSE_STATUS_PARSED;
238         return;
239     }
240     dataSeg.status = TS_PARSE_STATUS_INVALID;
241 }
GetNextSegment()242 int HtraceParser::GetNextSegment()
243 {
244     int head;
245     dataSegMux_.lock();
246     head = parseHead_;
247     HtraceDataSegment& seg = dataSegArray[head];
248     if (seg.status.load() != TS_PARSE_STATUS_SEPRATED) {
249         if (toExit_) {
250             parserThreadCount_--;
251             TS_LOGI("exiting parser, parserThread Count:%d\n", parserThreadCount_);
252             TS_LOGD("seprateHead_x:\t%d, parseHead_:\t%d, filterHead_:\t%d status:%d\n", rawDataHead_, parseHead_,
253                     filterHead_, seg.status.load());
254             dataSegMux_.unlock();
255             if (!parserThreadCount_ && !filterThreadStarted_) {
256                 exited_ = true;
257             }
258             return ERROR_CODE_EXIT;
259         }
260         if (seg.status.load() == TS_PARSE_STATUS_PARSING) {
261             dataSegMux_.unlock();
262             usleep(sleepDur_);
263             return ERROR_CODE_NODATA;
264         }
265         dataSegMux_.unlock();
266         usleep(sleepDur_);
267         return ERROR_CODE_NODATA;
268     }
269     parseHead_ = (parseHead_ + 1) % MAX_SEG_ARRAY_SIZE;
270     seg.status = TS_PARSE_STATUS_PARSING;
271     dataSegMux_.unlock();
272     return head;
273 }
ParseTraceDataSegment(std::unique_ptr<uint8_t[]> bufferStr,size_t size)274 void HtraceParser::ParseTraceDataSegment(std::unique_ptr<uint8_t[]> bufferStr, size_t size)
275 {
276     packagesBuffer_.insert(packagesBuffer_.end(), &bufferStr[0], &bufferStr[size]);
277     auto packagesBegin = packagesBuffer_.begin();
278     auto currentLength = packagesBuffer_.size();
279     if (!hasGotHeader) {
280         std::string start(reinterpret_cast<const char*>(bufferStr.get()), std::min<size_t>(size, 20));
281         if (start.compare(0, std::string("OHOSPROF").length(), "OHOSPROF") == 0) {
282             currentLength -= PACKET_HEADER_LENGTH;
283             packagesBegin += PACKET_HEADER_LENGTH;
284         }
285         hasGotHeader = true;
286     }
287     while (1) {
288         if (!hasGotSegLength_) {
289             if (currentLength < PACKET_SEG_LENGTH) {
290                 break;
291             }
292             std::string bufferLine(packagesBegin, packagesBegin + PACKET_SEG_LENGTH);
293             const uint32_t* len = reinterpret_cast<const uint32_t*>(bufferLine.data());
294             nextLength_ = *len;
295             hasGotSegLength_ = true;
296             currentLength -= PACKET_SEG_LENGTH;
297             packagesBegin += PACKET_SEG_LENGTH;
298         }
299         if (currentLength < nextLength_) {
300             break;
301         }
302         std::string bufferLine(packagesBegin, packagesBegin + nextLength_);
303         ParseTraceDataItem(bufferLine);
304         hasGotSegLength_ = false;
305         packagesBegin += nextLength_;
306         currentLength -= nextLength_;
307     }
308     packagesBuffer_.erase(packagesBuffer_.begin(), packagesBegin);
309     return;
310 }
311 } // namespace TraceStreamer
312 } // namespace SysTuning
313