• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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 #include "pbreader_native_hook_parser.h"
16 #include "clock_filter_ex.h"
17 #include "process_filter.h"
18 #include "stat_filter.h"
19 namespace SysTuning {
20 namespace TraceStreamer {
21 constexpr static uint32_t MAX_PROTO_BUFFER_SIZE = 4 * 1024 * 1024;
22 
PbreaderNativeHookParser(TraceDataCache * dataCache,const TraceStreamerFilters * ctx)23 PbreaderNativeHookParser::PbreaderNativeHookParser(TraceDataCache *dataCache, const TraceStreamerFilters *ctx)
24     : EventParserBase(dataCache, ctx), nativeHookFilter_(std::make_unique<NativeHookFilter>(dataCache, ctx))
25 {
26 }
27 
~PbreaderNativeHookParser()28 PbreaderNativeHookParser::~PbreaderNativeHookParser()
29 {
30     TS_LOGI("native hook data ts MIN:%llu, MAX:%llu", static_cast<unsigned long long>(GetPluginStartTime()),
31             static_cast<unsigned long long>(GetPluginEndTime()));
32     TS_LOGI("native real ts MIN:%llu, MAX:%llu", static_cast<unsigned long long>(MinTs()),
33             static_cast<unsigned long long>(MaxTs()));
34 }
35 
ParseStackMap(const ProtoReader::BytesView & bytesView)36 bool PbreaderNativeHookParser::ParseStackMap(const ProtoReader::BytesView &bytesView)
37 {
38     if (traceDataCache_->isSplitFile_) {
39         auto hookData = nativeHookFilter_->GetCommHookData().datas->add_events();
40         StackMap *stackMap = hookData->mutable_stack_map();
41         stackMap->ParseFromArray(bytesView.Data(), bytesView.Size());
42         nativeHookFilter_->GetCommHookData().size += bytesView.Size();
43         return false;
44     }
45     ProtoReader::StackMap_Reader stackMapReader(bytesView);
46     bool parseError = false;
47     auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(stackMapReader.pid(), "");
48     // stores frames info. if offlineSymbolization is true, storing ips data, else storing FrameMap id.
49     std::vector<uint64_t> frames;
50     if (stackMapReader.has_frame_map_id()) {
51         auto itor = stackMapReader.frame_map_id(&parseError);
52         TS_CHECK_TRUE(!parseError, false, "Parse packed varInt in ParseStackMap function failed!!!");
53         while (itor) {
54             frames.emplace_back(*itor);
55             itor++;
56         }
57     } else if (stackMapReader.has_ip()) {
58         auto itor = stackMapReader.ip(&parseError);
59         TS_CHECK_TRUE(!parseError, false, "Parse packed varInt in ParseStackMap function failed!!!");
60         // OfflineSymbolization use ipidToStartAddrToMapsInfoMap_ Multi-process differentiation
61         while (itor) {
62             frames.emplace_back(*itor);
63             itor++;
64         }
65     }
66     nativeHookFilter_->AppendStackMaps(ipid, stackMapReader.id(), frames);
67     return true;
68 }
69 
ParseFrameMap(std::unique_ptr<NativeHookMetaData> & nativeHookMetaData)70 void PbreaderNativeHookParser::ParseFrameMap(std::unique_ptr<NativeHookMetaData> &nativeHookMetaData)
71 {
72     segs_.emplace_back(nativeHookMetaData->seg_);
73     const ProtoReader::BytesView &frameMapByteView = nativeHookMetaData->reader_->frame_map();
74     if (traceDataCache_->isSplitFile_) {
75         auto hookData = nativeHookFilter_->GetCommHookData().datas->add_events();
76         FrameMap *frameMap = hookData->mutable_frame_map();
77         frameMap->ParseFromArray(frameMapByteView.Data(), frameMapByteView.Size());
78         nativeHookFilter_->GetCommHookData().size += frameMapByteView.Size();
79         return;
80     }
81     ProtoReader::FrameMap_Reader frameMapReader(frameMapByteView);
82     auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(frameMapReader.pid(), "");
83     // when callstack is compressed, Frame message only has ip data area.
84     nativeHookFilter_->AppendFrameMaps(ipid, frameMapReader.id(), frameMapReader.frame());
85 }
ParseFileEvent(const ProtoReader::BytesView & bytesView)86 void PbreaderNativeHookParser::ParseFileEvent(const ProtoReader::BytesView &bytesView)
87 {
88     if (traceDataCache_->isSplitFile_) {
89         auto hookData = nativeHookFilter_->GetCommHookData().datas->add_events();
90         FilePathMap *filePathMap = hookData->mutable_file_path();
91         filePathMap->ParseFromArray(bytesView.Data(), bytesView.Size());
92         nativeHookFilter_->GetCommHookData().size += bytesView.Size();
93         return;
94     }
95     ProtoReader::FilePathMap_Reader filePathMapReader(bytesView);
96     auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(filePathMapReader.pid(), "");
97     auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(filePathMapReader.name().ToStdString());
98     nativeHookFilter_->AppendFilePathMaps(ipid, filePathMapReader.id(), nameIndex);
99 }
ParseSymbolEvent(const ProtoReader::BytesView & bytesView)100 void PbreaderNativeHookParser::ParseSymbolEvent(const ProtoReader::BytesView &bytesView)
101 {
102     if (traceDataCache_->isSplitFile_) {
103         auto hookData = nativeHookFilter_->GetCommHookData().datas->add_events();
104         SymbolMap *symbolMap = hookData->mutable_symbol_name();
105         symbolMap->ParseFromArray(bytesView.Data(), bytesView.Size());
106         nativeHookFilter_->GetCommHookData().size += bytesView.Size();
107         return;
108     }
109     ProtoReader::SymbolMap_Reader symbolMapReader(bytesView);
110     auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(symbolMapReader.pid(), "");
111     auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(symbolMapReader.name().ToStdString());
112     nativeHookFilter_->AppendSymbolMap(ipid, symbolMapReader.id(), nameIndex);
113 }
ParseThreadEvent(const ProtoReader::BytesView & bytesView)114 void PbreaderNativeHookParser::ParseThreadEvent(const ProtoReader::BytesView &bytesView)
115 {
116     if (traceDataCache_->isSplitFile_) {
117         auto hookData = nativeHookFilter_->GetCommHookData().datas->add_events();
118         ThreadNameMap *threadNameMap = hookData->mutable_thread_name_map();
119         threadNameMap->ParseFromArray(bytesView.Data(), bytesView.Size());
120         nativeHookFilter_->GetCommHookData().size += bytesView.Size();
121         return;
122     }
123     ProtoReader::ThreadNameMap_Reader threadNameMapReader(bytesView);
124     auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(threadNameMapReader.pid(), "");
125     auto nameIndex = traceDataCache_->GetDataIndex(threadNameMapReader.name().ToStdString());
126     nativeHookFilter_->AppendThreadNameMap(ipid, threadNameMapReader.id(), nameIndex);
127 }
128 
ParseNativeHookAuxiliaryEvent(std::unique_ptr<NativeHookMetaData> & nativeHookMetaData)129 void PbreaderNativeHookParser::ParseNativeHookAuxiliaryEvent(std::unique_ptr<NativeHookMetaData> &nativeHookMetaData)
130 {
131     auto &reader = nativeHookMetaData->reader_;
132     if (reader->has_stack_map()) {
133         ParseStackMap(reader->stack_map());
134     } else if (reader->has_frame_map()) {
135         ParseFrameMap(nativeHookMetaData);
136     } else if (reader->has_file_path()) {
137         ParseFileEvent(reader->file_path());
138     } else if (reader->has_symbol_name()) {
139         ParseSymbolEvent(reader->symbol_name());
140     } else if (reader->has_thread_name_map()) {
141         ParseThreadEvent(reader->thread_name_map());
142     } else if (reader->has_maps_info()) {
143         nativeHookFilter_->ParseMapsEvent(nativeHookMetaData);
144     } else if (reader->has_symbol_tab()) {
145         nativeHookFilter_->ParseSymbolTableEvent(nativeHookMetaData);
146     } else if (reader->has_tag_event()) {
147         nativeHookFilter_->ParseTagEvent(reader->tag_event());
148     } else {
149         TS_LOGE("unsupported native_hook data!");
150     }
151 }
SplitHookData(std::unique_ptr<NativeHookMetaData> & nativeHookMetaData,bool & haveSplitSeg)152 void PbreaderNativeHookParser::SplitHookData(std::unique_ptr<NativeHookMetaData> &nativeHookMetaData,
153                                              bool &haveSplitSeg)
154 {
155     if (isCommData_ && hookBootTime_ <= traceDataCache_->SplitFileMinTime()) {
156         ParseNativeHookAuxiliaryEvent(nativeHookMetaData);
157     } else if (hookBootTime_ >= traceDataCache_->SplitFileMinTime() &&
158                hookBootTime_ <= traceDataCache_->SplitFileMaxTime()) {
159         haveSplitSeg = true;
160     }
161 }
162 // In order to improve the accuracy of data, it is necessary to sort the original data.
163 // Data sorting will be reduced by 5% to 10% Speed of parsing data.
Parse(PbreaderDataSegment & dataSeg,bool & haveSplitSeg)164 void PbreaderNativeHookParser::Parse(PbreaderDataSegment &dataSeg, bool &haveSplitSeg)
165 {
166     auto batchNativeHookDataReader = ProtoReader::BatchNativeHookData_Reader(dataSeg.protoData);
167     for (auto itor = batchNativeHookDataReader.events(); itor; itor++) {
168         auto nativeHookDataReader = std::make_unique<ProtoReader::NativeHookData_Reader>(itor->ToBytes());
169         auto nativeHookMetaData = std::make_unique<NativeHookMetaData>(dataSeg.seg, std::move(nativeHookDataReader));
170         isCommData_ =
171             !(nativeHookMetaData->reader_->has_alloc_event() || nativeHookMetaData->reader_->has_free_event() ||
172               nativeHookMetaData->reader_->has_mmap_event() || nativeHookMetaData->reader_->has_munmap_event() ||
173               nativeHookMetaData->reader_->has_statistics_event());
174         hookBootTime_ = 0;
175         if (!isCommData_ && (nativeHookMetaData->reader_->has_tv_sec() || nativeHookMetaData->reader_->has_tv_nsec())) {
176             auto timeStamp = nativeHookMetaData->reader_->tv_nsec() + nativeHookMetaData->reader_->tv_sec() * SEC_TO_NS;
177             hookBootTime_ = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, timeStamp);
178             auto timeRange = hookBootTime_ > statisticsInterval_ ? hookBootTime_ - statisticsInterval_ : 0;
179             UpdatePluginTimeRange(TS_CLOCK_REALTIME, timeStamp - statisticsInterval_, timeRange);
180             UpdatePluginTimeRange(TS_CLOCK_REALTIME, timeStamp, hookBootTime_);
181         }
182         if (haveSplitSeg) {
183             return;
184         } else if (traceDataCache_->isSplitFile_) {
185             SplitHookData(nativeHookMetaData, haveSplitSeg);
186             continue;
187         }
188         if (!isCommData_ || nativeHookMetaData->reader_->has_tag_event()) {
189             nativeHookFilter_->MaybeParseNativeHookMainEvent(hookBootTime_, std::move(nativeHookMetaData));
190         } else {
191             ParseNativeHookAuxiliaryEvent(nativeHookMetaData);
192         }
193     }
194     if (!traceDataCache_->isSplitFile_ || nativeHookFilter_->GetCommHookData().size < MAX_PROTO_BUFFER_SIZE) {
195         return;
196     }
197     nativeHookFilter_->SerializeHookCommDataToString();
198 }
ParseConfigInfo(PbreaderDataSegment & dataSeg)199 void PbreaderNativeHookParser::ParseConfigInfo(PbreaderDataSegment &dataSeg)
200 {
201     nativeHookFilter_->ParseConfigInfo(dataSeg.protoData, statisticsInterval_);
202 }
FinishSplitNativeHook()203 void PbreaderNativeHookParser::FinishSplitNativeHook()
204 {
205     nativeHookFilter_->SerializeHookCommDataToString();
206 }
FinishParseNativeHookData()207 void PbreaderNativeHookParser::FinishParseNativeHookData()
208 {
209     nativeHookFilter_->FinishParseNativeHookData();
210 }
Finish()211 void PbreaderNativeHookParser::Finish()
212 {
213     if (GetPluginStartTime() != GetPluginEndTime()) {
214         traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime());
215     } else {
216         traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginStartTime() + 1);
217     }
218 }
219 } // namespace TraceStreamer
220 } // namespace SysTuning
221