SampleDisplayer.h revision 18385c4b52c25f14475645172a2ce5dfd3fb1e9a
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
30template <typename EntryT, typename InfoT>
31std::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
39template <typename EntryT, typename InfoT>
40std::string DisplaySelfOverhead(const EntryT* sample, const InfoT* info) {
41  uint64_t period = sample->period;
42  uint64_t total_period = info->total_period;
43  double percentage = (total_period != 0) ? 100.0 * period / total_period : 0.0;
44  return android::base::StringPrintf("%.2f%%", percentage);
45}
46
47#define BUILD_DISPLAY_UINT64_FUNCTION(function_name, display_part)        \
48  template <typename EntryT>                                              \
49  std::string function_name(const EntryT* sample) {                       \
50    return android::base::StringPrintf("%" PRIu64, sample->display_part); \
51  }
52
53#define BUILD_DISPLAY_HEX64_FUNCTION(function_name, display_part)           \
54  template <typename EntryT>                                                \
55  std::string function_name(const EntryT* sample) {                         \
56    return android::base::StringPrintf("0x%" PRIx64, sample->display_part); \
57  }
58
59BUILD_DISPLAY_UINT64_FUNCTION(DisplaySampleCount, sample_count);
60
61template <typename EntryT>
62std::string DisplayPid(const EntryT* sample) {
63  return android::base::StringPrintf("%d", sample->thread->pid);
64}
65
66template <typename EntryT>
67std::string DisplayTid(const EntryT* sample) {
68  return android::base::StringPrintf("%d", sample->thread->tid);
69}
70
71template <typename EntryT>
72std::string DisplayComm(const EntryT* sample) {
73  return sample->thread_comm;
74}
75
76template <typename EntryT>
77std::string DisplayDso(const EntryT* sample) {
78  return sample->map->dso->Path();
79}
80
81template <typename EntryT>
82std::string DisplaySymbol(const EntryT* sample) {
83  return sample->symbol->DemangledName();
84}
85
86template <typename EntryT>
87std::string DisplayDsoFrom(const EntryT* sample) {
88  return sample->branch_from.map->dso->Path();
89}
90
91template <typename EntryT>
92std::string DisplaySymbolFrom(const EntryT* sample) {
93  return sample->branch_from.symbol->DemangledName();
94}
95
96template <typename SampleT, typename CallChainNodeT>
97class CallgraphDisplayer {
98 private:
99  static constexpr int SPACES_BETWEEN_CALLGRAPH_ENTRIES = 4;
100
101 public:
102  CallgraphDisplayer(uint32_t max_stack = UINT32_MAX,
103                     double percent_limit = 0.0)
104      : max_stack_(max_stack), percent_limit_(percent_limit) {}
105
106  virtual ~CallgraphDisplayer() {}
107
108  void operator()(FILE* fp, const SampleT* sample) {
109    std::string prefix = "       ";
110    fprintf(fp, "%s|\n", prefix.c_str());
111    fprintf(fp, "%s-- %s\n", prefix.c_str(), PrintSampleName(sample).c_str());
112    prefix.append(3, ' ');
113    for (size_t i = 0; i < sample->callchain.children.size(); ++i) {
114      DisplayCallGraphEntry(fp, 1, prefix, sample->callchain.children[i],
115                            sample->callchain.children_period + sample->GetPeriod(),
116                            (i + 1 == sample->callchain.children.size()));
117    }
118  }
119
120  void DisplayCallGraphEntry(FILE* fp, size_t depth, std::string prefix,
121                             const std::unique_ptr<CallChainNodeT>& node,
122                             uint64_t parent_period, bool last) {
123    if (depth > max_stack_) {
124      return;
125    }
126    std::string percentage_s = "-- ";
127    if (node->period + node->children_period != parent_period) {
128      double percentage =
129          100.0 * (node->period + node->children_period) / parent_period;
130      if (percentage < percent_limit_) {
131        return;
132      }
133      percentage_s = android::base::StringPrintf("--%.2f%%-- ", percentage);
134    }
135    prefix += "|";
136    fprintf(fp, "%s\n", prefix.c_str());
137    if (last) {
138      prefix.back() = ' ';
139    }
140    fprintf(fp, "%s%s%s\n", prefix.c_str(), percentage_s.c_str(),
141            PrintSampleName(node->chain[0]).c_str());
142    for (size_t i = 1; i < node->chain.size(); ++i) {
143      fprintf(fp, "%s%*s%s\n", prefix.c_str(), static_cast<int>(percentage_s.size()), "",
144              PrintSampleName(node->chain[i]).c_str());
145    }
146    prefix.append(SPACES_BETWEEN_CALLGRAPH_ENTRIES, ' ');
147    if (!node->children.empty() && node->period != 0) {
148      fprintf(fp, "%s|--%.2f%%-- [hit in function]\n", prefix.c_str(),
149              100.0 * node->period / (node->period + node->children_period));
150    }
151    for (size_t i = 0; i < node->children.size(); ++i) {
152      DisplayCallGraphEntry(fp, depth + 1, prefix, node->children[i],
153                            node->children_period + node->period,
154                            (i + 1 == node->children.size()));
155    }
156  }
157
158 protected:
159  virtual std::string PrintSampleName(const SampleT* sample) {
160    return sample->symbol->DemangledName();
161  }
162
163 private:
164  uint32_t max_stack_;
165  double percent_limit_;
166};
167
168// SampleDisplayer is a class using a collections of display functions to show a
169// sample.
170
171template <typename EntryT, typename InfoT>
172class SampleDisplayer {
173 public:
174  typedef std::string (*display_sample_func_t)(const EntryT*);
175  typedef std::string (*display_sample_with_info_func_t)(const EntryT*,
176                                                         const InfoT*);
177  using exclusive_display_sample_func_t =
178      std::function<void(FILE*, const EntryT*)>;
179
180 private:
181  struct Item {
182    std::string name;
183    size_t width;
184    display_sample_func_t func;
185    display_sample_with_info_func_t func_with_info;
186  };
187
188 public:
189  void SetInfo(const InfoT* info) { info_ = info; }
190
191  void AddDisplayFunction(const std::string& name, display_sample_func_t func) {
192    Item item;
193    item.name = name;
194    item.width = name.size();
195    item.func = func;
196    item.func_with_info = nullptr;
197    display_v_.push_back(item);
198  }
199
200  void AddDisplayFunction(const std::string& name,
201                          display_sample_with_info_func_t func_with_info) {
202    Item item;
203    item.name = name;
204    item.width = name.size();
205    item.func = nullptr;
206    item.func_with_info = func_with_info;
207    display_v_.push_back(item);
208  }
209
210  void AddExclusiveDisplayFunction(exclusive_display_sample_func_t func) {
211    exclusive_display_v_.push_back(func);
212  }
213
214  void AdjustWidth(const EntryT* sample) {
215    for (auto& item : display_v_) {
216      std::string data = (item.func != nullptr)
217                             ? item.func(sample)
218                             : item.func_with_info(sample, info_);
219      item.width = std::max(item.width, data.size());
220    }
221  }
222
223  void PrintNames(FILE* fp) {
224    for (size_t i = 0; i < display_v_.size(); ++i) {
225      auto& item = display_v_[i];
226      if (i != display_v_.size() - 1) {
227        fprintf(fp, "%-*s  ", static_cast<int>(item.width), item.name.c_str());
228      } else {
229        fprintf(fp, "%s\n", item.name.c_str());
230      }
231    }
232  }
233
234  void PrintSample(FILE* fp, const EntryT* sample) {
235    for (size_t i = 0; i < display_v_.size(); ++i) {
236      auto& item = display_v_[i];
237      std::string data = (item.func != nullptr)
238                             ? item.func(sample)
239                             : item.func_with_info(sample, info_);
240      if (i != display_v_.size() - 1) {
241        fprintf(fp, "%-*s  ", static_cast<int>(item.width), data.c_str());
242      } else {
243        fprintf(fp, "%s\n", data.c_str());
244      }
245    }
246    for (auto& func : exclusive_display_v_) {
247      func(fp, sample);
248    }
249  }
250
251 private:
252  const InfoT* info_;
253  std::vector<Item> display_v_;
254  std::vector<exclusive_display_sample_func_t> exclusive_display_v_;
255};
256
257#endif  // SIMPLE_PERF_SAMPLE_DISPLAYER_H_
258