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", static_cast<int>(sample->pid)); 70 } 71 72 template <typename EntryT> 73 std::string DisplayTid(const EntryT* sample) { 74 return android::base::StringPrintf("%d", static_cast<int>(sample->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