• 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 #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