• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #ifndef REPORT_H
17 #define REPORT_H
18 
19 #include <algorithm>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <functional>
23 #include <map>
24 
25 #include "debug_logger.h"
26 // remove me latter
27 #include "report_json_file.h"
28 #include "utilities.h"
29 #include "virtual_runtime.h"
30 
31 namespace OHOS {
32 namespace Developtools {
33 namespace HiPerf {
34 class ReportItemCallFrame {
35 public:
36     std::string func_;
37     uint64_t vaddr_;
38     std::string dso_;
39     uint64_t eventCount_ = 0;     // call chain event
40     uint64_t selfEventCount_ = 0; // call chain event end in this function
41     std::vector<ReportItemCallFrame> childs;
ReportItemCallFrame(std::string func,uint64_t vaddr,std::string dso,uint64_t eventCount,uint64_t selfEventCount)42     ReportItemCallFrame(std::string func, uint64_t vaddr, std::string dso,
43                         uint64_t eventCount, uint64_t selfEventCount)
44         : func_(func),
45           vaddr_(vaddr),
46           dso_(dso),
47           eventCount_(eventCount),
48           selfEventCount_(selfEventCount)
49     {
50     }
51 
52     bool operator==(const ReportItemCallFrame &b) const
53     {
54         return Same(b);
55     }
56 
57     bool operator!=(const ReportItemCallFrame &b) const
58     {
59         return !Same(b);
60     }
61 
CompareSortingEventCount(const ReportItemCallFrame & a,const ReportItemCallFrame & b)62     static int CompareSortingEventCount(const ReportItemCallFrame &a, const ReportItemCallFrame &b)
63     {
64         return a.eventCount_ > b.eventCount_;
65     }
66 
67     static void OrderCallFrames(std::vector<ReportItemCallFrame> &callframes, int indent = 2)
68     {
69         int i = 2;
70         if (callframes.size() > 0) {
71             std::sort(callframes.begin(), callframes.end(),
72                       &ReportItemCallFrame::CompareSortingEventCount);
73 
74             for (auto &callframe : callframes) {
75                 HLOGDUMMY("%*s%s", indent, "", callframe.ToDebugString().c_str());
76                 if (callframe.childs.size() > 0) {
77                     OrderCallFrames(callframe.childs, indent + i);
78                 }
79             }
80         }
81     }
82 
83     // just a log
84     static void DumpCallFrames(std::vector<ReportItemCallFrame> &callframes, int indent = 2)
85     {
86         int y = 2;
87         if (callframes.size() > 0) {
88             for (auto &callframe : callframes) {
89                 HLOGV("%*s%s", indent, "", callframe.ToDebugString().c_str());
90                 if (callframe.childs.size() > 0) {
91                     DumpCallFrames(callframe.childs, indent + y);
92                 }
93             }
94         }
95     }
96 
ToDebugString()97     const std::string ToDebugString() const
98     {
99         return StringPrintf("%" PRIu64 "(%" PRIu64 ")%s(%s+0x%" PRIx64 ") child %zu", eventCount_,
100                             selfEventCount_, func_.data(), dso_.data(), vaddr_, childs.size());
101     }
102 
103 private:
Same(const ReportItemCallFrame & b)104     bool Same(const ReportItemCallFrame &b) const
105     {
106         return (func_ == b.func_) and (vaddr_ == b.vaddr_) and (dso_ == b.dso_);
107     }
108 };
109 
110 // one item or one line in report
111 class ReportItem {
112 public:
113     pid_t pid_ = 0;
114     pid_t tid_ = 0;
115     std::string_view comm_ = "";
116     std::string_view dso_ = "";
117     std::string_view fromDso_ = "";
118     std::string_view fromFunc_ = "";
119     std::string_view func_ = "";
120     uint64_t vaddr_ = 0;
121     uint64_t eventCount_ = 0; // event count
122     std::vector<ReportItemCallFrame> callStacks_;
123     float heat = 0.0f;
124     static unsigned long long allIndex_; // debug only
125     unsigned long long index_;
126 
127     // only for ut test
ReportItem(pid_t pid,pid_t tid,const char * comm,const char * dso,const char * func,uint64_t vaddr,uint64_t eventCount)128     ReportItem(pid_t pid, pid_t tid, const char *comm, const char *dso, const char *func,
129                uint64_t vaddr, uint64_t eventCount)
130         : pid_(pid),
131           tid_(tid),
132           comm_(comm),
133           dso_(dso),
134           func_(func),
135           vaddr_(vaddr),
136           eventCount_(eventCount)
137     {
138         HLOG_ASSERT(comm != nullptr);
139         index_ = allIndex_++;
140     }
141 
ReportItem(pid_t pid,pid_t tid,std::string & comm,const std::string_view & dso,const std::string_view & func,uint64_t vaddr,uint64_t eventCount)142     ReportItem(pid_t pid, pid_t tid, std::string &comm, const std::string_view &dso,
143                const std::string_view &func, uint64_t vaddr, uint64_t eventCount)
144         : pid_(pid),
145           tid_(tid),
146           comm_(comm),
147           dso_(StringViewHold::Get().Hold(dso)),
148           func_(StringViewHold::Get().Hold(func)),
149           vaddr_(vaddr),
150           eventCount_(eventCount)
151     {
152         index_ = allIndex_++;
153     }
154 
155     bool operator==(const ReportItem &b) const
156     {
157         return Same(b);
158     }
159 
160     bool operator!=(const ReportItem &b) const
161     {
162         return !Same(b);
163     }
164 
165     // debug only
ToDebugString()166     const std::string ToDebugString() const
167     {
168         return StringPrintf("%d:%d:%s-%s(%s):%zu i:%llu", pid_, tid_, comm_.data(), func_.data(),
169                             dso_.data(), eventCount_, index_);
170     }
171 
172     // Count
CompareEventCount(const ReportItem & a,const ReportItem & b)173     static int CompareEventCount(const ReportItem &a, const ReportItem &b)
174     {
175         if (a.eventCount_ != b.eventCount_) {
176             return (a.eventCount_ > b.eventCount_) ? 1 : -1;
177         } else {
178             return 0;
179         }
180     }
181 
CompareSortingEventCount(const ReportItem & a,const ReportItem & b)182     static int CompareSortingEventCount(const ReportItem &a, const ReportItem &b)
183     {
184         return a.eventCount_ > b.eventCount_;
185     }
186 
GetEventCount(const ReportItem & a,size_t len,const std::string & format)187     static const std::string GetEventCount(const ReportItem &a, size_t len,
188                                            const std::string &format)
189     {
190         return StringPrintf(format.c_str(), len, a.eventCount_);
191     }
192 
193     // Pid
ComparePid(const ReportItem & a,const ReportItem & b)194     static int ComparePid(const ReportItem &a, const ReportItem &b)
195     {
196         if (a.pid_ != b.pid_) {
197             return (a.pid_ > b.pid_) ? 1 : -1;
198         } else {
199             return 0;
200         }
201     }
GetPid(const ReportItem & a,size_t len,const std::string & format)202     static const std::string GetPid(const ReportItem &a, size_t len, const std::string &format)
203     {
204         return StringPrintf(format.c_str(), len, a.pid_);
205     }
206 
207     // Tid
CompareTid(const ReportItem & a,const ReportItem & b)208     static int CompareTid(const ReportItem &a, const ReportItem &b)
209     {
210         if (a.tid_ != b.tid_) {
211             return (a.tid_ > b.tid_) ? 1 : -1;
212         } else {
213             return 0;
214         }
215     }
GetTid(const ReportItem & a,size_t len,const std::string & format)216     static const std::string GetTid(const ReportItem &a, size_t len, const std::string &format)
217     {
218         return StringPrintf(format.c_str(), len, a.tid_);
219     }
220 
221     // Comm
CompareComm(const ReportItem & a,const ReportItem & b)222     static int CompareComm(const ReportItem &a, const ReportItem &b)
223     {
224         int result = a.comm_.compare(b.comm_);
225         return result;
226     }
GetComm(const ReportItem & a,size_t len,const std::string & format)227     static const std::string GetComm(const ReportItem &a, size_t len, const std::string &format)
228     {
229         return StringPrintf(format.c_str(), len, a.comm_.data());
230     }
231 
232     // Func
CompareFunc(const ReportItem & a,const ReportItem & b)233     static int CompareFunc(const ReportItem &a, const ReportItem &b)
234     {
235         return a.func_.compare(b.func_);
236     }
GetFunc(const ReportItem & a,size_t len,const std::string & format)237     static const std::string GetFunc(const ReportItem &a, size_t len, const std::string &format)
238     {
239         return StringPrintf(format.c_str(), len, a.func_.data());
240     }
241 
242     // Dso
CompareDso(const ReportItem & a,const ReportItem & b)243     static int CompareDso(const ReportItem &a, const ReportItem &b)
244     {
245         return a.dso_.compare(b.dso_);
246     }
GetDso(const ReportItem & a,size_t len,const std::string & format)247     static const std::string GetDso(const ReportItem &a, size_t len, const std::string &format)
248     {
249         return StringPrintf(format.c_str(), len, a.dso_.data());
250     }
251 
252     // fromDso
CompareFromDso(const ReportItem & a,const ReportItem & b)253     static int CompareFromDso(const ReportItem &a, const ReportItem &b)
254     {
255         return a.fromDso_.compare(b.fromDso_);
256     }
GetFromDso(const ReportItem & a,size_t len,const std::string & format)257     static const std::string GetFromDso(const ReportItem &a, size_t len, const std::string &format)
258     {
259         return StringPrintf(format.c_str(), len, a.fromDso_.data());
260     }
261 
262     // fromFunc
CompareFromFunc(const ReportItem & a,const ReportItem & b)263     static int CompareFromFunc(const ReportItem &a, const ReportItem &b)
264     {
265         return a.fromFunc_.compare(b.fromFunc_);
266     }
GetFromFunc(const ReportItem & a,size_t len,const std::string & format)267     static const std::string GetFromFunc(const ReportItem &a, size_t len, const std::string &format)
268     {
269         return StringPrintf(format.c_str(), len, a.fromFunc_.data());
270     }
271 
272 private:
Same(const ReportItem & b)273     bool Same(const ReportItem &b) const
274     {
275         return (comm_ == b.comm_) && (pid_ == b.pid_) && (tid_ == b.tid_) && (func_ == b.func_) &&
276                (dso_ == b.dso_) && (vaddr_ == b.vaddr_);
277     }
278 };
279 
280 using ReportKeyCompareFunction = int(const ReportItem &, const ReportItem &);
281 using ReportKeyGetFunction = const std::string(const ReportItem &, size_t, const std::string &);
282 
283 constexpr const int MAX_FILED_LEN = 20;
284 constexpr const int CALLSTACK_INDENT = 4;
285 struct ReportKey {
286     const std::string keyName_;
287     const std::string valueFormat_;
288     size_t maxLen_ = 0u;
289     std::string maxValue_;
290     ReportKeyCompareFunction &compareFunction_;
291     ReportKeyGetFunction &GetFunction_;
292     const std::vector<std::string> &displayFilter_;
293 
ReportKeyReportKey294     ReportKey(const std::string keyName, ReportKeyCompareFunction &compareFunction,
295               ReportKeyGetFunction &GetFunction, const std::string valueFormat,
296               const std::vector<std::string> &displayFilter)
297         : keyName_(keyName),
298           valueFormat_(valueFormat),
299           compareFunction_(compareFunction),
300           GetFunction_(GetFunction),
301           displayFilter_(displayFilter)
302     {
303         maxLen_ = keyName.size();
304     }
305 
UpdateValueMaxLenReportKey306     void UpdateValueMaxLen(const std::string &value)
307     {
308         size_t newMaxLen = std::max(maxLen_, value.size());
309         if (maxLen_ < newMaxLen) {
310             maxValue_ = value;
311             maxLen_ = newMaxLen;
312         }
313     }
314 
UpdateValueMaxLenReportKey315     void UpdateValueMaxLen(size_t value)
316     {
317         size_t newMaxLen = std::max(maxLen_, std::to_string(value).size());
318         if (maxLen_ < newMaxLen) {
319             maxValue_ = std::to_string(value);
320             maxLen_ = newMaxLen;
321         }
322     }
323 
GetValueReportKey324     std::string GetValue(const ReportItem &i)
325     {
326         return GetFunction_(i, maxLen_, valueFormat_);
327     }
328 
ShouldDisplayReportKey329     bool ShouldDisplay(const ReportItem &i)
330     {
331         if (displayFilter_.size() == 0) {
332             return true;
333         } else {
334             std::string value = GetFunction_(i, 0, valueFormat_);
335             auto it = find(displayFilter_.begin(), displayFilter_.end(), value);
336             if (it == displayFilter_.end()) {
337                 HLOGV("  not found '%s' in %s", value.c_str(),
338                       VectorToString(displayFilter_).c_str());
339             }
340             return (it != displayFilter_.end());
341         }
342     }
343 };
344 
345 using ReportItems = std::vector<ReportItem>;
346 using ReportItemsIt = ReportItems::iterator;
347 using ReportItemsConstIt = ReportItems::const_iterator;
348 
349 struct ReportOption {
350     float heatLimit_ = 0.0f;
351     float callStackHeatLimit_ = 0.0f;
352 
353     // display filter
354     std::vector<std::string> displayComms_ {};
355     std::vector<std::string> displayPids_ {};
356     std::vector<std::string> displayTids_ {};
357     std::vector<std::string> displayDsos_ {};
358     std::vector<std::string> displayFromDsos_ {};
359     std::vector<std::string> displayFuncs_ {};
360     std::vector<std::string> displayFromFuncs_ {};
361     std::vector<std::string> displayDummy_ {};
362 
363     std::vector<std::string> sortKeys_ = {"comm", "pid", "tid", "dso", "func"};
364 
365     bool debug_ = false;
366     bool hideCount_ = false;
367 };
368 
369 class Report {
370 public:
Report()371     Report() : option_(defaultOption_), virtualRuntime_(false)
372     {
373         // works for ut test
374     }
Report(ReportOption & option)375     Report(ReportOption &option) : option_(option), virtualRuntime_(false) {}
376     bool MultiLevelSame(const ReportItem &a, const ReportItem &b);
377     void AdjustReportItems();
378     void AddReportItem(const PerfRecordSample &sample, bool includeCallStack);
379     void AddReportItemBranch(const PerfRecordSample &sample);
380     void OutputStd(FILE *output);
381     void OutputStdDiff(FILE *output, Report &other);
382 
383     ReportOption &option_;
384 
385     VirtualRuntime virtualRuntime_;
386 
387     std::map<std::string, ReportKey> reportKeyMap_ = {
388         {
389             "count",
390             {
391                 "count",
392                 ReportItem::CompareEventCount,
393                 ReportItem::GetEventCount,
394                 "%*" PRIu64 "",
395                 option_.displayDummy_,
396             },
397         },
398         {
399             "comm",
400             {
401                 "comm",
402                 ReportItem::CompareComm,
403                 ReportItem::GetComm,
404                 "%-*s",
405                 option_.displayComms_,
406             },
407         },
408         {
409             "pid",
410             {
411                 "pid",
412                 ReportItem::ComparePid,
413                 ReportItem::GetPid,
414                 "%*d",
415                 option_.displayPids_,
416             },
417         },
418         {
419             "tid",
420             {
421                 "tid",
422                 ReportItem::CompareTid,
423                 ReportItem::GetTid,
424                 "%*d",
425                 option_.displayTids_,
426             },
427         },
428         {
429             "dso",
430             {
431                 "dso",
432                 ReportItem::CompareDso,
433                 ReportItem::GetDso,
434                 "%-*s",
435                 option_.displayDsos_,
436             },
437         },
438         {
439             "from_dso",
440             {
441                 "from_dso",
442                 ReportItem::CompareFromDso,
443                 ReportItem::GetFromDso,
444                 "%-*s",
445                 option_.displayFromDsos_,
446             },
447         },
448         {
449             "func",
450             {
451                 "func",
452                 ReportItem::CompareFunc,
453                 ReportItem::GetFunc,
454                 "%-*s",
455                 option_.displayFuncs_,
456             },
457         },
458         {
459             "from_func",
460             {
461                 "from_func",
462                 ReportItem::CompareFromFunc,
463                 ReportItem::GetFromFunc,
464                 "%-*s",
465                 option_.displayFromFuncs_,
466             },
467         },
468     };
469     struct ReportEventConfigItem {
470         ReportEventConfigItem(const ReportEventConfigItem &) = delete;
471         ReportEventConfigItem &operator=(const ReportEventConfigItem &) = delete;
472         ReportEventConfigItem(ReportEventConfigItem &&) = default;
473         ReportEventConfigItem &operator=(ReportEventConfigItem &&) = default;
474         std::string eventName_;
475         uint64_t sampleCount_ = 0;
476         uint64_t eventCount_ = 0;
477         std::vector<ReportItem> reportItems_;
478         uint32_t type_;
479         uint64_t config_;
480         std::vector<uint64_t> ids_;
481 
482         bool coutMode_ = true; // use cout or time ?
483         bool operator==(const ReportEventConfigItem &o) const
484         {
485             return (type_ == o.type_) && (config_ == o.config_);
486         }
487         bool operator!=(const ReportEventConfigItem &o) const
488         {
489             return !(operator==(o));
490         }
toDebugStringReportEventConfigItem491         std::string toDebugString()
492         {
493             return StringPrintf("%s(%" PRIu32 "-%" PRIu64 "):PRIu64", eventName_.c_str(), type_,
494                                 config_, sampleCount_);
495         }
496         ReportEventConfigItem(std::string eventName, uint32_t type, uint64_t config,
497                               bool coutMode = true)
eventName_ReportEventConfigItem498             : eventName_(eventName), type_(type), config_(config), coutMode_(coutMode)
499         {
500         }
501     };
502     std::vector<ReportEventConfigItem> configs_;
~Report()503     virtual ~Report() {}
504 
505     std::map<uint64_t, size_t> configIdIndexMaps_; // index of configNames_
GetConfigName(uint64_t id)506     std::string GetConfigName(uint64_t id)
507     {
508         size_t index = GetConfigIndex(id);
509         HIPERF_ASSERT(index < configs_.size(), "unable found config index %zu\n", index);
510         return configs_[index].eventName_;
511     }
GetConfigIndex(uint64_t id)512     size_t GetConfigIndex(uint64_t id)
513     {
514         HIPERF_ASSERT(configIdIndexMaps_.find(id) != configIdIndexMaps_.end(), "unable found id %" PRIx64 "\n", id);
515         return configIdIndexMaps_.at(id);
516     }
517 
518 private:
519     FILE *output_ = nullptr;
520     const std::string TEXT_RED = "\x1b[31m";
521     const std::string TEXT_GREEN = "\x1b[32m";
522     const std::string TEXT_RESET = "\033[0m";
523     const unsigned int ConsoleDefaultWidth = 80;
524 
525     // sometime caller don't give the option
526     ReportOption defaultOption_;
527 
528     std::vector<std::string> displayKeyNames_;
529 
530     // use virtual only for gmock test
531     bool MultiLevelSorting(const ReportItem &a, const ReportItem &b);
532     bool MultiLevelSameAndUpdateCount(ReportItem &l, ReportItem &r);
533     void MergeCallFrameCount(ReportItem &leftItem, ReportItem &rightItem);
534     virtual int MultiLevelCompare(const ReportItem &a, const ReportItem &b);
535 
536     void StatisticsRecords();
537     void FilterDisplayRecords();
538     void UpdateReportItemsAfterAdjust();
539 
540     // std out
541     unsigned int consoleWidth_ = 0;
542     void PrepareConsole();
543 
544     void OutputStdStatistics(ReportEventConfigItem &config);
545 
546     void OutputStdHead(ReportEventConfigItem &config, bool diffMode = false);
547 
548     void OutputStdContent(ReportEventConfigItem &config);
549     void OutputStdContentDiff(ReportEventConfigItem &left, ReportEventConfigItem &right);
550 
551     void OutputStdContentItem(const ReportItem &reportItem);
552 
553     void OutputStdCallFrames(int indent, const ReportItemCallFrame &callFrame, uint64_t totalEventCount);
554     bool OutputStdCallFrame(int indent, const std::string_view &funcName, uint64_t eventCount,
555                             uint64_t totalEventCount);
556     void OutputStdItemHeating(float heat, float heat2);
557 };
558 } // namespace HiPerf
559 } // namespace Developtools
560 } // namespace OHOS
561 #endif // REPORT_H
562