• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "sample_stack_printer.h"
17 
18 #include <iostream>
19 #include <sstream>
20 
21 #include "dfx_frame_formatter.h"
22 #include "thread_sampler_utils.h"
23 
24 namespace OHOS {
25 namespace HiviewDFX {
Insert(std::shared_ptr<SampleStackItem> curNode,uintptr_t pc,int32_t count,uint64_t level,std::shared_ptr<SampleStackItem> acientNode)26 std::shared_ptr<SampleStackItem> SampleStackPrinter::Insert(std::shared_ptr<SampleStackItem> curNode,
27     uintptr_t pc, int32_t count, uint64_t level, std::shared_ptr<SampleStackItem> acientNode)
28 {
29     if (curNode == nullptr) {
30         return nullptr;
31     }
32 
33     if (curNode->pc == pc) {
34         curNode->count += count;
35         return curNode;
36     }
37 
38     if (curNode->pc == 0) {
39         curNode->pc = pc;
40         curNode->count += count;
41         return curNode;
42     }
43 
44     if (level > curNode->level) {
45         acientNode = curNode;
46 
47         if (curNode->child == nullptr) {
48             curNode->child = std::make_shared<SampleStackItem>();
49             curNode->child->level = curNode->level + 1;
50             return Insert(curNode->child, pc, count, level, acientNode);
51         }
52 
53         if (curNode->child->pc == pc) {
54             curNode->child->count += count;
55             return curNode->child;
56         }
57 
58         curNode = curNode->child;
59     }
60 
61     if (curNode->siblings == nullptr) {
62         curNode->siblings = std::make_shared<SampleStackItem>();
63         curNode->siblings->level = curNode->level;
64         std::shared_ptr<SampleStackItem> node = Insert(curNode->siblings, pc, count, level, acientNode);
65         curNode = AdjustSiblings(acientNode, curNode, node);
66         return curNode;
67     }
68 
69     if (curNode->siblings->pc == pc) {
70         curNode->siblings->count += count;
71         curNode = AdjustSiblings(acientNode, curNode, curNode->siblings);
72         return curNode;
73     }
74 
75     return Insert(curNode->siblings, pc, count, level, acientNode);
76 }
77 
Insert(std::vector<uintptr_t> & pcs,int32_t count)78 void SampleStackPrinter::Insert(std::vector<uintptr_t>& pcs, int32_t count)
79 {
80     if (root_ == nullptr) {
81         root_ = std::make_shared<SampleStackItem>();
82         root_->level = 0;
83     }
84 
85     std::shared_ptr<SampleStackItem> dummyNode = std::make_shared<SampleStackItem>();
86     std::shared_ptr<SampleStackItem> acientNode = dummyNode;
87     acientNode->child = root_;
88     std::shared_ptr<SampleStackItem> curNode = root_;
89     uint64_t level = 0;
90     for (auto iter = pcs.rbegin(); iter != pcs.rend(); ++iter) {
91         curNode = Insert(curNode, *iter, count, level, acientNode);
92         level++;
93     }
94 }
95 
AdjustSiblings(std::shared_ptr<SampleStackItem> acient,std::shared_ptr<SampleStackItem> cur,std::shared_ptr<SampleStackItem> node)96 std::shared_ptr<SampleStackItem> SampleStackPrinter::AdjustSiblings(std::shared_ptr<SampleStackItem> acient,
97     std::shared_ptr<SampleStackItem> cur, std::shared_ptr<SampleStackItem> node)
98 {
99     std::shared_ptr<SampleStackItem> dummy = std::make_shared<SampleStackItem>();
100     dummy->siblings = acient->child;
101     std::shared_ptr<SampleStackItem> p = dummy;
102     while (p->siblings != node && p->siblings->count >= node->count) {
103         p = p->siblings;
104     }
105     if (p->siblings != node) {
106         cur->siblings = node->siblings;
107         node->siblings = p->siblings;
108         if (p == dummy) {
109             acient->child = node;
110         }
111         p->siblings = node;
112     }
113     return node;
114 }
115 
GetFullStack(const std::vector<TimeAndFrames> & timeAndFrameList)116 std::string SampleStackPrinter::GetFullStack(const std::vector<TimeAndFrames>& timeAndFrameList)
117 {
118     std::string stack("");
119     for (const auto& taf : timeAndFrameList) {
120         std::string requestTimeStr = TimeFormat(taf.requestTime);
121         std::string snapshotTimeStr = TimeFormat(taf.snapshotTime);
122         if (requestTimeStr == "" || snapshotTimeStr == "") {
123             return stack;
124         }
125         stack += ("RequestTime:" + requestTimeStr + "\nSnapshotTime:" + snapshotTimeStr + "\n");
126         std::vector<DfxFrame> frames = taf.frameList;
127         for (auto& frame : frames) {
128             unwinder_->FillFrame(frame);
129             auto frameStr = DfxFrameFormatter::GetFrameStr(frame);
130             stack += frameStr;
131         }
132         stack += "\n";
133     }
134     return stack;
135 }
136 
GetTreeStack(std::vector<StackIdAndCount> & stackIdCount,std::unique_ptr<UniqueStackTable> & uniqueStackTable,std::string & heaviestStack)137 std::string SampleStackPrinter::GetTreeStack(std::vector<StackIdAndCount>& stackIdCount,
138     std::unique_ptr<UniqueStackTable>& uniqueStackTable, std::string& heaviestStack)
139 {
140     std::sort(stackIdCount.begin(), stackIdCount.end(), [](const auto& a, const auto& b) {
141         return a.count > b.count;
142     });
143     std::string stack("");
144     for (auto it = stackIdCount.begin(); it != stackIdCount.end(); it++) {
145         std::vector<uintptr_t> pcs;
146         OHOS::HiviewDFX::StackId stackId;
147         stackId.value = it->stackId;
148         if (uniqueStackTable->GetPcsByStackId(stackId, pcs)) {
149             Insert(pcs, it->count);
150         }
151         if (it == stackIdCount.begin()) {
152             heaviestStack = "heaviest stack: \nstack counts: " + std::to_string(it->count) + "\n";
153             for (auto i = pcs.size(); i > 0; i--) {
154                 DfxFrame frame;
155                 unwinder_->GetFrameByPc(pcs[i - 1], maps_, frame);
156                 frame.index = pcs.size() - i;
157                 auto frameStr = DfxFrameFormatter::GetFrameStr(frame);
158                 heaviestStack += frameStr;
159             }
160         }
161     }
162     stack += Print();
163     return stack;
164 }
165 
Print()166 std::string SampleStackPrinter::Print()
167 {
168     if (root_ == nullptr) {
169         return std::string("");
170     }
171 
172     std::stringstream ret;
173     std::vector<std::shared_ptr<SampleStackItem>> nodes;
174     nodes.push_back(root_);
175     const int indent = 2;
176     while (!nodes.empty()) {
177         std::shared_ptr<SampleStackItem> back = nodes.back();
178         back->current = std::make_shared<DfxFrame>();
179         back->current->index = back->level;
180         unwinder_->GetFrameByPc(back->pc, maps_, *(back->current));
181         std::shared_ptr<SampleStackItem> sibling = back->siblings;
182         std::shared_ptr<SampleStackItem> child = back->child;
183         std::string space(indent * back->level, ' ');
184         nodes.pop_back();
185 
186         ret << space << back->count << " " << DfxFrameFormatter::GetFrameStr(back->current);
187         if (sibling != nullptr) {
188             nodes.push_back(sibling);
189         }
190 
191         if (child != nullptr) {
192             nodes.push_back(child);
193         }
194     }
195     return ret.str();
196 }
197 } // end of namespace HiviewDFX
198 } // end of namespace OHOS
199