Home | History | Annotate | Download | only in simpleperf
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef SIMPLE_PERF_SAMPLE_DISPLAYER_H_
     18 #define SIMPLE_PERF_SAMPLE_DISPLAYER_H_
     19 
     20 #include <inttypes.h>
     21 
     22 #include <functional>
     23 #include <string>
     24 
     25 #include <android-base/logging.h>
     26 #include <android-base/stringprintf.h>
     27 
     28 // The display functions below are used to show items in a sample.
     29 
     30 template <typename EntryT, typename InfoT>
     31 std::string DisplayAccumulatedOverhead(const EntryT* sample,
     32                                        const InfoT* info) {
     33   uint64_t period = sample->period + sample->accumulated_period;
     34   uint64_t total_period = info->total_period;
     35   double percentage = (total_period != 0) ? 100.0 * period / total_period : 0.0;
     36   return android::base::StringPrintf("%.2f%%", percentage);
     37 }
     38 
     39 template <typename EntryT>
     40 std::string DisplayAccumulatedPeriod(const EntryT* sample) {
     41   return android::base::StringPrintf("%" PRIu64, sample->period + sample->accumulated_period);
     42 }
     43 
     44 template <typename EntryT, typename InfoT>
     45 std::string DisplaySelfOverhead(const EntryT* sample, const InfoT* info) {
     46   uint64_t period = sample->period;
     47   uint64_t total_period = info->total_period;
     48   double percentage = (total_period != 0) ? 100.0 * period / total_period : 0.0;
     49   return android::base::StringPrintf("%.2f%%", percentage);
     50 }
     51 
     52 #define BUILD_DISPLAY_UINT64_FUNCTION(function_name, display_part)        \
     53   template <typename EntryT>                                              \
     54   std::string function_name(const EntryT* sample) {                       \
     55     return android::base::StringPrintf("%" PRIu64, sample->display_part); \
     56   }
     57 
     58 #define BUILD_DISPLAY_HEX64_FUNCTION(function_name, display_part)           \
     59   template <typename EntryT>                                                \
     60   std::string function_name(const EntryT* sample) {                         \
     61     return android::base::StringPrintf("0x%" PRIx64, sample->display_part); \
     62   }
     63 
     64 BUILD_DISPLAY_UINT64_FUNCTION(DisplaySelfPeriod, period);
     65 BUILD_DISPLAY_UINT64_FUNCTION(DisplaySampleCount, sample_count);
     66 
     67 template <typename EntryT>
     68 std::string DisplayPid(const EntryT* sample) {
     69   return android::base::StringPrintf("%d", sample->thread->pid);
     70 }
     71 
     72 template <typename EntryT>
     73 std::string DisplayTid(const EntryT* sample) {
     74   return android::base::StringPrintf("%d", sample->thread->tid);
     75 }
     76 
     77 template <typename EntryT>
     78 std::string DisplayComm(const EntryT* sample) {
     79   return sample->thread_comm;
     80 }
     81 
     82 template <typename EntryT>
     83 std::string DisplayDso(const EntryT* sample) {
     84   return sample->map->dso->Path();
     85 }
     86 
     87 template <typename EntryT>
     88 std::string DisplaySymbol(const EntryT* sample) {
     89   return sample->symbol->DemangledName();
     90 }
     91 
     92 template <typename EntryT>
     93 std::string DisplayDsoFrom(const EntryT* sample) {
     94   return sample->branch_from.map->dso->Path();
     95 }
     96 
     97 template <typename EntryT>
     98 std::string DisplaySymbolFrom(const EntryT* sample) {
     99   return sample->branch_from.symbol->DemangledName();
    100 }
    101 
    102 template <typename SampleT, typename CallChainNodeT>
    103 class CallgraphDisplayer {
    104  private:
    105   static constexpr int SPACES_BETWEEN_CALLGRAPH_ENTRIES = 4;
    106 
    107  public:
    108   CallgraphDisplayer(uint32_t max_stack = UINT32_MAX,
    109                      double percent_limit = 0.0,
    110                      bool brief_callgraph = false)
    111       : max_stack_(max_stack), percent_limit_(percent_limit), brief_callgraph_(brief_callgraph) {}
    112 
    113   virtual ~CallgraphDisplayer() {}
    114 
    115   void operator()(FILE* fp, const SampleT* sample) {
    116     if (sample->callchain.children.empty()) {
    117       return;
    118     }
    119     std::string prefix = "       ";
    120     if (brief_callgraph_ && sample->callchain.duplicated) {
    121       fprintf(fp, "%s[skipped in brief callgraph mode]\n", prefix.c_str());
    122       return;
    123     }
    124     fprintf(fp, "%s|\n", prefix.c_str());
    125     fprintf(fp, "%s-- %s\n", prefix.c_str(), PrintSampleName(sample).c_str());
    126     prefix.append(3, ' ');
    127     for (size_t i = 0; i < sample->callchain.children.size(); ++i) {
    128       DisplayCallGraphEntry(fp, 1, prefix, sample->callchain.children[i],
    129                             sample->callchain.children_period + sample->GetPeriod(),
    130                             (i + 1 == sample->callchain.children.size()));
    131     }
    132   }
    133 
    134   void DisplayCallGraphEntry(FILE* fp, size_t depth, std::string prefix,
    135                              const std::unique_ptr<CallChainNodeT>& node,
    136                              uint64_t parent_period, bool last) {
    137     if (depth > max_stack_) {
    138       return;
    139     }
    140     std::string percentage_s = "-- ";
    141     if (node->period + node->children_period != parent_period) {
    142       double percentage =
    143           100.0 * (node->period + node->children_period) / parent_period;
    144       if (percentage < percent_limit_) {
    145         return;
    146       }
    147       percentage_s = android::base::StringPrintf("--%.2f%%-- ", percentage);
    148     }
    149     prefix += "|";
    150     fprintf(fp, "%s\n", prefix.c_str());
    151     if (last) {
    152       prefix.back() = ' ';
    153     }
    154     fprintf(fp, "%s%s%s\n", prefix.c_str(), percentage_s.c_str(),
    155             PrintSampleName(node->chain[0]).c_str());
    156     for (size_t i = 1; i < node->chain.size(); ++i) {
    157       fprintf(fp, "%s%*s%s\n", prefix.c_str(), static_cast<int>(percentage_s.size()), "",
    158               PrintSampleName(node->chain[i]).c_str());
    159     }
    160     prefix.append(SPACES_BETWEEN_CALLGRAPH_ENTRIES, ' ');
    161     if (!node->children.empty() && node->period != 0) {
    162       fprintf(fp, "%s|--%.2f%%-- [hit in function]\n", prefix.c_str(),
    163               100.0 * node->period / (node->period + node->children_period));
    164     }
    165     for (size_t i = 0; i < node->children.size(); ++i) {
    166       DisplayCallGraphEntry(fp, depth + 1, prefix, node->children[i],
    167                             node->children_period + node->period,
    168                             (i + 1 == node->children.size()));
    169     }
    170   }
    171 
    172  protected:
    173   virtual std::string PrintSampleName(const SampleT* sample) {
    174     return sample->symbol->DemangledName();
    175   }
    176 
    177  private:
    178   uint32_t max_stack_;
    179   double percent_limit_;
    180   bool brief_callgraph_;
    181 };
    182 
    183 // SampleDisplayer is a class using a collections of display functions to show a
    184 // sample.
    185 
    186 template <typename EntryT, typename InfoT>
    187 class SampleDisplayer {
    188  public:
    189   typedef std::string (*display_sample_func_t)(const EntryT*);
    190   typedef std::string (*display_sample_with_info_func_t)(const EntryT*,
    191                                                          const InfoT*);
    192   using exclusive_display_sample_func_t =
    193       std::function<void(FILE*, const EntryT*)>;
    194 
    195  private:
    196   struct Item {
    197     std::string name;
    198     size_t width;
    199     display_sample_func_t func;
    200     display_sample_with_info_func_t func_with_info;
    201   };
    202 
    203  public:
    204   void SetInfo(const InfoT* info) { info_ = info; }
    205 
    206   void AddDisplayFunction(const std::string& name, display_sample_func_t func) {
    207     Item item;
    208     item.name = name;
    209     item.width = name.size();
    210     item.func = func;
    211     item.func_with_info = nullptr;
    212     display_v_.push_back(item);
    213   }
    214 
    215   void AddDisplayFunction(const std::string& name,
    216                           display_sample_with_info_func_t func_with_info) {
    217     Item item;
    218     item.name = name;
    219     item.width = name.size();
    220     item.func = nullptr;
    221     item.func_with_info = func_with_info;
    222     display_v_.push_back(item);
    223   }
    224 
    225   void AddExclusiveDisplayFunction(exclusive_display_sample_func_t func) {
    226     exclusive_display_v_.push_back(func);
    227   }
    228 
    229   void AdjustWidth(const EntryT* sample) {
    230     for (auto& item : display_v_) {
    231       std::string data = (item.func != nullptr)
    232                              ? item.func(sample)
    233                              : item.func_with_info(sample, info_);
    234       item.width = std::max(item.width, data.size());
    235     }
    236   }
    237 
    238   void PrintNames(FILE* fp) {
    239     for (size_t i = 0; i < display_v_.size(); ++i) {
    240       auto& item = display_v_[i];
    241       if (i != display_v_.size() - 1) {
    242         fprintf(fp, "%-*s  ", static_cast<int>(item.width), item.name.c_str());
    243       } else {
    244         fprintf(fp, "%s\n", item.name.c_str());
    245       }
    246     }
    247   }
    248 
    249   void PrintSample(FILE* fp, const EntryT* sample) {
    250     for (size_t i = 0; i < display_v_.size(); ++i) {
    251       auto& item = display_v_[i];
    252       std::string data = (item.func != nullptr)
    253                              ? item.func(sample)
    254                              : item.func_with_info(sample, info_);
    255       if (i != display_v_.size() - 1) {
    256         fprintf(fp, "%-*s  ", static_cast<int>(item.width), data.c_str());
    257       } else {
    258         fprintf(fp, "%s\n", data.c_str());
    259       }
    260     }
    261     for (auto& func : exclusive_display_v_) {
    262       func(fp, sample);
    263     }
    264   }
    265 
    266  private:
    267   const InfoT* info_;
    268   std::vector<Item> display_v_;
    269   std::vector<exclusive_display_sample_func_t> exclusive_display_v_;
    270 };
    271 
    272 #endif  // SIMPLE_PERF_SAMPLE_DISPLAYER_H_
    273