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)26 SampleStackItem* SampleStackPrinter::Insert(SampleStackItem* curNode, uintptr_t pc, int32_t count, uint64_t level)
27 {
28 if (curNode == nullptr) {
29 return nullptr;
30 }
31
32 if (curNode->pc == pc) {
33 curNode->count += count;
34 return curNode;
35 }
36
37 if (curNode->pc == 0) {
38 curNode->pc = pc;
39 curNode->count += count;
40 curNode->current = std::make_shared<DfxFrame>();
41 curNode->current->index = curNode->level;
42
43 unwinder_->GetFrameByPc(pc, maps_, *(curNode->current));
44 return curNode;
45 }
46
47 if (level > curNode->level) {
48 if (curNode->child == nullptr) {
49 curNode->child = new SampleStackItem;
50 curNode->child->level = curNode->level + 1;
51 allNodes_.push_back(curNode->child);
52 return Insert(curNode->child, pc, count, level);
53 }
54
55 if (curNode->child->pc == pc) {
56 curNode->child->count += count;
57 return curNode->child;
58 }
59
60 curNode = curNode->child;
61 }
62
63 if (curNode->siblings == nullptr) {
64 curNode->siblings = new SampleStackItem;
65 curNode->siblings->level = curNode->level;
66 allNodes_.push_back(curNode->siblings);
67 return Insert(curNode->siblings, pc, count, level);
68 }
69
70 if (curNode->siblings->pc == pc) {
71 curNode->siblings->count += count;
72 return curNode->siblings;
73 }
74
75 return Insert(curNode->siblings, pc, count, level);
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_ = new SampleStackItem;
82 root_->level = 0;
83 allNodes_.push_back(root_);
84 }
85
86 SampleStackItem* curNode = root_;
87 uint64_t level = 0;
88 for (auto iter = pcs.rbegin(); iter != pcs.rend(); ++iter) {
89 curNode = Insert(curNode, *iter, count, level);
90 level++;
91 }
92 }
93
GetFullStack(std::vector<TimeAndFrames> & timeAndFrameList)94 std::string SampleStackPrinter::GetFullStack(std::vector<TimeAndFrames>& timeAndFrameList)
95 {
96 std::string stack("");
97 for (auto& taf : timeAndFrameList) {
98 std::string requestTimeStr = TimeFormat(taf.requestTime);
99 std::string snapshotTimeStr = TimeFormat(taf.snapshotTime);
100 if (requestTimeStr == "" || snapshotTimeStr == "") {
101 return stack;
102 }
103 stack += ("RequestTime:" + requestTimeStr + "\nSnapshotTime:" + snapshotTimeStr + "\n");
104 std::vector<DfxFrame> frames = taf.frameList;
105 for (auto& frame : frames) {
106 unwinder_->FillFrame(frame);
107 auto frameStr = DfxFrameFormatter::GetFrameStr(frame);
108 stack += frameStr;
109 }
110 stack += "\n";
111 }
112 return stack;
113 }
114
GetTreeStack(std::map<uint64_t,std::vector<uint64_t>> & stackIdTimeMap,std::unique_ptr<UniqueStackTable> & uniqueStackTable)115 std::string SampleStackPrinter::GetTreeStack(std::map<uint64_t, std::vector<uint64_t>>& stackIdTimeMap,
116 std::unique_ptr<UniqueStackTable>& uniqueStackTable)
117 {
118 std::vector<std::pair<uint64_t, uint64_t>> sortedStackId;
119 for (auto it = stackIdTimeMap.begin(); it != stackIdTimeMap.end(); it++) {
120 uint64_t stackId = it->first;
121 sortedStackId.emplace_back(std::make_pair<uint64_t, uint64_t>(std::move(stackId), it->second.size()));
122 std::sort(sortedStackId.begin(), sortedStackId.end(), [](auto& a, auto& b) {
123 return a.second > b.second;
124 });
125 }
126 for (auto it = sortedStackId.begin(); it != sortedStackId.end(); it++) {
127 std::vector<uintptr_t> pcs;
128 OHOS::HiviewDFX::StackId stackId;
129 stackId.value = it->first;
130 if (uniqueStackTable->GetPcsByStackId(stackId, pcs)) {
131 Insert(pcs, it->second);
132 }
133 }
134 std::string stack = Print();
135 return stack;
136 }
137
Print()138 std::string SampleStackPrinter::Print()
139 {
140 if (root_ == nullptr) {
141 return std::string("");
142 }
143
144 std::stringstream ret;
145 std::vector<SampleStackItem*> nodes;
146 nodes.push_back(root_);
147 const int indent = 2;
148 while (!nodes.empty()) {
149 SampleStackItem* back = nodes.back();
150 SampleStackItem* sibling = back->siblings;
151 SampleStackItem* child = back->child;
152 std::string space(indent * back->level, ' ');
153 nodes.pop_back();
154
155 ret << space << back->count << " " << DfxFrameFormatter::GetFrameStr(back->current);
156 if (sibling != nullptr) {
157 nodes.push_back(sibling);
158 }
159
160 if (child != nullptr) {
161 nodes.push_back(child);
162 }
163 }
164 return ret.str();
165 }
166
FreeNodes()167 void SampleStackPrinter::FreeNodes()
168 {
169 for (auto node : allNodes_) {
170 if (node != nullptr) {
171 delete node;
172 }
173 }
174 allNodes_.clear();
175 allNodes_.shrink_to_fit();
176 }
177 } // end of namespace HiviewDFX
178 } // end of namespace OHOS
179