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(SampleStackItem * curNode,uintptr_t pc,int32_t count,uint64_t level,SampleStackItem * acientNode)26 SampleStackItem* SampleStackPrinter::Insert(SampleStackItem* curNode,
27 uintptr_t pc, int32_t count, uint64_t level, 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 curNode->current = std::make_shared<DfxFrame>();
42 curNode->current->index = curNode->level;
43
44 unwinder_->GetFrameByPc(pc, maps_, *(curNode->current));
45 return curNode;
46 }
47
48 if (level > curNode->level) {
49 acientNode = curNode;
50
51 if (curNode->child == nullptr) {
52 curNode->child = new SampleStackItem;
53 curNode->child->level = curNode->level + 1;
54 return Insert(curNode->child, pc, count, level, acientNode);
55 }
56
57 if (curNode->child->pc == pc) {
58 curNode->child->count += count;
59 return curNode->child;
60 }
61
62 curNode = curNode->child;
63 }
64
65 if (curNode->siblings == nullptr) {
66 curNode->siblings = new SampleStackItem;
67 curNode->siblings->level = curNode->level;
68 SampleStackItem* node = Insert(curNode->siblings, pc, count, level, acientNode);
69 curNode = AdjustSiblings(acientNode, curNode, node);
70 return curNode;
71 }
72
73 if (curNode->siblings->pc == pc) {
74 curNode->siblings->count += count;
75 curNode = AdjustSiblings(acientNode, curNode, curNode->siblings);
76 return curNode;
77 }
78
79 return Insert(curNode->siblings, pc, count, level, acientNode);
80 }
81
Insert(std::vector<uintptr_t> & pcs,int32_t count)82 void SampleStackPrinter::Insert(std::vector<uintptr_t>& pcs, int32_t count)
83 {
84 if (root_ == nullptr) {
85 root_ = new SampleStackItem;
86 root_->level = 0;
87 }
88
89 SampleStackItem* dummyNode = new SampleStackItem;
90 SampleStackItem* acientNode = dummyNode;
91 acientNode->child = root_;
92 SampleStackItem* curNode = root_;
93 uint64_t level = 0;
94 for (auto iter = pcs.rbegin(); iter != pcs.rend(); ++iter) {
95 curNode = Insert(curNode, *iter, count, level, acientNode);
96 level++;
97 }
98 delete dummyNode;
99 }
100
AdjustSiblings(SampleStackItem * acient,SampleStackItem * cur,SampleStackItem * node)101 SampleStackItem* SampleStackPrinter::AdjustSiblings(SampleStackItem* acient,
102 SampleStackItem* cur, SampleStackItem* node)
103 {
104 SampleStackItem* dummy = new SampleStackItem;
105 dummy->siblings = acient->child;
106 SampleStackItem* p = dummy;
107 while (p->siblings != node && p->siblings->count >= node->count) {
108 p = p->siblings;
109 }
110 if (p->siblings != node) {
111 cur->siblings = node->siblings;
112 node->siblings = p->siblings;
113 if (p == dummy) {
114 acient->child = node;
115 }
116 p->siblings = node;
117 }
118 delete dummy;
119 return node;
120 }
121
GetFullStack(const std::vector<TimeAndFrames> & timeAndFrameList)122 std::string SampleStackPrinter::GetFullStack(const std::vector<TimeAndFrames>& timeAndFrameList)
123 {
124 std::string stack("");
125 for (const auto& taf : timeAndFrameList) {
126 std::string requestTimeStr = TimeFormat(taf.requestTime);
127 std::string snapshotTimeStr = TimeFormat(taf.snapshotTime);
128 if (requestTimeStr == "" || snapshotTimeStr == "") {
129 return stack;
130 }
131 stack += ("RequestTime:" + requestTimeStr + "\nSnapshotTime:" + snapshotTimeStr + "\n");
132 std::vector<DfxFrame> frames = taf.frameList;
133 for (auto& frame : frames) {
134 unwinder_->FillFrame(frame);
135 auto frameStr = DfxFrameFormatter::GetFrameStr(frame);
136 stack += frameStr;
137 }
138 stack += "\n";
139 }
140 return stack;
141 }
142
GetTreeStack(std::vector<StackIdAndCount> & stackIdCount,std::unique_ptr<UniqueStackTable> & uniqueStackTable)143 std::string SampleStackPrinter::GetTreeStack(std::vector<StackIdAndCount>& stackIdCount,
144 std::unique_ptr<UniqueStackTable>& uniqueStackTable)
145 {
146 std::sort(stackIdCount.begin(), stackIdCount.end(), [](const auto& a, const auto& b) {
147 return a.count > b.count;
148 });
149 for (auto it = stackIdCount.begin(); it != stackIdCount.end(); it++) {
150 std::vector<uintptr_t> pcs;
151 OHOS::HiviewDFX::StackId stackId;
152 stackId.value = it->stackId;
153 if (uniqueStackTable->GetPcsByStackId(stackId, pcs)) {
154 Insert(pcs, it->count);
155 }
156 }
157 std::string stack = Print();
158 return stack;
159 }
160
Print()161 std::string SampleStackPrinter::Print()
162 {
163 if (root_ == nullptr) {
164 return std::string("");
165 }
166
167 std::stringstream ret;
168 std::vector<SampleStackItem*> nodes;
169 nodes.push_back(root_);
170 const int indent = 2;
171 while (!nodes.empty()) {
172 SampleStackItem* back = nodes.back();
173 SampleStackItem* sibling = back->siblings;
174 SampleStackItem* child = back->child;
175 std::string space(indent * back->level, ' ');
176 nodes.pop_back();
177
178 ret << space << back->count << " " << DfxFrameFormatter::GetFrameStr(back->current);
179 if (sibling != nullptr) {
180 nodes.push_back(sibling);
181 }
182
183 if (child != nullptr) {
184 nodes.push_back(child);
185 }
186 }
187 return ret.str();
188 }
189
FreeNodes()190 void SampleStackPrinter::FreeNodes()
191 {
192 if (root_ == nullptr) {
193 return;
194 }
195 std::vector<SampleStackItem*> stk;
196 stk.emplace_back(root_);
197
198 while (!stk.empty()) {
199 SampleStackItem* cur = stk.back();
200 stk.pop_back();
201
202 if (cur != nullptr) {
203 // push siblings in stk and set siblings null
204 if (cur->siblings != nullptr) {
205 stk.emplace_back(cur->siblings);
206 cur->siblings = nullptr;
207 }
208 // push child in stk and set child null
209 if (cur->child != nullptr) {
210 stk.emplace_back(cur->child);
211 cur->child = nullptr;
212 }
213 // free cur and set null
214 delete cur;
215 cur = nullptr;
216 }
217 }
218 }
219 } // end of namespace HiviewDFX
220 } // end of namespace OHOS
221