• 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       htraceNativeHookParser_(std::make_unique<HtraceNativeHookParser>(dataCache, filters)),
37       htraceHidumpParser_(std::make_unique<HtraceHidumpParser>(dataCache, filters)),
38       dataSegArray(new HtraceDataSegment[MAX_SEG_ARRAY_SIZE])
39 {
40 #ifdef SUPPORTTHREAD
41     noThread_ = false;
42 #endif
43 }
44 
~HtraceParser()45 HtraceParser::~HtraceParser()
46 {
47     TS_LOGI("clockid 2 is for RealTime and 1 is for BootTime");
48 }
49 
WaitForParserEnd()50 void HtraceParser::WaitForParserEnd()
51 {
52     if (parseThreadStarted_ || filterThreadStarted_) {
53         toExit_ = true;
54         while (!exited_) {
55             usleep(sleepDur_ * sleepDur_);
56         }
57     }
58     streamFilters_->cpuFilter_->FinishCpuEvent();
59     streamFilters_->binderFilter_->FinishBinderEvent();
60     htraceHiLogParser_->Finish();
61     htraceMemParser_->Finish();
62     htraceNativeHookParser_->Finish();
63     htraceHidumpParser_->Finish();
64 }
65 
ParseTraceDataItem(const std::string & buffer)66 void HtraceParser::ParseTraceDataItem(const std::string& buffer)
67 {
68     int head = rawDataHead_;
69     while (!toExit_) {
70         if (!noThread_ && dataSegArray[head].status.load() != TS_PARSE_STATUS_INIT) {
71             usleep(sleepDur_);
72             continue;
73         }
74         dataSegArray[head].seg = std::move(buffer);
75         dataSegArray[head].status = TS_PARSE_STATUS_SEPRATED;
76         if (!noThread_) {
77             rawDataHead_ = (rawDataHead_ + 1) % MAX_SEG_ARRAY_SIZE;
78         }
79         break;
80     }
81     if (!parseThreadStarted_ && !noThread_) {
82         parseThreadStarted_ = true;
83         int tmp = maxThread_;
84         while (tmp--) {
85             parserThreadCount_++;
86             std::thread ParseTypeThread(&HtraceParser::ParseThread, this);
87             ParseTypeThread.detach();
88             TS_LOGI("parser Thread:%d/%d start working ...\n", maxThread_ - tmp, maxThread_);
89         }
90     }
91     if (noThread_) {
92         ParserData(dataSegArray[head]);
93     }
94 }
FilterData(HtraceDataSegment & seg)95 void HtraceParser::FilterData(HtraceDataSegment& seg)
96 {
97     if (seg.dataType == DATA_SOURCE_TYPE_TRACE) {
98         if (seg.traceData.ftrace_cpu_detail_size()) {
99             htraceCpuDetailParser_->Parse(seg.traceData, clock_); // has Event
100         }
101         if (seg.traceData.symbols_detail_size()) {
102             htraceSymbolsDetailParser_->Parse(seg.traceData); // has Event
103         }
104         if (seg.traceData.clocks_detail_size()) {
105             htraceClockDetailParser_->Parse(seg.traceData); // has Event
106         }
107     } else if (seg.dataType == DATA_SOURCE_TYPE_MEM) {
108         htraceMemParser_->Parse(seg.memData, seg.timeStamp, seg.clockId);
109     } else if (seg.dataType == DATA_SOURCE_TYPE_HILOG) {
110         htraceHiLogParser_->Parse(seg.logData);
111     } else if (seg.dataType == DATA_SOURCE_TYPE_HEAP) {
112         htraceNativeHookParser_->Parse(seg.batchNativeHookData);
113     } else if (seg.dataType == DATA_SOURCE_TYPE_FPS) {
114         htraceHidumpParser_->Parse(seg.hidumpInfo);
115     }
116     if (!noThread_) {
117         filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE;
118     }
119     seg.status = TS_PARSE_STATUS_INIT;
120 }
FilterThread()121 void HtraceParser::FilterThread()
122 {
123     while (1) {
124         HtraceDataSegment& seg = dataSegArray[filterHead_];
125         if (seg.status.load() == TS_PARSE_STATUS_INVALID) {
126             seg.status = TS_PARSE_STATUS_INIT;
127             filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE;
128             streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID);
129             TS_LOGI("seprateHead_d:\t%d, parseHead_:\t%d, filterHead_:\t%d\n", rawDataHead_, parseHead_, filterHead_);
130             continue;
131         }
132         if (seg.status.load() != TS_PARSE_STATUS_PARSED) {
133             if (toExit_ && !parserThreadCount_) {
134                 TS_LOGI("exiting ParseLine Thread");
135                 exited_ = true;
136                 filterThreadStarted_ = false;
137                 TS_LOGD("seprateHead:\t%d, parseHead_:\t%d, filterHead_:\t%d, status:%d\n", rawDataHead_, parseHead_,
138                         filterHead_, seg.status.load());
139                 return;
140             }
141             TS_LOGD("seprateHead:\t%d, parseHead_:\t%d, filterHead_:\t%d, status:%d\n", rawDataHead_, parseHead_,
142                     filterHead_, seg.status.load());
143             usleep(sleepDur_);
144             continue;
145         }
146         FilterData(seg);
147     }
148 }
149 
ParserData(HtraceDataSegment & dataSeg)150 void HtraceParser::ParserData(HtraceDataSegment& dataSeg)
151 {
152     ProfilerPluginData pluginData;
153     if (!pluginData.ParseFromArray(dataSeg.seg.data(), static_cast<int>(dataSeg.seg.length()))) {
154         TS_LOGW("ProfilerPluginData ParseFromArray failed\n");
155         dataSeg.status = TS_PARSE_STATUS_INVALID;
156         return;
157     }
158     if (pluginData.name() == "memory-plugin") {
159         ParseMemory(pluginData, dataSeg);
160     } else if (pluginData.name() == "hilog-plugin" || pluginData.name() == "/data/local/tmp/libhilogplugin.z.so") {
161         ParseHilog(pluginData, dataSeg);
162     } else if (pluginData.name() == "ftrace-plugin" || pluginData.name() == "/data/local/tmp/libftrace_plugin.z.so") {
163         ParseFtrace(pluginData, dataSeg);
164     } else if (pluginData.name() == "nativehook" || pluginData.name() == "hookdaemon") {
165         ParseNativeHook(pluginData, dataSeg);
166     } else if (pluginData.name() == "hidump-plugin" || pluginData.name() == "/data/local/tmp/libhidumpplugin.z.so") {
167         ParseFPS(pluginData, dataSeg);
168     } else {
169         TS_LOGW("unrecognized pluginData.name():%s", pluginData.name().c_str());
170     }
171     if (noThread_) { // do it only in wasm mode, wasm noThead_ will be true
172         FilterData(dataSeg);
173     }
174 }
ParseThread()175 void HtraceParser::ParseThread()
176 {
177     while (1) {
178         if (!filterThreadStarted_ && !noThread_) {
179             filterThreadStarted_ = true;
180             std::thread ParserThread(&HtraceParser::FilterThread, this);
181             ParserThread.detach();
182         }
183         int head = GetNextSegment();
184         if (head < 0) {
185             if (head == ERROR_CODE_EXIT) {
186                 return;
187             } else if (head == ERROR_CODE_NODATA) {
188                 continue;
189             }
190         }
191         HtraceDataSegment& dataSeg = dataSegArray[head];
192         ParserData(dataSeg);
193     }
194 }
195 
ParseMemory(const ProfilerPluginData & pluginData,HtraceDataSegment & dataSeg)196 void HtraceParser::ParseMemory(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg)
197 {
198     dataSeg.dataType = DATA_SOURCE_TYPE_MEM;
199     auto timeStamp = pluginData.tv_nsec() + pluginData.tv_sec() * SEC_TO_NS;
200     BuiltinClocks clockId = TS_CLOCK_REALTIME;
201     auto clockIdTemp = pluginData.clock_id();
202     if (clockIdTemp == ProfilerPluginData_ClockId_CLOCKID_REALTIME) {
203         clockId = TS_CLOCK_REALTIME;
204     }
205     dataSeg.memData.Clear();
206     if (!dataSeg.memData.ParseFromArray(pluginData.data().data(), static_cast<int>(pluginData.data().size()))) {
207         TS_LOGW("tracePacketParseFromArray failed\n");
208         dataSeg.status = TS_PARSE_STATUS_INVALID;
209         return;
210     }
211     if (dataSeg.memData.processesinfo_size()) {
212         dataSeg.dataType = DATA_SOURCE_TYPE_MEM;
213         dataSeg.timeStamp = timeStamp;
214         dataSeg.clockId = clockId;
215         dataSeg.status = TS_PARSE_STATUS_PARSED;
216     } else if (dataSeg.memData.meminfo_size()) {
217         dataSeg.dataType = DATA_SOURCE_TYPE_MEM;
218         dataSeg.timeStamp = timeStamp;
219         dataSeg.clockId = clockId;
220         dataSeg.status = TS_PARSE_STATUS_PARSED;
221     } else if (dataSeg.memData.vmeminfo_size()) {
222         dataSeg.dataType = DATA_SOURCE_TYPE_MEM;
223         dataSeg.timeStamp = timeStamp;
224         dataSeg.clockId = clockId;
225         dataSeg.status = TS_PARSE_STATUS_PARSED;
226     } else {
227         dataSeg.status = TS_PARSE_STATUS_INVALID;
228     }
229 }
ParseHilog(const ProfilerPluginData & pluginData,HtraceDataSegment & dataSeg)230 void HtraceParser::ParseHilog(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg)
231 {
232     dataSeg.dataType = DATA_SOURCE_TYPE_HILOG;
233     dataSeg.traceData.Clear();
234     if (!dataSeg.logData.ParseFromArray(pluginData.data().data(), static_cast<int>(pluginData.data().size()))) {
235         TS_LOGW("tracePacketParseFromArray failed\n");
236         dataSeg.status = TS_PARSE_STATUS_PARSED;
237         return;
238     }
239     if (dataSeg.logData.info_size()) {
240         dataSeg.status = TS_PARSE_STATUS_PARSED;
241         return;
242     }
243     dataSeg.status = TS_PARSE_STATUS_INVALID;
244 }
ParseFtrace(const ProfilerPluginData & pluginData,HtraceDataSegment & dataSeg)245 void HtraceParser::ParseFtrace(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg)
246 {
247     dataSeg.dataType = DATA_SOURCE_TYPE_TRACE;
248     dataSeg.traceData.Clear();
249     if (!dataSeg.traceData.ParseFromArray(pluginData.data().data(), static_cast<int>(pluginData.data().size()))) {
250         TS_LOGW("tracePacketParseFromArray failed\n");
251         dataSeg.status = TS_PARSE_STATUS_INVALID;
252         return;
253     }
254     if (dataSeg.traceData.ftrace_cpu_stats_size()) {
255         auto cpuStats = dataSeg.traceData.ftrace_cpu_stats(0);
256         auto s = cpuStats.per_cpu_stats(0);
257         TS_LOGD("s.overrun():%lu", s.overrun());
258         TS_LOGD("s.dropped_events():%lu", s.dropped_events());
259         auto clock = cpuStats.trace_clock();
260         if (clock == "boot") {
261             clock_ = TS_CLOCK_BOOTTIME;
262         }
263         dataSeg.clockId = clock_;
264         dataSeg.status = TS_PARSE_STATUS_PARSED;
265         return;
266     }
267     if (dataSeg.traceData.clocks_detail_size() || dataSeg.traceData.ftrace_cpu_detail_size() ||
268         dataSeg.traceData.symbols_detail_size()) {
269         dataSeg.status = TS_PARSE_STATUS_PARSED;
270         return;
271     }
272     dataSeg.status = TS_PARSE_STATUS_INVALID;
273 }
274 
ParseNativeHook(const ProfilerPluginData & pluginData,HtraceDataSegment & dataSeg)275 void HtraceParser::ParseNativeHook(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg)
276 {
277     dataSeg.dataType = DATA_SOURCE_TYPE_HEAP;
278     dataSeg.traceData.Clear();
279     if (!dataSeg.batchNativeHookData.ParseFromArray(pluginData.data().data(),
280                                                     static_cast<int>(pluginData.data().size()))) {
281         TS_LOGW("tracePacketParseFromArray failed\n");
282         dataSeg.status = TS_PARSE_STATUS_INVALID;
283         return;
284     }
285     if (dataSeg.batchNativeHookData.events_size()) {
286         dataSeg.status = TS_PARSE_STATUS_PARSED;
287         return;
288     }
289     dataSeg.status = TS_PARSE_STATUS_INVALID;
290 }
291 
ParseFPS(const ProfilerPluginData & pluginData,HtraceDataSegment & dataSeg)292 void HtraceParser::ParseFPS(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg)
293 {
294     dataSeg.dataType = DATA_SOURCE_TYPE_FPS;
295     dataSeg.traceData.Clear();
296     if (!dataSeg.hidumpInfo.ParseFromArray(pluginData.data().data(), static_cast<int>(pluginData.data().size()))) {
297         TS_LOGW("tracePacketParseFromArray failed\n");
298         dataSeg.status = TS_PARSE_STATUS_INVALID;
299         return;
300     }
301     if (dataSeg.hidumpInfo.fps_event_size()) {
302         dataSeg.status = TS_PARSE_STATUS_PARSED;
303         return;
304     }
305     dataSeg.status = TS_PARSE_STATUS_INVALID;
306 }
GetNextSegment()307 int HtraceParser::GetNextSegment()
308 {
309     int head;
310     dataSegMux_.lock();
311     head = parseHead_;
312     HtraceDataSegment& seg = dataSegArray[head];
313     if (seg.status.load() != TS_PARSE_STATUS_SEPRATED) {
314         if (toExit_) {
315             parserThreadCount_--;
316             TS_LOGI("exiting parser, parserThread Count:%d\n", parserThreadCount_);
317             TS_LOGD("seprateHead_x:\t%d, parseHead_:\t%d, filterHead_:\t%d status:%d\n", rawDataHead_, parseHead_,
318                     filterHead_, seg.status.load());
319             dataSegMux_.unlock();
320             if (!parserThreadCount_ && !filterThreadStarted_) {
321                 exited_ = true;
322             }
323             return ERROR_CODE_EXIT;
324         }
325         if (seg.status.load() == TS_PARSE_STATUS_PARSING) {
326             dataSegMux_.unlock();
327             usleep(sleepDur_);
328             return ERROR_CODE_NODATA;
329         }
330         dataSegMux_.unlock();
331         usleep(sleepDur_);
332         return ERROR_CODE_NODATA;
333     }
334     parseHead_ = (parseHead_ + 1) % MAX_SEG_ARRAY_SIZE;
335     seg.status = TS_PARSE_STATUS_PARSING;
336     dataSegMux_.unlock();
337     return head;
338 }
ParseTraceDataSegment(std::unique_ptr<uint8_t[]> bufferStr,size_t size)339 void HtraceParser::ParseTraceDataSegment(std::unique_ptr<uint8_t[]> bufferStr, size_t size)
340 {
341     packagesBuffer_.insert(packagesBuffer_.end(), &bufferStr[0], &bufferStr[size]);
342     auto packagesBegin = packagesBuffer_.begin();
343     auto currentLength = packagesBuffer_.size();
344     if (!hasGotHeader) {
345         std::string start(reinterpret_cast<const char*>(bufferStr.get()), std::min<size_t>(size, 20));
346         if (start.compare(0, std::string("OHOSPROF").length(), "OHOSPROF") == 0) {
347             currentLength -= PACKET_HEADER_LENGTH;
348             packagesBegin += PACKET_HEADER_LENGTH;
349         }
350         hasGotHeader = true;
351     }
352     while (1) {
353         if (!hasGotSegLength_) {
354             if (currentLength < PACKET_SEG_LENGTH) {
355                 break;
356             }
357             std::string bufferLine(packagesBegin, packagesBegin + PACKET_SEG_LENGTH);
358             const uint32_t* len = reinterpret_cast<const uint32_t*>(bufferLine.data());
359             nextLength_ = *len;
360             hasGotSegLength_ = true;
361             currentLength -= PACKET_SEG_LENGTH;
362             packagesBegin += PACKET_SEG_LENGTH;
363         }
364         if (currentLength < nextLength_) {
365             break;
366         }
367         std::string bufferLine(packagesBegin, packagesBegin + nextLength_);
368         ParseTraceDataItem(bufferLine);
369         hasGotSegLength_ = false;
370         packagesBegin += nextLength_;
371         currentLength -= nextLength_;
372     }
373     packagesBuffer_.erase(packagesBuffer_.begin(), packagesBegin);
374     return;
375 }
376 } // namespace TraceStreamer
377 } // namespace SysTuning
378