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