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