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