1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2018 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 <stdio.h>
18*288bf522SAndroid Build Coastguard Worker
19*288bf522SAndroid Build Coastguard Worker #include <algorithm>
20*288bf522SAndroid Build Coastguard Worker #include <memory>
21*288bf522SAndroid Build Coastguard Worker #include <string>
22*288bf522SAndroid Build Coastguard Worker #include <unordered_map>
23*288bf522SAndroid Build Coastguard Worker #include <unordered_set>
24*288bf522SAndroid Build Coastguard Worker #include <vector>
25*288bf522SAndroid Build Coastguard Worker
26*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
27*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
28*288bf522SAndroid Build Coastguard Worker #include <android-base/parseint.h>
29*288bf522SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
30*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
31*288bf522SAndroid Build Coastguard Worker
32*288bf522SAndroid Build Coastguard Worker #include "JITDebugReader.h"
33*288bf522SAndroid Build Coastguard Worker #include "OfflineUnwinder.h"
34*288bf522SAndroid Build Coastguard Worker #include "command.h"
35*288bf522SAndroid Build Coastguard Worker #include "environment.h"
36*288bf522SAndroid Build Coastguard Worker #include "perf_regs.h"
37*288bf522SAndroid Build Coastguard Worker #include "record_file.h"
38*288bf522SAndroid Build Coastguard Worker #include "report_utils.h"
39*288bf522SAndroid Build Coastguard Worker #include "thread_tree.h"
40*288bf522SAndroid Build Coastguard Worker #include "utils.h"
41*288bf522SAndroid Build Coastguard Worker
42*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
43*288bf522SAndroid Build Coastguard Worker namespace {
44*288bf522SAndroid Build Coastguard Worker
45*288bf522SAndroid Build Coastguard Worker struct MemStat {
46*288bf522SAndroid Build Coastguard Worker std::string vm_peak;
47*288bf522SAndroid Build Coastguard Worker std::string vm_size;
48*288bf522SAndroid Build Coastguard Worker std::string vm_hwm;
49*288bf522SAndroid Build Coastguard Worker std::string vm_rss;
50*288bf522SAndroid Build Coastguard Worker
ToStringsimpleperf::__anon8518cc540111::MemStat51*288bf522SAndroid Build Coastguard Worker std::string ToString() const {
52*288bf522SAndroid Build Coastguard Worker return android::base::StringPrintf("VmPeak:%s;VmSize:%s;VmHWM:%s;VmRSS:%s", vm_peak.c_str(),
53*288bf522SAndroid Build Coastguard Worker vm_size.c_str(), vm_hwm.c_str(), vm_rss.c_str());
54*288bf522SAndroid Build Coastguard Worker }
55*288bf522SAndroid Build Coastguard Worker };
56*288bf522SAndroid Build Coastguard Worker
GetMemStat(MemStat * stat)57*288bf522SAndroid Build Coastguard Worker static bool GetMemStat(MemStat* stat) {
58*288bf522SAndroid Build Coastguard Worker std::string s;
59*288bf522SAndroid Build Coastguard Worker if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/status", getpid()),
60*288bf522SAndroid Build Coastguard Worker &s)) {
61*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to read process status";
62*288bf522SAndroid Build Coastguard Worker return false;
63*288bf522SAndroid Build Coastguard Worker }
64*288bf522SAndroid Build Coastguard Worker std::vector<std::string> lines = android::base::Split(s, "\n");
65*288bf522SAndroid Build Coastguard Worker for (auto& line : lines) {
66*288bf522SAndroid Build Coastguard Worker if (android::base::StartsWith(line, "VmPeak:")) {
67*288bf522SAndroid Build Coastguard Worker stat->vm_peak = android::base::Trim(line.substr(strlen("VmPeak:")));
68*288bf522SAndroid Build Coastguard Worker } else if (android::base::StartsWith(line, "VmSize:")) {
69*288bf522SAndroid Build Coastguard Worker stat->vm_size = android::base::Trim(line.substr(strlen("VmSize:")));
70*288bf522SAndroid Build Coastguard Worker } else if (android::base::StartsWith(line, "VmHWM:")) {
71*288bf522SAndroid Build Coastguard Worker stat->vm_hwm = android::base::Trim(line.substr(strlen("VmHWM:")));
72*288bf522SAndroid Build Coastguard Worker } else if (android::base::StartsWith(line, "VmRSS:")) {
73*288bf522SAndroid Build Coastguard Worker stat->vm_rss = android::base::Trim(line.substr(strlen("VmRSS:")));
74*288bf522SAndroid Build Coastguard Worker }
75*288bf522SAndroid Build Coastguard Worker }
76*288bf522SAndroid Build Coastguard Worker return true;
77*288bf522SAndroid Build Coastguard Worker }
78*288bf522SAndroid Build Coastguard Worker
79*288bf522SAndroid Build Coastguard Worker struct UnwindingStat {
80*288bf522SAndroid Build Coastguard Worker // For testing unwinding performance
81*288bf522SAndroid Build Coastguard Worker uint64_t unwinding_sample_count = 0u;
82*288bf522SAndroid Build Coastguard Worker uint64_t total_unwinding_time_in_ns = 0u;
83*288bf522SAndroid Build Coastguard Worker uint64_t max_unwinding_time_in_ns = 0u;
84*288bf522SAndroid Build Coastguard Worker
85*288bf522SAndroid Build Coastguard Worker // For memory consumption
86*288bf522SAndroid Build Coastguard Worker MemStat mem_before_unwinding;
87*288bf522SAndroid Build Coastguard Worker MemStat mem_after_unwinding;
88*288bf522SAndroid Build Coastguard Worker
AddUnwindingResultsimpleperf::__anon8518cc540111::UnwindingStat89*288bf522SAndroid Build Coastguard Worker void AddUnwindingResult(const UnwindingResult& result) {
90*288bf522SAndroid Build Coastguard Worker unwinding_sample_count++;
91*288bf522SAndroid Build Coastguard Worker total_unwinding_time_in_ns += result.used_time;
92*288bf522SAndroid Build Coastguard Worker max_unwinding_time_in_ns = std::max(max_unwinding_time_in_ns, result.used_time);
93*288bf522SAndroid Build Coastguard Worker }
94*288bf522SAndroid Build Coastguard Worker
Dumpsimpleperf::__anon8518cc540111::UnwindingStat95*288bf522SAndroid Build Coastguard Worker void Dump(FILE* fp) {
96*288bf522SAndroid Build Coastguard Worker if (unwinding_sample_count == 0) {
97*288bf522SAndroid Build Coastguard Worker return;
98*288bf522SAndroid Build Coastguard Worker }
99*288bf522SAndroid Build Coastguard Worker fprintf(fp, "unwinding_sample_count: %" PRIu64 "\n", unwinding_sample_count);
100*288bf522SAndroid Build Coastguard Worker fprintf(fp, "average_unwinding_time: %.3f us\n",
101*288bf522SAndroid Build Coastguard Worker total_unwinding_time_in_ns / 1e3 / unwinding_sample_count);
102*288bf522SAndroid Build Coastguard Worker fprintf(fp, "max_unwinding_time: %.3f us\n", max_unwinding_time_in_ns / 1e3);
103*288bf522SAndroid Build Coastguard Worker
104*288bf522SAndroid Build Coastguard Worker if (!mem_before_unwinding.vm_peak.empty()) {
105*288bf522SAndroid Build Coastguard Worker fprintf(fp, "memory_change_VmPeak: %s -> %s\n", mem_before_unwinding.vm_peak.c_str(),
106*288bf522SAndroid Build Coastguard Worker mem_after_unwinding.vm_peak.c_str());
107*288bf522SAndroid Build Coastguard Worker fprintf(fp, "memory_change_VmSize: %s -> %s\n", mem_before_unwinding.vm_size.c_str(),
108*288bf522SAndroid Build Coastguard Worker mem_after_unwinding.vm_size.c_str());
109*288bf522SAndroid Build Coastguard Worker fprintf(fp, "memory_change_VmHwM: %s -> %s\n", mem_before_unwinding.vm_hwm.c_str(),
110*288bf522SAndroid Build Coastguard Worker mem_after_unwinding.vm_hwm.c_str());
111*288bf522SAndroid Build Coastguard Worker fprintf(fp, "memory_change_VmRSS: %s -> %s\n", mem_before_unwinding.vm_rss.c_str(),
112*288bf522SAndroid Build Coastguard Worker mem_after_unwinding.vm_rss.c_str());
113*288bf522SAndroid Build Coastguard Worker }
114*288bf522SAndroid Build Coastguard Worker }
115*288bf522SAndroid Build Coastguard Worker };
116*288bf522SAndroid Build Coastguard Worker
117*288bf522SAndroid Build Coastguard Worker class RecordFileProcessor {
118*288bf522SAndroid Build Coastguard Worker public:
RecordFileProcessor(const std::string & output_filename,bool output_binary_mode)119*288bf522SAndroid Build Coastguard Worker RecordFileProcessor(const std::string& output_filename, bool output_binary_mode)
120*288bf522SAndroid Build Coastguard Worker : output_filename_(output_filename),
121*288bf522SAndroid Build Coastguard Worker output_binary_mode_(output_binary_mode),
122*288bf522SAndroid Build Coastguard Worker unwinder_(OfflineUnwinder::Create(true)),
123*288bf522SAndroid Build Coastguard Worker callchain_report_builder_(thread_tree_) {}
124*288bf522SAndroid Build Coastguard Worker
~RecordFileProcessor()125*288bf522SAndroid Build Coastguard Worker virtual ~RecordFileProcessor() {
126*288bf522SAndroid Build Coastguard Worker if (out_fp_ != nullptr && out_fp_ != stdout) {
127*288bf522SAndroid Build Coastguard Worker fclose(out_fp_);
128*288bf522SAndroid Build Coastguard Worker }
129*288bf522SAndroid Build Coastguard Worker }
130*288bf522SAndroid Build Coastguard Worker
ProcessFile(const std::string & input_filename)131*288bf522SAndroid Build Coastguard Worker bool ProcessFile(const std::string& input_filename) {
132*288bf522SAndroid Build Coastguard Worker // 1. Check input file.
133*288bf522SAndroid Build Coastguard Worker record_filename_ = input_filename;
134*288bf522SAndroid Build Coastguard Worker reader_ = RecordFileReader::CreateInstance(record_filename_);
135*288bf522SAndroid Build Coastguard Worker if (!reader_) {
136*288bf522SAndroid Build Coastguard Worker return false;
137*288bf522SAndroid Build Coastguard Worker }
138*288bf522SAndroid Build Coastguard Worker std::string record_cmd = android::base::Join(reader_->ReadCmdlineFeature(), " ");
139*288bf522SAndroid Build Coastguard Worker if (record_cmd.find("-g") == std::string::npos &&
140*288bf522SAndroid Build Coastguard Worker record_cmd.find("--call-graph dwarf") == std::string::npos) {
141*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "file isn't recorded with dwarf call graph: " << record_filename_;
142*288bf522SAndroid Build Coastguard Worker return false;
143*288bf522SAndroid Build Coastguard Worker }
144*288bf522SAndroid Build Coastguard Worker if (!CheckRecordCmd(record_cmd)) {
145*288bf522SAndroid Build Coastguard Worker return false;
146*288bf522SAndroid Build Coastguard Worker }
147*288bf522SAndroid Build Coastguard Worker
148*288bf522SAndroid Build Coastguard Worker // 2. Load feature sections.
149*288bf522SAndroid Build Coastguard Worker if (!reader_->LoadBuildIdAndFileFeatures(thread_tree_)) {
150*288bf522SAndroid Build Coastguard Worker return false;
151*288bf522SAndroid Build Coastguard Worker }
152*288bf522SAndroid Build Coastguard Worker ScopedCurrentArch scoped_arch(
153*288bf522SAndroid Build Coastguard Worker GetArchType(reader_->ReadFeatureString(PerfFileFormat::FEAT_ARCH)));
154*288bf522SAndroid Build Coastguard Worker unwinder_->LoadMetaInfo(reader_->GetMetaInfoFeature());
155*288bf522SAndroid Build Coastguard Worker if (reader_->HasFeature(PerfFileFormat::FEAT_DEBUG_UNWIND) &&
156*288bf522SAndroid Build Coastguard Worker reader_->HasFeature(PerfFileFormat::FEAT_DEBUG_UNWIND_FILE)) {
157*288bf522SAndroid Build Coastguard Worker auto debug_unwind_feature = reader_->ReadDebugUnwindFeature();
158*288bf522SAndroid Build Coastguard Worker if (!debug_unwind_feature.has_value()) {
159*288bf522SAndroid Build Coastguard Worker return false;
160*288bf522SAndroid Build Coastguard Worker }
161*288bf522SAndroid Build Coastguard Worker uint64_t offset =
162*288bf522SAndroid Build Coastguard Worker reader_->FeatureSectionDescriptors().at(PerfFileFormat::FEAT_DEBUG_UNWIND_FILE).offset;
163*288bf522SAndroid Build Coastguard Worker for (DebugUnwindFile& file : debug_unwind_feature.value()) {
164*288bf522SAndroid Build Coastguard Worker auto& loc = debug_unwind_files_[file.path];
165*288bf522SAndroid Build Coastguard Worker loc.offset = offset;
166*288bf522SAndroid Build Coastguard Worker loc.size = file.size;
167*288bf522SAndroid Build Coastguard Worker offset += file.size;
168*288bf522SAndroid Build Coastguard Worker }
169*288bf522SAndroid Build Coastguard Worker }
170*288bf522SAndroid Build Coastguard Worker callchain_report_builder_.SetRemoveArtFrame(false);
171*288bf522SAndroid Build Coastguard Worker callchain_report_builder_.SetConvertJITFrame(false);
172*288bf522SAndroid Build Coastguard Worker
173*288bf522SAndroid Build Coastguard Worker // 3. Open output file.
174*288bf522SAndroid Build Coastguard Worker if (output_filename_.empty()) {
175*288bf522SAndroid Build Coastguard Worker out_fp_ = stdout;
176*288bf522SAndroid Build Coastguard Worker } else {
177*288bf522SAndroid Build Coastguard Worker out_fp_ = fopen(output_filename_.c_str(), output_binary_mode_ ? "web+" : "we+");
178*288bf522SAndroid Build Coastguard Worker if (out_fp_ == nullptr) {
179*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "failed to write to " << output_filename_;
180*288bf522SAndroid Build Coastguard Worker return false;
181*288bf522SAndroid Build Coastguard Worker }
182*288bf522SAndroid Build Coastguard Worker }
183*288bf522SAndroid Build Coastguard Worker
184*288bf522SAndroid Build Coastguard Worker // 4. Process records.
185*288bf522SAndroid Build Coastguard Worker return Process();
186*288bf522SAndroid Build Coastguard Worker }
187*288bf522SAndroid Build Coastguard Worker
188*288bf522SAndroid Build Coastguard Worker protected:
189*288bf522SAndroid Build Coastguard Worker struct DebugUnwindFileLocation {
190*288bf522SAndroid Build Coastguard Worker uint64_t offset;
191*288bf522SAndroid Build Coastguard Worker uint64_t size;
192*288bf522SAndroid Build Coastguard Worker };
193*288bf522SAndroid Build Coastguard Worker
194*288bf522SAndroid Build Coastguard Worker virtual bool CheckRecordCmd(const std::string& record_cmd) = 0;
195*288bf522SAndroid Build Coastguard Worker virtual bool Process() = 0;
196*288bf522SAndroid Build Coastguard Worker
197*288bf522SAndroid Build Coastguard Worker std::string record_filename_;
198*288bf522SAndroid Build Coastguard Worker std::unique_ptr<RecordFileReader> reader_;
199*288bf522SAndroid Build Coastguard Worker std::string output_filename_;
200*288bf522SAndroid Build Coastguard Worker bool output_binary_mode_;
201*288bf522SAndroid Build Coastguard Worker FILE* out_fp_ = nullptr;
202*288bf522SAndroid Build Coastguard Worker ThreadTree thread_tree_;
203*288bf522SAndroid Build Coastguard Worker std::unique_ptr<OfflineUnwinder> unwinder_;
204*288bf522SAndroid Build Coastguard Worker // Files stored in DEBUG_UNWIND_FILE feature section in the recording file.
205*288bf522SAndroid Build Coastguard Worker // Map from file path to offset in the recording file.
206*288bf522SAndroid Build Coastguard Worker std::unordered_map<std::string, DebugUnwindFileLocation> debug_unwind_files_;
207*288bf522SAndroid Build Coastguard Worker CallChainReportBuilder callchain_report_builder_;
208*288bf522SAndroid Build Coastguard Worker };
209*288bf522SAndroid Build Coastguard Worker
DumpUnwindingResult(const UnwindingResult & result,FILE * fp)210*288bf522SAndroid Build Coastguard Worker static void DumpUnwindingResult(const UnwindingResult& result, FILE* fp) {
211*288bf522SAndroid Build Coastguard Worker fprintf(fp, "unwinding_used_time: %.3f us\n", result.used_time / 1e3);
212*288bf522SAndroid Build Coastguard Worker fprintf(fp, "unwinding_error_code: %" PRIu64 "\n", result.error_code);
213*288bf522SAndroid Build Coastguard Worker fprintf(fp, "unwinding_error_addr: 0x%" PRIx64 "\n", result.error_addr);
214*288bf522SAndroid Build Coastguard Worker fprintf(fp, "stack_start: 0x%" PRIx64 "\n", result.stack_start);
215*288bf522SAndroid Build Coastguard Worker fprintf(fp, "stack_end: 0x%" PRIx64 "\n", result.stack_end);
216*288bf522SAndroid Build Coastguard Worker }
217*288bf522SAndroid Build Coastguard Worker
218*288bf522SAndroid Build Coastguard Worker class SampleUnwinder : public RecordFileProcessor {
219*288bf522SAndroid Build Coastguard Worker public:
SampleUnwinder(const std::string & output_filename,const std::unordered_set<uint64_t> & sample_times,bool skip_sample_print)220*288bf522SAndroid Build Coastguard Worker SampleUnwinder(const std::string& output_filename,
221*288bf522SAndroid Build Coastguard Worker const std::unordered_set<uint64_t>& sample_times, bool skip_sample_print)
222*288bf522SAndroid Build Coastguard Worker : RecordFileProcessor(output_filename, false),
223*288bf522SAndroid Build Coastguard Worker sample_times_(sample_times),
224*288bf522SAndroid Build Coastguard Worker skip_sample_print_(skip_sample_print) {}
225*288bf522SAndroid Build Coastguard Worker
226*288bf522SAndroid Build Coastguard Worker protected:
CheckRecordCmd(const std::string & record_cmd)227*288bf522SAndroid Build Coastguard Worker bool CheckRecordCmd(const std::string& record_cmd) override {
228*288bf522SAndroid Build Coastguard Worker if (record_cmd.find("--no-unwind") == std::string::npos &&
229*288bf522SAndroid Build Coastguard Worker record_cmd.find("--keep-failed-unwinding-debug-info") == std::string::npos) {
230*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "file isn't record with --no-unwind or --keep-failed-unwinding-debug-info: "
231*288bf522SAndroid Build Coastguard Worker << record_filename_;
232*288bf522SAndroid Build Coastguard Worker return false;
233*288bf522SAndroid Build Coastguard Worker }
234*288bf522SAndroid Build Coastguard Worker return true;
235*288bf522SAndroid Build Coastguard Worker }
236*288bf522SAndroid Build Coastguard Worker
Process()237*288bf522SAndroid Build Coastguard Worker bool Process() override {
238*288bf522SAndroid Build Coastguard Worker if (!GetMemStat(&stat_.mem_before_unwinding)) {
239*288bf522SAndroid Build Coastguard Worker return false;
240*288bf522SAndroid Build Coastguard Worker }
241*288bf522SAndroid Build Coastguard Worker if (!reader_->ReadDataSection(
242*288bf522SAndroid Build Coastguard Worker [&](std::unique_ptr<Record> r) { return ProcessRecord(std::move(r)); })) {
243*288bf522SAndroid Build Coastguard Worker return false;
244*288bf522SAndroid Build Coastguard Worker }
245*288bf522SAndroid Build Coastguard Worker if (!GetMemStat(&stat_.mem_after_unwinding)) {
246*288bf522SAndroid Build Coastguard Worker return false;
247*288bf522SAndroid Build Coastguard Worker }
248*288bf522SAndroid Build Coastguard Worker stat_.Dump(out_fp_);
249*288bf522SAndroid Build Coastguard Worker return true;
250*288bf522SAndroid Build Coastguard Worker }
251*288bf522SAndroid Build Coastguard Worker
ProcessRecord(std::unique_ptr<Record> r)252*288bf522SAndroid Build Coastguard Worker bool ProcessRecord(std::unique_ptr<Record> r) {
253*288bf522SAndroid Build Coastguard Worker UpdateRecord(r.get());
254*288bf522SAndroid Build Coastguard Worker thread_tree_.Update(*r);
255*288bf522SAndroid Build Coastguard Worker if (r->type() == SIMPLE_PERF_RECORD_UNWINDING_RESULT) {
256*288bf522SAndroid Build Coastguard Worker last_unwinding_result_.reset(static_cast<UnwindingResultRecord*>(r.release()));
257*288bf522SAndroid Build Coastguard Worker } else if (r->type() == PERF_RECORD_SAMPLE) {
258*288bf522SAndroid Build Coastguard Worker if (sample_times_.empty() || sample_times_.count(r->Timestamp())) {
259*288bf522SAndroid Build Coastguard Worker auto& sr = *static_cast<SampleRecord*>(r.get());
260*288bf522SAndroid Build Coastguard Worker const PerfSampleStackUserType* stack = &sr.stack_user_data;
261*288bf522SAndroid Build Coastguard Worker const PerfSampleRegsUserType* regs = &sr.regs_user_data;
262*288bf522SAndroid Build Coastguard Worker if (last_unwinding_result_ && last_unwinding_result_->Timestamp() == sr.Timestamp()) {
263*288bf522SAndroid Build Coastguard Worker stack = &last_unwinding_result_->stack_user_data;
264*288bf522SAndroid Build Coastguard Worker regs = &last_unwinding_result_->regs_user_data;
265*288bf522SAndroid Build Coastguard Worker }
266*288bf522SAndroid Build Coastguard Worker if (stack->size > 0 || regs->reg_mask > 0) {
267*288bf522SAndroid Build Coastguard Worker if (!UnwindRecord(sr, *regs, *stack)) {
268*288bf522SAndroid Build Coastguard Worker return false;
269*288bf522SAndroid Build Coastguard Worker }
270*288bf522SAndroid Build Coastguard Worker }
271*288bf522SAndroid Build Coastguard Worker }
272*288bf522SAndroid Build Coastguard Worker last_unwinding_result_.reset();
273*288bf522SAndroid Build Coastguard Worker }
274*288bf522SAndroid Build Coastguard Worker return true;
275*288bf522SAndroid Build Coastguard Worker }
276*288bf522SAndroid Build Coastguard Worker
UpdateRecord(Record * record)277*288bf522SAndroid Build Coastguard Worker void UpdateRecord(Record* record) {
278*288bf522SAndroid Build Coastguard Worker if (record->type() == PERF_RECORD_MMAP) {
279*288bf522SAndroid Build Coastguard Worker UpdateMmapRecordForEmbeddedFiles(*static_cast<MmapRecord*>(record));
280*288bf522SAndroid Build Coastguard Worker } else if (record->type() == PERF_RECORD_MMAP2) {
281*288bf522SAndroid Build Coastguard Worker UpdateMmapRecordForEmbeddedFiles(*static_cast<Mmap2Record*>(record));
282*288bf522SAndroid Build Coastguard Worker }
283*288bf522SAndroid Build Coastguard Worker }
284*288bf522SAndroid Build Coastguard Worker
285*288bf522SAndroid Build Coastguard Worker template <typename MmapRecordType>
UpdateMmapRecordForEmbeddedFiles(MmapRecordType & record)286*288bf522SAndroid Build Coastguard Worker void UpdateMmapRecordForEmbeddedFiles(MmapRecordType& record) {
287*288bf522SAndroid Build Coastguard Worker // Modify mmap records to point to files stored in DEBUG_UNWIND_FILE feature section.
288*288bf522SAndroid Build Coastguard Worker std::string filename = record.filename;
289*288bf522SAndroid Build Coastguard Worker if (auto it = debug_unwind_files_.find(filename); it != debug_unwind_files_.end()) {
290*288bf522SAndroid Build Coastguard Worker auto data = *record.data;
291*288bf522SAndroid Build Coastguard Worker uint64_t old_pgoff = data.pgoff;
292*288bf522SAndroid Build Coastguard Worker if (JITDebugReader::IsPathInJITSymFile(filename)) {
293*288bf522SAndroid Build Coastguard Worker data.pgoff = it->second.offset;
294*288bf522SAndroid Build Coastguard Worker } else {
295*288bf522SAndroid Build Coastguard Worker data.pgoff += it->second.offset;
296*288bf522SAndroid Build Coastguard Worker }
297*288bf522SAndroid Build Coastguard Worker debug_unwind_dsos_[data.pgoff] =
298*288bf522SAndroid Build Coastguard Worker std::make_pair(thread_tree_.FindUserDsoOrNew(filename), old_pgoff);
299*288bf522SAndroid Build Coastguard Worker record.SetDataAndFilename(data, record_filename_);
300*288bf522SAndroid Build Coastguard Worker }
301*288bf522SAndroid Build Coastguard Worker }
302*288bf522SAndroid Build Coastguard Worker
UnwindRecord(const SampleRecord & r,const PerfSampleRegsUserType & regs,const PerfSampleStackUserType & stack)303*288bf522SAndroid Build Coastguard Worker bool UnwindRecord(const SampleRecord& r, const PerfSampleRegsUserType& regs,
304*288bf522SAndroid Build Coastguard Worker const PerfSampleStackUserType& stack) {
305*288bf522SAndroid Build Coastguard Worker ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
306*288bf522SAndroid Build Coastguard Worker
307*288bf522SAndroid Build Coastguard Worker RegSet reg_set(regs.abi, regs.reg_mask, regs.regs);
308*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> ips;
309*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> sps;
310*288bf522SAndroid Build Coastguard Worker if (!unwinder_->UnwindCallChain(*thread, reg_set, stack.data, stack.size, &ips, &sps)) {
311*288bf522SAndroid Build Coastguard Worker return false;
312*288bf522SAndroid Build Coastguard Worker }
313*288bf522SAndroid Build Coastguard Worker stat_.AddUnwindingResult(unwinder_->GetUnwindingResult());
314*288bf522SAndroid Build Coastguard Worker
315*288bf522SAndroid Build Coastguard Worker if (!skip_sample_print_) {
316*288bf522SAndroid Build Coastguard Worker // Print unwinding result.
317*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "sample_time: %" PRIu64 "\n", r.Timestamp());
318*288bf522SAndroid Build Coastguard Worker DumpUnwindingResult(unwinder_->GetUnwindingResult(), out_fp_);
319*288bf522SAndroid Build Coastguard Worker std::vector<CallChainReportEntry> entries = callchain_report_builder_.Build(thread, ips, 0);
320*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < entries.size(); i++) {
321*288bf522SAndroid Build Coastguard Worker size_t id = i + 1;
322*288bf522SAndroid Build Coastguard Worker auto& entry = entries[i];
323*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "ip_%zu: 0x%" PRIx64 "\n", id, entry.ip);
324*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "sp_%zu: 0x%" PRIx64 "\n", id, sps[i]);
325*288bf522SAndroid Build Coastguard Worker
326*288bf522SAndroid Build Coastguard Worker Dso* dso = entry.map->dso;
327*288bf522SAndroid Build Coastguard Worker uint64_t pgoff = entry.map->pgoff;
328*288bf522SAndroid Build Coastguard Worker if (dso->Path() == record_filename_) {
329*288bf522SAndroid Build Coastguard Worker auto it = debug_unwind_dsos_.find(entry.map->pgoff);
330*288bf522SAndroid Build Coastguard Worker CHECK(it != debug_unwind_dsos_.end());
331*288bf522SAndroid Build Coastguard Worker const auto& p = it->second;
332*288bf522SAndroid Build Coastguard Worker dso = p.first;
333*288bf522SAndroid Build Coastguard Worker pgoff = p.second;
334*288bf522SAndroid Build Coastguard Worker if (!JITDebugReader::IsPathInJITSymFile(dso->Path())) {
335*288bf522SAndroid Build Coastguard Worker entry.vaddr_in_file = dso->IpToVaddrInFile(entry.ip, entry.map->start_addr, pgoff);
336*288bf522SAndroid Build Coastguard Worker }
337*288bf522SAndroid Build Coastguard Worker entry.symbol = dso->FindSymbol(entry.vaddr_in_file);
338*288bf522SAndroid Build Coastguard Worker }
339*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "map_%zu: [0x%" PRIx64 "-0x%" PRIx64 "], pgoff 0x%" PRIx64 "\n", id,
340*288bf522SAndroid Build Coastguard Worker entry.map->start_addr, entry.map->get_end_addr(), pgoff);
341*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "dso_%zu: %s\n", id, dso->Path().c_str());
342*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "vaddr_in_file_%zu: 0x%" PRIx64 "\n", id, entry.vaddr_in_file);
343*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "symbol_%zu: %s\n", id, entry.symbol->DemangledName());
344*288bf522SAndroid Build Coastguard Worker }
345*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "\n");
346*288bf522SAndroid Build Coastguard Worker }
347*288bf522SAndroid Build Coastguard Worker return true;
348*288bf522SAndroid Build Coastguard Worker }
349*288bf522SAndroid Build Coastguard Worker
350*288bf522SAndroid Build Coastguard Worker private:
351*288bf522SAndroid Build Coastguard Worker const std::unordered_set<uint64_t> sample_times_;
352*288bf522SAndroid Build Coastguard Worker bool skip_sample_print_;
353*288bf522SAndroid Build Coastguard Worker // Map from offset in recording file to the corresponding debug_unwind_file.
354*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint64_t, std::pair<Dso*, uint64_t>> debug_unwind_dsos_;
355*288bf522SAndroid Build Coastguard Worker UnwindingStat stat_;
356*288bf522SAndroid Build Coastguard Worker std::unique_ptr<UnwindingResultRecord> last_unwinding_result_;
357*288bf522SAndroid Build Coastguard Worker };
358*288bf522SAndroid Build Coastguard Worker
359*288bf522SAndroid Build Coastguard Worker class TestFileGenerator : public RecordFileProcessor {
360*288bf522SAndroid Build Coastguard Worker public:
TestFileGenerator(const std::string & output_filename,const std::unordered_set<uint64_t> & sample_times,const std::unordered_set<std::string> & kept_binaries)361*288bf522SAndroid Build Coastguard Worker TestFileGenerator(const std::string& output_filename,
362*288bf522SAndroid Build Coastguard Worker const std::unordered_set<uint64_t>& sample_times,
363*288bf522SAndroid Build Coastguard Worker const std::unordered_set<std::string>& kept_binaries)
364*288bf522SAndroid Build Coastguard Worker : RecordFileProcessor(output_filename, true),
365*288bf522SAndroid Build Coastguard Worker sample_times_(sample_times),
366*288bf522SAndroid Build Coastguard Worker kept_binaries_(kept_binaries) {}
367*288bf522SAndroid Build Coastguard Worker
368*288bf522SAndroid Build Coastguard Worker protected:
CheckRecordCmd(const std::string &)369*288bf522SAndroid Build Coastguard Worker bool CheckRecordCmd(const std::string&) override { return true; }
370*288bf522SAndroid Build Coastguard Worker
Process()371*288bf522SAndroid Build Coastguard Worker bool Process() override {
372*288bf522SAndroid Build Coastguard Worker writer_.reset(new RecordFileWriter(output_filename_, out_fp_, false));
373*288bf522SAndroid Build Coastguard Worker if (!writer_ || !writer_->WriteAttrSection(reader_->AttrSection())) {
374*288bf522SAndroid Build Coastguard Worker return false;
375*288bf522SAndroid Build Coastguard Worker }
376*288bf522SAndroid Build Coastguard Worker if (!reader_->ReadDataSection(
377*288bf522SAndroid Build Coastguard Worker [&](std::unique_ptr<Record> r) { return ProcessRecord(std::move(r)); })) {
378*288bf522SAndroid Build Coastguard Worker return false;
379*288bf522SAndroid Build Coastguard Worker }
380*288bf522SAndroid Build Coastguard Worker return WriteFeatureSections();
381*288bf522SAndroid Build Coastguard Worker }
382*288bf522SAndroid Build Coastguard Worker
ProcessRecord(std::unique_ptr<Record> r)383*288bf522SAndroid Build Coastguard Worker bool ProcessRecord(std::unique_ptr<Record> r) {
384*288bf522SAndroid Build Coastguard Worker thread_tree_.Update(*r);
385*288bf522SAndroid Build Coastguard Worker bool keep_record = false;
386*288bf522SAndroid Build Coastguard Worker if (r->type() == SIMPLE_PERF_RECORD_UNWINDING_RESULT) {
387*288bf522SAndroid Build Coastguard Worker keep_record = (sample_times_.count(r->Timestamp()) > 0);
388*288bf522SAndroid Build Coastguard Worker } else if (r->type() == PERF_RECORD_SAMPLE) {
389*288bf522SAndroid Build Coastguard Worker keep_record = (sample_times_.count(r->Timestamp()) > 0);
390*288bf522SAndroid Build Coastguard Worker if (keep_record) {
391*288bf522SAndroid Build Coastguard Worker // Dump maps needed to unwind this sample.
392*288bf522SAndroid Build Coastguard Worker if (!WriteMapsForSample(*static_cast<SampleRecord*>(r.get()))) {
393*288bf522SAndroid Build Coastguard Worker return false;
394*288bf522SAndroid Build Coastguard Worker }
395*288bf522SAndroid Build Coastguard Worker }
396*288bf522SAndroid Build Coastguard Worker }
397*288bf522SAndroid Build Coastguard Worker if (keep_record) {
398*288bf522SAndroid Build Coastguard Worker return writer_->WriteRecord(*r);
399*288bf522SAndroid Build Coastguard Worker }
400*288bf522SAndroid Build Coastguard Worker return true;
401*288bf522SAndroid Build Coastguard Worker }
402*288bf522SAndroid Build Coastguard Worker
WriteMapsForSample(const SampleRecord & r)403*288bf522SAndroid Build Coastguard Worker bool WriteMapsForSample(const SampleRecord& r) {
404*288bf522SAndroid Build Coastguard Worker ThreadEntry* thread = thread_tree_.FindThread(r.tid_data.tid);
405*288bf522SAndroid Build Coastguard Worker if (thread != nullptr && thread->maps) {
406*288bf522SAndroid Build Coastguard Worker const EventAttrIds& attrs = reader_->AttrSection();
407*288bf522SAndroid Build Coastguard Worker const perf_event_attr& attr = attrs[0].attr;
408*288bf522SAndroid Build Coastguard Worker uint64_t event_id = attrs[0].ids[0];
409*288bf522SAndroid Build Coastguard Worker
410*288bf522SAndroid Build Coastguard Worker for (const auto& p : thread->maps->maps) {
411*288bf522SAndroid Build Coastguard Worker const MapEntry* map = p.second;
412*288bf522SAndroid Build Coastguard Worker Mmap2Record map_record(attr, false, r.tid_data.pid, r.tid_data.tid, map->start_addr,
413*288bf522SAndroid Build Coastguard Worker map->len, map->pgoff, map->flags, map->dso->Path(), event_id,
414*288bf522SAndroid Build Coastguard Worker r.Timestamp());
415*288bf522SAndroid Build Coastguard Worker if (!writer_->WriteRecord(map_record)) {
416*288bf522SAndroid Build Coastguard Worker return false;
417*288bf522SAndroid Build Coastguard Worker }
418*288bf522SAndroid Build Coastguard Worker }
419*288bf522SAndroid Build Coastguard Worker }
420*288bf522SAndroid Build Coastguard Worker return true;
421*288bf522SAndroid Build Coastguard Worker }
422*288bf522SAndroid Build Coastguard Worker
WriteFeatureSections()423*288bf522SAndroid Build Coastguard Worker bool WriteFeatureSections() {
424*288bf522SAndroid Build Coastguard Worker if (!writer_->BeginWriteFeatures(reader_->FeatureSectionDescriptors().size())) {
425*288bf522SAndroid Build Coastguard Worker return false;
426*288bf522SAndroid Build Coastguard Worker }
427*288bf522SAndroid Build Coastguard Worker std::unordered_set<int> feature_types_to_copy = {
428*288bf522SAndroid Build Coastguard Worker PerfFileFormat::FEAT_ARCH, PerfFileFormat::FEAT_CMDLINE, PerfFileFormat::FEAT_META_INFO};
429*288bf522SAndroid Build Coastguard Worker const size_t BUFFER_SIZE = 64 * kKilobyte;
430*288bf522SAndroid Build Coastguard Worker std::string buffer(BUFFER_SIZE, '\0');
431*288bf522SAndroid Build Coastguard Worker for (const auto& p : reader_->FeatureSectionDescriptors()) {
432*288bf522SAndroid Build Coastguard Worker auto feat_type = p.first;
433*288bf522SAndroid Build Coastguard Worker if (feat_type == PerfFileFormat::FEAT_DEBUG_UNWIND) {
434*288bf522SAndroid Build Coastguard Worker DebugUnwindFeature feature;
435*288bf522SAndroid Build Coastguard Worker buffer.resize(BUFFER_SIZE);
436*288bf522SAndroid Build Coastguard Worker for (const auto& file_p : debug_unwind_files_) {
437*288bf522SAndroid Build Coastguard Worker if (kept_binaries_.count(file_p.first)) {
438*288bf522SAndroid Build Coastguard Worker feature.resize(feature.size() + 1);
439*288bf522SAndroid Build Coastguard Worker feature.back().path = file_p.first;
440*288bf522SAndroid Build Coastguard Worker feature.back().size = file_p.second.size;
441*288bf522SAndroid Build Coastguard Worker if (!CopyDebugUnwindFile(file_p.second, buffer)) {
442*288bf522SAndroid Build Coastguard Worker return false;
443*288bf522SAndroid Build Coastguard Worker }
444*288bf522SAndroid Build Coastguard Worker }
445*288bf522SAndroid Build Coastguard Worker }
446*288bf522SAndroid Build Coastguard Worker if (!writer_->WriteDebugUnwindFeature(feature)) {
447*288bf522SAndroid Build Coastguard Worker return false;
448*288bf522SAndroid Build Coastguard Worker }
449*288bf522SAndroid Build Coastguard Worker } else if (feat_type == PerfFileFormat::FEAT_FILE ||
450*288bf522SAndroid Build Coastguard Worker feat_type == PerfFileFormat::FEAT_FILE2) {
451*288bf522SAndroid Build Coastguard Worker uint64_t read_pos = 0;
452*288bf522SAndroid Build Coastguard Worker FileFeature file_feature;
453*288bf522SAndroid Build Coastguard Worker bool error = false;
454*288bf522SAndroid Build Coastguard Worker while (reader_->ReadFileFeature(read_pos, file_feature, error)) {
455*288bf522SAndroid Build Coastguard Worker if (kept_binaries_.count(file_feature.path) && !writer_->WriteFileFeature(file_feature)) {
456*288bf522SAndroid Build Coastguard Worker return false;
457*288bf522SAndroid Build Coastguard Worker }
458*288bf522SAndroid Build Coastguard Worker }
459*288bf522SAndroid Build Coastguard Worker if (error) {
460*288bf522SAndroid Build Coastguard Worker return false;
461*288bf522SAndroid Build Coastguard Worker }
462*288bf522SAndroid Build Coastguard Worker } else if (feat_type == PerfFileFormat::FEAT_BUILD_ID) {
463*288bf522SAndroid Build Coastguard Worker std::vector<BuildIdRecord> build_ids = reader_->ReadBuildIdFeature();
464*288bf522SAndroid Build Coastguard Worker std::vector<BuildIdRecord> write_build_ids;
465*288bf522SAndroid Build Coastguard Worker for (auto& build_id : build_ids) {
466*288bf522SAndroid Build Coastguard Worker if (kept_binaries_.count(build_id.filename)) {
467*288bf522SAndroid Build Coastguard Worker write_build_ids.emplace_back(std::move(build_id));
468*288bf522SAndroid Build Coastguard Worker }
469*288bf522SAndroid Build Coastguard Worker }
470*288bf522SAndroid Build Coastguard Worker if (!writer_->WriteBuildIdFeature(write_build_ids)) {
471*288bf522SAndroid Build Coastguard Worker return false;
472*288bf522SAndroid Build Coastguard Worker }
473*288bf522SAndroid Build Coastguard Worker } else if (feature_types_to_copy.count(feat_type)) {
474*288bf522SAndroid Build Coastguard Worker if (!reader_->ReadFeatureSection(feat_type, &buffer) ||
475*288bf522SAndroid Build Coastguard Worker !writer_->WriteFeature(feat_type, buffer.data(), buffer.size())) {
476*288bf522SAndroid Build Coastguard Worker return false;
477*288bf522SAndroid Build Coastguard Worker }
478*288bf522SAndroid Build Coastguard Worker }
479*288bf522SAndroid Build Coastguard Worker }
480*288bf522SAndroid Build Coastguard Worker return writer_->EndWriteFeatures() && writer_->Close();
481*288bf522SAndroid Build Coastguard Worker }
482*288bf522SAndroid Build Coastguard Worker
CopyDebugUnwindFile(const DebugUnwindFileLocation & loc,std::string & buffer)483*288bf522SAndroid Build Coastguard Worker bool CopyDebugUnwindFile(const DebugUnwindFileLocation& loc, std::string& buffer) {
484*288bf522SAndroid Build Coastguard Worker uint64_t offset = loc.offset;
485*288bf522SAndroid Build Coastguard Worker uint64_t left_size = loc.size;
486*288bf522SAndroid Build Coastguard Worker while (left_size > 0) {
487*288bf522SAndroid Build Coastguard Worker size_t nread = std::min<size_t>(left_size, buffer.size());
488*288bf522SAndroid Build Coastguard Worker if (!reader_->ReadAtOffset(offset, buffer.data(), nread) ||
489*288bf522SAndroid Build Coastguard Worker !writer_->WriteFeature(PerfFileFormat::FEAT_DEBUG_UNWIND_FILE, buffer.data(), nread)) {
490*288bf522SAndroid Build Coastguard Worker return false;
491*288bf522SAndroid Build Coastguard Worker }
492*288bf522SAndroid Build Coastguard Worker offset += nread;
493*288bf522SAndroid Build Coastguard Worker left_size -= nread;
494*288bf522SAndroid Build Coastguard Worker }
495*288bf522SAndroid Build Coastguard Worker return true;
496*288bf522SAndroid Build Coastguard Worker }
497*288bf522SAndroid Build Coastguard Worker
498*288bf522SAndroid Build Coastguard Worker private:
499*288bf522SAndroid Build Coastguard Worker const std::unordered_set<uint64_t> sample_times_;
500*288bf522SAndroid Build Coastguard Worker const std::unordered_set<std::string> kept_binaries_;
501*288bf522SAndroid Build Coastguard Worker std::unique_ptr<RecordFileWriter> writer_;
502*288bf522SAndroid Build Coastguard Worker };
503*288bf522SAndroid Build Coastguard Worker
504*288bf522SAndroid Build Coastguard Worker class ReportGenerator : public RecordFileProcessor {
505*288bf522SAndroid Build Coastguard Worker public:
ReportGenerator(const std::string & output_filename)506*288bf522SAndroid Build Coastguard Worker ReportGenerator(const std::string& output_filename)
507*288bf522SAndroid Build Coastguard Worker : RecordFileProcessor(output_filename, false) {}
508*288bf522SAndroid Build Coastguard Worker
509*288bf522SAndroid Build Coastguard Worker protected:
CheckRecordCmd(const std::string & record_cmd)510*288bf522SAndroid Build Coastguard Worker bool CheckRecordCmd(const std::string& record_cmd) override {
511*288bf522SAndroid Build Coastguard Worker if (record_cmd.find("--keep-failed-unwinding-debug-info") == std::string::npos &&
512*288bf522SAndroid Build Coastguard Worker record_cmd.find("--keep-failed-unwinding-result") == std::string::npos) {
513*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "file isn't record with --keep-failed-unwinding-debug-info or "
514*288bf522SAndroid Build Coastguard Worker << "--keep-failed-unwinding-result: " << record_filename_;
515*288bf522SAndroid Build Coastguard Worker return false;
516*288bf522SAndroid Build Coastguard Worker }
517*288bf522SAndroid Build Coastguard Worker return true;
518*288bf522SAndroid Build Coastguard Worker }
519*288bf522SAndroid Build Coastguard Worker
Process()520*288bf522SAndroid Build Coastguard Worker bool Process() override {
521*288bf522SAndroid Build Coastguard Worker if (!reader_->ReadDataSection(
522*288bf522SAndroid Build Coastguard Worker [&](std::unique_ptr<Record> r) { return ProcessRecord(std::move(r)); })) {
523*288bf522SAndroid Build Coastguard Worker return false;
524*288bf522SAndroid Build Coastguard Worker }
525*288bf522SAndroid Build Coastguard Worker return true;
526*288bf522SAndroid Build Coastguard Worker }
527*288bf522SAndroid Build Coastguard Worker
528*288bf522SAndroid Build Coastguard Worker private:
ProcessRecord(std::unique_ptr<Record> r)529*288bf522SAndroid Build Coastguard Worker bool ProcessRecord(std::unique_ptr<Record> r) {
530*288bf522SAndroid Build Coastguard Worker thread_tree_.Update(*r);
531*288bf522SAndroid Build Coastguard Worker if (r->type() == SIMPLE_PERF_RECORD_UNWINDING_RESULT) {
532*288bf522SAndroid Build Coastguard Worker last_unwinding_result_.reset(static_cast<UnwindingResultRecord*>(r.release()));
533*288bf522SAndroid Build Coastguard Worker } else if (r->type() == PERF_RECORD_SAMPLE) {
534*288bf522SAndroid Build Coastguard Worker if (last_unwinding_result_) {
535*288bf522SAndroid Build Coastguard Worker ReportUnwindingResult(*static_cast<SampleRecord*>(r.get()), *last_unwinding_result_);
536*288bf522SAndroid Build Coastguard Worker last_unwinding_result_.reset();
537*288bf522SAndroid Build Coastguard Worker }
538*288bf522SAndroid Build Coastguard Worker }
539*288bf522SAndroid Build Coastguard Worker return true;
540*288bf522SAndroid Build Coastguard Worker }
541*288bf522SAndroid Build Coastguard Worker
ReportUnwindingResult(const SampleRecord & sr,const UnwindingResultRecord & unwinding_r)542*288bf522SAndroid Build Coastguard Worker void ReportUnwindingResult(const SampleRecord& sr, const UnwindingResultRecord& unwinding_r) {
543*288bf522SAndroid Build Coastguard Worker ThreadEntry* thread = thread_tree_.FindThreadOrNew(sr.tid_data.pid, sr.tid_data.tid);
544*288bf522SAndroid Build Coastguard Worker size_t kernel_ip_count;
545*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> ips = sr.GetCallChain(&kernel_ip_count);
546*288bf522SAndroid Build Coastguard Worker if (kernel_ip_count != 0) {
547*288bf522SAndroid Build Coastguard Worker ips.erase(ips.begin(), ips.begin() + kernel_ip_count);
548*288bf522SAndroid Build Coastguard Worker }
549*288bf522SAndroid Build Coastguard Worker
550*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "sample_time: %" PRIu64 "\n", sr.Timestamp());
551*288bf522SAndroid Build Coastguard Worker DumpUnwindingResult(unwinding_r.unwinding_result, out_fp_);
552*288bf522SAndroid Build Coastguard Worker // Print callchain.
553*288bf522SAndroid Build Coastguard Worker std::vector<CallChainReportEntry> entries = callchain_report_builder_.Build(thread, ips, 0);
554*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < entries.size(); i++) {
555*288bf522SAndroid Build Coastguard Worker size_t id = i + 1;
556*288bf522SAndroid Build Coastguard Worker const auto& entry = entries[i];
557*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "ip_%zu: 0x%" PRIx64 "\n", id, entry.ip);
558*288bf522SAndroid Build Coastguard Worker if (i < unwinding_r.callchain.length) {
559*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "unwinding_ip_%zu: 0x%" PRIx64 "\n", id, unwinding_r.callchain.ips[i]);
560*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "unwinding_sp_%zu: 0x%" PRIx64 "\n", id, unwinding_r.callchain.sps[i]);
561*288bf522SAndroid Build Coastguard Worker }
562*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "map_%zu: [0x%" PRIx64 "-0x%" PRIx64 "], pgoff 0x%" PRIx64 "\n", id,
563*288bf522SAndroid Build Coastguard Worker entry.map->start_addr, entry.map->get_end_addr(), entry.map->pgoff);
564*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "dso_%zu: %s\n", id, entry.map->dso->Path().c_str());
565*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "vaddr_in_file_%zu: 0x%" PRIx64 "\n", id, entry.vaddr_in_file);
566*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "symbol_%zu: %s\n", id, entry.symbol->DemangledName());
567*288bf522SAndroid Build Coastguard Worker }
568*288bf522SAndroid Build Coastguard Worker // Print regs.
569*288bf522SAndroid Build Coastguard Worker uint64_t stack_addr = 0;
570*288bf522SAndroid Build Coastguard Worker if (unwinding_r.regs_user_data.reg_nr > 0) {
571*288bf522SAndroid Build Coastguard Worker auto& reg_data = unwinding_r.regs_user_data;
572*288bf522SAndroid Build Coastguard Worker RegSet regs(reg_data.abi, reg_data.reg_mask, reg_data.regs);
573*288bf522SAndroid Build Coastguard Worker uint64_t value;
574*288bf522SAndroid Build Coastguard Worker if (regs.GetSpRegValue(&value)) {
575*288bf522SAndroid Build Coastguard Worker stack_addr = value;
576*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < 64; i++) {
577*288bf522SAndroid Build Coastguard Worker if (regs.GetRegValue(i, &value)) {
578*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "reg_%s: 0x%" PRIx64 "\n", GetRegName(i, regs.arch).c_str(), value);
579*288bf522SAndroid Build Coastguard Worker }
580*288bf522SAndroid Build Coastguard Worker }
581*288bf522SAndroid Build Coastguard Worker }
582*288bf522SAndroid Build Coastguard Worker }
583*288bf522SAndroid Build Coastguard Worker // Print stack.
584*288bf522SAndroid Build Coastguard Worker if (unwinding_r.stack_user_data.size > 0) {
585*288bf522SAndroid Build Coastguard Worker auto& stack = unwinding_r.stack_user_data;
586*288bf522SAndroid Build Coastguard Worker const char* p = stack.data;
587*288bf522SAndroid Build Coastguard Worker const char* end = stack.data + stack.size;
588*288bf522SAndroid Build Coastguard Worker uint64_t value;
589*288bf522SAndroid Build Coastguard Worker while (p + 8 <= end) {
590*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "stack_%" PRIx64 ":", stack_addr);
591*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < 4 && p + 8 <= end; ++i) {
592*288bf522SAndroid Build Coastguard Worker MoveFromBinaryFormat(value, p);
593*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, " %016" PRIx64, value);
594*288bf522SAndroid Build Coastguard Worker }
595*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "\n");
596*288bf522SAndroid Build Coastguard Worker stack_addr += 32;
597*288bf522SAndroid Build Coastguard Worker }
598*288bf522SAndroid Build Coastguard Worker fprintf(out_fp_, "\n");
599*288bf522SAndroid Build Coastguard Worker }
600*288bf522SAndroid Build Coastguard Worker }
601*288bf522SAndroid Build Coastguard Worker
602*288bf522SAndroid Build Coastguard Worker std::unique_ptr<UnwindingResultRecord> last_unwinding_result_;
603*288bf522SAndroid Build Coastguard Worker };
604*288bf522SAndroid Build Coastguard Worker
605*288bf522SAndroid Build Coastguard Worker class DebugUnwindCommand : public Command {
606*288bf522SAndroid Build Coastguard Worker public:
DebugUnwindCommand()607*288bf522SAndroid Build Coastguard Worker DebugUnwindCommand()
608*288bf522SAndroid Build Coastguard Worker : Command(
609*288bf522SAndroid Build Coastguard Worker "debug-unwind", "Debug/test offline unwinding.",
610*288bf522SAndroid Build Coastguard Worker // clang-format off
611*288bf522SAndroid Build Coastguard Worker "Usage: simpleperf debug-unwind [options]\n"
612*288bf522SAndroid Build Coastguard Worker "--generate-report Generate a failed unwinding report.\n"
613*288bf522SAndroid Build Coastguard Worker "--generate-test-file Generate a test file with only one sample.\n"
614*288bf522SAndroid Build Coastguard Worker "-i <file> Input recording file. Default is perf.data.\n"
615*288bf522SAndroid Build Coastguard Worker "-o <file> Output file. Default is stdout.\n"
616*288bf522SAndroid Build Coastguard Worker "--keep-binaries-in-test-file binary1,binary2... Keep binaries in test file.\n"
617*288bf522SAndroid Build Coastguard Worker "--sample-time time1,time2... Only process samples recorded at selected times.\n"
618*288bf522SAndroid Build Coastguard Worker "--symfs <dir> Look for files with symbols relative to this directory.\n"
619*288bf522SAndroid Build Coastguard Worker "--unwind-sample Unwind samples.\n"
620*288bf522SAndroid Build Coastguard Worker "--skip-sample-print Skip printing unwound samples.\n"
621*288bf522SAndroid Build Coastguard Worker "\n"
622*288bf522SAndroid Build Coastguard Worker "Examples:\n"
623*288bf522SAndroid Build Coastguard Worker "1. Unwind a sample.\n"
624*288bf522SAndroid Build Coastguard Worker "$ simpleperf debug-unwind -i perf.data --unwind-sample --sample-time 626970493946976\n"
625*288bf522SAndroid Build Coastguard Worker " perf.data should be generated with \"--no-unwind\" or \"--keep-failed-unwinding-debug-info\".\n"
626*288bf522SAndroid Build Coastguard Worker "2. Generate a test file.\n"
627*288bf522SAndroid Build Coastguard Worker "$ simpleperf debug-unwind -i perf.data --generate-test-file -o test.data --sample-time \\\n"
628*288bf522SAndroid Build Coastguard Worker " 626970493946976 --keep-binaries-in-test-file perf.data_jit_app_cache:255984-259968\n"
629*288bf522SAndroid Build Coastguard Worker "3. Generate a failed unwinding report.\n"
630*288bf522SAndroid Build Coastguard Worker "$ simpleperf debug-unwind -i perf.data --generate-report -o report.txt\n"
631*288bf522SAndroid Build Coastguard Worker " perf.data should be generated with \"--keep-failed-unwinding-debug-info\" or \\\n"
632*288bf522SAndroid Build Coastguard Worker " \"--keep-failed-unwinding-result\".\n"
633*288bf522SAndroid Build Coastguard Worker "\n"
634*288bf522SAndroid Build Coastguard Worker // clang-format on
635*288bf522SAndroid Build Coastguard Worker ) {}
636*288bf522SAndroid Build Coastguard Worker
637*288bf522SAndroid Build Coastguard Worker bool Run(const std::vector<std::string>& args);
638*288bf522SAndroid Build Coastguard Worker
639*288bf522SAndroid Build Coastguard Worker private:
640*288bf522SAndroid Build Coastguard Worker bool ParseOptions(const std::vector<std::string>& args);
641*288bf522SAndroid Build Coastguard Worker
642*288bf522SAndroid Build Coastguard Worker std::string input_filename_ = "perf.data";
643*288bf522SAndroid Build Coastguard Worker std::string output_filename_;
644*288bf522SAndroid Build Coastguard Worker bool unwind_sample_ = false;
645*288bf522SAndroid Build Coastguard Worker bool skip_sample_print_ = false;
646*288bf522SAndroid Build Coastguard Worker bool generate_report_ = false;
647*288bf522SAndroid Build Coastguard Worker bool generate_test_file_;
648*288bf522SAndroid Build Coastguard Worker std::unordered_set<std::string> kept_binaries_in_test_file_;
649*288bf522SAndroid Build Coastguard Worker std::unordered_set<uint64_t> sample_times_;
650*288bf522SAndroid Build Coastguard Worker };
651*288bf522SAndroid Build Coastguard Worker
Run(const std::vector<std::string> & args)652*288bf522SAndroid Build Coastguard Worker bool DebugUnwindCommand::Run(const std::vector<std::string>& args) {
653*288bf522SAndroid Build Coastguard Worker // 1. Parse options.
654*288bf522SAndroid Build Coastguard Worker if (!ParseOptions(args)) {
655*288bf522SAndroid Build Coastguard Worker return false;
656*288bf522SAndroid Build Coastguard Worker }
657*288bf522SAndroid Build Coastguard Worker
658*288bf522SAndroid Build Coastguard Worker // 2. Distribute sub commands.
659*288bf522SAndroid Build Coastguard Worker if (unwind_sample_) {
660*288bf522SAndroid Build Coastguard Worker SampleUnwinder sample_unwinder(output_filename_, sample_times_, skip_sample_print_);
661*288bf522SAndroid Build Coastguard Worker return sample_unwinder.ProcessFile(input_filename_);
662*288bf522SAndroid Build Coastguard Worker }
663*288bf522SAndroid Build Coastguard Worker if (generate_test_file_) {
664*288bf522SAndroid Build Coastguard Worker TestFileGenerator test_file_generator(output_filename_, sample_times_,
665*288bf522SAndroid Build Coastguard Worker kept_binaries_in_test_file_);
666*288bf522SAndroid Build Coastguard Worker return test_file_generator.ProcessFile(input_filename_);
667*288bf522SAndroid Build Coastguard Worker }
668*288bf522SAndroid Build Coastguard Worker if (generate_report_) {
669*288bf522SAndroid Build Coastguard Worker ReportGenerator report_generator(output_filename_);
670*288bf522SAndroid Build Coastguard Worker return report_generator.ProcessFile(input_filename_);
671*288bf522SAndroid Build Coastguard Worker }
672*288bf522SAndroid Build Coastguard Worker return true;
673*288bf522SAndroid Build Coastguard Worker }
674*288bf522SAndroid Build Coastguard Worker
ParseOptions(const std::vector<std::string> & args)675*288bf522SAndroid Build Coastguard Worker bool DebugUnwindCommand::ParseOptions(const std::vector<std::string>& args) {
676*288bf522SAndroid Build Coastguard Worker const OptionFormatMap option_formats = {
677*288bf522SAndroid Build Coastguard Worker {"--generate-report", {OptionValueType::NONE, OptionType::SINGLE}},
678*288bf522SAndroid Build Coastguard Worker {"--generate-test-file", {OptionValueType::NONE, OptionType::SINGLE}},
679*288bf522SAndroid Build Coastguard Worker {"-i", {OptionValueType::STRING, OptionType::SINGLE}},
680*288bf522SAndroid Build Coastguard Worker {"--keep-binaries-in-test-file", {OptionValueType::STRING, OptionType::MULTIPLE}},
681*288bf522SAndroid Build Coastguard Worker {"-o", {OptionValueType::STRING, OptionType::SINGLE}},
682*288bf522SAndroid Build Coastguard Worker {"--sample-time", {OptionValueType::STRING, OptionType::MULTIPLE}},
683*288bf522SAndroid Build Coastguard Worker {"--skip-sample-print", {OptionValueType::NONE, OptionType::SINGLE}},
684*288bf522SAndroid Build Coastguard Worker {"--symfs", {OptionValueType::STRING, OptionType::MULTIPLE}},
685*288bf522SAndroid Build Coastguard Worker {"--unwind-sample", {OptionValueType::NONE, OptionType::SINGLE}},
686*288bf522SAndroid Build Coastguard Worker };
687*288bf522SAndroid Build Coastguard Worker OptionValueMap options;
688*288bf522SAndroid Build Coastguard Worker std::vector<std::pair<OptionName, OptionValue>> ordered_options;
689*288bf522SAndroid Build Coastguard Worker if (!PreprocessOptions(args, option_formats, &options, &ordered_options)) {
690*288bf522SAndroid Build Coastguard Worker return false;
691*288bf522SAndroid Build Coastguard Worker }
692*288bf522SAndroid Build Coastguard Worker generate_report_ = options.PullBoolValue("--generate-report");
693*288bf522SAndroid Build Coastguard Worker generate_test_file_ = options.PullBoolValue("--generate-test-file");
694*288bf522SAndroid Build Coastguard Worker options.PullStringValue("-i", &input_filename_);
695*288bf522SAndroid Build Coastguard Worker for (auto& value : options.PullValues("--keep-binaries-in-test-file")) {
696*288bf522SAndroid Build Coastguard Worker std::vector<std::string> binaries = android::base::Split(value.str_value, ",");
697*288bf522SAndroid Build Coastguard Worker kept_binaries_in_test_file_.insert(binaries.begin(), binaries.end());
698*288bf522SAndroid Build Coastguard Worker }
699*288bf522SAndroid Build Coastguard Worker skip_sample_print_ = options.PullBoolValue("--skip-sample-print");
700*288bf522SAndroid Build Coastguard Worker options.PullStringValue("-o", &output_filename_);
701*288bf522SAndroid Build Coastguard Worker for (auto& value : options.PullValues("--sample-time")) {
702*288bf522SAndroid Build Coastguard Worker auto times = ParseUintVector<uint64_t>(value.str_value);
703*288bf522SAndroid Build Coastguard Worker if (!times) {
704*288bf522SAndroid Build Coastguard Worker return false;
705*288bf522SAndroid Build Coastguard Worker }
706*288bf522SAndroid Build Coastguard Worker sample_times_.insert(times.value().begin(), times.value().end());
707*288bf522SAndroid Build Coastguard Worker }
708*288bf522SAndroid Build Coastguard Worker if (auto value = options.PullValue("--symfs"); value) {
709*288bf522SAndroid Build Coastguard Worker if (!Dso::SetSymFsDir(value->str_value)) {
710*288bf522SAndroid Build Coastguard Worker return false;
711*288bf522SAndroid Build Coastguard Worker }
712*288bf522SAndroid Build Coastguard Worker }
713*288bf522SAndroid Build Coastguard Worker unwind_sample_ = options.PullBoolValue("--unwind-sample");
714*288bf522SAndroid Build Coastguard Worker CHECK(options.values.empty());
715*288bf522SAndroid Build Coastguard Worker
716*288bf522SAndroid Build Coastguard Worker if (generate_test_file_) {
717*288bf522SAndroid Build Coastguard Worker if (output_filename_.empty()) {
718*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "no output path for generated test file";
719*288bf522SAndroid Build Coastguard Worker return false;
720*288bf522SAndroid Build Coastguard Worker }
721*288bf522SAndroid Build Coastguard Worker if (sample_times_.empty()) {
722*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "no samples are selected via --sample-time";
723*288bf522SAndroid Build Coastguard Worker return false;
724*288bf522SAndroid Build Coastguard Worker }
725*288bf522SAndroid Build Coastguard Worker }
726*288bf522SAndroid Build Coastguard Worker
727*288bf522SAndroid Build Coastguard Worker return true;
728*288bf522SAndroid Build Coastguard Worker }
729*288bf522SAndroid Build Coastguard Worker
730*288bf522SAndroid Build Coastguard Worker } // namespace
731*288bf522SAndroid Build Coastguard Worker
RegisterDebugUnwindCommand()732*288bf522SAndroid Build Coastguard Worker void RegisterDebugUnwindCommand() {
733*288bf522SAndroid Build Coastguard Worker RegisterCommand("debug-unwind",
734*288bf522SAndroid Build Coastguard Worker [] { return std::unique_ptr<Command>(new DebugUnwindCommand()); });
735*288bf522SAndroid Build Coastguard Worker }
736*288bf522SAndroid Build Coastguard Worker
737*288bf522SAndroid Build Coastguard Worker } // namespace simpleperf
738