1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker */
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Worker #include <inttypes.h>
18*288bf522SAndroid Build Coastguard Worker #include <algorithm>
19*288bf522SAndroid Build Coastguard Worker #include <functional>
20*288bf522SAndroid Build Coastguard Worker #include <map>
21*288bf522SAndroid Build Coastguard Worker #include <set>
22*288bf522SAndroid Build Coastguard Worker #include <string>
23*288bf522SAndroid Build Coastguard Worker #include <unordered_map>
24*288bf522SAndroid Build Coastguard Worker #include <unordered_set>
25*288bf522SAndroid Build Coastguard Worker #include <vector>
26*288bf522SAndroid Build Coastguard Worker
27*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
28*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
29*288bf522SAndroid Build Coastguard Worker #include <android-base/parseint.h>
30*288bf522SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
31*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
32*288bf522SAndroid Build Coastguard Worker
33*288bf522SAndroid Build Coastguard Worker #include "RecordFilter.h"
34*288bf522SAndroid Build Coastguard Worker #include "command.h"
35*288bf522SAndroid Build Coastguard Worker #include "event_attr.h"
36*288bf522SAndroid Build Coastguard Worker #include "event_type.h"
37*288bf522SAndroid Build Coastguard Worker #include "perf_regs.h"
38*288bf522SAndroid Build Coastguard Worker #include "record.h"
39*288bf522SAndroid Build Coastguard Worker #include "record_file.h"
40*288bf522SAndroid Build Coastguard Worker #include "sample_tree.h"
41*288bf522SAndroid Build Coastguard Worker #include "thread_tree.h"
42*288bf522SAndroid Build Coastguard Worker #include "tracing.h"
43*288bf522SAndroid Build Coastguard Worker #include "utils.h"
44*288bf522SAndroid Build Coastguard Worker
45*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
46*288bf522SAndroid Build Coastguard Worker namespace {
47*288bf522SAndroid Build Coastguard Worker
48*288bf522SAndroid Build Coastguard Worker using android::base::Split;
49*288bf522SAndroid Build Coastguard Worker
50*288bf522SAndroid Build Coastguard Worker static std::set<std::string> branch_sort_keys = {
51*288bf522SAndroid Build Coastguard Worker "dso_from",
52*288bf522SAndroid Build Coastguard Worker "dso_to",
53*288bf522SAndroid Build Coastguard Worker "symbol_from",
54*288bf522SAndroid Build Coastguard Worker "symbol_to",
55*288bf522SAndroid Build Coastguard Worker };
56*288bf522SAndroid Build Coastguard Worker struct BranchFromEntry {
57*288bf522SAndroid Build Coastguard Worker const MapEntry* map;
58*288bf522SAndroid Build Coastguard Worker const Symbol* symbol;
59*288bf522SAndroid Build Coastguard Worker uint64_t vaddr_in_file;
60*288bf522SAndroid Build Coastguard Worker uint64_t flags;
61*288bf522SAndroid Build Coastguard Worker
BranchFromEntrysimpleperf::__anondeabb9150111::BranchFromEntry62*288bf522SAndroid Build Coastguard Worker BranchFromEntry() : map(nullptr), symbol(nullptr), vaddr_in_file(0), flags(0) {}
63*288bf522SAndroid Build Coastguard Worker };
64*288bf522SAndroid Build Coastguard Worker
65*288bf522SAndroid Build Coastguard Worker struct SampleEntry {
66*288bf522SAndroid Build Coastguard Worker uint64_t time;
67*288bf522SAndroid Build Coastguard Worker uint64_t period;
68*288bf522SAndroid Build Coastguard Worker // accumuated when appearing in other sample's callchain
69*288bf522SAndroid Build Coastguard Worker uint64_t accumulated_period;
70*288bf522SAndroid Build Coastguard Worker uint64_t sample_count;
71*288bf522SAndroid Build Coastguard Worker int cpu;
72*288bf522SAndroid Build Coastguard Worker pid_t pid;
73*288bf522SAndroid Build Coastguard Worker pid_t tid;
74*288bf522SAndroid Build Coastguard Worker const char* thread_comm;
75*288bf522SAndroid Build Coastguard Worker const MapEntry* map;
76*288bf522SAndroid Build Coastguard Worker const Symbol* symbol;
77*288bf522SAndroid Build Coastguard Worker uint64_t vaddr_in_file;
78*288bf522SAndroid Build Coastguard Worker BranchFromEntry branch_from;
79*288bf522SAndroid Build Coastguard Worker // a callchain tree representing all callchains in the sample
80*288bf522SAndroid Build Coastguard Worker CallChainRoot<SampleEntry> callchain;
81*288bf522SAndroid Build Coastguard Worker // event counts for the sample
82*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> counts;
83*288bf522SAndroid Build Coastguard Worker // accumulated event counts for the sample
84*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> acc_counts;
85*288bf522SAndroid Build Coastguard Worker
SampleEntrysimpleperf::__anondeabb9150111::SampleEntry86*288bf522SAndroid Build Coastguard Worker SampleEntry(uint64_t time, uint64_t period, uint64_t accumulated_period, uint64_t sample_count,
87*288bf522SAndroid Build Coastguard Worker int cpu, const ThreadEntry* thread, const MapEntry* map, const Symbol* symbol,
88*288bf522SAndroid Build Coastguard Worker uint64_t vaddr_in_file, const std::vector<uint64_t>& counts,
89*288bf522SAndroid Build Coastguard Worker const std::vector<uint64_t>& acc_counts)
90*288bf522SAndroid Build Coastguard Worker : time(time),
91*288bf522SAndroid Build Coastguard Worker period(period),
92*288bf522SAndroid Build Coastguard Worker accumulated_period(accumulated_period),
93*288bf522SAndroid Build Coastguard Worker sample_count(sample_count),
94*288bf522SAndroid Build Coastguard Worker cpu(cpu),
95*288bf522SAndroid Build Coastguard Worker pid(thread->pid),
96*288bf522SAndroid Build Coastguard Worker tid(thread->tid),
97*288bf522SAndroid Build Coastguard Worker thread_comm(thread->comm),
98*288bf522SAndroid Build Coastguard Worker map(map),
99*288bf522SAndroid Build Coastguard Worker symbol(symbol),
100*288bf522SAndroid Build Coastguard Worker vaddr_in_file(vaddr_in_file),
101*288bf522SAndroid Build Coastguard Worker counts(counts),
102*288bf522SAndroid Build Coastguard Worker acc_counts(acc_counts) {}
103*288bf522SAndroid Build Coastguard Worker
104*288bf522SAndroid Build Coastguard Worker // The data member 'callchain' can only move, not copy.
105*288bf522SAndroid Build Coastguard Worker SampleEntry(SampleEntry&&) = default;
106*288bf522SAndroid Build Coastguard Worker SampleEntry(SampleEntry&) = delete;
107*288bf522SAndroid Build Coastguard Worker
GetPeriodsimpleperf::__anondeabb9150111::SampleEntry108*288bf522SAndroid Build Coastguard Worker uint64_t GetPeriod() const { return period; }
109*288bf522SAndroid Build Coastguard Worker };
110*288bf522SAndroid Build Coastguard Worker
111*288bf522SAndroid Build Coastguard Worker struct SampleTree {
112*288bf522SAndroid Build Coastguard Worker std::vector<SampleEntry*> samples;
113*288bf522SAndroid Build Coastguard Worker uint64_t total_samples;
114*288bf522SAndroid Build Coastguard Worker uint64_t total_period;
115*288bf522SAndroid Build Coastguard Worker uint64_t total_error_callchains;
116*288bf522SAndroid Build Coastguard Worker std::string event_name;
117*288bf522SAndroid Build Coastguard Worker };
118*288bf522SAndroid Build Coastguard Worker
119*288bf522SAndroid Build Coastguard Worker BUILD_COMPARE_VALUE_FUNCTION(CompareVaddrInFile, vaddr_in_file);
120*288bf522SAndroid Build Coastguard Worker BUILD_DISPLAY_HEX64_FUNCTION(DisplayVaddrInFile, vaddr_in_file);
121*288bf522SAndroid Build Coastguard Worker
DisplayEventName(const SampleEntry *,const SampleTree * info)122*288bf522SAndroid Build Coastguard Worker static std::string DisplayEventName(const SampleEntry*, const SampleTree* info) {
123*288bf522SAndroid Build Coastguard Worker return info->event_name;
124*288bf522SAndroid Build Coastguard Worker }
125*288bf522SAndroid Build Coastguard Worker
126*288bf522SAndroid Build Coastguard Worker struct AccInfo {
127*288bf522SAndroid Build Coastguard Worker uint64_t period = 0;
128*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> counts;
129*288bf522SAndroid Build Coastguard Worker };
130*288bf522SAndroid Build Coastguard Worker
131*288bf522SAndroid Build Coastguard Worker class ReportCmdSampleTreeBuilder : public SampleTreeBuilder<SampleEntry, AccInfo> {
132*288bf522SAndroid Build Coastguard Worker public:
ReportCmdSampleTreeBuilder(const SampleComparator<SampleEntry> & sample_comparator,ThreadTree * thread_tree,const std::unordered_map<uint64_t,size_t> & event_id_to_attr_index)133*288bf522SAndroid Build Coastguard Worker ReportCmdSampleTreeBuilder(const SampleComparator<SampleEntry>& sample_comparator,
134*288bf522SAndroid Build Coastguard Worker ThreadTree* thread_tree,
135*288bf522SAndroid Build Coastguard Worker const std::unordered_map<uint64_t, size_t>& event_id_to_attr_index)
136*288bf522SAndroid Build Coastguard Worker : SampleTreeBuilder(sample_comparator),
137*288bf522SAndroid Build Coastguard Worker thread_tree_(thread_tree),
138*288bf522SAndroid Build Coastguard Worker event_id_to_attr_index_(event_id_to_attr_index),
139*288bf522SAndroid Build Coastguard Worker total_samples_(0),
140*288bf522SAndroid Build Coastguard Worker total_period_(0),
141*288bf522SAndroid Build Coastguard Worker total_error_callchains_(0) {}
142*288bf522SAndroid Build Coastguard Worker
SetFilters(const std::unordered_set<int> & cpu_filter,const std::unordered_set<std::string> & comm_filter,const std::unordered_set<std::string> & dso_filter,const std::unordered_set<std::string> & symbol_filter)143*288bf522SAndroid Build Coastguard Worker void SetFilters(const std::unordered_set<int>& cpu_filter,
144*288bf522SAndroid Build Coastguard Worker const std::unordered_set<std::string>& comm_filter,
145*288bf522SAndroid Build Coastguard Worker const std::unordered_set<std::string>& dso_filter,
146*288bf522SAndroid Build Coastguard Worker const std::unordered_set<std::string>& symbol_filter) {
147*288bf522SAndroid Build Coastguard Worker cpu_filter_ = cpu_filter;
148*288bf522SAndroid Build Coastguard Worker comm_filter_ = comm_filter;
149*288bf522SAndroid Build Coastguard Worker dso_filter_ = dso_filter;
150*288bf522SAndroid Build Coastguard Worker symbol_filter_ = symbol_filter;
151*288bf522SAndroid Build Coastguard Worker }
152*288bf522SAndroid Build Coastguard Worker
SetEventName(const std::string & event_name)153*288bf522SAndroid Build Coastguard Worker void SetEventName(const std::string& event_name) { event_name_ = event_name; }
154*288bf522SAndroid Build Coastguard Worker
GetSampleTree()155*288bf522SAndroid Build Coastguard Worker SampleTree GetSampleTree() {
156*288bf522SAndroid Build Coastguard Worker AddCallChainDuplicateInfo();
157*288bf522SAndroid Build Coastguard Worker SampleTree sample_tree;
158*288bf522SAndroid Build Coastguard Worker sample_tree.samples = GetSamples();
159*288bf522SAndroid Build Coastguard Worker sample_tree.total_samples = total_samples_;
160*288bf522SAndroid Build Coastguard Worker sample_tree.total_period = total_period_;
161*288bf522SAndroid Build Coastguard Worker sample_tree.total_error_callchains = total_error_callchains_;
162*288bf522SAndroid Build Coastguard Worker sample_tree.event_name = event_name_;
163*288bf522SAndroid Build Coastguard Worker return sample_tree;
164*288bf522SAndroid Build Coastguard Worker }
165*288bf522SAndroid Build Coastguard Worker
ReportCmdProcessSampleRecord(std::shared_ptr<SampleRecord> & r)166*288bf522SAndroid Build Coastguard Worker virtual void ReportCmdProcessSampleRecord(std::shared_ptr<SampleRecord>& r) {
167*288bf522SAndroid Build Coastguard Worker return ProcessSampleRecord(*r);
168*288bf522SAndroid Build Coastguard Worker }
169*288bf522SAndroid Build Coastguard Worker
ReportCmdProcessSampleRecord(const SampleRecord & r)170*288bf522SAndroid Build Coastguard Worker virtual void ReportCmdProcessSampleRecord(const SampleRecord& r) {
171*288bf522SAndroid Build Coastguard Worker return ProcessSampleRecord(r);
172*288bf522SAndroid Build Coastguard Worker }
173*288bf522SAndroid Build Coastguard Worker
174*288bf522SAndroid Build Coastguard Worker protected:
175*288bf522SAndroid Build Coastguard Worker virtual uint64_t GetPeriod(const SampleRecord& r) = 0;
176*288bf522SAndroid Build Coastguard Worker
CreateSample(const SampleRecord & r,bool in_kernel,AccInfo * acc_info)177*288bf522SAndroid Build Coastguard Worker SampleEntry* CreateSample(const SampleRecord& r, bool in_kernel, AccInfo* acc_info) override {
178*288bf522SAndroid Build Coastguard Worker const ThreadEntry* thread = thread_tree_->FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
179*288bf522SAndroid Build Coastguard Worker const MapEntry* map = thread_tree_->FindMap(thread, r.ip_data.ip, in_kernel);
180*288bf522SAndroid Build Coastguard Worker uint64_t vaddr_in_file;
181*288bf522SAndroid Build Coastguard Worker const Symbol* symbol = thread_tree_->FindSymbol(map, r.ip_data.ip, &vaddr_in_file);
182*288bf522SAndroid Build Coastguard Worker uint64_t period = GetPeriod(r);
183*288bf522SAndroid Build Coastguard Worker acc_info->period = period;
184*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> counts = GetCountsForSample(r);
185*288bf522SAndroid Build Coastguard Worker acc_info->counts = counts;
186*288bf522SAndroid Build Coastguard Worker std::unique_ptr<SampleEntry> sample(new SampleEntry(r.time_data.time, period, 0, 1, r.Cpu(),
187*288bf522SAndroid Build Coastguard Worker thread, map, symbol, vaddr_in_file, counts,
188*288bf522SAndroid Build Coastguard Worker counts));
189*288bf522SAndroid Build Coastguard Worker return InsertSample(std::move(sample));
190*288bf522SAndroid Build Coastguard Worker }
191*288bf522SAndroid Build Coastguard Worker
CreateBranchSample(const SampleRecord & r,const BranchStackItemType & item)192*288bf522SAndroid Build Coastguard Worker SampleEntry* CreateBranchSample(const SampleRecord& r, const BranchStackItemType& item) override {
193*288bf522SAndroid Build Coastguard Worker const ThreadEntry* thread = thread_tree_->FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
194*288bf522SAndroid Build Coastguard Worker const MapEntry* from_map = thread_tree_->FindMap(thread, item.from);
195*288bf522SAndroid Build Coastguard Worker uint64_t from_vaddr_in_file;
196*288bf522SAndroid Build Coastguard Worker const Symbol* from_symbol = thread_tree_->FindSymbol(from_map, item.from, &from_vaddr_in_file);
197*288bf522SAndroid Build Coastguard Worker const MapEntry* to_map = thread_tree_->FindMap(thread, item.to);
198*288bf522SAndroid Build Coastguard Worker uint64_t to_vaddr_in_file;
199*288bf522SAndroid Build Coastguard Worker const Symbol* to_symbol = thread_tree_->FindSymbol(to_map, item.to, &to_vaddr_in_file);
200*288bf522SAndroid Build Coastguard Worker std::unique_ptr<SampleEntry> sample(new SampleEntry(r.time_data.time, r.period_data.period, 0,
201*288bf522SAndroid Build Coastguard Worker 1, r.Cpu(), thread, to_map, to_symbol,
202*288bf522SAndroid Build Coastguard Worker to_vaddr_in_file, {}, {}));
203*288bf522SAndroid Build Coastguard Worker sample->branch_from.map = from_map;
204*288bf522SAndroid Build Coastguard Worker sample->branch_from.symbol = from_symbol;
205*288bf522SAndroid Build Coastguard Worker sample->branch_from.vaddr_in_file = from_vaddr_in_file;
206*288bf522SAndroid Build Coastguard Worker sample->branch_from.flags = item.flags;
207*288bf522SAndroid Build Coastguard Worker return InsertSample(std::move(sample));
208*288bf522SAndroid Build Coastguard Worker }
209*288bf522SAndroid Build Coastguard Worker
CreateCallChainSample(const ThreadEntry * thread,const SampleEntry * sample,uint64_t ip,bool in_kernel,const std::vector<SampleEntry * > & callchain,const AccInfo & acc_info)210*288bf522SAndroid Build Coastguard Worker SampleEntry* CreateCallChainSample(const ThreadEntry* thread, const SampleEntry* sample,
211*288bf522SAndroid Build Coastguard Worker uint64_t ip, bool in_kernel,
212*288bf522SAndroid Build Coastguard Worker const std::vector<SampleEntry*>& callchain,
213*288bf522SAndroid Build Coastguard Worker const AccInfo& acc_info) override {
214*288bf522SAndroid Build Coastguard Worker const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel);
215*288bf522SAndroid Build Coastguard Worker if (thread_tree_->IsUnknownDso(map->dso)) {
216*288bf522SAndroid Build Coastguard Worker // The unwinders can give wrong ip addresses, which can't map to a valid dso. Skip them.
217*288bf522SAndroid Build Coastguard Worker total_error_callchains_++;
218*288bf522SAndroid Build Coastguard Worker return nullptr;
219*288bf522SAndroid Build Coastguard Worker }
220*288bf522SAndroid Build Coastguard Worker uint64_t vaddr_in_file;
221*288bf522SAndroid Build Coastguard Worker const Symbol* symbol = thread_tree_->FindSymbol(map, ip, &vaddr_in_file);
222*288bf522SAndroid Build Coastguard Worker std::unique_ptr<SampleEntry> callchain_sample(
223*288bf522SAndroid Build Coastguard Worker new SampleEntry(sample->time, 0, acc_info.period, 0, sample->cpu, thread, map, symbol,
224*288bf522SAndroid Build Coastguard Worker vaddr_in_file, {}, acc_info.counts));
225*288bf522SAndroid Build Coastguard Worker callchain_sample->thread_comm = sample->thread_comm;
226*288bf522SAndroid Build Coastguard Worker return InsertCallChainSample(std::move(callchain_sample), callchain);
227*288bf522SAndroid Build Coastguard Worker }
228*288bf522SAndroid Build Coastguard Worker
GetThreadOfSample(SampleEntry * sample)229*288bf522SAndroid Build Coastguard Worker const ThreadEntry* GetThreadOfSample(SampleEntry* sample) override {
230*288bf522SAndroid Build Coastguard Worker return thread_tree_->FindThreadOrNew(sample->pid, sample->tid);
231*288bf522SAndroid Build Coastguard Worker }
232*288bf522SAndroid Build Coastguard Worker
GetPeriodForCallChain(const AccInfo & acc_info)233*288bf522SAndroid Build Coastguard Worker uint64_t GetPeriodForCallChain(const AccInfo& acc_info) override { return acc_info.period; }
234*288bf522SAndroid Build Coastguard Worker
FilterSample(const SampleEntry * sample)235*288bf522SAndroid Build Coastguard Worker bool FilterSample(const SampleEntry* sample) override {
236*288bf522SAndroid Build Coastguard Worker if (!cpu_filter_.empty() && cpu_filter_.count(sample->cpu) == 0) {
237*288bf522SAndroid Build Coastguard Worker return false;
238*288bf522SAndroid Build Coastguard Worker }
239*288bf522SAndroid Build Coastguard Worker if (!comm_filter_.empty() && comm_filter_.count(sample->thread_comm) == 0) {
240*288bf522SAndroid Build Coastguard Worker return false;
241*288bf522SAndroid Build Coastguard Worker }
242*288bf522SAndroid Build Coastguard Worker if (!dso_filter_.empty() && dso_filter_.count(sample->map->dso->GetReportPath().data()) == 0) {
243*288bf522SAndroid Build Coastguard Worker return false;
244*288bf522SAndroid Build Coastguard Worker }
245*288bf522SAndroid Build Coastguard Worker if (!symbol_filter_.empty() && symbol_filter_.count(sample->symbol->DemangledName()) == 0) {
246*288bf522SAndroid Build Coastguard Worker return false;
247*288bf522SAndroid Build Coastguard Worker }
248*288bf522SAndroid Build Coastguard Worker return true;
249*288bf522SAndroid Build Coastguard Worker }
250*288bf522SAndroid Build Coastguard Worker
UpdateSummary(const SampleEntry * sample)251*288bf522SAndroid Build Coastguard Worker void UpdateSummary(const SampleEntry* sample) override {
252*288bf522SAndroid Build Coastguard Worker total_samples_ += sample->sample_count;
253*288bf522SAndroid Build Coastguard Worker total_period_ += sample->period;
254*288bf522SAndroid Build Coastguard Worker }
255*288bf522SAndroid Build Coastguard Worker
MergeSample(SampleEntry * sample1,SampleEntry * sample2)256*288bf522SAndroid Build Coastguard Worker void MergeSample(SampleEntry* sample1, SampleEntry* sample2) override {
257*288bf522SAndroid Build Coastguard Worker sample1->period += sample2->period;
258*288bf522SAndroid Build Coastguard Worker sample1->accumulated_period += sample2->accumulated_period;
259*288bf522SAndroid Build Coastguard Worker sample1->sample_count += sample2->sample_count;
260*288bf522SAndroid Build Coastguard Worker if (sample1->counts.size() < sample2->counts.size()) {
261*288bf522SAndroid Build Coastguard Worker sample1->counts.resize(sample2->counts.size(), 0);
262*288bf522SAndroid Build Coastguard Worker }
263*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < sample2->counts.size(); i++) {
264*288bf522SAndroid Build Coastguard Worker sample1->counts[i] += sample2->counts[i];
265*288bf522SAndroid Build Coastguard Worker }
266*288bf522SAndroid Build Coastguard Worker if (sample1->acc_counts.size() < sample2->acc_counts.size()) {
267*288bf522SAndroid Build Coastguard Worker sample1->acc_counts.resize(sample2->acc_counts.size(), 0);
268*288bf522SAndroid Build Coastguard Worker }
269*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < sample2->acc_counts.size(); i++) {
270*288bf522SAndroid Build Coastguard Worker sample1->acc_counts[i] += sample2->acc_counts[i];
271*288bf522SAndroid Build Coastguard Worker }
272*288bf522SAndroid Build Coastguard Worker }
273*288bf522SAndroid Build Coastguard Worker
274*288bf522SAndroid Build Coastguard Worker private:
GetCountsForSample(const SampleRecord & r)275*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> GetCountsForSample(const SampleRecord& r) {
276*288bf522SAndroid Build Coastguard Worker CHECK_EQ(r.read_data.counts.size(), r.read_data.ids.size());
277*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> res(r.read_data.counts.size(), 0);
278*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < r.read_data.counts.size(); i++) {
279*288bf522SAndroid Build Coastguard Worker uint64_t event_id = r.read_data.ids[i];
280*288bf522SAndroid Build Coastguard Worker uint64_t count = r.read_data.counts[i];
281*288bf522SAndroid Build Coastguard Worker uint64_t& last_count = event_id_count_map_[event_id];
282*288bf522SAndroid Build Coastguard Worker uint64_t added_count = count - last_count;
283*288bf522SAndroid Build Coastguard Worker last_count = count;
284*288bf522SAndroid Build Coastguard Worker auto it = event_id_to_attr_index_.find(event_id);
285*288bf522SAndroid Build Coastguard Worker CHECK(it != event_id_to_attr_index_.end());
286*288bf522SAndroid Build Coastguard Worker CHECK_LT(it->second, res.size());
287*288bf522SAndroid Build Coastguard Worker // Count for the current sample is the added event count after generating the previous sample.
288*288bf522SAndroid Build Coastguard Worker res[it->second] = added_count;
289*288bf522SAndroid Build Coastguard Worker }
290*288bf522SAndroid Build Coastguard Worker return res;
291*288bf522SAndroid Build Coastguard Worker }
292*288bf522SAndroid Build Coastguard Worker
293*288bf522SAndroid Build Coastguard Worker ThreadTree* thread_tree_;
294*288bf522SAndroid Build Coastguard Worker const std::unordered_map<uint64_t, size_t>& event_id_to_attr_index_;
295*288bf522SAndroid Build Coastguard Worker
296*288bf522SAndroid Build Coastguard Worker std::unordered_set<int> cpu_filter_;
297*288bf522SAndroid Build Coastguard Worker std::unordered_set<std::string> comm_filter_;
298*288bf522SAndroid Build Coastguard Worker std::unordered_set<std::string> dso_filter_;
299*288bf522SAndroid Build Coastguard Worker std::unordered_set<std::string> symbol_filter_;
300*288bf522SAndroid Build Coastguard Worker
301*288bf522SAndroid Build Coastguard Worker uint64_t total_samples_;
302*288bf522SAndroid Build Coastguard Worker uint64_t total_period_;
303*288bf522SAndroid Build Coastguard Worker uint64_t total_error_callchains_;
304*288bf522SAndroid Build Coastguard Worker
305*288bf522SAndroid Build Coastguard Worker std::string event_name_;
306*288bf522SAndroid Build Coastguard Worker // Map from event_id to its last event count.
307*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint64_t, uint64_t> event_id_count_map_;
308*288bf522SAndroid Build Coastguard Worker };
309*288bf522SAndroid Build Coastguard Worker
310*288bf522SAndroid Build Coastguard Worker // Build sample tree based on event count in each sample.
311*288bf522SAndroid Build Coastguard Worker class EventCountSampleTreeBuilder : public ReportCmdSampleTreeBuilder {
312*288bf522SAndroid Build Coastguard Worker public:
EventCountSampleTreeBuilder(const SampleComparator<SampleEntry> & sample_comparator,ThreadTree * thread_tree,const std::unordered_map<uint64_t,size_t> & event_id_to_attr_index)313*288bf522SAndroid Build Coastguard Worker EventCountSampleTreeBuilder(const SampleComparator<SampleEntry>& sample_comparator,
314*288bf522SAndroid Build Coastguard Worker ThreadTree* thread_tree,
315*288bf522SAndroid Build Coastguard Worker const std::unordered_map<uint64_t, size_t>& event_id_to_attr_index)
316*288bf522SAndroid Build Coastguard Worker : ReportCmdSampleTreeBuilder(sample_comparator, thread_tree, event_id_to_attr_index) {}
317*288bf522SAndroid Build Coastguard Worker
318*288bf522SAndroid Build Coastguard Worker protected:
GetPeriod(const SampleRecord & r)319*288bf522SAndroid Build Coastguard Worker uint64_t GetPeriod(const SampleRecord& r) override { return r.period_data.period; }
320*288bf522SAndroid Build Coastguard Worker };
321*288bf522SAndroid Build Coastguard Worker
322*288bf522SAndroid Build Coastguard Worker // Build sample tree based on the time difference between current sample and next sample.
323*288bf522SAndroid Build Coastguard Worker class TimestampSampleTreeBuilder : public ReportCmdSampleTreeBuilder {
324*288bf522SAndroid Build Coastguard Worker public:
TimestampSampleTreeBuilder(const SampleComparator<SampleEntry> & sample_comparator,ThreadTree * thread_tree,const std::unordered_map<uint64_t,size_t> & event_id_to_attr_index)325*288bf522SAndroid Build Coastguard Worker TimestampSampleTreeBuilder(const SampleComparator<SampleEntry>& sample_comparator,
326*288bf522SAndroid Build Coastguard Worker ThreadTree* thread_tree,
327*288bf522SAndroid Build Coastguard Worker const std::unordered_map<uint64_t, size_t>& event_id_to_attr_index)
328*288bf522SAndroid Build Coastguard Worker : ReportCmdSampleTreeBuilder(sample_comparator, thread_tree, event_id_to_attr_index) {}
329*288bf522SAndroid Build Coastguard Worker
ReportCmdProcessSampleRecord(std::shared_ptr<SampleRecord> & r)330*288bf522SAndroid Build Coastguard Worker void ReportCmdProcessSampleRecord(std::shared_ptr<SampleRecord>& r) override {
331*288bf522SAndroid Build Coastguard Worker pid_t tid = static_cast<pid_t>(r->tid_data.tid);
332*288bf522SAndroid Build Coastguard Worker auto it = next_sample_cache_.find(tid);
333*288bf522SAndroid Build Coastguard Worker if (it == next_sample_cache_.end()) {
334*288bf522SAndroid Build Coastguard Worker next_sample_cache_[tid] = r;
335*288bf522SAndroid Build Coastguard Worker } else {
336*288bf522SAndroid Build Coastguard Worker std::shared_ptr<SampleRecord> cur = it->second;
337*288bf522SAndroid Build Coastguard Worker it->second = r;
338*288bf522SAndroid Build Coastguard Worker ProcessSampleRecord(*cur);
339*288bf522SAndroid Build Coastguard Worker }
340*288bf522SAndroid Build Coastguard Worker }
341*288bf522SAndroid Build Coastguard Worker
342*288bf522SAndroid Build Coastguard Worker protected:
GetPeriod(const SampleRecord & r)343*288bf522SAndroid Build Coastguard Worker uint64_t GetPeriod(const SampleRecord& r) override {
344*288bf522SAndroid Build Coastguard Worker auto it = next_sample_cache_.find(r.tid_data.tid);
345*288bf522SAndroid Build Coastguard Worker CHECK(it != next_sample_cache_.end());
346*288bf522SAndroid Build Coastguard Worker // Normally the samples are sorted by time, but check here for safety.
347*288bf522SAndroid Build Coastguard Worker if (it->second->time_data.time > r.time_data.time) {
348*288bf522SAndroid Build Coastguard Worker return it->second->time_data.time - r.time_data.time;
349*288bf522SAndroid Build Coastguard Worker }
350*288bf522SAndroid Build Coastguard Worker return 1u;
351*288bf522SAndroid Build Coastguard Worker }
352*288bf522SAndroid Build Coastguard Worker
353*288bf522SAndroid Build Coastguard Worker private:
354*288bf522SAndroid Build Coastguard Worker std::unordered_map<pid_t, std::shared_ptr<SampleRecord>> next_sample_cache_;
355*288bf522SAndroid Build Coastguard Worker };
356*288bf522SAndroid Build Coastguard Worker
357*288bf522SAndroid Build Coastguard Worker struct SampleTreeBuilderOptions {
358*288bf522SAndroid Build Coastguard Worker SampleComparator<SampleEntry> comparator;
359*288bf522SAndroid Build Coastguard Worker ThreadTree* thread_tree;
360*288bf522SAndroid Build Coastguard Worker std::unordered_set<std::string> comm_filter;
361*288bf522SAndroid Build Coastguard Worker std::unordered_set<std::string> dso_filter;
362*288bf522SAndroid Build Coastguard Worker std::unordered_set<std::string> symbol_filter;
363*288bf522SAndroid Build Coastguard Worker std::unordered_set<int> cpu_filter;
364*288bf522SAndroid Build Coastguard Worker bool use_branch_address;
365*288bf522SAndroid Build Coastguard Worker bool accumulate_callchain;
366*288bf522SAndroid Build Coastguard Worker bool build_callchain;
367*288bf522SAndroid Build Coastguard Worker bool use_caller_as_callchain_root;
368*288bf522SAndroid Build Coastguard Worker bool trace_offcpu;
369*288bf522SAndroid Build Coastguard Worker
CreateSampleTreeBuildersimpleperf::__anondeabb9150111::SampleTreeBuilderOptions370*288bf522SAndroid Build Coastguard Worker std::unique_ptr<ReportCmdSampleTreeBuilder> CreateSampleTreeBuilder(
371*288bf522SAndroid Build Coastguard Worker const RecordFileReader& reader) {
372*288bf522SAndroid Build Coastguard Worker std::unique_ptr<ReportCmdSampleTreeBuilder> builder;
373*288bf522SAndroid Build Coastguard Worker if (trace_offcpu) {
374*288bf522SAndroid Build Coastguard Worker builder.reset(new TimestampSampleTreeBuilder(comparator, thread_tree, reader.EventIdMap()));
375*288bf522SAndroid Build Coastguard Worker } else {
376*288bf522SAndroid Build Coastguard Worker builder.reset(new EventCountSampleTreeBuilder(comparator, thread_tree, reader.EventIdMap()));
377*288bf522SAndroid Build Coastguard Worker }
378*288bf522SAndroid Build Coastguard Worker builder->SetFilters(cpu_filter, comm_filter, dso_filter, symbol_filter);
379*288bf522SAndroid Build Coastguard Worker builder->SetBranchSampleOption(use_branch_address);
380*288bf522SAndroid Build Coastguard Worker builder->SetCallChainSampleOptions(accumulate_callchain, build_callchain,
381*288bf522SAndroid Build Coastguard Worker use_caller_as_callchain_root);
382*288bf522SAndroid Build Coastguard Worker return builder;
383*288bf522SAndroid Build Coastguard Worker }
384*288bf522SAndroid Build Coastguard Worker };
385*288bf522SAndroid Build Coastguard Worker
386*288bf522SAndroid Build Coastguard Worker using ReportCmdSampleTreeSorter = SampleTreeSorter<SampleEntry>;
387*288bf522SAndroid Build Coastguard Worker using ReportCmdSampleTreeDisplayer = SampleTreeDisplayer<SampleEntry, SampleTree>;
388*288bf522SAndroid Build Coastguard Worker
389*288bf522SAndroid Build Coastguard Worker using ReportCmdCallgraphDisplayer = CallgraphDisplayer<SampleEntry, CallChainNode<SampleEntry>>;
390*288bf522SAndroid Build Coastguard Worker
391*288bf522SAndroid Build Coastguard Worker class ReportCmdCallgraphDisplayerWithVaddrInFile : public ReportCmdCallgraphDisplayer {
392*288bf522SAndroid Build Coastguard Worker protected:
PrintSampleName(const SampleEntry * sample)393*288bf522SAndroid Build Coastguard Worker std::string PrintSampleName(const SampleEntry* sample) override {
394*288bf522SAndroid Build Coastguard Worker return android::base::StringPrintf("%s [+0x%" PRIx64 "]", sample->symbol->DemangledName(),
395*288bf522SAndroid Build Coastguard Worker sample->vaddr_in_file);
396*288bf522SAndroid Build Coastguard Worker }
397*288bf522SAndroid Build Coastguard Worker };
398*288bf522SAndroid Build Coastguard Worker
399*288bf522SAndroid Build Coastguard Worker class ReportCommand : public Command {
400*288bf522SAndroid Build Coastguard Worker public:
ReportCommand()401*288bf522SAndroid Build Coastguard Worker ReportCommand()
402*288bf522SAndroid Build Coastguard Worker : Command(
403*288bf522SAndroid Build Coastguard Worker "report", "report sampling information in perf.data",
404*288bf522SAndroid Build Coastguard Worker // clang-format off
405*288bf522SAndroid Build Coastguard Worker "Usage: simpleperf report [options]\n"
406*288bf522SAndroid Build Coastguard Worker "The default options are: -i perf.data --sort comm,pid,tid,dso,symbol.\n"
407*288bf522SAndroid Build Coastguard Worker "-b Use the branch-to addresses in sampled take branches instead of the\n"
408*288bf522SAndroid Build Coastguard Worker " instruction addresses. Only valid for perf.data recorded with -b/-j\n"
409*288bf522SAndroid Build Coastguard Worker " option.\n"
410*288bf522SAndroid Build Coastguard Worker "--children Print the overhead accumulated by appearing in the callchain.\n"
411*288bf522SAndroid Build Coastguard Worker " In the report, Children column shows overhead for a symbol and functions called\n"
412*288bf522SAndroid Build Coastguard Worker " by the symbol, while Self column shows overhead for the symbol itself.\n"
413*288bf522SAndroid Build Coastguard Worker "--csv Report in csv format.\n"
414*288bf522SAndroid Build Coastguard Worker "--csv-separator <sep> Set separator for csv columns. Default is ','.\n"
415*288bf522SAndroid Build Coastguard Worker "--full-callgraph Print full call graph. Used with -g option. By default,\n"
416*288bf522SAndroid Build Coastguard Worker " brief call graph is printed.\n"
417*288bf522SAndroid Build Coastguard Worker "-g [callee|caller] Print call graph. If callee mode is used, the graph\n"
418*288bf522SAndroid Build Coastguard Worker " shows how functions are called from others. Otherwise,\n"
419*288bf522SAndroid Build Coastguard Worker " the graph shows how functions call others.\n"
420*288bf522SAndroid Build Coastguard Worker " Default is caller mode.\n"
421*288bf522SAndroid Build Coastguard Worker "-i <file> Specify path of record file, default is perf.data.\n"
422*288bf522SAndroid Build Coastguard Worker "--kallsyms <file> Set the file to read kernel symbols.\n"
423*288bf522SAndroid Build Coastguard Worker "--max-stack <frames> Set max stack frames shown when printing call graph.\n"
424*288bf522SAndroid Build Coastguard Worker "-n Print the sample count for each item.\n"
425*288bf522SAndroid Build Coastguard Worker "--no-demangle Don't demangle symbol names.\n"
426*288bf522SAndroid Build Coastguard Worker "--no-show-ip Don't show vaddr in file for unknown symbols.\n"
427*288bf522SAndroid Build Coastguard Worker "-o report_file_name Set report file name, default is stdout.\n"
428*288bf522SAndroid Build Coastguard Worker "--percent-limit <percent> Set min percentage in report entries and call graphs.\n"
429*288bf522SAndroid Build Coastguard Worker "--print-event-count Print event counts for each item. Additional events can be added by\n"
430*288bf522SAndroid Build Coastguard Worker " --add-counter in record cmd.\n"
431*288bf522SAndroid Build Coastguard Worker "--raw-period Report period count instead of period percentage.\n"
432*288bf522SAndroid Build Coastguard Worker "--sort key1,key2,... Select keys used to group samples into report entries. Samples having\n"
433*288bf522SAndroid Build Coastguard Worker " the same key values are aggregated into one report entry. Each report\n"
434*288bf522SAndroid Build Coastguard Worker " entry is printed in one row, having columns to show key values.\n"
435*288bf522SAndroid Build Coastguard Worker " Possible keys include:\n"
436*288bf522SAndroid Build Coastguard Worker " pid -- process id\n"
437*288bf522SAndroid Build Coastguard Worker " tid -- thread id\n"
438*288bf522SAndroid Build Coastguard Worker " comm -- thread name (can be changed during\n"
439*288bf522SAndroid Build Coastguard Worker " the lifetime of a thread)\n"
440*288bf522SAndroid Build Coastguard Worker " dso -- shared library\n"
441*288bf522SAndroid Build Coastguard Worker " symbol -- function name in the shared library\n"
442*288bf522SAndroid Build Coastguard Worker " vaddr_in_file -- virtual address in the shared\n"
443*288bf522SAndroid Build Coastguard Worker " library\n"
444*288bf522SAndroid Build Coastguard Worker " Keys can only be used with -b option:\n"
445*288bf522SAndroid Build Coastguard Worker " dso_from -- shared library branched from\n"
446*288bf522SAndroid Build Coastguard Worker " dso_to -- shared library branched to\n"
447*288bf522SAndroid Build Coastguard Worker " symbol_from -- name of function branched from\n"
448*288bf522SAndroid Build Coastguard Worker " symbol_to -- name of function branched to\n"
449*288bf522SAndroid Build Coastguard Worker " The default sort keys are:\n"
450*288bf522SAndroid Build Coastguard Worker " comm,pid,tid,dso,symbol\n"
451*288bf522SAndroid Build Coastguard Worker "--symfs <dir> Look for files with symbols relative to this directory.\n"
452*288bf522SAndroid Build Coastguard Worker "--symdir <dir> Look for files with symbols in a directory recursively.\n"
453*288bf522SAndroid Build Coastguard Worker "--vmlinux <file> Parse kernel symbols from <file>.\n"
454*288bf522SAndroid Build Coastguard Worker "\n"
455*288bf522SAndroid Build Coastguard Worker "Sample filter options:\n"
456*288bf522SAndroid Build Coastguard Worker "--comms comm1,comm2,... Report only for threads with selected names.\n"
457*288bf522SAndroid Build Coastguard Worker "--dsos dso1,dso2,... Report only for selected dsos.\n"
458*288bf522SAndroid Build Coastguard Worker "--pids pid1,pid2,... Same as '--include-pid'.\n"
459*288bf522SAndroid Build Coastguard Worker "--symbols symbol1;symbol2;... Report only for selected symbols.\n"
460*288bf522SAndroid Build Coastguard Worker "--tids tid1,tid2,... Same as '--include-tid'.\n"
461*288bf522SAndroid Build Coastguard Worker RECORD_FILTER_OPTION_HELP_MSG_FOR_REPORTING
462*288bf522SAndroid Build Coastguard Worker // clang-format on
463*288bf522SAndroid Build Coastguard Worker ),
464*288bf522SAndroid Build Coastguard Worker record_filename_("perf.data"),
465*288bf522SAndroid Build Coastguard Worker record_file_arch_(GetTargetArch()),
466*288bf522SAndroid Build Coastguard Worker use_branch_address_(false),
467*288bf522SAndroid Build Coastguard Worker accumulate_callchain_(false),
468*288bf522SAndroid Build Coastguard Worker print_callgraph_(false),
469*288bf522SAndroid Build Coastguard Worker callgraph_show_callee_(false),
470*288bf522SAndroid Build Coastguard Worker callgraph_max_stack_(UINT32_MAX),
471*288bf522SAndroid Build Coastguard Worker percent_limit_(0),
472*288bf522SAndroid Build Coastguard Worker raw_period_(false),
473*288bf522SAndroid Build Coastguard Worker brief_callgraph_(true),
474*288bf522SAndroid Build Coastguard Worker trace_offcpu_(false),
475*288bf522SAndroid Build Coastguard Worker sched_switch_attr_id_(0u),
476*288bf522SAndroid Build Coastguard Worker record_filter_(thread_tree_) {}
477*288bf522SAndroid Build Coastguard Worker
478*288bf522SAndroid Build Coastguard Worker bool Run(const std::vector<std::string>& args);
479*288bf522SAndroid Build Coastguard Worker
480*288bf522SAndroid Build Coastguard Worker private:
481*288bf522SAndroid Build Coastguard Worker bool ParseOptions(const std::vector<std::string>& args);
482*288bf522SAndroid Build Coastguard Worker bool BuildSampleComparatorAndDisplayer();
483*288bf522SAndroid Build Coastguard Worker bool ReadMetaInfoFromRecordFile();
484*288bf522SAndroid Build Coastguard Worker bool ReadEventAttrFromRecordFile();
485*288bf522SAndroid Build Coastguard Worker bool ReadFeaturesFromRecordFile();
486*288bf522SAndroid Build Coastguard Worker bool ReadSampleTreeFromRecordFile();
487*288bf522SAndroid Build Coastguard Worker bool ProcessRecord(std::unique_ptr<Record> record);
488*288bf522SAndroid Build Coastguard Worker void ProcessSampleRecordInTraceOffCpuMode(std::unique_ptr<Record> record, size_t attr_id);
489*288bf522SAndroid Build Coastguard Worker bool ProcessTracingData(const std::vector<char>& data);
490*288bf522SAndroid Build Coastguard Worker bool PrintReport();
491*288bf522SAndroid Build Coastguard Worker void PrintReportContext(FILE* fp);
492*288bf522SAndroid Build Coastguard Worker
493*288bf522SAndroid Build Coastguard Worker std::string record_filename_;
494*288bf522SAndroid Build Coastguard Worker ArchType record_file_arch_;
495*288bf522SAndroid Build Coastguard Worker std::unique_ptr<RecordFileReader> record_file_reader_;
496*288bf522SAndroid Build Coastguard Worker std::vector<perf_event_attr> event_attrs_;
497*288bf522SAndroid Build Coastguard Worker std::vector<std::string> attr_names_;
498*288bf522SAndroid Build Coastguard Worker ThreadTree thread_tree_;
499*288bf522SAndroid Build Coastguard Worker // Create a SampleTreeBuilder and SampleTree for each event_attr.
500*288bf522SAndroid Build Coastguard Worker std::vector<SampleTree> sample_tree_;
501*288bf522SAndroid Build Coastguard Worker SampleTreeBuilderOptions sample_tree_builder_options_;
502*288bf522SAndroid Build Coastguard Worker std::vector<std::unique_ptr<ReportCmdSampleTreeBuilder>> sample_tree_builder_;
503*288bf522SAndroid Build Coastguard Worker
504*288bf522SAndroid Build Coastguard Worker std::unique_ptr<ReportCmdSampleTreeSorter> sample_tree_sorter_;
505*288bf522SAndroid Build Coastguard Worker std::unique_ptr<ReportCmdSampleTreeDisplayer> sample_tree_displayer_;
506*288bf522SAndroid Build Coastguard Worker bool use_branch_address_;
507*288bf522SAndroid Build Coastguard Worker std::string record_cmdline_;
508*288bf522SAndroid Build Coastguard Worker bool accumulate_callchain_;
509*288bf522SAndroid Build Coastguard Worker bool print_callgraph_;
510*288bf522SAndroid Build Coastguard Worker bool callgraph_show_callee_;
511*288bf522SAndroid Build Coastguard Worker uint32_t callgraph_max_stack_;
512*288bf522SAndroid Build Coastguard Worker double percent_limit_;
513*288bf522SAndroid Build Coastguard Worker bool raw_period_;
514*288bf522SAndroid Build Coastguard Worker bool brief_callgraph_;
515*288bf522SAndroid Build Coastguard Worker bool trace_offcpu_;
516*288bf522SAndroid Build Coastguard Worker size_t sched_switch_attr_id_;
517*288bf522SAndroid Build Coastguard Worker bool report_csv_ = false;
518*288bf522SAndroid Build Coastguard Worker std::string csv_separator_ = ",";
519*288bf522SAndroid Build Coastguard Worker bool print_sample_count_ = false;
520*288bf522SAndroid Build Coastguard Worker bool print_event_count_ = false;
521*288bf522SAndroid Build Coastguard Worker std::vector<std::string> sort_keys_;
522*288bf522SAndroid Build Coastguard Worker std::string report_filename_;
523*288bf522SAndroid Build Coastguard Worker RecordFilter record_filter_;
524*288bf522SAndroid Build Coastguard Worker };
525*288bf522SAndroid Build Coastguard Worker
Run(const std::vector<std::string> & args)526*288bf522SAndroid Build Coastguard Worker bool ReportCommand::Run(const std::vector<std::string>& args) {
527*288bf522SAndroid Build Coastguard Worker // 1. Parse options.
528*288bf522SAndroid Build Coastguard Worker if (!ParseOptions(args)) {
529*288bf522SAndroid Build Coastguard Worker return false;
530*288bf522SAndroid Build Coastguard Worker }
531*288bf522SAndroid Build Coastguard Worker
532*288bf522SAndroid Build Coastguard Worker // 2. Read record file and build SampleTree.
533*288bf522SAndroid Build Coastguard Worker record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
534*288bf522SAndroid Build Coastguard Worker if (record_file_reader_ == nullptr) {
535*288bf522SAndroid Build Coastguard Worker return false;
536*288bf522SAndroid Build Coastguard Worker }
537*288bf522SAndroid Build Coastguard Worker if (!ReadMetaInfoFromRecordFile()) {
538*288bf522SAndroid Build Coastguard Worker return false;
539*288bf522SAndroid Build Coastguard Worker }
540*288bf522SAndroid Build Coastguard Worker if (!ReadEventAttrFromRecordFile()) {
541*288bf522SAndroid Build Coastguard Worker return false;
542*288bf522SAndroid Build Coastguard Worker }
543*288bf522SAndroid Build Coastguard Worker if (!BuildSampleComparatorAndDisplayer()) {
544*288bf522SAndroid Build Coastguard Worker return false;
545*288bf522SAndroid Build Coastguard Worker }
546*288bf522SAndroid Build Coastguard Worker // Read features first to prepare build ids used when building SampleTree.
547*288bf522SAndroid Build Coastguard Worker if (!ReadFeaturesFromRecordFile()) {
548*288bf522SAndroid Build Coastguard Worker return false;
549*288bf522SAndroid Build Coastguard Worker }
550*288bf522SAndroid Build Coastguard Worker ScopedCurrentArch scoped_arch(record_file_arch_);
551*288bf522SAndroid Build Coastguard Worker if (!ReadSampleTreeFromRecordFile()) {
552*288bf522SAndroid Build Coastguard Worker return false;
553*288bf522SAndroid Build Coastguard Worker }
554*288bf522SAndroid Build Coastguard Worker
555*288bf522SAndroid Build Coastguard Worker // 3. Show collected information.
556*288bf522SAndroid Build Coastguard Worker if (!PrintReport()) {
557*288bf522SAndroid Build Coastguard Worker return false;
558*288bf522SAndroid Build Coastguard Worker }
559*288bf522SAndroid Build Coastguard Worker
560*288bf522SAndroid Build Coastguard Worker return true;
561*288bf522SAndroid Build Coastguard Worker }
562*288bf522SAndroid Build Coastguard Worker
ParseOptions(const std::vector<std::string> & args)563*288bf522SAndroid Build Coastguard Worker bool ReportCommand::ParseOptions(const std::vector<std::string>& args) {
564*288bf522SAndroid Build Coastguard Worker OptionFormatMap option_formats = {
565*288bf522SAndroid Build Coastguard Worker {"-b", {OptionValueType::NONE, OptionType::SINGLE}},
566*288bf522SAndroid Build Coastguard Worker {"--children", {OptionValueType::NONE, OptionType::SINGLE}},
567*288bf522SAndroid Build Coastguard Worker {"--comms", {OptionValueType::STRING, OptionType::MULTIPLE}},
568*288bf522SAndroid Build Coastguard Worker {"--cpu", {OptionValueType::STRING, OptionType::MULTIPLE}},
569*288bf522SAndroid Build Coastguard Worker {"--csv", {OptionValueType::NONE, OptionType::SINGLE}},
570*288bf522SAndroid Build Coastguard Worker {"--csv-separator", {OptionValueType::STRING, OptionType::SINGLE}},
571*288bf522SAndroid Build Coastguard Worker {"--dsos", {OptionValueType::STRING, OptionType::MULTIPLE}},
572*288bf522SAndroid Build Coastguard Worker {"--full-callgraph", {OptionValueType::NONE, OptionType::SINGLE}},
573*288bf522SAndroid Build Coastguard Worker {"-g", {OptionValueType::OPT_STRING, OptionType::SINGLE}},
574*288bf522SAndroid Build Coastguard Worker {"-i", {OptionValueType::STRING, OptionType::SINGLE}},
575*288bf522SAndroid Build Coastguard Worker {"--kallsyms", {OptionValueType::STRING, OptionType::SINGLE}},
576*288bf522SAndroid Build Coastguard Worker {"--max-stack", {OptionValueType::UINT, OptionType::SINGLE}},
577*288bf522SAndroid Build Coastguard Worker {"-n", {OptionValueType::NONE, OptionType::SINGLE}},
578*288bf522SAndroid Build Coastguard Worker {"--no-demangle", {OptionValueType::NONE, OptionType::SINGLE}},
579*288bf522SAndroid Build Coastguard Worker {"--no-show-ip", {OptionValueType::NONE, OptionType::SINGLE}},
580*288bf522SAndroid Build Coastguard Worker {"-o", {OptionValueType::STRING, OptionType::SINGLE}},
581*288bf522SAndroid Build Coastguard Worker {"--percent-limit", {OptionValueType::DOUBLE, OptionType::SINGLE}},
582*288bf522SAndroid Build Coastguard Worker {"--pids", {OptionValueType::STRING, OptionType::MULTIPLE}},
583*288bf522SAndroid Build Coastguard Worker {"--print-event-count", {OptionValueType::NONE, OptionType::SINGLE}},
584*288bf522SAndroid Build Coastguard Worker {"--tids", {OptionValueType::STRING, OptionType::MULTIPLE}},
585*288bf522SAndroid Build Coastguard Worker {"--raw-period", {OptionValueType::NONE, OptionType::SINGLE}},
586*288bf522SAndroid Build Coastguard Worker {"--sort", {OptionValueType::STRING, OptionType::SINGLE}},
587*288bf522SAndroid Build Coastguard Worker {"--symbols", {OptionValueType::STRING, OptionType::MULTIPLE}},
588*288bf522SAndroid Build Coastguard Worker {"--symfs", {OptionValueType::STRING, OptionType::SINGLE}},
589*288bf522SAndroid Build Coastguard Worker {"--symdir", {OptionValueType::STRING, OptionType::SINGLE}},
590*288bf522SAndroid Build Coastguard Worker {"--vmlinux", {OptionValueType::STRING, OptionType::SINGLE}},
591*288bf522SAndroid Build Coastguard Worker };
592*288bf522SAndroid Build Coastguard Worker OptionFormatMap record_filter_options = GetRecordFilterOptionFormats(false);
593*288bf522SAndroid Build Coastguard Worker option_formats.insert(record_filter_options.begin(), record_filter_options.end());
594*288bf522SAndroid Build Coastguard Worker
595*288bf522SAndroid Build Coastguard Worker OptionValueMap options;
596*288bf522SAndroid Build Coastguard Worker std::vector<std::pair<OptionName, OptionValue>> ordered_options;
597*288bf522SAndroid Build Coastguard Worker if (!PreprocessOptions(args, option_formats, &options, &ordered_options, nullptr)) {
598*288bf522SAndroid Build Coastguard Worker return false;
599*288bf522SAndroid Build Coastguard Worker }
600*288bf522SAndroid Build Coastguard Worker
601*288bf522SAndroid Build Coastguard Worker // Process options.
602*288bf522SAndroid Build Coastguard Worker use_branch_address_ = options.PullBoolValue("-b");
603*288bf522SAndroid Build Coastguard Worker accumulate_callchain_ = options.PullBoolValue("--children");
604*288bf522SAndroid Build Coastguard Worker for (const OptionValue& value : options.PullValues("--comms")) {
605*288bf522SAndroid Build Coastguard Worker std::vector<std::string> strs = Split(value.str_value, ",");
606*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.comm_filter.insert(strs.begin(), strs.end());
607*288bf522SAndroid Build Coastguard Worker }
608*288bf522SAndroid Build Coastguard Worker if (!record_filter_.ParseOptions(options)) {
609*288bf522SAndroid Build Coastguard Worker return false;
610*288bf522SAndroid Build Coastguard Worker }
611*288bf522SAndroid Build Coastguard Worker for (const OptionValue& value : options.PullValues("--cpu")) {
612*288bf522SAndroid Build Coastguard Worker if (auto cpus = GetCpusFromString(value.str_value); cpus) {
613*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.cpu_filter.insert(cpus->begin(), cpus->end());
614*288bf522SAndroid Build Coastguard Worker } else {
615*288bf522SAndroid Build Coastguard Worker return false;
616*288bf522SAndroid Build Coastguard Worker }
617*288bf522SAndroid Build Coastguard Worker }
618*288bf522SAndroid Build Coastguard Worker report_csv_ = options.PullBoolValue("--csv");
619*288bf522SAndroid Build Coastguard Worker options.PullStringValue("--csv-separator", &csv_separator_);
620*288bf522SAndroid Build Coastguard Worker for (const OptionValue& value : options.PullValues("--dsos")) {
621*288bf522SAndroid Build Coastguard Worker std::vector<std::string> strs = Split(value.str_value, ",");
622*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.dso_filter.insert(strs.begin(), strs.end());
623*288bf522SAndroid Build Coastguard Worker }
624*288bf522SAndroid Build Coastguard Worker brief_callgraph_ = !options.PullBoolValue("--full-callgraph");
625*288bf522SAndroid Build Coastguard Worker
626*288bf522SAndroid Build Coastguard Worker if (auto value = options.PullValue("-g"); value) {
627*288bf522SAndroid Build Coastguard Worker print_callgraph_ = true;
628*288bf522SAndroid Build Coastguard Worker accumulate_callchain_ = true;
629*288bf522SAndroid Build Coastguard Worker if (!value->str_value.empty()) {
630*288bf522SAndroid Build Coastguard Worker if (value->str_value == "callee") {
631*288bf522SAndroid Build Coastguard Worker callgraph_show_callee_ = true;
632*288bf522SAndroid Build Coastguard Worker } else if (value->str_value == "caller") {
633*288bf522SAndroid Build Coastguard Worker callgraph_show_callee_ = false;
634*288bf522SAndroid Build Coastguard Worker } else {
635*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "Unknown argument with -g option: " << value->str_value;
636*288bf522SAndroid Build Coastguard Worker return false;
637*288bf522SAndroid Build Coastguard Worker }
638*288bf522SAndroid Build Coastguard Worker }
639*288bf522SAndroid Build Coastguard Worker }
640*288bf522SAndroid Build Coastguard Worker options.PullStringValue("-i", &record_filename_);
641*288bf522SAndroid Build Coastguard Worker if (auto value = options.PullValue("--kallsyms"); value) {
642*288bf522SAndroid Build Coastguard Worker std::string kallsyms;
643*288bf522SAndroid Build Coastguard Worker if (!android::base::ReadFileToString(value->str_value, &kallsyms)) {
644*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "Can't read kernel symbols from " << value->str_value;
645*288bf522SAndroid Build Coastguard Worker return false;
646*288bf522SAndroid Build Coastguard Worker }
647*288bf522SAndroid Build Coastguard Worker Dso::SetKallsyms(kallsyms);
648*288bf522SAndroid Build Coastguard Worker }
649*288bf522SAndroid Build Coastguard Worker if (!options.PullUintValue("--max-stack", &callgraph_max_stack_)) {
650*288bf522SAndroid Build Coastguard Worker return false;
651*288bf522SAndroid Build Coastguard Worker }
652*288bf522SAndroid Build Coastguard Worker print_sample_count_ = options.PullBoolValue("-n");
653*288bf522SAndroid Build Coastguard Worker
654*288bf522SAndroid Build Coastguard Worker Dso::SetDemangle(!options.PullBoolValue("--no-demangle"));
655*288bf522SAndroid Build Coastguard Worker
656*288bf522SAndroid Build Coastguard Worker if (!options.PullBoolValue("--no-show-ip")) {
657*288bf522SAndroid Build Coastguard Worker thread_tree_.ShowIpForUnknownSymbol();
658*288bf522SAndroid Build Coastguard Worker }
659*288bf522SAndroid Build Coastguard Worker
660*288bf522SAndroid Build Coastguard Worker options.PullStringValue("-o", &report_filename_);
661*288bf522SAndroid Build Coastguard Worker if (!options.PullDoubleValue("--percent-limit", &percent_limit_, 0)) {
662*288bf522SAndroid Build Coastguard Worker return false;
663*288bf522SAndroid Build Coastguard Worker }
664*288bf522SAndroid Build Coastguard Worker
665*288bf522SAndroid Build Coastguard Worker if (auto strs = options.PullStringValues("--pids"); !strs.empty()) {
666*288bf522SAndroid Build Coastguard Worker if (auto pids = GetPidsFromStrings(strs, false, false); pids) {
667*288bf522SAndroid Build Coastguard Worker record_filter_.AddPids(pids.value(), false);
668*288bf522SAndroid Build Coastguard Worker } else {
669*288bf522SAndroid Build Coastguard Worker return false;
670*288bf522SAndroid Build Coastguard Worker }
671*288bf522SAndroid Build Coastguard Worker }
672*288bf522SAndroid Build Coastguard Worker print_event_count_ = options.PullBoolValue("--print-event-count");
673*288bf522SAndroid Build Coastguard Worker for (const OptionValue& value : options.PullValues("--tids")) {
674*288bf522SAndroid Build Coastguard Worker if (auto tids = GetTidsFromString(value.str_value, false); tids) {
675*288bf522SAndroid Build Coastguard Worker record_filter_.AddTids(tids.value(), false);
676*288bf522SAndroid Build Coastguard Worker } else {
677*288bf522SAndroid Build Coastguard Worker return false;
678*288bf522SAndroid Build Coastguard Worker }
679*288bf522SAndroid Build Coastguard Worker }
680*288bf522SAndroid Build Coastguard Worker raw_period_ = options.PullBoolValue("--raw-period");
681*288bf522SAndroid Build Coastguard Worker
682*288bf522SAndroid Build Coastguard Worker sort_keys_ = {"comm", "pid", "tid", "dso", "symbol"};
683*288bf522SAndroid Build Coastguard Worker if (auto value = options.PullValue("--sort"); value) {
684*288bf522SAndroid Build Coastguard Worker sort_keys_ = Split(value->str_value, ",");
685*288bf522SAndroid Build Coastguard Worker }
686*288bf522SAndroid Build Coastguard Worker
687*288bf522SAndroid Build Coastguard Worker for (const OptionValue& value : options.PullValues("--symbols")) {
688*288bf522SAndroid Build Coastguard Worker std::vector<std::string> symbols = Split(value.str_value, ";");
689*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.symbol_filter.insert(symbols.begin(), symbols.end());
690*288bf522SAndroid Build Coastguard Worker }
691*288bf522SAndroid Build Coastguard Worker
692*288bf522SAndroid Build Coastguard Worker if (auto value = options.PullValue("--symfs"); value) {
693*288bf522SAndroid Build Coastguard Worker if (!Dso::SetSymFsDir(value->str_value)) {
694*288bf522SAndroid Build Coastguard Worker return false;
695*288bf522SAndroid Build Coastguard Worker }
696*288bf522SAndroid Build Coastguard Worker }
697*288bf522SAndroid Build Coastguard Worker if (auto value = options.PullValue("--symdir"); value) {
698*288bf522SAndroid Build Coastguard Worker if (!Dso::AddSymbolDir(value->str_value)) {
699*288bf522SAndroid Build Coastguard Worker return false;
700*288bf522SAndroid Build Coastguard Worker }
701*288bf522SAndroid Build Coastguard Worker }
702*288bf522SAndroid Build Coastguard Worker if (auto value = options.PullValue("--vmlinux"); value) {
703*288bf522SAndroid Build Coastguard Worker Dso::SetVmlinux(value->str_value);
704*288bf522SAndroid Build Coastguard Worker }
705*288bf522SAndroid Build Coastguard Worker CHECK(options.values.empty());
706*288bf522SAndroid Build Coastguard Worker return true;
707*288bf522SAndroid Build Coastguard Worker }
708*288bf522SAndroid Build Coastguard Worker
BuildSampleComparatorAndDisplayer()709*288bf522SAndroid Build Coastguard Worker bool ReportCommand::BuildSampleComparatorAndDisplayer() {
710*288bf522SAndroid Build Coastguard Worker SampleDisplayer<SampleEntry, SampleTree> displayer;
711*288bf522SAndroid Build Coastguard Worker displayer.SetReportFormat(report_csv_, csv_separator_);
712*288bf522SAndroid Build Coastguard Worker SampleComparator<SampleEntry> comparator;
713*288bf522SAndroid Build Coastguard Worker
714*288bf522SAndroid Build Coastguard Worker if (accumulate_callchain_) {
715*288bf522SAndroid Build Coastguard Worker if (raw_period_) {
716*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Children", DisplayAccumulatedPeriod<SampleEntry>);
717*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Self", DisplaySelfPeriod<SampleEntry>);
718*288bf522SAndroid Build Coastguard Worker } else {
719*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Children", DisplayAccumulatedOverhead<SampleEntry, SampleTree>);
720*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Self", DisplaySelfOverhead<SampleEntry, SampleTree>);
721*288bf522SAndroid Build Coastguard Worker }
722*288bf522SAndroid Build Coastguard Worker } else {
723*288bf522SAndroid Build Coastguard Worker if (raw_period_) {
724*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Overhead", DisplaySelfPeriod<SampleEntry>);
725*288bf522SAndroid Build Coastguard Worker } else {
726*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Overhead", DisplaySelfOverhead<SampleEntry, SampleTree>);
727*288bf522SAndroid Build Coastguard Worker }
728*288bf522SAndroid Build Coastguard Worker }
729*288bf522SAndroid Build Coastguard Worker if (print_sample_count_) {
730*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Sample", DisplaySampleCount<SampleEntry>);
731*288bf522SAndroid Build Coastguard Worker }
732*288bf522SAndroid Build Coastguard Worker if (print_event_count_) {
733*288bf522SAndroid Build Coastguard Worker if (event_attrs_.size() == attr_names_.size()) {
734*288bf522SAndroid Build Coastguard Worker // Without additional counters, counts field isn't available. So print period field instead.
735*288bf522SAndroid Build Coastguard Worker if (accumulate_callchain_) {
736*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("AccEventCount", DisplayAccumulatedPeriod<SampleEntry>);
737*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("SelfEventCount", DisplaySelfPeriod<SampleEntry>);
738*288bf522SAndroid Build Coastguard Worker } else {
739*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("EventCount", DisplaySelfPeriod<SampleEntry>);
740*288bf522SAndroid Build Coastguard Worker }
741*288bf522SAndroid Build Coastguard Worker } else {
742*288bf522SAndroid Build Coastguard Worker // With additional counters, print counts field.
743*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < attr_names_.size(); i++) {
744*288bf522SAndroid Build Coastguard Worker auto self_event_count_fn = [i](const SampleEntry* s) {
745*288bf522SAndroid Build Coastguard Worker return i < s->counts.size() ? std::to_string(s->counts[i]) : "0";
746*288bf522SAndroid Build Coastguard Worker };
747*288bf522SAndroid Build Coastguard Worker auto acc_event_count_fn = [i](const SampleEntry* s) {
748*288bf522SAndroid Build Coastguard Worker return i < s->acc_counts.size() ? std::to_string(s->acc_counts[i]) : "0";
749*288bf522SAndroid Build Coastguard Worker };
750*288bf522SAndroid Build Coastguard Worker if (accumulate_callchain_) {
751*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("AccEventCount_" + attr_names_[i], acc_event_count_fn);
752*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("SelfEventCount_" + attr_names_[i], self_event_count_fn);
753*288bf522SAndroid Build Coastguard Worker } else {
754*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("EventCount_" + attr_names_[i], self_event_count_fn);
755*288bf522SAndroid Build Coastguard Worker }
756*288bf522SAndroid Build Coastguard Worker }
757*288bf522SAndroid Build Coastguard Worker }
758*288bf522SAndroid Build Coastguard Worker }
759*288bf522SAndroid Build Coastguard Worker
760*288bf522SAndroid Build Coastguard Worker for (auto& key : sort_keys_) {
761*288bf522SAndroid Build Coastguard Worker if (!use_branch_address_ && branch_sort_keys.find(key) != branch_sort_keys.end()) {
762*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "sort key '" << key << "' can only be used with -b option.";
763*288bf522SAndroid Build Coastguard Worker return false;
764*288bf522SAndroid Build Coastguard Worker }
765*288bf522SAndroid Build Coastguard Worker if (key == "pid") {
766*288bf522SAndroid Build Coastguard Worker comparator.AddCompareFunction(ComparePid);
767*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Pid", DisplayPid<SampleEntry>);
768*288bf522SAndroid Build Coastguard Worker } else if (key == "tid") {
769*288bf522SAndroid Build Coastguard Worker comparator.AddCompareFunction(CompareTid);
770*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Tid", DisplayTid<SampleEntry>);
771*288bf522SAndroid Build Coastguard Worker } else if (key == "comm") {
772*288bf522SAndroid Build Coastguard Worker comparator.AddCompareFunction(CompareComm);
773*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Command", DisplayComm<SampleEntry>);
774*288bf522SAndroid Build Coastguard Worker } else if (key == "dso") {
775*288bf522SAndroid Build Coastguard Worker comparator.AddCompareFunction(CompareDso);
776*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Shared Object", DisplayDso<SampleEntry>);
777*288bf522SAndroid Build Coastguard Worker } else if (key == "symbol") {
778*288bf522SAndroid Build Coastguard Worker comparator.AddCompareFunction(CompareSymbol);
779*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Symbol", DisplaySymbol<SampleEntry>);
780*288bf522SAndroid Build Coastguard Worker } else if (key == "vaddr_in_file") {
781*288bf522SAndroid Build Coastguard Worker comparator.AddCompareFunction(CompareVaddrInFile);
782*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("VaddrInFile", DisplayVaddrInFile<SampleEntry>);
783*288bf522SAndroid Build Coastguard Worker } else if (key == "dso_from") {
784*288bf522SAndroid Build Coastguard Worker comparator.AddCompareFunction(CompareDsoFrom);
785*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Source Shared Object", DisplayDsoFrom<SampleEntry>);
786*288bf522SAndroid Build Coastguard Worker } else if (key == "dso_to") {
787*288bf522SAndroid Build Coastguard Worker comparator.AddCompareFunction(CompareDso);
788*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Target Shared Object", DisplayDso<SampleEntry>);
789*288bf522SAndroid Build Coastguard Worker } else if (key == "symbol_from") {
790*288bf522SAndroid Build Coastguard Worker comparator.AddCompareFunction(CompareSymbolFrom);
791*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Source Symbol", DisplaySymbolFrom<SampleEntry>);
792*288bf522SAndroid Build Coastguard Worker } else if (key == "symbol_to") {
793*288bf522SAndroid Build Coastguard Worker comparator.AddCompareFunction(CompareSymbol);
794*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("Target Symbol", DisplaySymbol<SampleEntry>);
795*288bf522SAndroid Build Coastguard Worker } else {
796*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "Unknown sort key: " << key;
797*288bf522SAndroid Build Coastguard Worker return false;
798*288bf522SAndroid Build Coastguard Worker }
799*288bf522SAndroid Build Coastguard Worker }
800*288bf522SAndroid Build Coastguard Worker
801*288bf522SAndroid Build Coastguard Worker // Reporting with --csv will add event count and event name columns. But if --print-event-count is
802*288bf522SAndroid Build Coastguard Worker // used, there is no need to duplicate printing event counts.
803*288bf522SAndroid Build Coastguard Worker if (report_csv_ && !print_event_count_) {
804*288bf522SAndroid Build Coastguard Worker if (accumulate_callchain_) {
805*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("AccEventCount", DisplayAccumulatedPeriod<SampleEntry>);
806*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("SelfEventCount", DisplaySelfPeriod<SampleEntry>);
807*288bf522SAndroid Build Coastguard Worker } else {
808*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("EventCount", DisplaySelfPeriod<SampleEntry>);
809*288bf522SAndroid Build Coastguard Worker }
810*288bf522SAndroid Build Coastguard Worker displayer.AddDisplayFunction("EventName", DisplayEventName);
811*288bf522SAndroid Build Coastguard Worker }
812*288bf522SAndroid Build Coastguard Worker
813*288bf522SAndroid Build Coastguard Worker if (print_callgraph_) {
814*288bf522SAndroid Build Coastguard Worker bool has_symbol_key = false;
815*288bf522SAndroid Build Coastguard Worker bool has_vaddr_in_file_key = false;
816*288bf522SAndroid Build Coastguard Worker for (const auto& key : sort_keys_) {
817*288bf522SAndroid Build Coastguard Worker if (key == "symbol") {
818*288bf522SAndroid Build Coastguard Worker has_symbol_key = true;
819*288bf522SAndroid Build Coastguard Worker } else if (key == "vaddr_in_file") {
820*288bf522SAndroid Build Coastguard Worker has_vaddr_in_file_key = true;
821*288bf522SAndroid Build Coastguard Worker }
822*288bf522SAndroid Build Coastguard Worker }
823*288bf522SAndroid Build Coastguard Worker if (has_symbol_key) {
824*288bf522SAndroid Build Coastguard Worker if (has_vaddr_in_file_key) {
825*288bf522SAndroid Build Coastguard Worker displayer.AddExclusiveDisplayFunction(ReportCmdCallgraphDisplayerWithVaddrInFile());
826*288bf522SAndroid Build Coastguard Worker } else {
827*288bf522SAndroid Build Coastguard Worker displayer.AddExclusiveDisplayFunction(
828*288bf522SAndroid Build Coastguard Worker ReportCmdCallgraphDisplayer(callgraph_max_stack_, percent_limit_, brief_callgraph_));
829*288bf522SAndroid Build Coastguard Worker }
830*288bf522SAndroid Build Coastguard Worker }
831*288bf522SAndroid Build Coastguard Worker }
832*288bf522SAndroid Build Coastguard Worker
833*288bf522SAndroid Build Coastguard Worker if (percent_limit_ != 0.0) {
834*288bf522SAndroid Build Coastguard Worker displayer.SetFilterFunction([this](const SampleEntry* sample, const SampleTree* sample_tree) {
835*288bf522SAndroid Build Coastguard Worker uint64_t total_period = sample->period + sample->accumulated_period;
836*288bf522SAndroid Build Coastguard Worker return total_period >= sample_tree->total_period * percent_limit_ / 100.0;
837*288bf522SAndroid Build Coastguard Worker });
838*288bf522SAndroid Build Coastguard Worker }
839*288bf522SAndroid Build Coastguard Worker
840*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.comparator = comparator;
841*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.thread_tree = &thread_tree_;
842*288bf522SAndroid Build Coastguard Worker
843*288bf522SAndroid Build Coastguard Worker SampleComparator<SampleEntry> sort_comparator;
844*288bf522SAndroid Build Coastguard Worker sort_comparator.AddCompareFunction(CompareTotalPeriod);
845*288bf522SAndroid Build Coastguard Worker if (print_callgraph_) {
846*288bf522SAndroid Build Coastguard Worker sort_comparator.AddCompareFunction(CompareCallGraphDuplicated);
847*288bf522SAndroid Build Coastguard Worker }
848*288bf522SAndroid Build Coastguard Worker sort_comparator.AddCompareFunction(ComparePeriod);
849*288bf522SAndroid Build Coastguard Worker sort_comparator.AddComparator(comparator);
850*288bf522SAndroid Build Coastguard Worker sample_tree_sorter_.reset(new ReportCmdSampleTreeSorter(sort_comparator));
851*288bf522SAndroid Build Coastguard Worker sample_tree_displayer_.reset(new ReportCmdSampleTreeDisplayer(displayer));
852*288bf522SAndroid Build Coastguard Worker return true;
853*288bf522SAndroid Build Coastguard Worker }
854*288bf522SAndroid Build Coastguard Worker
ReadMetaInfoFromRecordFile()855*288bf522SAndroid Build Coastguard Worker bool ReportCommand::ReadMetaInfoFromRecordFile() {
856*288bf522SAndroid Build Coastguard Worker auto& meta_info = record_file_reader_->GetMetaInfoFeature();
857*288bf522SAndroid Build Coastguard Worker if (auto it = meta_info.find("trace_offcpu"); it != meta_info.end()) {
858*288bf522SAndroid Build Coastguard Worker trace_offcpu_ = it->second == "true";
859*288bf522SAndroid Build Coastguard Worker }
860*288bf522SAndroid Build Coastguard Worker return record_filter_.CheckClock(record_file_reader_->GetClockId());
861*288bf522SAndroid Build Coastguard Worker }
862*288bf522SAndroid Build Coastguard Worker
ReadEventAttrFromRecordFile()863*288bf522SAndroid Build Coastguard Worker bool ReportCommand::ReadEventAttrFromRecordFile() {
864*288bf522SAndroid Build Coastguard Worker for (const EventAttrWithId& attr_with_id : record_file_reader_->AttrSection()) {
865*288bf522SAndroid Build Coastguard Worker const perf_event_attr& attr = attr_with_id.attr;
866*288bf522SAndroid Build Coastguard Worker attr_names_.emplace_back(GetEventNameByAttr(attr));
867*288bf522SAndroid Build Coastguard Worker
868*288bf522SAndroid Build Coastguard Worker // There are no samples for events added by --add-counter. So skip them.
869*288bf522SAndroid Build Coastguard Worker if ((attr.read_format & PERF_FORMAT_GROUP) && (attr.freq == 0) &&
870*288bf522SAndroid Build Coastguard Worker (attr.sample_period == INFINITE_SAMPLE_PERIOD)) {
871*288bf522SAndroid Build Coastguard Worker continue;
872*288bf522SAndroid Build Coastguard Worker }
873*288bf522SAndroid Build Coastguard Worker event_attrs_.emplace_back(attr);
874*288bf522SAndroid Build Coastguard Worker }
875*288bf522SAndroid Build Coastguard Worker if (use_branch_address_) {
876*288bf522SAndroid Build Coastguard Worker bool has_branch_stack = true;
877*288bf522SAndroid Build Coastguard Worker for (const auto& attr : event_attrs_) {
878*288bf522SAndroid Build Coastguard Worker if ((attr.sample_type & PERF_SAMPLE_BRANCH_STACK) == 0) {
879*288bf522SAndroid Build Coastguard Worker has_branch_stack = false;
880*288bf522SAndroid Build Coastguard Worker break;
881*288bf522SAndroid Build Coastguard Worker }
882*288bf522SAndroid Build Coastguard Worker }
883*288bf522SAndroid Build Coastguard Worker if (!has_branch_stack) {
884*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << record_filename_ << " is not recorded with branch stack sampling option.";
885*288bf522SAndroid Build Coastguard Worker return false;
886*288bf522SAndroid Build Coastguard Worker }
887*288bf522SAndroid Build Coastguard Worker }
888*288bf522SAndroid Build Coastguard Worker if (trace_offcpu_) {
889*288bf522SAndroid Build Coastguard Worker size_t i;
890*288bf522SAndroid Build Coastguard Worker for (i = 0; i < event_attrs_.size(); ++i) {
891*288bf522SAndroid Build Coastguard Worker if (attr_names_[i] == "sched:sched_switch") {
892*288bf522SAndroid Build Coastguard Worker break;
893*288bf522SAndroid Build Coastguard Worker }
894*288bf522SAndroid Build Coastguard Worker }
895*288bf522SAndroid Build Coastguard Worker CHECK_NE(i, event_attrs_.size());
896*288bf522SAndroid Build Coastguard Worker sched_switch_attr_id_ = i;
897*288bf522SAndroid Build Coastguard Worker }
898*288bf522SAndroid Build Coastguard Worker return true;
899*288bf522SAndroid Build Coastguard Worker }
900*288bf522SAndroid Build Coastguard Worker
ReadFeaturesFromRecordFile()901*288bf522SAndroid Build Coastguard Worker bool ReportCommand::ReadFeaturesFromRecordFile() {
902*288bf522SAndroid Build Coastguard Worker if (!record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_)) {
903*288bf522SAndroid Build Coastguard Worker return false;
904*288bf522SAndroid Build Coastguard Worker }
905*288bf522SAndroid Build Coastguard Worker
906*288bf522SAndroid Build Coastguard Worker std::string arch = record_file_reader_->ReadFeatureString(PerfFileFormat::FEAT_ARCH);
907*288bf522SAndroid Build Coastguard Worker if (!arch.empty()) {
908*288bf522SAndroid Build Coastguard Worker record_file_arch_ = GetArchType(arch);
909*288bf522SAndroid Build Coastguard Worker if (record_file_arch_ == ARCH_UNSUPPORTED) {
910*288bf522SAndroid Build Coastguard Worker return false;
911*288bf522SAndroid Build Coastguard Worker }
912*288bf522SAndroid Build Coastguard Worker }
913*288bf522SAndroid Build Coastguard Worker
914*288bf522SAndroid Build Coastguard Worker std::vector<std::string> cmdline = record_file_reader_->ReadCmdlineFeature();
915*288bf522SAndroid Build Coastguard Worker if (!cmdline.empty()) {
916*288bf522SAndroid Build Coastguard Worker record_cmdline_ = android::base::Join(cmdline, ' ');
917*288bf522SAndroid Build Coastguard Worker }
918*288bf522SAndroid Build Coastguard Worker if (record_file_reader_->HasFeature(PerfFileFormat::FEAT_TRACING_DATA)) {
919*288bf522SAndroid Build Coastguard Worker std::vector<char> tracing_data;
920*288bf522SAndroid Build Coastguard Worker if (!record_file_reader_->ReadFeatureSection(PerfFileFormat::FEAT_TRACING_DATA,
921*288bf522SAndroid Build Coastguard Worker &tracing_data)) {
922*288bf522SAndroid Build Coastguard Worker return false;
923*288bf522SAndroid Build Coastguard Worker }
924*288bf522SAndroid Build Coastguard Worker if (!ProcessTracingData(tracing_data)) {
925*288bf522SAndroid Build Coastguard Worker return false;
926*288bf522SAndroid Build Coastguard Worker }
927*288bf522SAndroid Build Coastguard Worker }
928*288bf522SAndroid Build Coastguard Worker return true;
929*288bf522SAndroid Build Coastguard Worker }
930*288bf522SAndroid Build Coastguard Worker
ReadSampleTreeFromRecordFile()931*288bf522SAndroid Build Coastguard Worker bool ReportCommand::ReadSampleTreeFromRecordFile() {
932*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.use_branch_address = use_branch_address_;
933*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.accumulate_callchain = accumulate_callchain_;
934*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.build_callchain = print_callgraph_;
935*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.use_caller_as_callchain_root = !callgraph_show_callee_;
936*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.trace_offcpu = trace_offcpu_;
937*288bf522SAndroid Build Coastguard Worker
938*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < event_attrs_.size(); ++i) {
939*288bf522SAndroid Build Coastguard Worker sample_tree_builder_.push_back(
940*288bf522SAndroid Build Coastguard Worker sample_tree_builder_options_.CreateSampleTreeBuilder(*record_file_reader_));
941*288bf522SAndroid Build Coastguard Worker sample_tree_builder_.back()->SetEventName(attr_names_[i]);
942*288bf522SAndroid Build Coastguard Worker OfflineUnwinder* unwinder = sample_tree_builder_.back()->GetUnwinder();
943*288bf522SAndroid Build Coastguard Worker if (unwinder != nullptr) {
944*288bf522SAndroid Build Coastguard Worker unwinder->LoadMetaInfo(record_file_reader_->GetMetaInfoFeature());
945*288bf522SAndroid Build Coastguard Worker }
946*288bf522SAndroid Build Coastguard Worker }
947*288bf522SAndroid Build Coastguard Worker
948*288bf522SAndroid Build Coastguard Worker if (!record_file_reader_->ReadDataSection(
949*288bf522SAndroid Build Coastguard Worker [this](std::unique_ptr<Record> record) { return ProcessRecord(std::move(record)); })) {
950*288bf522SAndroid Build Coastguard Worker return false;
951*288bf522SAndroid Build Coastguard Worker }
952*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < sample_tree_builder_.size(); ++i) {
953*288bf522SAndroid Build Coastguard Worker sample_tree_.push_back(sample_tree_builder_[i]->GetSampleTree());
954*288bf522SAndroid Build Coastguard Worker sample_tree_sorter_->Sort(sample_tree_.back().samples, print_callgraph_);
955*288bf522SAndroid Build Coastguard Worker }
956*288bf522SAndroid Build Coastguard Worker return true;
957*288bf522SAndroid Build Coastguard Worker }
958*288bf522SAndroid Build Coastguard Worker
ProcessRecord(std::unique_ptr<Record> record)959*288bf522SAndroid Build Coastguard Worker bool ReportCommand::ProcessRecord(std::unique_ptr<Record> record) {
960*288bf522SAndroid Build Coastguard Worker thread_tree_.Update(*record);
961*288bf522SAndroid Build Coastguard Worker if (record->type() == PERF_RECORD_SAMPLE) {
962*288bf522SAndroid Build Coastguard Worker if (!record_filter_.Check(static_cast<SampleRecord&>(*record))) {
963*288bf522SAndroid Build Coastguard Worker return true;
964*288bf522SAndroid Build Coastguard Worker }
965*288bf522SAndroid Build Coastguard Worker size_t attr_id = record_file_reader_->GetAttrIndexOfRecord(record.get());
966*288bf522SAndroid Build Coastguard Worker if (!trace_offcpu_) {
967*288bf522SAndroid Build Coastguard Worker sample_tree_builder_[attr_id]->ReportCmdProcessSampleRecord(
968*288bf522SAndroid Build Coastguard Worker *static_cast<SampleRecord*>(record.get()));
969*288bf522SAndroid Build Coastguard Worker } else {
970*288bf522SAndroid Build Coastguard Worker ProcessSampleRecordInTraceOffCpuMode(std::move(record), attr_id);
971*288bf522SAndroid Build Coastguard Worker }
972*288bf522SAndroid Build Coastguard Worker } else if (record->type() == PERF_RECORD_TRACING_DATA ||
973*288bf522SAndroid Build Coastguard Worker record->type() == SIMPLE_PERF_RECORD_TRACING_DATA) {
974*288bf522SAndroid Build Coastguard Worker const auto& r = *static_cast<TracingDataRecord*>(record.get());
975*288bf522SAndroid Build Coastguard Worker if (!ProcessTracingData(std::vector<char>(r.data, r.data + r.data_size))) {
976*288bf522SAndroid Build Coastguard Worker return false;
977*288bf522SAndroid Build Coastguard Worker }
978*288bf522SAndroid Build Coastguard Worker }
979*288bf522SAndroid Build Coastguard Worker return true;
980*288bf522SAndroid Build Coastguard Worker }
981*288bf522SAndroid Build Coastguard Worker
ProcessSampleRecordInTraceOffCpuMode(std::unique_ptr<Record> record,size_t attr_id)982*288bf522SAndroid Build Coastguard Worker void ReportCommand::ProcessSampleRecordInTraceOffCpuMode(std::unique_ptr<Record> record,
983*288bf522SAndroid Build Coastguard Worker size_t attr_id) {
984*288bf522SAndroid Build Coastguard Worker std::shared_ptr<SampleRecord> r(static_cast<SampleRecord*>(record.release()));
985*288bf522SAndroid Build Coastguard Worker if (attr_id == sched_switch_attr_id_) {
986*288bf522SAndroid Build Coastguard Worker // If this sample belongs to sched_switch event, we should broadcast the offcpu info
987*288bf522SAndroid Build Coastguard Worker // to other event types.
988*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < event_attrs_.size(); ++i) {
989*288bf522SAndroid Build Coastguard Worker if (i == sched_switch_attr_id_) {
990*288bf522SAndroid Build Coastguard Worker continue;
991*288bf522SAndroid Build Coastguard Worker }
992*288bf522SAndroid Build Coastguard Worker sample_tree_builder_[i]->ReportCmdProcessSampleRecord(r);
993*288bf522SAndroid Build Coastguard Worker }
994*288bf522SAndroid Build Coastguard Worker } else {
995*288bf522SAndroid Build Coastguard Worker sample_tree_builder_[attr_id]->ReportCmdProcessSampleRecord(r);
996*288bf522SAndroid Build Coastguard Worker }
997*288bf522SAndroid Build Coastguard Worker }
998*288bf522SAndroid Build Coastguard Worker
ProcessTracingData(const std::vector<char> & data)999*288bf522SAndroid Build Coastguard Worker bool ReportCommand::ProcessTracingData(const std::vector<char>& data) {
1000*288bf522SAndroid Build Coastguard Worker auto tracing = Tracing::Create(data);
1001*288bf522SAndroid Build Coastguard Worker if (!tracing) {
1002*288bf522SAndroid Build Coastguard Worker return false;
1003*288bf522SAndroid Build Coastguard Worker }
1004*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < event_attrs_.size(); i++) {
1005*288bf522SAndroid Build Coastguard Worker if (event_attrs_[i].type == PERF_TYPE_TRACEPOINT) {
1006*288bf522SAndroid Build Coastguard Worker uint64_t trace_event_id = event_attrs_[i].config;
1007*288bf522SAndroid Build Coastguard Worker attr_names_[i] = tracing->GetTracingEventNameHavingId(trace_event_id);
1008*288bf522SAndroid Build Coastguard Worker }
1009*288bf522SAndroid Build Coastguard Worker }
1010*288bf522SAndroid Build Coastguard Worker return true;
1011*288bf522SAndroid Build Coastguard Worker }
1012*288bf522SAndroid Build Coastguard Worker
PrintReport()1013*288bf522SAndroid Build Coastguard Worker bool ReportCommand::PrintReport() {
1014*288bf522SAndroid Build Coastguard Worker std::unique_ptr<FILE, decltype(&fclose)> file_handler(nullptr, fclose);
1015*288bf522SAndroid Build Coastguard Worker FILE* report_fp = stdout;
1016*288bf522SAndroid Build Coastguard Worker if (!report_filename_.empty()) {
1017*288bf522SAndroid Build Coastguard Worker report_fp = fopen(report_filename_.c_str(), "w");
1018*288bf522SAndroid Build Coastguard Worker if (report_fp == nullptr) {
1019*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "failed to open file " << report_filename_;
1020*288bf522SAndroid Build Coastguard Worker return false;
1021*288bf522SAndroid Build Coastguard Worker }
1022*288bf522SAndroid Build Coastguard Worker file_handler.reset(report_fp);
1023*288bf522SAndroid Build Coastguard Worker }
1024*288bf522SAndroid Build Coastguard Worker PrintReportContext(report_fp);
1025*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < event_attrs_.size(); ++i) {
1026*288bf522SAndroid Build Coastguard Worker if (trace_offcpu_ && i == sched_switch_attr_id_) {
1027*288bf522SAndroid Build Coastguard Worker continue;
1028*288bf522SAndroid Build Coastguard Worker }
1029*288bf522SAndroid Build Coastguard Worker if (i != 0) {
1030*288bf522SAndroid Build Coastguard Worker fprintf(report_fp, "\n");
1031*288bf522SAndroid Build Coastguard Worker }
1032*288bf522SAndroid Build Coastguard Worker SampleTree& sample_tree = sample_tree_[i];
1033*288bf522SAndroid Build Coastguard Worker fprintf(report_fp, "Event: %s (type %u, config %llu)\n", attr_names_[i].c_str(),
1034*288bf522SAndroid Build Coastguard Worker event_attrs_[i].type, event_attrs_[i].config);
1035*288bf522SAndroid Build Coastguard Worker fprintf(report_fp, "Samples: %" PRIu64 "\n", sample_tree.total_samples);
1036*288bf522SAndroid Build Coastguard Worker if (sample_tree.total_error_callchains != 0) {
1037*288bf522SAndroid Build Coastguard Worker fprintf(report_fp, "Error Callchains: %" PRIu64 ", %f%%\n",
1038*288bf522SAndroid Build Coastguard Worker sample_tree.total_error_callchains,
1039*288bf522SAndroid Build Coastguard Worker sample_tree.total_error_callchains * 100.0 / sample_tree.total_samples);
1040*288bf522SAndroid Build Coastguard Worker }
1041*288bf522SAndroid Build Coastguard Worker const char* period_prefix = trace_offcpu_ ? "Time in ns" : "Event count";
1042*288bf522SAndroid Build Coastguard Worker fprintf(report_fp, "%s: %" PRIu64 "\n\n", period_prefix, sample_tree.total_period);
1043*288bf522SAndroid Build Coastguard Worker sample_tree_displayer_->DisplaySamples(report_fp, sample_tree.samples, &sample_tree);
1044*288bf522SAndroid Build Coastguard Worker }
1045*288bf522SAndroid Build Coastguard Worker fflush(report_fp);
1046*288bf522SAndroid Build Coastguard Worker if (ferror(report_fp) != 0) {
1047*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "print report failed";
1048*288bf522SAndroid Build Coastguard Worker return false;
1049*288bf522SAndroid Build Coastguard Worker }
1050*288bf522SAndroid Build Coastguard Worker return true;
1051*288bf522SAndroid Build Coastguard Worker }
1052*288bf522SAndroid Build Coastguard Worker
PrintReportContext(FILE * report_fp)1053*288bf522SAndroid Build Coastguard Worker void ReportCommand::PrintReportContext(FILE* report_fp) {
1054*288bf522SAndroid Build Coastguard Worker if (!record_cmdline_.empty()) {
1055*288bf522SAndroid Build Coastguard Worker fprintf(report_fp, "Cmdline: %s\n", record_cmdline_.c_str());
1056*288bf522SAndroid Build Coastguard Worker }
1057*288bf522SAndroid Build Coastguard Worker fprintf(report_fp, "Arch: %s\n", GetArchString(record_file_arch_).c_str());
1058*288bf522SAndroid Build Coastguard Worker }
1059*288bf522SAndroid Build Coastguard Worker
1060*288bf522SAndroid Build Coastguard Worker } // namespace
1061*288bf522SAndroid Build Coastguard Worker
RegisterReportCommand()1062*288bf522SAndroid Build Coastguard Worker void RegisterReportCommand() {
1063*288bf522SAndroid Build Coastguard Worker RegisterCommand("report", [] { return std::unique_ptr<Command>(new ReportCommand()); });
1064*288bf522SAndroid Build Coastguard Worker }
1065*288bf522SAndroid Build Coastguard Worker
1066*288bf522SAndroid Build Coastguard Worker } // namespace simpleperf
1067