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