• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "stack_printer.h"
17 
18 #include <iostream>
19 #include <mutex>
20 #include <sstream>
21 
22 #include <sys/prctl.h>
23 
24 #include "dfx_frame.h"
25 #include "dfx_frame_formatter.h"
26 #include "unique_stack_table.h"
27 
28 namespace OHOS {
29 namespace HiviewDFX {
30 
31 namespace {
32 constexpr uint64_t SEC_TO_NANOSEC = 1000000000;
33 constexpr uint64_t MICROSEC_TO_NANOSEC = 1000;
34 constexpr int FORMAT_TIME_LEN = 20;
35 constexpr int MICROSEC_LEN = 6;
36 constexpr size_t MAX_SAMPLE_TIDS = 10;
37 }  // namespace
38 
39 struct StackRecord {
40     uint64_t stackId {0};
41     std::vector<uint64_t> snapshotTimes;
42 };
43 
44 struct StackItem {
45     uintptr_t pc {0};
46     int32_t pcCount {0};
47     uint32_t level {0};
48     uint64_t stackId {0};  // Only leaf node update this.
49     std::shared_ptr<DfxFrame> current {nullptr};
50     std::shared_ptr<StackItem> child {nullptr};
51     std::shared_ptr<StackItem> siblings {nullptr};
52 };
53 
operator <<(std::ostream & os,const SampledFrame & frame)54 std::ostream& operator<<(std::ostream& os, const SampledFrame& frame)
55 {
56     os << frame.indent << " " << frame.count << " " << frame.level << " " << frame.pc << " " << frame.isLeaf << " " <<
57           frame.timestamps.size();
58     for (auto timestamp : frame.timestamps) {
59         os << " " << timestamp;
60     }
61     return os;
62 }
63 
operator >>(std::istream & is,SampledFrame & frame)64 std::istream& operator>>(std::istream& is, SampledFrame& frame)
65 {
66     size_t timestampsSize;
67     is >> frame.indent >> frame.count >> frame.level >> frame.pc >> frame.isLeaf >> timestampsSize;
68     if (timestampsSize > 0) {
69         frame.timestamps.resize(timestampsSize);
70         for (size_t i = 0; i < timestampsSize; i++) {
71             is >> frame.timestamps[i];
72         }
73     }
74     return is;
75 }
76 
TimeFormat(uint64_t time)77 static std::string TimeFormat(uint64_t time)
78 {
79     uint64_t nsec = time % SEC_TO_NANOSEC;
80     time_t sec = static_cast<time_t>(time / SEC_TO_NANOSEC);
81     char timeChars[FORMAT_TIME_LEN];
82     struct tm localTime;
83     if (localtime_r(&sec, &localTime) == nullptr) {
84         return "";
85     }
86     size_t sz = strftime(timeChars, FORMAT_TIME_LEN, "%Y-%m-%d-%H-%M-%S", &localTime);
87     if (sz == 0) {
88         return "";
89     }
90     std::string s = timeChars;
91     uint64_t usec = nsec / MICROSEC_TO_NANOSEC;
92     std::string usecStr = std::to_string(usec);
93     while (usecStr.size() < MICROSEC_LEN) {
94         usecStr = "0" + usecStr;
95     }
96     s = s + "." + usecStr;
97     return s;
98 }
99 
TimeFilter(const std::vector<StackRecord> & stackRecordVec,uint64_t beginTime,uint64_t endTime)100 static std::vector<StackRecord> TimeFilter(const std::vector<StackRecord>& stackRecordVec, uint64_t beginTime,
101                                            uint64_t endTime)
102 {
103     if ((beginTime == 0 && endTime == 0) || (beginTime > endTime)) {
104         return stackRecordVec;
105     }
106     std::vector<StackRecord> vec;
107     for (const auto& stackRecord : stackRecordVec) {
108         StackRecord record;
109         for (auto t : stackRecord.snapshotTimes) {
110             if (t >= beginTime && t < endTime) {
111                 record.snapshotTimes.emplace_back(t);
112             }
113         }
114         if (!record.snapshotTimes.empty()) {
115             record.stackId = stackRecord.stackId;
116             vec.emplace_back(std::move(record));
117         }
118     }
119     return vec;
120 }
121 
122 class StackPrinter::Impl {
123 public:
Impl()124     Impl() : root_(nullptr)
125     {}
126 
SetUnwindInfo(const std::shared_ptr<Unwinder> & unwinder,const std::shared_ptr<DfxMaps> & maps)127     inline void SetUnwindInfo(const std::shared_ptr<Unwinder>& unwinder, const std::shared_ptr<DfxMaps>& maps)
128     {
129         unwinder_ = unwinder;
130         maps_ = maps;
131     }
132 
133     bool InitUniqueTable(pid_t pid, uint32_t size, std::string name = "unique_stack_table");
134     bool PutPcsInTable(const std::vector<uintptr_t>& pcs, int tid, uint64_t snapshotTime);
135     std::string GetFullStack(const std::vector<TimeStampedPcs>& timeStampedPcsVec);
136     std::map<int, std::vector<SampledFrame>> GetThreadSampledFrames(uint64_t beginTime = 0, uint64_t endTime = 0);
137     std::string GetTreeStack(int tid, bool printTimes = false, uint64_t beginTime = 0, uint64_t endTime = 0);
138     std::string GetHeaviestStack(int tid, uint64_t beginTime = 0, uint64_t endTime = 0);
139 
140     static std::string PrintTreeStackBySampledStack(const std::vector<SampledFrame>& sampledFrameVec, bool printTimes,
141                                                     const std::shared_ptr<Unwinder>& unwinder,
142                                                     const std::shared_ptr<DfxMaps>& maps);
143     static void SerializeSampledFrameMap(const std::map<int, std::vector<SampledFrame>>& sampledFrameMap,
144                                          std::ostream& os);
145     static std::map<int, std::vector<SampledFrame>> DeserializeSampledFrameMap(std::istream& is);
146 
147 private:
148     void Insert(const std::vector<uintptr_t>& pcs, int32_t count, StackId stackId);
149     std::shared_ptr<StackItem> InsertImpl(std::shared_ptr<StackItem> curNode, uintptr_t pc, int32_t count,
150                                           uint64_t level, std::shared_ptr<StackItem> acientNode);
151     std::shared_ptr<StackItem> AdjustSiblings(std::shared_ptr<StackItem> acient, std::shared_ptr<StackItem> cur,
152                                               std::shared_ptr<StackItem> node);
153     void BuildStackTree(std::vector<StackRecord>& stackRecordVec);
154     std::vector<SampledFrame> GenerateTreeStackFrames(const std::vector<StackRecord>& stackRecordVec);
155     std::vector<SampledFrame> GetSampledFramesByTid(int tid, uint64_t beginTime, uint64_t endTime);
156 
157     static void PrintTimesStr(std::string& frameStr, const std::vector<uint64_t>& snapshotTimes);
158     static std::string PrintStackByPcs(const std::vector<uintptr_t>& pcs, const std::shared_ptr<Unwinder>& unwinder,
159                                        const std::shared_ptr<DfxMaps>& maps);
160 
161     std::shared_ptr<StackItem> root_;
162     std::shared_ptr<Unwinder> unwinder_ {nullptr};
163     std::shared_ptr<DfxMaps> maps_ {nullptr};
164     std::unique_ptr<UniqueStackTable> uniqueStackTable_ {nullptr};
165     std::map<int, std::vector<StackRecord>> tidStackRecordMap_;
166     std::mutex mutex_;
167 };
168 
StackPrinter()169 StackPrinter::StackPrinter() : impl_(std::make_shared<Impl>())
170 {}
171 
SetUnwindInfo(const std::shared_ptr<Unwinder> & unwinder,const std::shared_ptr<DfxMaps> & maps)172 void StackPrinter::SetUnwindInfo(const std::shared_ptr<Unwinder>& unwinder, const std::shared_ptr<DfxMaps>& maps)
173 {
174     impl_->SetUnwindInfo(unwinder, maps);
175 }
176 
PutPcsInTable(const std::vector<uintptr_t> & pcs,int tid,uint64_t snapshotTime)177 bool StackPrinter::PutPcsInTable(const std::vector<uintptr_t>& pcs, int tid, uint64_t snapshotTime)
178 {
179     return impl_->PutPcsInTable(pcs, tid, snapshotTime);
180 }
181 
GetFullStack(const std::vector<TimeStampedPcs> & timeStampedPcsVec)182 std::string StackPrinter::GetFullStack(const std::vector<TimeStampedPcs>& timeStampedPcsVec)
183 {
184     return impl_->GetFullStack(timeStampedPcsVec);
185 }
186 
GetThreadSampledFrames(uint64_t beginTime,uint64_t endTime)187 std::map<int, std::vector<SampledFrame>> StackPrinter::GetThreadSampledFrames(uint64_t beginTime, uint64_t endTime)
188 {
189     return impl_->GetThreadSampledFrames(beginTime, endTime);
190 }
191 
GetHeaviestStack(int tid,uint64_t beginTime,uint64_t endTime)192 std::string StackPrinter::GetHeaviestStack(int tid, uint64_t beginTime, uint64_t endTime)
193 {
194     return impl_->GetHeaviestStack(tid, beginTime, endTime);
195 }
196 
InitUniqueTable(pid_t pid,uint32_t size,std::string name)197 bool StackPrinter::InitUniqueTable(pid_t pid, uint32_t size, std::string name)
198 {
199     return impl_->InitUniqueTable(pid, size, name);
200 }
201 
PrintTreeStackBySampledStack(const std::vector<SampledFrame> & sampledFrameVec,bool printTimes,const std::shared_ptr<Unwinder> & unwinder,const std::shared_ptr<DfxMaps> & maps)202 std::string StackPrinter::PrintTreeStackBySampledStack(const std::vector<SampledFrame>& sampledFrameVec,
203                                                        bool printTimes, const std::shared_ptr<Unwinder>& unwinder,
204                                                        const std::shared_ptr<DfxMaps>& maps)
205 {
206     return Impl::PrintTreeStackBySampledStack(sampledFrameVec, printTimes, unwinder, maps);
207 }
208 
GetTreeStack(int tid,bool printTimes,uint64_t beginTime,uint64_t endTime)209 std::string StackPrinter::GetTreeStack(int tid, bool printTimes, uint64_t beginTime, uint64_t endTime)
210 {
211     return impl_->GetTreeStack(tid, printTimes, beginTime, endTime);
212 }
213 
SerializeSampledFrameMap(const std::map<int,std::vector<SampledFrame>> & sampledFrameMap,std::ostream & os)214 void StackPrinter::SerializeSampledFrameMap(const std::map<int, std::vector<SampledFrame>>& sampledFrameMap,
215                                             std::ostream& os)
216 {
217     Impl::SerializeSampledFrameMap(sampledFrameMap, os);
218 }
219 
DeserializeSampledFrameMap(std::istream & is)220 std::map<int, std::vector<SampledFrame>> StackPrinter::DeserializeSampledFrameMap(std::istream& is)
221 {
222     return Impl::DeserializeSampledFrameMap(is);
223 }
224 
InsertImpl(std::shared_ptr<StackItem> curNode,uintptr_t pc,int32_t pcCount,uint64_t level,std::shared_ptr<StackItem> acientNode)225 std::shared_ptr<StackItem> StackPrinter::Impl::InsertImpl(std::shared_ptr<StackItem> curNode, uintptr_t pc,
226                                                           int32_t pcCount, uint64_t level,
227                                                           std::shared_ptr<StackItem> acientNode)
228 {
229     if (curNode == nullptr) {
230         return nullptr;
231     }
232 
233     if (curNode->pc == pc) {
234         curNode->pcCount += pcCount;
235         return curNode;
236     }
237 
238     if (curNode->pc == 0) {
239         curNode->pc = pc;
240         curNode->pcCount += pcCount;
241         return curNode;
242     }
243 
244     if (level > curNode->level) {
245         acientNode = curNode;
246 
247         if (curNode->child == nullptr) {
248             curNode->child = std::make_shared<StackItem>();
249             curNode->child->level = curNode->level + 1;
250             return InsertImpl(curNode->child, pc, pcCount, level, acientNode);
251         }
252 
253         if (curNode->child->pc == pc) {
254             curNode->child->pcCount += pcCount;
255             return curNode->child;
256         }
257 
258         curNode = curNode->child;
259     }
260 
261     if (curNode->siblings == nullptr) {
262         curNode->siblings = std::make_shared<StackItem>();
263         curNode->siblings->level = curNode->level;
264         std::shared_ptr<StackItem> node = InsertImpl(curNode->siblings, pc, pcCount, level, acientNode);
265         curNode = AdjustSiblings(acientNode, curNode, node);
266         return curNode;
267     }
268 
269     if (curNode->siblings->pc == pc) {
270         curNode->siblings->pcCount += pcCount;
271         curNode = AdjustSiblings(acientNode, curNode, curNode->siblings);
272         return curNode;
273     }
274 
275     return InsertImpl(curNode->siblings, pc, pcCount, level, acientNode);
276 }
277 
Insert(const std::vector<uintptr_t> & pcs,int32_t pcCount,StackId stackId)278 void StackPrinter::Impl::Insert(const std::vector<uintptr_t>& pcs, int32_t pcCount, StackId stackId)
279 {
280     if (root_ == nullptr) {
281         root_ = std::make_shared<StackItem>();
282         root_->level = 0;
283     }
284 
285     std::shared_ptr<StackItem> dummyNode = std::make_shared<StackItem>();
286     std::shared_ptr<StackItem> acientNode = dummyNode;
287     acientNode->child = root_;
288     std::shared_ptr<StackItem> curNode = root_;
289     uint64_t level = 0;
290     for (auto iter = pcs.rbegin(); iter != pcs.rend(); ++iter) {
291         curNode = InsertImpl(curNode, *iter, pcCount, level, acientNode);
292         level++;
293     }
294     curNode->stackId = stackId.value;
295 }
296 
AdjustSiblings(std::shared_ptr<StackItem> acient,std::shared_ptr<StackItem> cur,std::shared_ptr<StackItem> node)297 std::shared_ptr<StackItem> StackPrinter::Impl::AdjustSiblings(std::shared_ptr<StackItem> acient,
298                                                               std::shared_ptr<StackItem> cur,
299                                                               std::shared_ptr<StackItem> node)
300 {
301     std::shared_ptr<StackItem> dummy = std::make_shared<StackItem>();
302     dummy->siblings = acient->child;
303     std::shared_ptr<StackItem> p = dummy;
304     while (p->siblings != node && p->siblings->pcCount >= node->pcCount) {
305         p = p->siblings;
306     }
307     if (p->siblings != node) {
308         cur->siblings = node->siblings;
309         node->siblings = p->siblings;
310         if (p == dummy) {
311             acient->child = node;
312         }
313         p->siblings = node;
314     }
315     return node;
316 }
317 
PutPcsInTable(const std::vector<uintptr_t> & pcs,int tid,uint64_t snapshotTime)318 bool StackPrinter::Impl::PutPcsInTable(const std::vector<uintptr_t>& pcs, int tid, uint64_t snapshotTime)
319 {
320     if (uniqueStackTable_ == nullptr) {
321         return false;
322     }
323     uint64_t stackId = 0;
324     auto stackIdPtr = reinterpret_cast<StackId*>(&stackId);
325     uniqueStackTable_->PutPcsInTable(stackIdPtr, pcs.data(), pcs.size());
326 
327     std::lock_guard<std::mutex> lock(mutex_);
328     auto& stackRecordVec = tidStackRecordMap_[tid];
329     auto it = std::find_if(stackRecordVec.begin(), stackRecordVec.end(), [&stackId](const auto& stackRecord) {
330         return stackRecord.stackId == stackId;
331     });
332     if (it == stackRecordVec.end()) {
333         StackRecord record;
334         record.stackId = stackId;
335         record.snapshotTimes.emplace_back(snapshotTime);
336         stackRecordVec.emplace_back(record);
337     } else {
338         it->snapshotTimes.emplace_back(snapshotTime);
339     }
340     return true;
341 }
342 
GetFullStack(const std::vector<TimeStampedPcs> & timeStampedPcsVec)343 std::string StackPrinter::Impl::GetFullStack(const std::vector<TimeStampedPcs>& timeStampedPcsVec)
344 {
345     std::stringstream stack;
346     for (const auto& timeStampedPcs : timeStampedPcsVec) {
347         std::string snapshotTimeStr = TimeFormat(timeStampedPcs.snapshotTime);
348         stack << "SnapshotTime:" << snapshotTimeStr << "\n";
349         std::vector<uintptr_t> pcs = timeStampedPcs.pcVec;
350         stack << PrintStackByPcs(pcs, unwinder_, maps_);
351         stack << "\n";
352     }
353     return stack.str();
354 }
355 
GetSampledFramesByTid(int tid,uint64_t beginTime,uint64_t endTime)356 std::vector<SampledFrame> StackPrinter::Impl::GetSampledFramesByTid(int tid, uint64_t beginTime, uint64_t endTime)
357 {
358     std::lock_guard<std::mutex> lock(mutex_);
359     auto& stackRecordVec = tidStackRecordMap_[tid];
360     std::vector<StackRecord> vec = TimeFilter(stackRecordVec, beginTime, endTime);
361     BuildStackTree(vec);
362     return GenerateTreeStackFrames(vec);
363 }
364 
GetTreeStack(int tid,bool printTimes,uint64_t beginTime,uint64_t endTime)365 std::string StackPrinter::Impl::GetTreeStack(int tid, bool printTimes, uint64_t beginTime, uint64_t endTime)
366 {
367     std::vector<SampledFrame> sampledFrameVec = GetSampledFramesByTid(tid, beginTime, endTime);
368     return PrintTreeStackBySampledStack(sampledFrameVec, printTimes, unwinder_, maps_);
369 }
370 
GetHeaviestStack(int tid,uint64_t beginTime,uint64_t endTime)371 std::string StackPrinter::Impl::GetHeaviestStack(int tid, uint64_t beginTime, uint64_t endTime)
372 {
373     if (unwinder_ == nullptr || maps_ == nullptr) {
374         return std::string("");
375     }
376     std::lock_guard<std::mutex> lock(mutex_);
377     auto& stackRecordVec = tidStackRecordMap_[tid];
378     std::vector<StackRecord> vec = TimeFilter(stackRecordVec, beginTime, endTime);
379     std::sort(vec.begin(), vec.end(), [](const auto& a, const auto& b) {
380         return a.snapshotTimes.size() > b.snapshotTimes.size();
381     });
382     auto it = vec.begin();
383     std::vector<uintptr_t> pcs;
384     StackId stackId;
385     stackId.value = it->stackId;
386     uniqueStackTable_->GetPcsByStackId(stackId, pcs);
387 
388     std::stringstream heaviestStack;
389     heaviestStack << "heaviest stack: \nstack counts: " << std::to_string(it->snapshotTimes.size()) << "\n";
390     heaviestStack << PrintStackByPcs(pcs, unwinder_, maps_);
391     return heaviestStack.str();
392 }
393 
InitUniqueTable(pid_t pid,uint32_t size,std::string name)394 bool StackPrinter::Impl::InitUniqueTable(pid_t pid, uint32_t size, std::string name)
395 {
396     uniqueStackTable_ = std::make_unique<UniqueStackTable>(pid, size);
397     if (!uniqueStackTable_->Init()) {
398         return false;
399     }
400     void* uniqueTableBufMMap = reinterpret_cast<void*>(uniqueStackTable_->GetHeadNode());
401     if (!name.empty()) {
402         prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, uniqueTableBufMMap, size, name.c_str());
403     }
404     return true;
405 }
406 
BuildStackTree(std::vector<StackRecord> & stackRecordVec)407 void StackPrinter::Impl::BuildStackTree(std::vector<StackRecord>& stackRecordVec)
408 {
409     std::sort(stackRecordVec.begin(), stackRecordVec.end(), [](const auto& a, const auto& b) {
410         return a.snapshotTimes.size() > b.snapshotTimes.size();
411     });
412     for (const auto& record : stackRecordVec) {
413         std::vector<uintptr_t> pcs;
414         StackId stackId;
415         stackId.value = record.stackId;
416         if (uniqueStackTable_->GetPcsByStackId(stackId, pcs)) {
417             Insert(pcs, record.snapshotTimes.size(), stackId);
418         }
419     }
420 }
421 
PrintTimesStr(std::string & frameStr,const std::vector<uint64_t> & snapshotTimes)422 void StackPrinter::Impl::PrintTimesStr(std::string& frameStr, const std::vector<uint64_t>& snapshotTimes)
423 {
424     // rm last '\n'
425     auto pos = frameStr.find("\n");
426     if (pos != std::string::npos) {
427         frameStr.replace(pos, 1, "");
428     }
429 
430     for (auto t : snapshotTimes) {
431         frameStr.append(" ");
432         frameStr.append(TimeFormat(t));
433     }
434     frameStr.append("\n");
435 }
436 
PrintTreeStackBySampledStack(const std::vector<SampledFrame> & sampledFrameVec,bool printTimes,const std::shared_ptr<Unwinder> & unwinder,const std::shared_ptr<DfxMaps> & maps)437 std::string StackPrinter::Impl::PrintTreeStackBySampledStack(const std::vector<SampledFrame>& sampledFrameVec,
438                                                              bool printTimes, const std::shared_ptr<Unwinder>& unwinder,
439                                                              const std::shared_ptr<DfxMaps>& maps)
440 {
441     if (unwinder == nullptr || maps == nullptr) {
442         return std::string("");
443     }
444 
445     std::stringstream ss;
446     for (const auto& sampledFrame : sampledFrameVec) {
447         std::string space(sampledFrame.indent, ' ');
448         DfxFrame frame;
449         frame.index = sampledFrame.level;
450         unwinder->GetFrameByPc(sampledFrame.pc, maps, frame);
451         std::string frameStr = DfxFrameFormatter::GetFrameStr(frame);
452 
453         if (sampledFrame.isLeaf && printTimes) {
454             PrintTimesStr(frameStr, sampledFrame.timestamps);
455         }
456         ss << space << sampledFrame.count << " " << frameStr;
457     }
458     return ss.str();
459 }
460 
GenerateTreeStackFrames(const std::vector<StackRecord> & stackRecordVec)461 std::vector<SampledFrame> StackPrinter::Impl::GenerateTreeStackFrames(const std::vector<StackRecord>& stackRecordVec)
462 {
463     std::vector<SampledFrame> sampledFrameVec;
464     std::vector<std::shared_ptr<StackItem>> nodes;
465     if (root_ != nullptr) {
466         nodes.emplace_back(root_);
467     }
468     const uint32_t indent = 2;
469     while (!nodes.empty()) {
470         std::shared_ptr<StackItem> back = nodes.back();
471         SampledFrame sampledFrame;
472         sampledFrame.indent = indent * back->level;
473         sampledFrame.count = back->pcCount;
474         sampledFrame.level = back->level;
475         sampledFrame.pc = back->pc;
476         nodes.pop_back();
477 
478         if (back->siblings != nullptr) {
479             nodes.emplace_back(back->siblings);
480         }
481 
482         if (back->child != nullptr) {
483             nodes.emplace_back(back->child);
484             sampledFrame.isLeaf = false;
485         } else {
486             sampledFrame.isLeaf = true;
487             uint64_t stackId = back->stackId;
488             auto it = std::find_if(stackRecordVec.begin(), stackRecordVec.end(), [&stackId](const auto& record) {
489                 return record.stackId == stackId;
490             });
491             if (it != stackRecordVec.end()) {
492                 sampledFrame.timestamps = it->snapshotTimes;
493             }
494         }
495         sampledFrameVec.emplace_back(sampledFrame);
496     }
497     root_ = nullptr;
498     return sampledFrameVec;
499 }
500 
PrintStackByPcs(const std::vector<uintptr_t> & pcs,const std::shared_ptr<Unwinder> & unwinder,const std::shared_ptr<DfxMaps> & maps)501 std::string StackPrinter::Impl::PrintStackByPcs(const std::vector<uintptr_t>& pcs,
502                                                 const std::shared_ptr<Unwinder>& unwinder,
503                                                 const std::shared_ptr<DfxMaps>& maps)
504 {
505     std::stringstream ss;
506     for (size_t i = 0; i < pcs.size(); i++) {
507         DfxFrame frame;
508         unwinder->GetFrameByPc(pcs[i], maps, frame);
509         frame.index = i;
510         auto frameStr = DfxFrameFormatter::GetFrameStr(frame);
511         ss << frameStr;
512     }
513     return ss.str();
514 }
515 
GetThreadSampledFrames(uint64_t beginTime,uint64_t endTime)516 std::map<int, std::vector<SampledFrame>> StackPrinter::Impl::GetThreadSampledFrames(uint64_t beginTime,
517                                                                                     uint64_t endTime)
518 {
519     std::map<int, std::vector<SampledFrame>> sampledFrameMap;
520     for (const auto& [tid, _] : tidStackRecordMap_) {
521         sampledFrameMap[tid] = GetSampledFramesByTid(tid, beginTime, endTime);
522     }
523     return sampledFrameMap;
524 }
525 
SerializeSampledFrameMap(const std::map<int,std::vector<SampledFrame>> & sampledFrameMap,std::ostream & os)526 void StackPrinter::Impl::SerializeSampledFrameMap(const std::map<int, std::vector<SampledFrame>>& sampledFrameMap,
527                                                   std::ostream& os)
528 {
529     os << sampledFrameMap.size() << "\n";
530     for (const auto& [tid, sampledFrameVec] : sampledFrameMap) {
531         os << tid << " " << sampledFrameVec.size();
532         for (const auto& frame : sampledFrameVec) {
533             os << " " << frame;
534         }
535         os << "\n";
536     }
537 }
538 
DeserializeSampledFrameMap(std::istream & is)539 std::map<int, std::vector<SampledFrame>> StackPrinter::Impl::DeserializeSampledFrameMap(std::istream& is)
540 {
541     std::map<int, std::vector<SampledFrame>> sampledFrameMap;
542     size_t mapSize;
543     if (!(is >> mapSize)) {
544         is.setstate(std::ios::failbit);
545         return std::map<int, std::vector<SampledFrame>>();
546     }
547     if (mapSize > MAX_SAMPLE_TIDS) {
548         is.setstate(std::ios::failbit);
549         return std::map<int, std::vector<SampledFrame>>();
550     }
551     is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
552     for (size_t i = 0; i < mapSize; i++) {
553         std::string tidStr;
554         size_t vecSize;
555         if (!(is >> tidStr >> vecSize)) {
556             is.setstate(std::ios::failbit);
557             return std::map<int, std::vector<SampledFrame>>();
558         }
559         int base = 10;
560         char* endPtr;
561         long tidNum = std::strtol(tidStr.c_str(), &endPtr, base);
562         if (*endPtr != '\0' || tidNum < INT_MIN || tidNum > INT_MAX) {
563             return std::map<int, std::vector<SampledFrame>>();
564         }
565         int tid = static_cast<int>(tidNum);
566         std::vector<SampledFrame> sampledFrameVec;
567         for (size_t j = 0; j < vecSize; j++) {
568             SampledFrame frame;
569             if (!(is >> frame)) {
570                 is.setstate(std::ios::failbit);
571                 return std::map<int, std::vector<SampledFrame>>();
572             }
573             sampledFrameVec.emplace_back(frame);
574         }
575         is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
576         if (tid < 0) {
577             return std::map<int, std::vector<SampledFrame>>();
578         }
579         sampledFrameMap[tid] = sampledFrameVec;
580     }
581     return sampledFrameMap;
582 }
583 }  // end of namespace HiviewDFX
584 }  // end of namespace OHOS
585