2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef SIMPLE_PERF_SAMPLE_DISPLAYER_H_
18 #define SIMPLE_PERF_SAMPLE_DISPLAYER_H_
25 #include <android-base/logging.h>
26 #include <android-base/stringprintf.h>
28 // The display functions below are used to show items in a sample.
30 template <typename EntryT, typename InfoT>
31 std::string DisplayAccumulatedOverhead(const EntryT* sample,
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);
39 template <typename EntryT>
40 std::string DisplayAccumulatedPeriod(const EntryT* sample) {
41 return android::base::StringPrintf("%" PRIu64, sample->period + sample->accumulated_period);
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);
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); \
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); \
64 BUILD_DISPLAY_UINT64_FUNCTION(DisplaySelfPeriod, period);
65 BUILD_DISPLAY_UINT64_FUNCTION(DisplaySampleCount, sample_count);
67 template <typename EntryT>
68 std::string DisplayPid(const EntryT* sample) {
69 return android::base::StringPrintf("%d", sample->thread->pid);
72 template <typename EntryT>
73 std::string DisplayTid(const EntryT* sample) {
74 return android::base::StringPrintf("%d", sample->thread->tid);
77 template <typename EntryT>
78 std::string DisplayComm(const EntryT* sample) {
79 return sample->thread_comm;
82 template <typename EntryT>
83 std::string DisplayDso(const EntryT* sample) {
84 return sample->map->dso->Path();
87 template <typename EntryT>
88 std::string DisplaySymbol(const EntryT* sample) {
89 return sample->symbol->DemangledName();
92 template <typename EntryT>
93 std::string DisplayDsoFrom(const EntryT* sample) {
94 return sample->branch_from.map->dso->Path();
97 template <typename EntryT>
98 std::string DisplaySymbolFrom(const EntryT* sample) {
99 return sample->branch_from.symbol->DemangledName();
102 template <typename SampleT, typename CallChainNodeT>
103 class CallgraphDisplayer {
105 static constexpr int SPACES_BETWEEN_CALLGRAPH_ENTRIES = 4;
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) {}
113 virtual ~CallgraphDisplayer() {}
115 void operator()(FILE* fp, const SampleT* sample) {
116 if (sample->callchain.children.empty()) {
119 std::string prefix = " ";
120 if (brief_callgraph_ && sample->callchain.duplicated) {
121 fprintf(fp, "%s[skipped in brief callgraph mode]\n", prefix.c_str());
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()));
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_) {
140 std::string percentage_s = "-- ";
141 if (node->period + node->children_period != parent_period) {
143 100.0 * (node->period + node->children_period) / parent_period;
144 if (percentage < percent_limit_) {
147 percentage_s = android::base::StringPrintf("--%.2f%%-- ", percentage);
150 fprintf(fp, "%s\n", prefix.c_str());
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());
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));
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()));
173 virtual std::string PrintSampleName(const SampleT* sample) {
174 return sample->symbol->DemangledName();
179 double percent_limit_;
180 bool brief_callgraph_;
183 // SampleDisplayer is a class using a collections of display functions to show a
186 template <typename EntryT, typename InfoT>
187 class SampleDisplayer {
189 typedef std::string (*display_sample_func_t)(const EntryT*);
190 typedef std::string (*display_sample_with_info_func_t)(const EntryT*,
192 using exclusive_display_sample_func_t =
193 std::function<void(FILE*, const EntryT*)>;
199 display_sample_func_t func;
200 display_sample_with_info_func_t func_with_info;
204 void SetInfo(const InfoT* info) { info_ = info; }
206 void AddDisplayFunction(const std::string& name, display_sample_func_t func) {
209 item.width = name.size();
211 item.func_with_info = nullptr;
212 display_v_.push_back(item);
215 void AddDisplayFunction(const std::string& name,
216 display_sample_with_info_func_t func_with_info) {
219 item.width = name.size();
221 item.func_with_info = func_with_info;
222 display_v_.push_back(item);
225 void AddExclusiveDisplayFunction(exclusive_display_sample_func_t func) {
226 exclusive_display_v_.push_back(func);
229 void AdjustWidth(const EntryT* sample) {
230 for (auto& item : display_v_) {
231 std::string data = (item.func != nullptr)
233 : item.func_with_info(sample, info_);
234 item.width = std::max(item.width, data.size());
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());
244 fprintf(fp, "%s\n", item.name.c_str());
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)
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());
258 fprintf(fp, "%s\n", data.c_str());
261 for (auto& func : exclusive_display_v_) {
268 std::vector<Item> display_v_;
269 std::vector<exclusive_display_sample_func_t> exclusive_display_v_;
272 #endif // SIMPLE_PERF_SAMPLE_DISPLAYER_H_