• 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 <cstdlib>
21 #include <functional>
22 #include <map>
23 #include <stdio.h>
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_view func_;
37     uint64_t vaddr_;
38     std::string_view 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_view func,uint64_t vaddr,std::string_view dso,uint64_t eventCount,uint64_t selfEventCount)42     ReportItemCallFrame(std::string_view func, uint64_t vaddr, std::string_view 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_(dso),
148           func_(func),
149           vaddr_(vaddr),
150           eventCount_(eventCount)
151     {
152         HLOG_ASSERT(!comm.empty());
153         index_ = allIndex_++;
154     }
155 
156     bool operator==(const ReportItem &b) const
157     {
158         return Same(b);
159     }
160 
161     bool operator!=(const ReportItem &b) const
162     {
163         return !Same(b);
164     }
165 
166     // debug only
ToDebugString()167     const std::string ToDebugString() const
168     {
169         return StringPrintf("%d:%d:%s-%s(%s):%zu i:%llu", pid_, tid_, comm_.data(), func_.data(),
170                             dso_.data(), eventCount_, index_);
171     }
172 
173     // Count
CompareEventCount(const ReportItem & a,const ReportItem & b)174     static int CompareEventCount(const ReportItem &a, const ReportItem &b)
175     {
176         if (a.eventCount_ != b.eventCount_) {
177             return (a.eventCount_ > b.eventCount_) ? 1 : -1;
178         } else {
179             return 0;
180         }
181     }
182 
CompareSortingEventCount(const ReportItem & a,const ReportItem & b)183     static int CompareSortingEventCount(const ReportItem &a, const ReportItem &b)
184     {
185         return a.eventCount_ > b.eventCount_;
186     }
187 
GetEventCount(const ReportItem & a,size_t len,const std::string & format)188     static const std::string GetEventCount(const ReportItem &a, size_t len,
189                                            const std::string &format)
190     {
191         return StringPrintf(format.c_str(), len, a.eventCount_);
192     }
193 
194     // Pid
ComparePid(const ReportItem & a,const ReportItem & b)195     static int ComparePid(const ReportItem &a, const ReportItem &b)
196     {
197         if (a.pid_ != b.pid_) {
198             return (a.pid_ > b.pid_) ? 1 : -1;
199         } else {
200             return 0;
201         }
202     }
GetPid(const ReportItem & a,size_t len,const std::string & format)203     static const std::string GetPid(const ReportItem &a, size_t len, const std::string &format)
204     {
205         return StringPrintf(format.c_str(), len, a.pid_);
206     }
207 
208     // Tid
CompareTid(const ReportItem & a,const ReportItem & b)209     static int CompareTid(const ReportItem &a, const ReportItem &b)
210     {
211         if (a.tid_ != b.tid_) {
212             return (a.tid_ > b.tid_) ? 1 : -1;
213         } else {
214             return 0;
215         }
216     }
GetTid(const ReportItem & a,size_t len,const std::string & format)217     static const std::string GetTid(const ReportItem &a, size_t len, const std::string &format)
218     {
219         return StringPrintf(format.c_str(), len, a.tid_);
220     }
221 
222     // Comm
CompareComm(const ReportItem & a,const ReportItem & b)223     static int CompareComm(const ReportItem &a, const ReportItem &b)
224     {
225         int result = a.comm_.compare(b.comm_);
226         return result;
227     }
GetComm(const ReportItem & a,size_t len,const std::string & format)228     static const std::string GetComm(const ReportItem &a, size_t len, const std::string &format)
229     {
230         return StringPrintf(format.c_str(), len, a.comm_.data());
231     }
232 
233     // Func
CompareFunc(const ReportItem & a,const ReportItem & b)234     static int CompareFunc(const ReportItem &a, const ReportItem &b)
235     {
236         return a.func_.compare(b.func_);
237     }
GetFunc(const ReportItem & a,size_t len,const std::string & format)238     static const std::string GetFunc(const ReportItem &a, size_t len, const std::string &format)
239     {
240         return StringPrintf(format.c_str(), len, a.func_.data());
241     }
242 
243     // Dso
CompareDso(const ReportItem & a,const ReportItem & b)244     static int CompareDso(const ReportItem &a, const ReportItem &b)
245     {
246         return a.dso_.compare(b.dso_);
247     }
GetDso(const ReportItem & a,size_t len,const std::string & format)248     static const std::string GetDso(const ReportItem &a, size_t len, const std::string &format)
249     {
250         return StringPrintf(format.c_str(), len, a.dso_.data());
251     }
252 
253     // fromDso
CompareFromDso(const ReportItem & a,const ReportItem & b)254     static int CompareFromDso(const ReportItem &a, const ReportItem &b)
255     {
256         return a.fromDso_.compare(b.fromDso_);
257     }
GetFromDso(const ReportItem & a,size_t len,const std::string & format)258     static const std::string GetFromDso(const ReportItem &a, size_t len, const std::string &format)
259     {
260         return StringPrintf(format.c_str(), len, a.fromDso_.data());
261     }
262 
263     // fromFunc
CompareFromFunc(const ReportItem & a,const ReportItem & b)264     static int CompareFromFunc(const ReportItem &a, const ReportItem &b)
265     {
266         return a.fromFunc_.compare(b.fromFunc_);
267     }
GetFromFunc(const ReportItem & a,size_t len,const std::string & format)268     static const std::string GetFromFunc(const ReportItem &a, size_t len, const std::string &format)
269     {
270         return StringPrintf(format.c_str(), len, a.fromFunc_.data());
271     }
272 
273 private:
Same(const ReportItem & b)274     bool Same(const ReportItem &b) const
275     {
276         return (comm_ == b.comm_) && (pid_ == b.pid_) && (tid_ == b.tid_) && (func_ == b.func_) &&
277                (dso_ == b.dso_) && (vaddr_ == b.vaddr_);
278     }
279 };
280 
281 using ReportKeyCompareFunction = int(const ReportItem &, const ReportItem &);
282 using ReportKeyGetFunction = const std::string(const ReportItem &, size_t, const std::string &);
283 
284 constexpr const int MAX_FILED_LEN = 20;
285 constexpr const int CALLSTACK_INDENT = 4;
286 struct ReportKey {
287     const std::string keyName_;
288     const std::string valueFormat_;
289     size_t maxLen_ = 0u;
290     std::string maxValue_;
291     ReportKeyCompareFunction &compareFunction_;
292     ReportKeyGetFunction &GetFunction_;
293     const std::vector<std::string> &displayFilter_;
294 
ReportKeyReportKey295     ReportKey(const std::string keyName, ReportKeyCompareFunction &compareFunction,
296               ReportKeyGetFunction &GetFunction, const std::string valueFormat,
297               const std::vector<std::string> &displayFilter)
298         : keyName_(keyName),
299           valueFormat_(valueFormat),
300           compareFunction_(compareFunction),
301           GetFunction_(GetFunction),
302           displayFilter_(displayFilter)
303     {
304         maxLen_ = keyName.size();
305     }
306 
UpdateValueMaxLenReportKey307     void UpdateValueMaxLen(const std::string &value)
308     {
309         size_t newMaxLen = std::max(maxLen_, value.size());
310         if (maxLen_ < newMaxLen) {
311             maxValue_ = value;
312             maxLen_ = newMaxLen;
313         }
314     }
315 
UpdateValueMaxLenReportKey316     void UpdateValueMaxLen(size_t value)
317     {
318         size_t newMaxLen = std::max(maxLen_, std::to_string(value).size());
319         if (maxLen_ < newMaxLen) {
320             maxValue_ = std::to_string(value);
321             maxLen_ = newMaxLen;
322         }
323     }
324 
GetValueReportKey325     std::string GetValue(const ReportItem &i)
326     {
327         return GetFunction_(i, maxLen_, valueFormat_);
328     }
329 
ShouldDisplayReportKey330     bool ShouldDisplay(const ReportItem &i)
331     {
332         if (displayFilter_.size() == 0) {
333             return true;
334         } else {
335             std::string value = GetFunction_(i, 0, valueFormat_);
336             auto it = find(displayFilter_.begin(), displayFilter_.end(), value);
337             if (it == displayFilter_.end()) {
338                 HLOGV("  not found '%s' in %s", value.c_str(),
339                       VectorToString(displayFilter_).c_str());
340             }
341             return (it != displayFilter_.end());
342         }
343     }
344 };
345 
346 using ReportItems = std::vector<ReportItem>;
347 using ReportItemsIt = ReportItems::iterator;
348 using ReportItemsConstIt = ReportItems::const_iterator;
349 
350 struct ReportOption {
351     float heatLimit_ = 0.0f;
352     float callStackHeatLimit_ = 0.0f;
353 
354     // display filter
355     std::vector<std::string> displayComms_ {};
356     std::vector<std::string> displayPids_ {};
357     std::vector<std::string> displayTids_ {};
358     std::vector<std::string> displayDsos_ {};
359     std::vector<std::string> displayFromDsos_ {};
360     std::vector<std::string> displayFuncs_ {};
361     std::vector<std::string> displayFromFuncs_ {};
362     std::vector<std::string> displayDummy_ {};
363 
364     std::vector<std::string> sortKeys_ = {"comm", "pid", "tid", "dso", "func"};
365 
366     bool debug_ = false;
367     bool hideCount_ = false;
368 };
369 
370 class Report {
371 public:
Report()372     Report() : option_(defaultOption_), virtualRuntime_(false)
373     {
374         // works for ut test
375     }
Report(ReportOption & option)376     Report(ReportOption &option) : option_(option), virtualRuntime_(false) {}
377     bool MultiLevelSame(const ReportItem &a, const ReportItem &b);
378     void AdjustReportItems();
379     void AddReportItem(const PerfRecordSample &sample, bool includeCallStack);
380     void AddReportItemBranch(const PerfRecordSample &sample);
381     void OutputStd(FILE *output);
382     void OutputStdDiff(FILE *output, Report &other);
383 
384     ReportOption &option_;
385 
386     VirtualRuntime virtualRuntime_;
387 
388     std::map<std::string, ReportKey> reportKeyMap_ = {
389         {
390             "count",
391             {
392                 "count",
393                 ReportItem::CompareEventCount,
394                 ReportItem::GetEventCount,
395                 "%*" PRIu64 "",
396                 option_.displayDummy_,
397             },
398         },
399         {
400             "comm",
401             {
402                 "comm",
403                 ReportItem::CompareComm,
404                 ReportItem::GetComm,
405                 "%-*s",
406                 option_.displayComms_,
407             },
408         },
409         {
410             "pid",
411             {
412                 "pid",
413                 ReportItem::ComparePid,
414                 ReportItem::GetPid,
415                 "%*d",
416                 option_.displayPids_,
417             },
418         },
419         {
420             "tid",
421             {
422                 "tid",
423                 ReportItem::CompareTid,
424                 ReportItem::GetTid,
425                 "%*d",
426                 option_.displayTids_,
427             },
428         },
429         {
430             "dso",
431             {
432                 "dso",
433                 ReportItem::CompareDso,
434                 ReportItem::GetDso,
435                 "%-*s",
436                 option_.displayDsos_,
437             },
438         },
439         {
440             "from_dso",
441             {
442                 "from_dso",
443                 ReportItem::CompareFromDso,
444                 ReportItem::GetFromDso,
445                 "%-*s",
446                 option_.displayFromDsos_,
447             },
448         },
449         {
450             "func",
451             {
452                 "func",
453                 ReportItem::CompareFunc,
454                 ReportItem::GetFunc,
455                 "%-*s",
456                 option_.displayFuncs_,
457             },
458         },
459         {
460             "from_func",
461             {
462                 "from_func",
463                 ReportItem::CompareFromFunc,
464                 ReportItem::GetFromFunc,
465                 "%-*s",
466                 option_.displayFromFuncs_,
467             },
468         },
469     };
470     struct ReportEventConfigItem {
471         ReportEventConfigItem(const ReportEventConfigItem &) = delete;
472         ReportEventConfigItem &operator=(const ReportEventConfigItem &) = delete;
473         ReportEventConfigItem(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         return configs_[GetConfigIndex(id)].eventName_;
509     }
GetConfigIndex(uint64_t id)510     size_t GetConfigIndex(uint64_t id)
511     {
512         HLOG_ASSERT_MESSAGE(configIdIndexMaps_.find(id) != configIdIndexMaps_.end(),
513                             "unable found id %" PRIx64 "", id);
514         return configIdIndexMaps_.at(id);
515     }
516 
517 private:
518     FILE *output_ = nullptr;
519     const std::string TEXT_RED = "\x1b[31m";
520     const std::string TEXT_GREEN = "\x1b[32m";
521     const std::string TEXT_RESET = "\033[0m";
522     const unsigned int ConsoleDefaultWidth = 80;
523 
524     // sometime caller don't give the option
525     ReportOption defaultOption_;
526 
527     std::vector<std::string> displayKeyNames_;
528 
529     // use virtual only for gmock test
530     bool MultiLevelSorting(const ReportItem &a, const ReportItem &b);
531     bool MultiLevelSameAndUpdateCount(ReportItem &l, ReportItem &r);
532     void MergeCallFrameCount(ReportItem &l, ReportItem &r);
533     virtual int MultiLevelCompare(const ReportItem &a, const ReportItem &b);
534 
535     void StatisticsRecords();
536     void FilterDisplayRecords();
537     void UpdateReportItemsAfterAdjust();
538 
539     // std out
540     unsigned int consoleWidth_ = 0;
541     void PrepareConsole();
542 
543     void OutputStdStatistics(ReportEventConfigItem &);
544     bool OutputStdStatistics(ReportEventConfigItem &config, ReportEventConfigItem &otherConfig);
545 
546     void OutputStdHead(ReportEventConfigItem &, bool diffMode = false);
547 
548     void OutputStdContent(ReportEventConfigItem &);
549     void OutputStdContentDiff(ReportEventConfigItem &, ReportEventConfigItem &);
550 
551     void OutputStdContentItem(const ReportItem &reportItem);
552     void OutputStdContentDiffOneSide(bool leftOnly, ReportItem &reportItem);
553 
554     void OutputStdCallFrames(int indent, const ReportItemCallFrame &callFrames,
555                              uint64_t totalEventCount);
556     bool OutputStdCallFrame(int indent, const std::string_view &funcName, uint64_t eventCount,
557                             uint64_t totalEventCount);
558     void OutputStdItemHeating(float heat, float heat2);
559 
560     FRIEND_TEST(ReportTest, MultiLevelSorting);
561     FRIEND_TEST(ReportTest, MultiLevelSameAndUpdateCount);
562     FRIEND_TEST(ReportTest, MergeCallFrameCount);
563     FRIEND_TEST(ReportTest, MultiLevelCompare);
564     FRIEND_TEST(ReportTest, PrepareConsole);
565 };
566 } // namespace HiPerf
567 } // namespace Developtools
568 } // namespace OHOS
569 #endif // REPORT_H
570