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 #include "segment_analysis_twolayers.h"
16
17 #include <unistd.h>
18
19 #include "logger.h"
20 #include "log_util.h"
21 #include "string_util.h"
22 using namespace std;
23 namespace OHOS {
24 namespace HiviewDFX {
25 DEFINE_LOG_TAG("SegmentAnalysisTwoLayers");
SegmentAnalysisTwoLayers()26 SegmentAnalysisTwoLayers::SegmentAnalysisTwoLayers()
27 {
28 nextHandleVec_.clear();
29 nextHandleVec_.push_back(make_pair(SEGMENT_WAIT_OTHER,
30 bind(&SegmentAnalysisTwoLayers::GetNextSegWaitOther, this,
31 placeholders::_1, placeholders::_2, placeholders::_3)));
32 nextHandleVec_.push_back(make_pair(SEGMENT_IPC_TRANS,
33 bind(&SegmentAnalysisTwoLayers::GetNextSegIpcTrans, this,
34 placeholders::_1, placeholders::_2, placeholders::_3)));
35 nextHandleVec_.push_back(make_pair(SEGMENT_IPC_FULL,
36 bind(&SegmentAnalysisTwoLayers::GetNextSegIpcFull, this,
37 placeholders::_1, placeholders::_2, placeholders::_3)));
38 }
39
CheckParam(const ParamFeature & feature,const vector<string> & startSeg) const40 bool SegmentAnalysisTwoLayers::CheckParam(const ParamFeature& feature, const vector<string>& startSeg) const
41 {
42 if (startSeg.size() != 2 || feature.size() == 0) { // 2: size of startSeg vector
43 HIVIEW_LOGE("startSeg size: %{public}zu, ParamFeature size: %{public}zu", startSeg.size(), feature.size());
44 return false;
45 }
46 return true;
47 }
48
AddSegment(UniqSegment & seg)49 void SegmentAnalysisTwoLayers::AddSegment(UniqSegment& seg)
50 {
51 if (curLayerOneSegId_ < 0) {
52 HIVIEW_LOGE("segment id invalid: %{public}d", curLayerOneSegId_);
53 return;
54 }
55 segInfoVec_.push_back(make_tuple(curLayerOneSegId_, seg->GetValue(SEGMENT_PARENT_NAME),
56 seg->GetId(), seg->GetName(), seg->GetSysTid()));
57 pairMap_.insert(make_pair(make_pair(curLayerOneSegId_, seg->GetId()), move(seg)));
58 }
59
60 // key: pair(pid, tid)
GetSegment(const pair<int,int> & key,UniqSegment & seg)61 bool SegmentAnalysisTwoLayers::GetSegment(const pair<int, int>& key, UniqSegment& seg)
62 {
63 auto it = pairMap_.find(key);
64 if (it != pairMap_.end()) {
65 seg = move(it->second);
66 pairMap_.erase(it);
67 return true;
68 }
69 return false;
70 }
71
72 // key: pair(pname, tname)
GetSegment(const pair<string,string> & key,UniqSegment & seg)73 bool SegmentAnalysisTwoLayers::GetSegment(const pair<string, string>& key, UniqSegment& seg)
74 {
75 pair<int, int> p(-1, -1);
76 for (const auto& info : segInfoVec_) {
77 if (get<TUPLE_IDX_PNAME>(info) == key.first && get<TUPLE_IDX_TNAME>(info) == key.second) {
78 p.first = get<TUPLE_IDX_PID>(info);
79 p.second = get<TUPLE_IDX_TID>(info);
80 break;
81 }
82 }
83 return (p.first < 0 || p.second < 0) ? false : GetSegment(p, seg);
84 }
85
86 // key: pair(pid, sysTid)
GetSegmentBySysTid(const pair<int,int> & key,UniqSegment & seg)87 bool SegmentAnalysisTwoLayers::GetSegmentBySysTid(const pair<int, int>& key, UniqSegment& seg)
88 {
89 pair<int, int> p(-1, -1);
90 for (const auto& info : segInfoVec_) {
91 if (get<TUPLE_IDX_PID>(info) == key.first && get<TUPLE_IDX_SYSTID>(info) == key.second) {
92 p.first = get<TUPLE_IDX_PID>(info);
93 p.second = get<TUPLE_IDX_TID>(info);
94 break;
95 }
96 }
97 return (p.first < 0 || p.second < 0) ? false : GetSegment(p, seg);
98 }
99
GetStartSegment(const vector<string> & startSeg)100 bool SegmentAnalysisTwoLayers::GetStartSegment(const vector<string>& startSeg)
101 {
102 // search by (pid, sysTid) or (processName, threadName)
103 int pid = StringUtil::StrToInt(startSeg[0]);
104 int sysTid = StringUtil::StrToInt(startSeg[1]);
105 if (pid > 0 && sysTid > 0) {
106 if (!GetSegmentBySysTid(make_pair(pid, sysTid), startSeg_)) {
107 HIVIEW_LOGE("Failed to get segment: %{public}s %{public}s", startSeg[0].c_str(), startSeg[1].c_str());
108 return false;
109 }
110 } else {
111 if (!GetSegment(make_pair(startSeg[0], startSeg[1]), startSeg_)) {
112 HIVIEW_LOGE("Failed to get segment: %{public}s %{public}s", startSeg[0].c_str(), startSeg[1].c_str());
113 if (!GetSegment(make_pair(startSeg[0], SEGMENT_DEFAULT_THD_NAME), startSeg_)) {
114 HIVIEW_LOGE("Failed to get segment: %{public}s main", startSeg[0].c_str());
115 return false;
116 }
117 }
118 }
119 return true;
120 }
121
RecordLayerTwoSegment(const ParamFeature & feature,ParamFeatureIter begin,ParamFeatureIter end)122 void SegmentAnalysisTwoLayers::RecordLayerTwoSegment(const ParamFeature& feature,
123 ParamFeatureIter begin, ParamFeatureIter end)
124 {
125 auto isFirst = [](const pair<string, LineFeature> &p) {return p.first.find(SEGMENT_CMD_LAYER_TWO) == 0;};
126 auto iter = find_if(begin, end, isFirst);
127 while (iter != end) {
128 auto nextBegin = iter->first;
129 string value = iter->second.value;
130 auto seg = make_unique<Segment>();
131 seg->SetValue(StringUtil::GetRightSubstr(iter->first, SEGMENT_DELIM), iter->second.value);
132 seg->SetValue(SEGMENT_CURSOR, to_string(iter->second.lineCursor));
133 seg->SetValue(SEGMENT_PARENT_ID, to_string(curLayerOneSegId_));
134 seg->SetValue(SEGMENT_PARENT_NAME, GetNameById(curLayerOneSegId_));
135 for (int i = 1; i < LAYER_TWO_CMD_PARAM_NUM; ++i) {
136 ++iter; // to prevent dead loop
137 if (iter != end &&
138 iter->first != nextBegin &&
139 iter->first.find(SEGMENT_CMD_LAYER_TWO) == 0) {
140 seg->SetValue(StringUtil::GetRightSubstr(iter->first, SEGMENT_DELIM), iter->second.value);
141 } else {
142 HIVIEW_LOGE("wrong format, nextBegin: %{public}s %{public}s", nextBegin.c_str(), value.c_str());
143 break;
144 }
145 }
146 AddSegment(seg);
147 auto isNext = [&](const pair<string, LineFeature> &p) {return p.first == nextBegin;};
148 iter = find_if(iter, end, isNext);
149 }
150 }
151
RecordIpcSegment(const ParamFeature & feature)152 void SegmentAnalysisTwoLayers::RecordIpcSegment(const ParamFeature& feature)
153 {
154 if (isIpcBuilded_) {
155 return;
156 }
157 auto isEqual = [](const pair<string, LineFeature> &p) {return p.first == SEGMENT_CMD_IPC + "." + SEGMENT_NAME;};
158 auto iter = find_if(begin(feature), end(feature), isEqual);
159 if (iter != end(feature)) {
160 ipcSeg_ = make_unique<Segment>();
161 ipcSeg_->SetValue(SEGMENT_NAME, iter->second.value);
162 ipcSeg_->SetValue(SEGMENT_CURSOR, to_string(iter->second.lineCursor));
163 }
164 isIpcBuilded_ = true;
165 }
166
RecordOtherSegment(const ParamFeature & feature,int layerOneId,ParamFeatureIter begin,ParamFeatureIter end)167 void SegmentAnalysisTwoLayers::RecordOtherSegment(const ParamFeature& feature,
168 int layerOneId, ParamFeatureIter begin, ParamFeatureIter end)
169 {
170 /*
171 * examples of feature:
172 * ("LayerOneCmd.s_id", LineFeature) -- two-layers segment starts
173 * ("LayerOneCmd.s_name", LineFeature)
174 * ("LayerTwoCmd.s_id", LineFeature)
175 * ("LayerTwoCmd.s_name", LineFeature)
176 * ("LayerTwoCmd.s_sysTid", LineFeature)
177 * ...
178 * ("LayerTwoCmd.s_id", LineFeature)
179 * ("LayerTwoCmd.s_name", LineFeature)
180 * ("LayerTwoCmd.s_sysTid", LineFeature)
181 * ("LayerOneCmd.s_id", LineFeature) -- another two-layers segment starts
182 * ("LayerOneCmd.s_name", LineFeature)
183 * ("LayerTwoCmd.s_id", LineFeature)
184 * ("LayerTwoCmd.s_name", LineFeature)
185 * ("LayerTwoCmd.s_sysTid", LineFeature)
186 * ...
187 * ("LayerTwoCmd.s_id", LineFeature)
188 * ("LayerTwoCmd.s_name", LineFeature)
189 * ("LayerTwoCmd.s_sysTid", LineFeature)
190 */
191 if (layerOneId < 0) {
192 HIVIEW_LOGE("segment id invalid: %{public}d", layerOneId);
193 return;
194 }
195 SetCurLayerOneSegmentId(layerOneId); // when a new two-layers segment starts, save its id
196 RecordLayerTwoSegment(feature, begin, end);
197 RecordIpcSegment(feature);
198 }
199
HasNextSegment(const UniqSegment & seg) const200 bool SegmentAnalysisTwoLayers::HasNextSegment(const UniqSegment& seg) const
201 {
202 if (!seg->GetValue(SEGMENT_WAIT_OTHER).empty() ||
203 !seg->GetValue(SEGMENT_IPC_TRANS).empty() ||
204 !seg->GetValue(SEGMENT_IPC_FULL).empty()) {
205 return true;
206 }
207 return false;
208 }
209
GetNextSegWaitOther(int pid,const UniqSegment & seg,UniqSegment & nextSeg)210 bool SegmentAnalysisTwoLayers::GetNextSegWaitOther(int pid, const UniqSegment& seg, UniqSegment& nextSeg)
211 {
212 return GetSegment(make_pair(pid, StringUtil::StrToInt(seg->GetValue(SEGMENT_WAIT_OTHER))), nextSeg);
213 }
214
GetNextSegIpcTrans(int pid,UniqSegment & seg,UniqSegment & nextSeg)215 bool SegmentAnalysisTwoLayers::GetNextSegIpcTrans(int pid, UniqSegment& seg, UniqSegment& nextSeg)
216 {
217 if (reason_.empty()) {
218 reason_ = REASON_IPC_TIMEOUT;
219 }
220 if (ipcSeg_ == nullptr) {
221 HIVIEW_LOGE("Failed to get ipc segment, cur %{public}d:%{public}d", pid, seg->GetSysTid());
222 return false;
223 }
224 int cursor = StringUtil::StrToInt(ipcSeg_->GetValue(SEGMENT_CURSOR));
225 if (cursor < 0) {
226 HIVIEW_LOGE("Failed to get cursor, segment: %{public}s", ipcSeg_->GetName().c_str());
227 return false;
228 }
229 HIVIEW_LOGI("Begin parse ipc info, cursor:%{public}d", cursor);
230 LogUtil logParse;
231 pair<int, int> pidTid(-1, -1);
232 vector<string> lines;
233 tie(pidTid, lines) = logParse.ParseIpcInfo(errLogBuf_, cursor, make_pair(pid, seg->GetSysTid()));
234 if (!errLogBuf_.good()) {
235 HIVIEW_LOGI("After parse ipc info, the state may change to EOF, need to clear");
236 errLogBuf_.clear();
237 }
238 if (pidTid.first > 0) {
239 string ipcInfo;
240 for (const auto& line : lines) {
241 ipcInfo += line + LogUtil::SPLIT_PATTERN;
242 }
243 seg->SetValue(SEGMENT_IPC_INFO, ipcInfo);
244 HIVIEW_LOGI("ipc target, %{public}d:%{public}d", pidTid.first, pidTid.second);
245 return GetSegmentBySysTid(pidTid, nextSeg);
246 }
247 HIVIEW_LOGE("Parse ipc info failed, cursor:%{public}d, %{public}d:%{public}d", cursor, pid, seg->GetSysTid());
248 return false;
249 }
250
ExtractSegment(UniqSegment & seg)251 void SegmentAnalysisTwoLayers::ExtractSegment(UniqSegment& seg)
252 {
253 if (!seg->GetValue(SEGMENT_EXTRACTED).empty()) {
254 HIVIEW_LOGI("segment: %{public}s already extracted", seg->GetName().c_str());
255 return;
256 }
257 int cursor = StringUtil::StrToInt(seg->GetValue(SEGMENT_CURSOR));
258 if (cursor < 0) {
259 HIVIEW_LOGE("Failed to get cursor, segment: %{public}s", seg->GetName().c_str());
260 return;
261 }
262 errLogBuf_.seekg(cursor, ios::beg);
263 int num = 0;
264 string line;
265 while (getline(errLogBuf_, line) && !line.empty() && num++ < LogUtil::TOTAL_LINE_NUM) {
266 for (auto iter = segStatusCfg_.begin(); iter != segStatusCfg_.end(); iter++) {
267 smatch result;
268 if (!iter->second[0].empty() && regex_search(line, result, regex(iter->second[0]))) {
269 seg->SetValue(iter->first, result.str(1));
270 }
271 }
272 if (segStatusCfg_.empty()) {
273 break;
274 }
275 }
276 seg->SetValue(SEGMENT_EXTRACTED, "true");
277 }
278
GetFirstBlockedIpcSeg(int pid,UniqSegment & seg)279 bool SegmentAnalysisTwoLayers::GetFirstBlockedIpcSeg(int pid, UniqSegment& seg)
280 {
281 for (const auto& i : segInfoVec_) {
282 if (get<TUPLE_IDX_PID>(i) == pid && get<TUPLE_IDX_TNAME>(i).find(SEGMENT_IPC_THREAD + to_string(pid)) == 0) {
283 auto it = pairMap_.find(make_pair(get<TUPLE_IDX_PID>(i), get<TUPLE_IDX_TID>(i)));
284 if (it == pairMap_.end()) {
285 continue;
286 }
287 if (it->second->GetValue(SEGMENT_STATUS).empty()) { // hasn't been extracted yet
288 ExtractSegment(it->second);
289 }
290 if (it->second->GetValue(SEGMENT_STATUS) != "Runnable") {
291 seg = move(it->second);
292 pairMap_.erase(it);
293 return true;
294 }
295 }
296 }
297 return false;
298 }
299
GetNextSegIpcFull(int pid,const UniqSegment & seg,UniqSegment & nextSeg)300 bool SegmentAnalysisTwoLayers::GetNextSegIpcFull(int pid, const UniqSegment& seg, UniqSegment& nextSeg)
301 {
302 if (reason_.empty()) {
303 reason_ = REASON_IPC_FULL;
304 }
305 return GetFirstBlockedIpcSeg(pid, nextSeg);
306 }
307
GetNextSegment(UniqSegment & seg,UniqSegment & nextSeg)308 bool SegmentAnalysisTwoLayers::GetNextSegment(UniqSegment& seg, UniqSegment& nextSeg)
309 {
310 int pid = StringUtil::StrToInt(seg->GetValue(SEGMENT_PARENT_ID));
311 if (pid < 0) {
312 HIVIEW_LOGE("Invalid pid: %{public}d, segment: %{public}s", pid, seg->GetName().c_str());
313 return false;
314 }
315 for (const auto& handle : nextHandleVec_) {
316 if (!seg->GetValue(handle.first).empty()) {
317 return handle.second(pid, seg, nextSeg);
318 }
319 }
320 HIVIEW_LOGI("No next handle for segment: %{public}s", seg->GetName().c_str());
321 return false;
322 }
323
NextSegHasAnalyzed(const UniqSegment & seg,Segment * & retSeg) const324 bool SegmentAnalysisTwoLayers::NextSegHasAnalyzed(const UniqSegment& seg, Segment*& retSeg) const
325 {
326 int lockTookTid = StringUtil::StrToInt(seg->GetValue(SEGMENT_WAIT_OTHER));
327 if (lockTookTid < 0) {
328 return false;
329 }
330 int pid = StringUtil::StrToInt(seg->GetValue(SEGMENT_PARENT_ID));
331 auto isEqual = [&](const UniqSegment& s) {return s->GetId() == lockTookTid &&
332 StringUtil::StrToInt(s->GetValue(SEGMENT_PARENT_ID)) == pid;};
333 auto iter = find_if(begin(blockedSegVec_), end(blockedSegVec_), isEqual);
334 if (iter != end(blockedSegVec_)) {
335 retSeg = (*iter).get();
336 return true;
337 }
338 return false;
339 }
340
341 // from startSeg, add all dependent segments to blockedSegVec_, update reason_ at the same time
AnalyzeBlockedChain()342 void SegmentAnalysisTwoLayers::AnalyzeBlockedChain()
343 {
344 ExtractSegment(startSeg_);
345 blockedSegVec_.push_back(move(startSeg_));
346 startSeg_ = nullptr;
347
348 UniqSegment nextSeg = nullptr;
349 while (HasNextSegment(blockedSegVec_.back()) && blockedSegVec_.size() <= SEGMENT_MAX_BLOCKED_NUM) {
350 if (GetNextSegment(blockedSegVec_.back(), nextSeg) && nextSeg != nullptr) {
351 ExtractSegment(nextSeg);
352 blockedSegVec_.push_back(move(nextSeg));
353 } else {
354 Segment* retSeg = nullptr;
355 if (NextSegHasAnalyzed(blockedSegVec_.back(), retSeg)) {
356 reason_ = REASON_DEAD_LOCK; // overwrite old value
357 }
358 break;
359 }
360 }
361 if (reason_.empty()) {
362 reason_ = REASON_THREAD_TIMEOUT; // set default value
363 }
364 }
365
GetOriginalInfo(int cursor)366 string SegmentAnalysisTwoLayers::GetOriginalInfo(int cursor)
367 {
368 errLogBuf_.seekg(cursor, ios::beg);
369 string ret;
370 string line;
371 int num = 0;
372 while (getline(errLogBuf_, line) && num++ < LogUtil::TOTAL_LINE_NUM) {
373 if (line.empty()) {
374 break;
375 }
376 ret += line + LogUtil::SPLIT_PATTERN;
377 }
378 return ret + LogUtil::SPLIT_PATTERN;
379 }
380
GetBlockedChain(void)381 void SegmentAnalysisTwoLayers::GetBlockedChain(void)
382 {
383 string desc;
384 size_t vecSize = blockedSegVec_.size();
385 for (size_t i = 0; i < vecSize; ++i) {
386 allStacks_ += GetOriginalInfo(StringUtil::StrToInt(blockedSegVec_[i]->GetValue(SEGMENT_CURSOR)));
387 desc += blockedSegVec_[i]->GetDesc(segStatusCfg_);
388 if (i == vecSize - 1) {
389 Segment* retSeg = nullptr;
390 if (NextSegHasAnalyzed(blockedSegVec_[i], retSeg)) {
391 desc += retSeg->GetFullName();
392 }
393 break;
394 }
395 if (!blockedSegVec_[i]->GetValue(SEGMENT_WAIT_OTHER).empty()) {
396 desc += blockedSegVec_[i + 1]->GetFullName() + "," + LogUtil::SPLIT_PATTERN;
397 } else if (!blockedSegVec_[i]->GetValue(SEGMENT_IPC_TRANS).empty()) {
398 desc += LogUtil::SPLIT_PATTERN + blockedSegVec_[i]->GetValue(SEGMENT_IPC_INFO);
399 } else {
400 desc += LogUtil::SPLIT_PATTERN;
401 }
402 }
403 blockedChain_ = desc;
404 }
405
GetEndStack(const vector<string> & segStack)406 void SegmentAnalysisTwoLayers::GetEndStack(const vector<string>& segStack)
407 {
408 int cursor = StringUtil::StrToInt(blockedSegVec_.back()->GetValue(SEGMENT_CURSOR));
409 if (cursor < 0) {
410 HIVIEW_LOGE("Failed to get cursor, segment: %{public}s", blockedSegVec_.back()->GetName().c_str());
411 return;
412 }
413 string stackMatch = (segStack.size() == 2) ? segStack[0] : DEFAULT_LAYER_TWO_STACK_MATCH; // 2: size of segStack
414 string stackStart = (segStack.size() == 2) ? segStack[1] : stackMatch; // 2: size of segStack
415 LogUtil::GetTrace(errLogBuf_, cursor, stackMatch, endStack_, stackStart);
416 }
417 } // namespace HiviewDFX
418 } // namespace OHOS