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