blob: cc622858fc6b4ec7ff45ae90b745f3e91cbecde5 [file] [log] [blame]
Yabin Cui2672dea2015-05-21 12:17:23 -07001/*
2 * Copyright (C) 2015 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#include <inttypes.h>
Yabin Cuic42867e2015-08-04 17:33:47 -070018#include <algorithm>
Yabin Cui2672dea2015-05-21 12:17:23 -070019#include <functional>
20#include <map>
Yabin Cui8a530e32015-06-23 20:42:01 -070021#include <set>
Yabin Cui2672dea2015-05-21 12:17:23 -070022#include <string>
23#include <unordered_map>
Yabin Cui38e573e2015-08-06 11:25:09 -070024#include <unordered_set>
Yabin Cui2672dea2015-05-21 12:17:23 -070025#include <vector>
26
Yabin Cui18385c42016-12-09 14:51:04 -080027#include <android-base/file.h>
Elliott Hughes66dd09e2015-12-04 14:00:57 -080028#include <android-base/logging.h>
Yabin Cuic0565bb2016-09-29 15:59:33 -070029#include <android-base/parsedouble.h>
Yabin Cui569f64a2016-02-05 17:32:08 -080030#include <android-base/parseint.h>
Elliott Hughes66dd09e2015-12-04 14:00:57 -080031#include <android-base/stringprintf.h>
32#include <android-base/strings.h>
Yabin Cui2672dea2015-05-21 12:17:23 -070033
34#include "command.h"
Yabin Cui3c8c2132015-08-13 20:30:20 -070035#include "dwarf_unwind.h"
Yabin Cui2672dea2015-05-21 12:17:23 -070036#include "event_attr.h"
37#include "event_type.h"
Yabin Cui76769e52015-07-13 12:23:54 -070038#include "perf_regs.h"
Yabin Cui2672dea2015-05-21 12:17:23 -070039#include "record.h"
40#include "record_file.h"
41#include "sample_tree.h"
Yabin Cui60a0ea92015-07-22 20:30:43 -070042#include "thread_tree.h"
Yabin Cui4f41df62016-06-01 17:29:06 -070043#include "tracing.h"
Yabin Cui38e573e2015-08-06 11:25:09 -070044#include "utils.h"
Yabin Cui2672dea2015-05-21 12:17:23 -070045
Yabin Cuib64a8632016-05-24 18:23:33 -070046namespace {
Yabin Cui8a530e32015-06-23 20:42:01 -070047
48static std::set<std::string> branch_sort_keys = {
49 "dso_from", "dso_to", "symbol_from", "symbol_to",
Yabin Cui2672dea2015-05-21 12:17:23 -070050};
Yabin Cuib64a8632016-05-24 18:23:33 -070051struct BranchFromEntry {
Yabin Cuib64a8632016-05-24 18:23:33 -070052 const MapEntry* map;
53 const Symbol* symbol;
Yabin Cui9970a232016-06-29 12:18:11 -070054 uint64_t vaddr_in_file;
Yabin Cuib64a8632016-05-24 18:23:33 -070055 uint64_t flags;
56
Yabin Cui9970a232016-06-29 12:18:11 -070057 BranchFromEntry()
58 : map(nullptr), symbol(nullptr), vaddr_in_file(0), flags(0) {}
Yabin Cuib64a8632016-05-24 18:23:33 -070059};
60
61struct SampleEntry {
Yabin Cuib64a8632016-05-24 18:23:33 -070062 uint64_t time;
63 uint64_t period;
64 // accumuated when appearing in other sample's callchain
65 uint64_t accumulated_period;
66 uint64_t sample_count;
67 const ThreadEntry* thread;
68 const char* thread_comm;
69 const MapEntry* map;
70 const Symbol* symbol;
Yabin Cui9970a232016-06-29 12:18:11 -070071 uint64_t vaddr_in_file;
Yabin Cuib64a8632016-05-24 18:23:33 -070072 BranchFromEntry branch_from;
73 // a callchain tree representing all callchains in the sample
74 CallChainRoot<SampleEntry> callchain;
75
Yabin Cui9970a232016-06-29 12:18:11 -070076 SampleEntry(uint64_t time, uint64_t period, uint64_t accumulated_period,
77 uint64_t sample_count, const ThreadEntry* thread,
78 const MapEntry* map, const Symbol* symbol, uint64_t vaddr_in_file)
79 : time(time),
Yabin Cuib64a8632016-05-24 18:23:33 -070080 period(period),
81 accumulated_period(accumulated_period),
82 sample_count(sample_count),
83 thread(thread),
84 thread_comm(thread->comm),
85 map(map),
Yabin Cui9970a232016-06-29 12:18:11 -070086 symbol(symbol),
87 vaddr_in_file(vaddr_in_file) {}
Yabin Cuib64a8632016-05-24 18:23:33 -070088
89 // The data member 'callchain' can only move, not copy.
90 SampleEntry(SampleEntry&&) = default;
91 SampleEntry(SampleEntry&) = delete;
Yabin Cui18385c42016-12-09 14:51:04 -080092
93 uint64_t GetPeriod() const {
94 return period;
95 }
Yabin Cuib64a8632016-05-24 18:23:33 -070096};
97
98struct SampleTree {
99 std::vector<SampleEntry*> samples;
100 uint64_t total_samples;
101 uint64_t total_period;
Yabin Cui98c75842017-04-28 13:43:08 -0700102 uint64_t total_error_callchains;
Yabin Cuib64a8632016-05-24 18:23:33 -0700103};
104
Yabin Cui9970a232016-06-29 12:18:11 -0700105BUILD_COMPARE_VALUE_FUNCTION(CompareVaddrInFile, vaddr_in_file);
106BUILD_DISPLAY_HEX64_FUNCTION(DisplayVaddrInFile, vaddr_in_file);
107
Yabin Cui68b83832017-07-19 17:54:57 -0700108class ReportCmdSampleTreeBuilder : public SampleTreeBuilder<SampleEntry, uint64_t> {
Yabin Cuib64a8632016-05-24 18:23:33 -0700109 public:
Yabin Cui68b83832017-07-19 17:54:57 -0700110 ReportCmdSampleTreeBuilder(const SampleComparator<SampleEntry>& sample_comparator,
Yabin Cuib64a8632016-05-24 18:23:33 -0700111 ThreadTree* thread_tree)
112 : SampleTreeBuilder(sample_comparator),
113 thread_tree_(thread_tree),
114 total_samples_(0),
Yabin Cui98c75842017-04-28 13:43:08 -0700115 total_period_(0),
116 total_error_callchains_(0) {}
Yabin Cuib64a8632016-05-24 18:23:33 -0700117
118 void SetFilters(const std::unordered_set<int>& pid_filter,
119 const std::unordered_set<int>& tid_filter,
120 const std::unordered_set<std::string>& comm_filter,
Yabin Cuif79fbd12016-07-06 12:26:13 -0700121 const std::unordered_set<std::string>& dso_filter,
122 const std::unordered_set<std::string>& symbol_filter) {
Yabin Cuib64a8632016-05-24 18:23:33 -0700123 pid_filter_ = pid_filter;
124 tid_filter_ = tid_filter;
125 comm_filter_ = comm_filter;
126 dso_filter_ = dso_filter;
Yabin Cuif79fbd12016-07-06 12:26:13 -0700127 symbol_filter_ = symbol_filter;
Yabin Cuib64a8632016-05-24 18:23:33 -0700128 }
129
Yabin Cui0c093f32017-04-19 11:48:44 -0700130 SampleTree GetSampleTree() {
131 AddCallChainDuplicateInfo();
Yabin Cuib64a8632016-05-24 18:23:33 -0700132 SampleTree sample_tree;
133 sample_tree.samples = GetSamples();
134 sample_tree.total_samples = total_samples_;
135 sample_tree.total_period = total_period_;
Yabin Cui98c75842017-04-28 13:43:08 -0700136 sample_tree.total_error_callchains = total_error_callchains_;
Yabin Cuib64a8632016-05-24 18:23:33 -0700137 return sample_tree;
138 }
139
Yabin Cui68b83832017-07-19 17:54:57 -0700140 virtual void ReportCmdProcessSampleRecord(std::shared_ptr<SampleRecord>& r) {
141 return ProcessSampleRecord(*r);
142 }
143
144 virtual void ReportCmdProcessSampleRecord(const SampleRecord& r) {
145 return ProcessSampleRecord(r);
146 }
147
Yabin Cuib64a8632016-05-24 18:23:33 -0700148 protected:
Yabin Cui68b83832017-07-19 17:54:57 -0700149 virtual uint64_t GetPeriod(const SampleRecord& r) = 0;
150
Yabin Cuib64a8632016-05-24 18:23:33 -0700151 SampleEntry* CreateSample(const SampleRecord& r, bool in_kernel,
152 uint64_t* acc_info) override {
153 const ThreadEntry* thread =
154 thread_tree_->FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
155 const MapEntry* map =
156 thread_tree_->FindMap(thread, r.ip_data.ip, in_kernel);
Yabin Cui9970a232016-06-29 12:18:11 -0700157 uint64_t vaddr_in_file;
158 const Symbol* symbol =
159 thread_tree_->FindSymbol(map, r.ip_data.ip, &vaddr_in_file);
Yabin Cui68b83832017-07-19 17:54:57 -0700160 uint64_t period = GetPeriod(r);
161 *acc_info = period;
Yabin Cuib64a8632016-05-24 18:23:33 -0700162 return InsertSample(std::unique_ptr<SampleEntry>(
Yabin Cui68b83832017-07-19 17:54:57 -0700163 new SampleEntry(r.time_data.time, period, 0, 1, thread, map, symbol, vaddr_in_file)));
Yabin Cuib64a8632016-05-24 18:23:33 -0700164 }
165
166 SampleEntry* CreateBranchSample(const SampleRecord& r,
167 const BranchStackItemType& item) override {
168 const ThreadEntry* thread =
169 thread_tree_->FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
170 const MapEntry* from_map = thread_tree_->FindMap(thread, item.from);
Yabin Cui9970a232016-06-29 12:18:11 -0700171 uint64_t from_vaddr_in_file;
172 const Symbol* from_symbol =
173 thread_tree_->FindSymbol(from_map, item.from, &from_vaddr_in_file);
Yabin Cuib64a8632016-05-24 18:23:33 -0700174 const MapEntry* to_map = thread_tree_->FindMap(thread, item.to);
Yabin Cui9970a232016-06-29 12:18:11 -0700175 uint64_t to_vaddr_in_file;
176 const Symbol* to_symbol =
177 thread_tree_->FindSymbol(to_map, item.to, &to_vaddr_in_file);
Yabin Cuib64a8632016-05-24 18:23:33 -0700178 std::unique_ptr<SampleEntry> sample(
Yabin Cui9970a232016-06-29 12:18:11 -0700179 new SampleEntry(r.time_data.time, r.period_data.period, 0, 1, thread,
180 to_map, to_symbol, to_vaddr_in_file));
Yabin Cuib64a8632016-05-24 18:23:33 -0700181 sample->branch_from.map = from_map;
182 sample->branch_from.symbol = from_symbol;
Yabin Cui9970a232016-06-29 12:18:11 -0700183 sample->branch_from.vaddr_in_file = from_vaddr_in_file;
Yabin Cuib64a8632016-05-24 18:23:33 -0700184 sample->branch_from.flags = item.flags;
185 return InsertSample(std::move(sample));
186 }
187
188 SampleEntry* CreateCallChainSample(const SampleEntry* sample, uint64_t ip,
189 bool in_kernel,
190 const std::vector<SampleEntry*>& callchain,
191 const uint64_t& acc_info) override {
192 const ThreadEntry* thread = sample->thread;
193 const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel);
Yabin Cui98c75842017-04-28 13:43:08 -0700194 if (thread_tree_->IsUnknownDso(map->dso)) {
195 // The unwinders can give wrong ip addresses, which can't map to a valid dso. Skip them.
196 total_error_callchains_++;
197 return nullptr;
198 }
Yabin Cui9970a232016-06-29 12:18:11 -0700199 uint64_t vaddr_in_file;
200 const Symbol* symbol = thread_tree_->FindSymbol(map, ip, &vaddr_in_file);
201 std::unique_ptr<SampleEntry> callchain_sample(new SampleEntry(
202 sample->time, 0, acc_info, 0, thread, map, symbol, vaddr_in_file));
Yabin Cuib92bae82017-02-10 12:07:29 -0800203 callchain_sample->thread_comm = sample->thread_comm;
Yabin Cuib64a8632016-05-24 18:23:33 -0700204 return InsertCallChainSample(std::move(callchain_sample), callchain);
205 }
206
207 const ThreadEntry* GetThreadOfSample(SampleEntry* sample) override {
208 return sample->thread;
209 }
210
Yabin Cui9970a232016-06-29 12:18:11 -0700211 uint64_t GetPeriodForCallChain(const uint64_t& acc_info) override {
212 return acc_info;
Yabin Cuib64a8632016-05-24 18:23:33 -0700213 }
214
215 bool FilterSample(const SampleEntry* sample) override {
216 if (!pid_filter_.empty() &&
217 pid_filter_.find(sample->thread->pid) == pid_filter_.end()) {
218 return false;
219 }
220 if (!tid_filter_.empty() &&
221 tid_filter_.find(sample->thread->tid) == tid_filter_.end()) {
222 return false;
223 }
224 if (!comm_filter_.empty() &&
225 comm_filter_.find(sample->thread_comm) == comm_filter_.end()) {
226 return false;
227 }
228 if (!dso_filter_.empty() &&
229 dso_filter_.find(sample->map->dso->Path()) == dso_filter_.end()) {
230 return false;
231 }
Yabin Cuif79fbd12016-07-06 12:26:13 -0700232 if (!symbol_filter_.empty() &&
233 symbol_filter_.find(sample->symbol->DemangledName()) ==
234 symbol_filter_.end()) {
235 return false;
236 }
Yabin Cuib64a8632016-05-24 18:23:33 -0700237 return true;
238 }
239
240 void UpdateSummary(const SampleEntry* sample) override {
241 total_samples_ += sample->sample_count;
242 total_period_ += sample->period;
243 }
244
245 void MergeSample(SampleEntry* sample1, SampleEntry* sample2) override {
246 sample1->period += sample2->period;
247 sample1->accumulated_period += sample2->accumulated_period;
248 sample1->sample_count += sample2->sample_count;
249 }
250
251 private:
252 ThreadTree* thread_tree_;
253
254 std::unordered_set<int> pid_filter_;
255 std::unordered_set<int> tid_filter_;
256 std::unordered_set<std::string> comm_filter_;
257 std::unordered_set<std::string> dso_filter_;
Yabin Cuif79fbd12016-07-06 12:26:13 -0700258 std::unordered_set<std::string> symbol_filter_;
Yabin Cuib64a8632016-05-24 18:23:33 -0700259
260 uint64_t total_samples_;
261 uint64_t total_period_;
Yabin Cui98c75842017-04-28 13:43:08 -0700262 uint64_t total_error_callchains_;
Yabin Cuib64a8632016-05-24 18:23:33 -0700263};
264
Yabin Cui68b83832017-07-19 17:54:57 -0700265// Build sample tree based on event count in each sample.
266class EventCountSampleTreeBuilder : public ReportCmdSampleTreeBuilder {
267 public:
268 EventCountSampleTreeBuilder(const SampleComparator<SampleEntry>& sample_comparator,
269 ThreadTree* thread_tree)
270 : ReportCmdSampleTreeBuilder(sample_comparator, thread_tree) { }
271
272 protected:
273 uint64_t GetPeriod(const SampleRecord& r) override {
274 return r.period_data.period;
275 }
276};
277
278// Build sample tree based on the time difference between current sample and next sample.
279class TimestampSampleTreeBuilder : public ReportCmdSampleTreeBuilder {
280 public:
281 TimestampSampleTreeBuilder(const SampleComparator<SampleEntry>& sample_comparator,
282 ThreadTree* thread_tree)
283 : ReportCmdSampleTreeBuilder(sample_comparator, thread_tree) { }
284
285 void ReportCmdProcessSampleRecord(std::shared_ptr<SampleRecord>& r) override {
286 pid_t tid = static_cast<pid_t>(r->tid_data.tid);
287 auto it = next_sample_cache_.find(tid);
288 if (it == next_sample_cache_.end()) {
289 next_sample_cache_[tid] = r;
290 } else {
291 std::shared_ptr<SampleRecord> cur = it->second;
292 it->second = r;
293 ProcessSampleRecord(*cur);
294 }
295 }
296
297 protected:
298 uint64_t GetPeriod(const SampleRecord& r) override {
299 auto it = next_sample_cache_.find(r.tid_data.tid);
300 CHECK(it != next_sample_cache_.end());
301 // Normally the samples are sorted by time, but check here for safety.
302 if (it->second->time_data.time > r.time_data.time) {
303 return it->second->time_data.time - r.time_data.time;
304 }
305 return 1u;
306 }
307
308 private:
309 std::unordered_map<pid_t, std::shared_ptr<SampleRecord>> next_sample_cache_;
310};
311
Yabin Cuiada97db2017-02-23 15:54:11 -0800312struct SampleTreeBuilderOptions {
313 SampleComparator<SampleEntry> comparator;
314 ThreadTree* thread_tree;
315 std::unordered_set<std::string> comm_filter;
316 std::unordered_set<std::string> dso_filter;
317 std::unordered_set<std::string> symbol_filter;
318 std::unordered_set<int> pid_filter;
319 std::unordered_set<int> tid_filter;
320 bool use_branch_address;
321 bool accumulate_callchain;
322 bool build_callchain;
323 bool use_caller_as_callchain_root;
324 bool strict_unwind_arch_check;
Yabin Cui68b83832017-07-19 17:54:57 -0700325 bool trace_offcpu;
Yabin Cuiada97db2017-02-23 15:54:11 -0800326
327 std::unique_ptr<ReportCmdSampleTreeBuilder> CreateSampleTreeBuilder() {
Yabin Cui68b83832017-07-19 17:54:57 -0700328 std::unique_ptr<ReportCmdSampleTreeBuilder> builder;
329 if (trace_offcpu) {
330 builder.reset(new TimestampSampleTreeBuilder(comparator, thread_tree));
331 } else {
332 builder.reset(new EventCountSampleTreeBuilder(comparator, thread_tree));
333 }
Yabin Cuiada97db2017-02-23 15:54:11 -0800334 builder->SetFilters(pid_filter, tid_filter, comm_filter, dso_filter, symbol_filter);
335 builder->SetBranchSampleOption(use_branch_address);
336 builder->SetCallChainSampleOptions(accumulate_callchain, build_callchain,
337 use_caller_as_callchain_root, strict_unwind_arch_check);
338 return builder;
339 }
340};
341
Yabin Cuib64a8632016-05-24 18:23:33 -0700342using ReportCmdSampleTreeSorter = SampleTreeSorter<SampleEntry>;
343using ReportCmdSampleTreeDisplayer =
344 SampleTreeDisplayer<SampleEntry, SampleTree>;
Yabin Cui2672dea2015-05-21 12:17:23 -0700345
Yabin Cui9970a232016-06-29 12:18:11 -0700346using ReportCmdCallgraphDisplayer =
347 CallgraphDisplayer<SampleEntry, CallChainNode<SampleEntry>>;
348
349class ReportCmdCallgraphDisplayerWithVaddrInFile
350 : public ReportCmdCallgraphDisplayer {
351 protected:
352 std::string PrintSampleName(const SampleEntry* sample) override {
353 return android::base::StringPrintf("%s [+0x%" PRIx64 "]",
354 sample->symbol->DemangledName(),
355 sample->vaddr_in_file);
356 }
357};
358
Yabin Cui4f41df62016-06-01 17:29:06 -0700359struct EventAttrWithName {
360 perf_event_attr attr;
361 std::string name;
Yabin Cui4f41df62016-06-01 17:29:06 -0700362};
363
Yabin Cui2672dea2015-05-21 12:17:23 -0700364class ReportCommand : public Command {
365 public:
366 ReportCommand()
Yabin Cui8a530e32015-06-23 20:42:01 -0700367 : Command(
368 "report", "report sampling information in perf.data",
Yabin Cuib64a8632016-05-24 18:23:33 -0700369 // clang-format off
370"Usage: simpleperf report [options]\n"
Yabin Cuidcb2a3e2017-05-18 17:11:32 -0700371"The default options are: -i perf.data --sort comm,pid,tid,dso,symbol.\n"
Yabin Cuib64a8632016-05-24 18:23:33 -0700372"-b Use the branch-to addresses in sampled take branches instead of the\n"
373" instruction addresses. Only valid for perf.data recorded with -b/-j\n"
374" option.\n"
375"--children Print the overhead accumulated by appearing in the callchain.\n"
376"--comms comm1,comm2,... Report only for selected comms.\n"
377"--dsos dso1,dso2,... Report only for selected dsos.\n"
Yabin Cuidcb2a3e2017-05-18 17:11:32 -0700378"--full-callgraph Print full call graph. Used with -g option. By default,\n"
379" brief call graph is printed.\n"
Yabin Cuib64a8632016-05-24 18:23:33 -0700380"-g [callee|caller] Print call graph. If callee mode is used, the graph\n"
381" shows how functions are called from others. Otherwise,\n"
382" the graph shows how functions call others.\n"
Yabin Cui5e6ff6e2016-07-14 11:50:31 -0700383" Default is caller mode.\n"
Yabin Cuib64a8632016-05-24 18:23:33 -0700384"-i <file> Specify path of record file, default is perf.data.\n"
Yabin Cui18385c42016-12-09 14:51:04 -0800385"--kallsyms <file> Set the file to read kernel symbols.\n"
Yabin Cuic0565bb2016-09-29 15:59:33 -0700386"--max-stack <frames> Set max stack frames shown when printing call graph.\n"
Yabin Cuib64a8632016-05-24 18:23:33 -0700387"-n Print the sample count for each item.\n"
388"--no-demangle Don't demangle symbol names.\n"
Yabin Cui15475e62016-07-14 13:26:19 -0700389"--no-show-ip Don't show vaddr in file for unknown symbols.\n"
Yabin Cuib64a8632016-05-24 18:23:33 -0700390"-o report_file_name Set report file name, default is stdout.\n"
Yabin Cuic0565bb2016-09-29 15:59:33 -0700391"--percent-limit <percent> Set min percentage shown when printing call graph.\n"
Yabin Cuib64a8632016-05-24 18:23:33 -0700392"--pids pid1,pid2,... Report only for selected pids.\n"
Yabin Cuiafe99a52017-02-23 16:27:09 -0800393"--raw-period Report period count instead of period percentage.\n"
Yabin Cui9970a232016-06-29 12:18:11 -0700394"--sort key1,key2,... Select keys used to sort and print the report. The\n"
395" appearance order of keys decides the order of keys used\n"
396" to sort and print the report.\n"
397" Possible keys include:\n"
398" pid -- process id\n"
399" tid -- thread id\n"
400" comm -- thread name (can be changed during\n"
401" the lifetime of a thread)\n"
402" dso -- shared library\n"
403" symbol -- function name in the shared library\n"
404" vaddr_in_file -- virtual address in the shared\n"
405" library\n"
406" Keys can only be used with -b option:\n"
407" dso_from -- shared library branched from\n"
408" dso_to -- shared library branched to\n"
409" symbol_from -- name of function branched from\n"
410" symbol_to -- name of function branched to\n"
411" The default sort keys are:\n"
412" comm,pid,tid,dso,symbol\n"
Yabin Cui05ef2ea2016-07-11 13:50:01 -0700413"--symbols symbol1;symbol2;... Report only for selected symbols.\n"
Yabin Cuib64a8632016-05-24 18:23:33 -0700414"--symfs <dir> Look for files with symbols relative to this directory.\n"
415"--tids tid1,tid2,... Report only for selected tids.\n"
416"--vmlinux <file> Parse kernel symbols from <file>.\n"
417 // clang-format on
418 ),
Yabin Cui8a530e32015-06-23 20:42:01 -0700419 record_filename_("perf.data"),
Yabin Cui48460892016-03-18 12:30:31 -0700420 record_file_arch_(GetBuildArch()),
Yabin Cui36c662b2015-06-29 18:19:46 -0700421 use_branch_address_(false),
Yabin Cui4b6720d2016-03-31 14:39:19 -0700422 system_wide_collection_(false),
Yabin Cuiecb9a302015-07-01 10:00:52 -0700423 accumulate_callchain_(false),
Yabin Cuic42867e2015-08-04 17:33:47 -0700424 print_callgraph_(false),
Yabin Cuic0565bb2016-09-29 15:59:33 -0700425 callgraph_show_callee_(false),
426 callgraph_max_stack_(UINT32_MAX),
Yabin Cuiafe99a52017-02-23 16:27:09 -0800427 callgraph_percent_limit_(0),
Yabin Cui0c093f32017-04-19 11:48:44 -0700428 raw_period_(false),
Yabin Cui68b83832017-07-19 17:54:57 -0700429 brief_callgraph_(true),
430 trace_offcpu_(false),
431 sched_switch_attr_id_(0u) {}
Yabin Cui2672dea2015-05-21 12:17:23 -0700432
433 bool Run(const std::vector<std::string>& args);
434
435 private:
436 bool ParseOptions(const std::vector<std::string>& args);
Yabin Cui68b83832017-07-19 17:54:57 -0700437 bool ReadMetaInfoFromRecordFile();
Yabin Cui2672dea2015-05-21 12:17:23 -0700438 bool ReadEventAttrFromRecordFile();
Yabin Cui76769e52015-07-13 12:23:54 -0700439 bool ReadFeaturesFromRecordFile();
Yabin Cuib64a8632016-05-24 18:23:33 -0700440 bool ReadSampleTreeFromRecordFile();
441 bool ProcessRecord(std::unique_ptr<Record> record);
Yabin Cui68b83832017-07-19 17:54:57 -0700442 void ProcessSampleRecordInTraceOffCpuMode(std::unique_ptr<Record> record, size_t attr_id);
Yabin Cui4f41df62016-06-01 17:29:06 -0700443 bool ProcessTracingData(const std::vector<char>& data);
Yabin Cuib1a885b2016-02-14 19:18:02 -0800444 bool PrintReport();
Yabin Cuib64a8632016-05-24 18:23:33 -0700445 void PrintReportContext(FILE* fp);
Yabin Cui2672dea2015-05-21 12:17:23 -0700446
447 std::string record_filename_;
Yabin Cui48460892016-03-18 12:30:31 -0700448 ArchType record_file_arch_;
Yabin Cui2672dea2015-05-21 12:17:23 -0700449 std::unique_ptr<RecordFileReader> record_file_reader_;
Yabin Cui4f41df62016-06-01 17:29:06 -0700450 std::vector<EventAttrWithName> event_attrs_;
Yabin Cui60a0ea92015-07-22 20:30:43 -0700451 ThreadTree thread_tree_;
Yabin Cuiada97db2017-02-23 15:54:11 -0800452 // Create a SampleTreeBuilder and SampleTree for each event_attr.
453 std::vector<SampleTree> sample_tree_;
454 SampleTreeBuilderOptions sample_tree_builder_options_;
455 std::vector<std::unique_ptr<ReportCmdSampleTreeBuilder>> sample_tree_builder_;
456
Yabin Cuib64a8632016-05-24 18:23:33 -0700457 std::unique_ptr<ReportCmdSampleTreeSorter> sample_tree_sorter_;
458 std::unique_ptr<ReportCmdSampleTreeDisplayer> sample_tree_displayer_;
Yabin Cui8a530e32015-06-23 20:42:01 -0700459 bool use_branch_address_;
Yabin Cuid713f952015-06-23 18:50:36 -0700460 std::string record_cmdline_;
Yabin Cui4b6720d2016-03-31 14:39:19 -0700461 bool system_wide_collection_;
Yabin Cui36c662b2015-06-29 18:19:46 -0700462 bool accumulate_callchain_;
Yabin Cuiecb9a302015-07-01 10:00:52 -0700463 bool print_callgraph_;
Yabin Cuic42867e2015-08-04 17:33:47 -0700464 bool callgraph_show_callee_;
Yabin Cuic0565bb2016-09-29 15:59:33 -0700465 uint32_t callgraph_max_stack_;
466 double callgraph_percent_limit_;
Yabin Cuiafe99a52017-02-23 16:27:09 -0800467 bool raw_period_;
Yabin Cui0c093f32017-04-19 11:48:44 -0700468 bool brief_callgraph_;
Yabin Cui68b83832017-07-19 17:54:57 -0700469 bool trace_offcpu_;
470 size_t sched_switch_attr_id_;
Yabin Cuib1a885b2016-02-14 19:18:02 -0800471
472 std::string report_filename_;
Yabin Cui68b83832017-07-19 17:54:57 -0700473 std::unordered_map<std::string, std::string> meta_info_;
474 std::unique_ptr<ScopedEventTypes> scoped_event_types_;
Yabin Cui2672dea2015-05-21 12:17:23 -0700475};
476
477bool ReportCommand::Run(const std::vector<std::string>& args) {
478 // 1. Parse options.
479 if (!ParseOptions(args)) {
480 return false;
481 }
482
483 // 2. Read record file and build SampleTree.
484 record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
485 if (record_file_reader_ == nullptr) {
486 return false;
487 }
Yabin Cui68b83832017-07-19 17:54:57 -0700488 if (!ReadMetaInfoFromRecordFile()) {
489 return false;
490 }
Yabin Cui2672dea2015-05-21 12:17:23 -0700491 if (!ReadEventAttrFromRecordFile()) {
492 return false;
493 }
Yabin Cui638c5582015-07-01 16:16:57 -0700494 // Read features first to prepare build ids used when building SampleTree.
Yabin Cui76769e52015-07-13 12:23:54 -0700495 if (!ReadFeaturesFromRecordFile()) {
496 return false;
497 }
Yabin Cui48460892016-03-18 12:30:31 -0700498 ScopedCurrentArch scoped_arch(record_file_arch_);
Yabin Cuib64a8632016-05-24 18:23:33 -0700499 if (!ReadSampleTreeFromRecordFile()) {
500 return false;
501 }
Yabin Cui2672dea2015-05-21 12:17:23 -0700502
Yabin Cui8a530e32015-06-23 20:42:01 -0700503 // 3. Show collected information.
Yabin Cuib1a885b2016-02-14 19:18:02 -0800504 if (!PrintReport()) {
505 return false;
506 }
Yabin Cui2672dea2015-05-21 12:17:23 -0700507
508 return true;
509}
510
511bool ReportCommand::ParseOptions(const std::vector<std::string>& args) {
Yabin Cui638c5582015-07-01 16:16:57 -0700512 bool demangle = true;
Yabin Cui15475e62016-07-14 13:26:19 -0700513 bool show_ip_for_unknown_symbol = true;
Yabin Cui638c5582015-07-01 16:16:57 -0700514 std::string symfs_dir;
Yabin Cui39d3cae2015-07-13 16:23:13 -0700515 std::string vmlinux;
Yabin Cui8e277402015-06-11 14:02:10 -0700516 bool print_sample_count = false;
Yabin Cui8a530e32015-06-23 20:42:01 -0700517 std::vector<std::string> sort_keys = {"comm", "pid", "tid", "dso", "symbol"};
Yabin Cui38e573e2015-08-06 11:25:09 -0700518
Yabin Cui2672dea2015-05-21 12:17:23 -0700519 for (size_t i = 0; i < args.size(); ++i) {
Yabin Cui8a530e32015-06-23 20:42:01 -0700520 if (args[i] == "-b") {
521 use_branch_address_ = true;
Yabin Cui36c662b2015-06-29 18:19:46 -0700522 } else if (args[i] == "--children") {
523 accumulate_callchain_ = true;
Yabin Cui05ef2ea2016-07-11 13:50:01 -0700524 } else if (args[i] == "--comms" || args[i] == "--dsos") {
Yabin Cuib64a8632016-05-24 18:23:33 -0700525 std::unordered_set<std::string>& filter =
Yabin Cuiada97db2017-02-23 15:54:11 -0800526 (args[i] == "--comms" ? sample_tree_builder_options_.comm_filter
527 : sample_tree_builder_options_.dso_filter);
Yabin Cui38e573e2015-08-06 11:25:09 -0700528 if (!NextArgumentOrError(args, &i)) {
529 return false;
530 }
531 std::vector<std::string> strs = android::base::Split(args[i], ",");
Yabin Cui38e573e2015-08-06 11:25:09 -0700532 filter.insert(strs.begin(), strs.end());
Yabin Cuidcb2a3e2017-05-18 17:11:32 -0700533 } else if (args[i] == "--full-callgraph") {
534 brief_callgraph_ = false;
Yabin Cuiecb9a302015-07-01 10:00:52 -0700535 } else if (args[i] == "-g") {
536 print_callgraph_ = true;
537 accumulate_callchain_ = true;
Yabin Cuic42867e2015-08-04 17:33:47 -0700538 if (i + 1 < args.size() && args[i + 1][0] != '-') {
539 ++i;
540 if (args[i] == "callee") {
541 callgraph_show_callee_ = true;
542 } else if (args[i] == "caller") {
543 callgraph_show_callee_ = false;
544 } else {
545 LOG(ERROR) << "Unknown argument with -g option: " << args[i];
546 return false;
547 }
548 }
Yabin Cui8a530e32015-06-23 20:42:01 -0700549 } else if (args[i] == "-i") {
Yabin Cui2672dea2015-05-21 12:17:23 -0700550 if (!NextArgumentOrError(args, &i)) {
551 return false;
552 }
553 record_filename_ = args[i];
Yabin Cui8e277402015-06-11 14:02:10 -0700554
Yabin Cui18385c42016-12-09 14:51:04 -0800555 } else if (args[i] == "--kallsyms") {
556 if (!NextArgumentOrError(args, &i)) {
557 return false;
558 }
559 std::string kallsyms;
560 if (!android::base::ReadFileToString(args[i], &kallsyms)) {
561 LOG(ERROR) << "Can't read kernel symbols from " << args[i];
562 return false;
563 }
564 Dso::SetKallsyms(kallsyms);
Yabin Cuic0565bb2016-09-29 15:59:33 -0700565 } else if (args[i] == "--max-stack") {
566 if (!NextArgumentOrError(args, &i)) {
567 return false;
568 }
569 if (!android::base::ParseUint(args[i].c_str(), &callgraph_max_stack_)) {
570 LOG(ERROR) << "invalid arg for --max-stack: " << args[i];
571 return false;
572 }
Yabin Cui8e277402015-06-11 14:02:10 -0700573 } else if (args[i] == "-n") {
574 print_sample_count = true;
575
Yabin Cuib3783552015-06-11 11:15:42 -0700576 } else if (args[i] == "--no-demangle") {
Yabin Cui638c5582015-07-01 16:16:57 -0700577 demangle = false;
Yabin Cui15475e62016-07-14 13:26:19 -0700578 } else if (args[i] == "--no-show-ip") {
579 show_ip_for_unknown_symbol = false;
Yabin Cuib1a885b2016-02-14 19:18:02 -0800580 } else if (args[i] == "-o") {
581 if (!NextArgumentOrError(args, &i)) {
582 return false;
583 }
584 report_filename_ = args[i];
Yabin Cuic0565bb2016-09-29 15:59:33 -0700585 } else if (args[i] == "--percent-limit") {
586 if (!NextArgumentOrError(args, &i)) {
587 return false;
588 }
589 if (!android::base::ParseDouble(args[i].c_str(),
590 &callgraph_percent_limit_, 0.0)) {
591 LOG(ERROR) << "invalid arg for --percent-limit: " << args[i];
592 }
Yabin Cui38e573e2015-08-06 11:25:09 -0700593 } else if (args[i] == "--pids" || args[i] == "--tids") {
Yabin Cui861f6552016-08-08 14:42:25 -0700594 const std::string& option = args[i];
595 std::unordered_set<int>& filter =
Yabin Cuiada97db2017-02-23 15:54:11 -0800596 (option == "--pids" ? sample_tree_builder_options_.pid_filter
597 : sample_tree_builder_options_.tid_filter);
Yabin Cui38e573e2015-08-06 11:25:09 -0700598 if (!NextArgumentOrError(args, &i)) {
599 return false;
600 }
601 std::vector<std::string> strs = android::base::Split(args[i], ",");
Yabin Cui569f64a2016-02-05 17:32:08 -0800602 for (const auto& s : strs) {
Yabin Cui38e573e2015-08-06 11:25:09 -0700603 int id;
Yabin Cui569f64a2016-02-05 17:32:08 -0800604 if (!android::base::ParseInt(s.c_str(), &id, 0)) {
Yabin Cui861f6552016-08-08 14:42:25 -0700605 LOG(ERROR) << "invalid id in " << option << " option: " << s;
Yabin Cui38e573e2015-08-06 11:25:09 -0700606 return false;
607 }
Yabin Cui861f6552016-08-08 14:42:25 -0700608 filter.insert(id);
Yabin Cui38e573e2015-08-06 11:25:09 -0700609 }
Yabin Cuiafe99a52017-02-23 16:27:09 -0800610 } else if (args[i] == "--raw-period") {
611 raw_period_ = true;
Yabin Cui2672dea2015-05-21 12:17:23 -0700612 } else if (args[i] == "--sort") {
613 if (!NextArgumentOrError(args, &i)) {
614 return false;
615 }
Yabin Cui8a530e32015-06-23 20:42:01 -0700616 sort_keys = android::base::Split(args[i], ",");
Yabin Cui05ef2ea2016-07-11 13:50:01 -0700617 } else if (args[i] == "--symbols") {
618 if (!NextArgumentOrError(args, &i)) {
619 return false;
620 }
621 std::vector<std::string> strs = android::base::Split(args[i], ";");
Yabin Cuiada97db2017-02-23 15:54:11 -0800622 sample_tree_builder_options_.symbol_filter.insert(strs.begin(), strs.end());
Yabin Cuib3783552015-06-11 11:15:42 -0700623 } else if (args[i] == "--symfs") {
624 if (!NextArgumentOrError(args, &i)) {
625 return false;
626 }
Yabin Cui638c5582015-07-01 16:16:57 -0700627 symfs_dir = args[i];
Yabin Cui38e573e2015-08-06 11:25:09 -0700628
Yabin Cui39d3cae2015-07-13 16:23:13 -0700629 } else if (args[i] == "--vmlinux") {
630 if (!NextArgumentOrError(args, &i)) {
631 return false;
632 }
633 vmlinux = args[i];
Yabin Cui2672dea2015-05-21 12:17:23 -0700634 } else {
635 ReportUnknownOption(args, i);
636 return false;
637 }
638 }
639
Yabin Cuic8485602015-08-20 15:04:39 -0700640 Dso::SetDemangle(demangle);
641 if (!Dso::SetSymFsDir(symfs_dir)) {
Yabin Cui638c5582015-07-01 16:16:57 -0700642 return false;
643 }
Yabin Cui39d3cae2015-07-13 16:23:13 -0700644 if (!vmlinux.empty()) {
Yabin Cuic8485602015-08-20 15:04:39 -0700645 Dso::SetVmlinux(vmlinux);
Yabin Cui39d3cae2015-07-13 16:23:13 -0700646 }
Yabin Cui638c5582015-07-01 16:16:57 -0700647
Yabin Cui15475e62016-07-14 13:26:19 -0700648 if (show_ip_for_unknown_symbol) {
649 thread_tree_.ShowIpForUnknownSymbol();
650 }
651
Yabin Cuib64a8632016-05-24 18:23:33 -0700652 SampleDisplayer<SampleEntry, SampleTree> displayer;
653 SampleComparator<SampleEntry> comparator;
654
655 if (accumulate_callchain_) {
Yabin Cuiafe99a52017-02-23 16:27:09 -0800656 if (raw_period_) {
657 displayer.AddDisplayFunction("Children", DisplayAccumulatedPeriod);
658 displayer.AddDisplayFunction("Self", DisplaySelfPeriod);
659 } else {
660 displayer.AddDisplayFunction("Children", DisplayAccumulatedOverhead);
661 displayer.AddDisplayFunction("Self", DisplaySelfOverhead);
662 }
Yabin Cui36c662b2015-06-29 18:19:46 -0700663 } else {
Yabin Cuiafe99a52017-02-23 16:27:09 -0800664 if (raw_period_) {
665 displayer.AddDisplayFunction("Overhead", DisplaySelfPeriod);
666 } else {
667 displayer.AddDisplayFunction("Overhead", DisplaySelfOverhead);
668 }
Yabin Cuib64a8632016-05-24 18:23:33 -0700669 }
Yabin Cui8e277402015-06-11 14:02:10 -0700670 if (print_sample_count) {
Yabin Cuib64a8632016-05-24 18:23:33 -0700671 displayer.AddDisplayFunction("Sample", DisplaySampleCount);
Yabin Cui8a530e32015-06-23 20:42:01 -0700672 }
Yabin Cuib64a8632016-05-24 18:23:33 -0700673
Yabin Cui8a530e32015-06-23 20:42:01 -0700674 for (auto& key : sort_keys) {
Yabin Cuib64a8632016-05-24 18:23:33 -0700675 if (!use_branch_address_ &&
676 branch_sort_keys.find(key) != branch_sort_keys.end()) {
Yabin Cui8a530e32015-06-23 20:42:01 -0700677 LOG(ERROR) << "sort key '" << key << "' can only be used with -b option.";
678 return false;
679 }
Yabin Cui36c662b2015-06-29 18:19:46 -0700680 if (key == "pid") {
Yabin Cuib64a8632016-05-24 18:23:33 -0700681 comparator.AddCompareFunction(ComparePid);
682 displayer.AddDisplayFunction("Pid", DisplayPid);
Yabin Cui36c662b2015-06-29 18:19:46 -0700683 } else if (key == "tid") {
Yabin Cuib64a8632016-05-24 18:23:33 -0700684 comparator.AddCompareFunction(CompareTid);
685 displayer.AddDisplayFunction("Tid", DisplayTid);
Yabin Cui36c662b2015-06-29 18:19:46 -0700686 } else if (key == "comm") {
Yabin Cuib64a8632016-05-24 18:23:33 -0700687 comparator.AddCompareFunction(CompareComm);
688 displayer.AddDisplayFunction("Command", DisplayComm);
Yabin Cui36c662b2015-06-29 18:19:46 -0700689 } else if (key == "dso") {
Yabin Cuib64a8632016-05-24 18:23:33 -0700690 comparator.AddCompareFunction(CompareDso);
691 displayer.AddDisplayFunction("Shared Object", DisplayDso);
Yabin Cui36c662b2015-06-29 18:19:46 -0700692 } else if (key == "symbol") {
Yabin Cuib64a8632016-05-24 18:23:33 -0700693 comparator.AddCompareFunction(CompareSymbol);
694 displayer.AddDisplayFunction("Symbol", DisplaySymbol);
Yabin Cui9970a232016-06-29 12:18:11 -0700695 } else if (key == "vaddr_in_file") {
696 comparator.AddCompareFunction(CompareVaddrInFile);
697 displayer.AddDisplayFunction("VaddrInFile", DisplayVaddrInFile);
Yabin Cui36c662b2015-06-29 18:19:46 -0700698 } else if (key == "dso_from") {
Yabin Cuib64a8632016-05-24 18:23:33 -0700699 comparator.AddCompareFunction(CompareDsoFrom);
700 displayer.AddDisplayFunction("Source Shared Object", DisplayDsoFrom);
Yabin Cui36c662b2015-06-29 18:19:46 -0700701 } else if (key == "dso_to") {
Yabin Cuib64a8632016-05-24 18:23:33 -0700702 comparator.AddCompareFunction(CompareDso);
703 displayer.AddDisplayFunction("Target Shared Object", DisplayDso);
Yabin Cui36c662b2015-06-29 18:19:46 -0700704 } else if (key == "symbol_from") {
Yabin Cuib64a8632016-05-24 18:23:33 -0700705 comparator.AddCompareFunction(CompareSymbolFrom);
706 displayer.AddDisplayFunction("Source Symbol", DisplaySymbolFrom);
Yabin Cui36c662b2015-06-29 18:19:46 -0700707 } else if (key == "symbol_to") {
Yabin Cuib64a8632016-05-24 18:23:33 -0700708 comparator.AddCompareFunction(CompareSymbol);
709 displayer.AddDisplayFunction("Target Symbol", DisplaySymbol);
Yabin Cui8a530e32015-06-23 20:42:01 -0700710 } else {
711 LOG(ERROR) << "Unknown sort key: " << key;
712 return false;
713 }
Yabin Cui8e277402015-06-11 14:02:10 -0700714 }
Yabin Cui9970a232016-06-29 12:18:11 -0700715 if (print_callgraph_) {
716 bool has_symbol_key = false;
717 bool has_vaddr_in_file_key = false;
718 for (const auto& key : sort_keys) {
719 if (key == "symbol") {
720 has_symbol_key = true;
721 } else if (key == "vaddr_in_file") {
722 has_vaddr_in_file_key = true;
723 }
724 }
725 if (has_symbol_key) {
726 if (has_vaddr_in_file_key) {
727 displayer.AddExclusiveDisplayFunction(
728 ReportCmdCallgraphDisplayerWithVaddrInFile());
729 } else {
Yabin Cuic0565bb2016-09-29 15:59:33 -0700730 displayer.AddExclusiveDisplayFunction(ReportCmdCallgraphDisplayer(
Yabin Cui0c093f32017-04-19 11:48:44 -0700731 callgraph_max_stack_, callgraph_percent_limit_, brief_callgraph_));
Yabin Cui9970a232016-06-29 12:18:11 -0700732 }
733 }
734 }
Yabin Cuib64a8632016-05-24 18:23:33 -0700735
Yabin Cuiada97db2017-02-23 15:54:11 -0800736 sample_tree_builder_options_.comparator = comparator;
737 sample_tree_builder_options_.thread_tree = &thread_tree_;
Yabin Cuib64a8632016-05-24 18:23:33 -0700738
739 SampleComparator<SampleEntry> sort_comparator;
740 sort_comparator.AddCompareFunction(CompareTotalPeriod);
Yabin Cui0c093f32017-04-19 11:48:44 -0700741 if (print_callgraph_) {
742 sort_comparator.AddCompareFunction(CompareCallGraphDuplicated);
743 }
744 sort_comparator.AddCompareFunction(ComparePeriod);
Yabin Cuib64a8632016-05-24 18:23:33 -0700745 sort_comparator.AddComparator(comparator);
746 sample_tree_sorter_.reset(new ReportCmdSampleTreeSorter(sort_comparator));
747 sample_tree_displayer_.reset(new ReportCmdSampleTreeDisplayer(displayer));
Yabin Cui2672dea2015-05-21 12:17:23 -0700748 return true;
749}
750
Yabin Cui68b83832017-07-19 17:54:57 -0700751bool ReportCommand::ReadMetaInfoFromRecordFile() {
752 if (record_file_reader_->HasFeature(PerfFileFormat::FEAT_META_INFO)) {
753 if (!record_file_reader_->ReadMetaInfoFeature(&meta_info_)) {
754 return false;
755 }
756 auto it = meta_info_.find("system_wide_collection");
757 if (it != meta_info_.end()) {
758 system_wide_collection_ = it->second == "true";
759 }
760 it = meta_info_.find("trace_offcpu");
761 if (it != meta_info_.end()) {
762 trace_offcpu_ = it->second == "true";
763 }
764 it = meta_info_.find("event_type_info");
765 if (it != meta_info_.end()) {
766 scoped_event_types_.reset(new ScopedEventTypes(it->second));
767 }
768 }
769 return true;
770}
771
Yabin Cui2672dea2015-05-21 12:17:23 -0700772bool ReportCommand::ReadEventAttrFromRecordFile() {
Yabin Cui003b2452016-09-29 15:32:45 -0700773 std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
Yabin Cui4f41df62016-06-01 17:29:06 -0700774 for (const auto& attr_with_id : attrs) {
775 EventAttrWithName attr;
776 attr.attr = *attr_with_id.attr;
Yabin Cuic10a9dc2016-06-15 12:10:33 -0700777 attr.name = GetEventNameByAttr(attr.attr);
Yabin Cui4f41df62016-06-01 17:29:06 -0700778 event_attrs_.push_back(attr);
Yabin Cui2672dea2015-05-21 12:17:23 -0700779 }
Yabin Cui2d6efe42016-04-01 20:22:35 -0700780 if (use_branch_address_) {
781 bool has_branch_stack = true;
782 for (const auto& attr : event_attrs_) {
Yabin Cui4f41df62016-06-01 17:29:06 -0700783 if ((attr.attr.sample_type & PERF_SAMPLE_BRANCH_STACK) == 0) {
Yabin Cui2d6efe42016-04-01 20:22:35 -0700784 has_branch_stack = false;
785 break;
786 }
787 }
788 if (!has_branch_stack) {
Yabin Cuib64a8632016-05-24 18:23:33 -0700789 LOG(ERROR) << record_filename_
790 << " is not recorded with branch stack sampling option.";
Yabin Cui2d6efe42016-04-01 20:22:35 -0700791 return false;
792 }
Yabin Cui8a530e32015-06-23 20:42:01 -0700793 }
Yabin Cui68b83832017-07-19 17:54:57 -0700794 if (trace_offcpu_) {
795 size_t i;
796 for (i = 0; i < event_attrs_.size(); ++i) {
Yabin Cui68b83832017-07-19 17:54:57 -0700797 if (event_attrs_[i].name == "sched:sched_switch") {
798 break;
799 }
800 }
801 CHECK_NE(i, event_attrs_.size());
802 sched_switch_attr_id_ = i;
803 }
Yabin Cui2672dea2015-05-21 12:17:23 -0700804 return true;
805}
806
Yabin Cui76769e52015-07-13 12:23:54 -0700807bool ReportCommand::ReadFeaturesFromRecordFile() {
Yabin Cui010b2322016-11-04 16:49:35 -0700808 record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_);
Yabin Cuic5b4a312016-10-24 13:38:38 -0700809
Yabin Cuib64a8632016-05-24 18:23:33 -0700810 std::string arch =
811 record_file_reader_->ReadFeatureString(PerfFileFormat::FEAT_ARCH);
Yabin Cui76769e52015-07-13 12:23:54 -0700812 if (!arch.empty()) {
Yabin Cui48460892016-03-18 12:30:31 -0700813 record_file_arch_ = GetArchType(arch);
814 if (record_file_arch_ == ARCH_UNSUPPORTED) {
Yabin Cui76769e52015-07-13 12:23:54 -0700815 return false;
816 }
817 }
818
Yabin Cuid713f952015-06-23 18:50:36 -0700819 std::vector<std::string> cmdline = record_file_reader_->ReadCmdlineFeature();
820 if (!cmdline.empty()) {
821 record_cmdline_ = android::base::Join(cmdline, ' ');
Yabin Cui68b83832017-07-19 17:54:57 -0700822 if (meta_info_.find("system_wide_collection") == meta_info_.end()) {
823 // TODO: the code to detect system wide collection option is fragile, remove
824 // it once we can do cross unwinding.
825 for (size_t i = 0; i < cmdline.size(); i++) {
826 std::string& s = cmdline[i];
827 if (s == "-a") {
828 system_wide_collection_ = true;
829 break;
830 } else if (s == "--call-graph" || s == "--cpu" || s == "-e" ||
831 s == "-f" || s == "-F" || s == "-j" || s == "-m" ||
832 s == "-o" || s == "-p" || s == "-t") {
833 i++;
834 } else if (!s.empty() && s[0] != '-') {
835 break;
836 }
Yabin Cui4b6720d2016-03-31 14:39:19 -0700837 }
838 }
Yabin Cuid713f952015-06-23 18:50:36 -0700839 }
Yabin Cui4f41df62016-06-01 17:29:06 -0700840 if (record_file_reader_->HasFeature(PerfFileFormat::FEAT_TRACING_DATA)) {
841 std::vector<char> tracing_data;
842 if (!record_file_reader_->ReadFeatureSection(
843 PerfFileFormat::FEAT_TRACING_DATA, &tracing_data)) {
844 return false;
845 }
846 if (!ProcessTracingData(tracing_data)) {
847 return false;
848 }
849 }
Yabin Cui76769e52015-07-13 12:23:54 -0700850 return true;
Yabin Cuid713f952015-06-23 18:50:36 -0700851}
852
Yabin Cuib64a8632016-05-24 18:23:33 -0700853bool ReportCommand::ReadSampleTreeFromRecordFile() {
Yabin Cuiada97db2017-02-23 15:54:11 -0800854 sample_tree_builder_options_.use_branch_address = use_branch_address_;
Yabin Cuib64a8632016-05-24 18:23:33 -0700855 // Normally do strict arch check when unwinding stack. But allow unwinding
856 // 32-bit processes on 64-bit devices for system wide profiling.
Yabin Cuiada97db2017-02-23 15:54:11 -0800857 sample_tree_builder_options_.strict_unwind_arch_check = !system_wide_collection_;
858 sample_tree_builder_options_.accumulate_callchain = accumulate_callchain_;
859 sample_tree_builder_options_.build_callchain = print_callgraph_;
860 sample_tree_builder_options_.use_caller_as_callchain_root = !callgraph_show_callee_;
Yabin Cui68b83832017-07-19 17:54:57 -0700861 sample_tree_builder_options_.trace_offcpu = trace_offcpu_;
Yabin Cuiada97db2017-02-23 15:54:11 -0800862
863 for (size_t i = 0; i < event_attrs_.size(); ++i) {
864 sample_tree_builder_.push_back(sample_tree_builder_options_.CreateSampleTreeBuilder());
865 }
866
Yabin Cuib64a8632016-05-24 18:23:33 -0700867 if (!record_file_reader_->ReadDataSection(
868 [this](std::unique_ptr<Record> record) {
869 return ProcessRecord(std::move(record));
870 })) {
871 return false;
Yabin Cui2672dea2015-05-21 12:17:23 -0700872 }
Yabin Cuiada97db2017-02-23 15:54:11 -0800873 for (size_t i = 0; i < sample_tree_builder_.size(); ++i) {
874 sample_tree_.push_back(sample_tree_builder_[i]->GetSampleTree());
875 sample_tree_sorter_->Sort(sample_tree_.back().samples, print_callgraph_);
876 }
Yabin Cuib64a8632016-05-24 18:23:33 -0700877 return true;
878}
879
880bool ReportCommand::ProcessRecord(std::unique_ptr<Record> record) {
Yabin Cui767dd172016-06-02 21:02:43 -0700881 thread_tree_.Update(*record);
Yabin Cuib4212972016-05-25 14:08:05 -0700882 if (record->type() == PERF_RECORD_SAMPLE) {
Yabin Cuiada97db2017-02-23 15:54:11 -0800883 size_t attr_id = record_file_reader_->GetAttrIndexOfRecord(record.get());
Yabin Cui68b83832017-07-19 17:54:57 -0700884 if (!trace_offcpu_) {
885 sample_tree_builder_[attr_id]->ReportCmdProcessSampleRecord(
886 *static_cast<SampleRecord*>(record.get()));
887 } else {
888 ProcessSampleRecordInTraceOffCpuMode(std::move(record), attr_id);
889 }
Yabin Cui4f41df62016-06-01 17:29:06 -0700890 } else if (record->type() == PERF_RECORD_TRACING_DATA) {
891 const auto& r = *static_cast<TracingDataRecord*>(record.get());
Yabin Cui190a8482016-08-04 10:22:17 -0700892 if (!ProcessTracingData(std::vector<char>(r.data, r.data + r.data_size))) {
Yabin Cui4f41df62016-06-01 17:29:06 -0700893 return false;
894 }
895 }
896 return true;
897}
898
Yabin Cui68b83832017-07-19 17:54:57 -0700899
900void ReportCommand::ProcessSampleRecordInTraceOffCpuMode(std::unique_ptr<Record> record,
901 size_t attr_id) {
902 std::shared_ptr<SampleRecord> r(static_cast<SampleRecord*>(record.release()));
903 if (attr_id == sched_switch_attr_id_) {
904 // If this sample belongs to sched_switch event, we should broadcast the offcpu info
905 // to other event types.
906 for (size_t i = 0; i < event_attrs_.size(); ++i) {
907 if (i == sched_switch_attr_id_) {
908 continue;
909 }
910 sample_tree_builder_[i]->ReportCmdProcessSampleRecord(r);
911 }
912 } else {
913 sample_tree_builder_[attr_id]->ReportCmdProcessSampleRecord(r);
914 }
915}
916
Yabin Cui4f41df62016-06-01 17:29:06 -0700917bool ReportCommand::ProcessTracingData(const std::vector<char>& data) {
918 Tracing tracing(data);
919 for (auto& attr : event_attrs_) {
920 if (attr.attr.type == PERF_TYPE_TRACEPOINT) {
921 uint64_t trace_event_id = attr.attr.config;
922 attr.name = tracing.GetTracingEventNameHavingId(trace_event_id);
923 }
Yabin Cuib64a8632016-05-24 18:23:33 -0700924 }
925 return true;
Yabin Cui2672dea2015-05-21 12:17:23 -0700926}
927
Yabin Cuib1a885b2016-02-14 19:18:02 -0800928bool ReportCommand::PrintReport() {
929 std::unique_ptr<FILE, decltype(&fclose)> file_handler(nullptr, fclose);
Yabin Cuib64a8632016-05-24 18:23:33 -0700930 FILE* report_fp = stdout;
931 if (!report_filename_.empty()) {
932 report_fp = fopen(report_filename_.c_str(), "w");
933 if (report_fp == nullptr) {
Yabin Cuib1a885b2016-02-14 19:18:02 -0800934 PLOG(ERROR) << "failed to open file " << report_filename_;
935 return false;
936 }
Yabin Cuib64a8632016-05-24 18:23:33 -0700937 file_handler.reset(report_fp);
Yabin Cuib1a885b2016-02-14 19:18:02 -0800938 }
Yabin Cuib64a8632016-05-24 18:23:33 -0700939 PrintReportContext(report_fp);
Yabin Cuiada97db2017-02-23 15:54:11 -0800940 for (size_t i = 0; i < event_attrs_.size(); ++i) {
Yabin Cui68b83832017-07-19 17:54:57 -0700941 if (trace_offcpu_ && i == sched_switch_attr_id_) {
942 continue;
943 }
Yabin Cuiada97db2017-02-23 15:54:11 -0800944 if (i != 0) {
945 fprintf(report_fp, "\n");
946 }
947 EventAttrWithName& attr = event_attrs_[i];
948 SampleTree& sample_tree = sample_tree_[i];
949 fprintf(report_fp, "Event: %s (type %u, config %llu)\n", attr.name.c_str(),
950 attr.attr.type, attr.attr.config);
951 fprintf(report_fp, "Samples: %" PRIu64 "\n", sample_tree.total_samples);
Yabin Cui98c75842017-04-28 13:43:08 -0700952 if (sample_tree.total_error_callchains != 0) {
953 fprintf(report_fp, "Error Callchains: %" PRIu64 ", %f%%\n",
954 sample_tree.total_error_callchains,
955 sample_tree.total_error_callchains * 100.0 / sample_tree.total_samples);
956 }
Yabin Cui68b83832017-07-19 17:54:57 -0700957 const char* period_prefix = trace_offcpu_ ? "Time in ns" : "Event count";
958 fprintf(report_fp, "%s: %" PRIu64 "\n\n", period_prefix, sample_tree.total_period);
Yabin Cuiada97db2017-02-23 15:54:11 -0800959 sample_tree_displayer_->DisplaySamples(report_fp, sample_tree.samples, &sample_tree);
960 }
Yabin Cuib64a8632016-05-24 18:23:33 -0700961 fflush(report_fp);
962 if (ferror(report_fp) != 0) {
Yabin Cuib1a885b2016-02-14 19:18:02 -0800963 PLOG(ERROR) << "print report failed";
964 return false;
965 }
966 return true;
Yabin Cui2672dea2015-05-21 12:17:23 -0700967}
968
Yabin Cuib64a8632016-05-24 18:23:33 -0700969void ReportCommand::PrintReportContext(FILE* report_fp) {
Yabin Cuid713f952015-06-23 18:50:36 -0700970 if (!record_cmdline_.empty()) {
Yabin Cuib64a8632016-05-24 18:23:33 -0700971 fprintf(report_fp, "Cmdline: %s\n", record_cmdline_.c_str());
Yabin Cuid713f952015-06-23 18:50:36 -0700972 }
Yabin Cuib4212972016-05-25 14:08:05 -0700973 fprintf(report_fp, "Arch: %s\n", GetArchString(record_file_arch_).c_str());
Yabin Cui2672dea2015-05-21 12:17:23 -0700974}
975
Yabin Cuib64a8632016-05-24 18:23:33 -0700976} // namespace
Yabin Cuiecb9a302015-07-01 10:00:52 -0700977
Yabin Cuiff7465c2016-02-25 11:02:30 -0800978void RegisterReportCommand() {
Yabin Cuib64a8632016-05-24 18:23:33 -0700979 RegisterCommand("report",
980 [] { return std::unique_ptr<Command>(new ReportCommand()); });
Yabin Cui2672dea2015-05-21 12:17:23 -0700981}