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