1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2016 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
19*288bf522SAndroid Build Coastguard Worker #include <limits>
20*288bf522SAndroid Build Coastguard Worker #include <memory>
21*288bf522SAndroid Build Coastguard Worker
22*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
23*288bf522SAndroid Build Coastguard Worker
24*288bf522SAndroid Build Coastguard Worker #include "system/extras/simpleperf/cmd_report_sample.pb.h"
25*288bf522SAndroid Build Coastguard Worker
26*288bf522SAndroid Build Coastguard Worker #include <google/protobuf/io/coded_stream.h>
27*288bf522SAndroid Build Coastguard Worker #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
28*288bf522SAndroid Build Coastguard Worker
29*288bf522SAndroid Build Coastguard Worker #include "OfflineUnwinder.h"
30*288bf522SAndroid Build Coastguard Worker #include "RecordFilter.h"
31*288bf522SAndroid Build Coastguard Worker #include "command.h"
32*288bf522SAndroid Build Coastguard Worker #include "event_attr.h"
33*288bf522SAndroid Build Coastguard Worker #include "event_type.h"
34*288bf522SAndroid Build Coastguard Worker #include "record_file.h"
35*288bf522SAndroid Build Coastguard Worker #include "report_utils.h"
36*288bf522SAndroid Build Coastguard Worker #include "thread_tree.h"
37*288bf522SAndroid Build Coastguard Worker #include "utils.h"
38*288bf522SAndroid Build Coastguard Worker
39*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
40*288bf522SAndroid Build Coastguard Worker namespace {
41*288bf522SAndroid Build Coastguard Worker
42*288bf522SAndroid Build Coastguard Worker namespace proto = simpleperf_report_proto;
43*288bf522SAndroid Build Coastguard Worker
44*288bf522SAndroid Build Coastguard Worker static const char PROT_FILE_MAGIC[] = "SIMPLEPERF";
45*288bf522SAndroid Build Coastguard Worker static const uint16_t PROT_FILE_VERSION = 1u;
46*288bf522SAndroid Build Coastguard Worker
47*288bf522SAndroid Build Coastguard Worker class ProtobufFileWriter : public google::protobuf::io::CopyingOutputStream {
48*288bf522SAndroid Build Coastguard Worker public:
ProtobufFileWriter(FILE * out_fp)49*288bf522SAndroid Build Coastguard Worker explicit ProtobufFileWriter(FILE* out_fp) : out_fp_(out_fp) {}
50*288bf522SAndroid Build Coastguard Worker
Write(const void * buffer,int size)51*288bf522SAndroid Build Coastguard Worker bool Write(const void* buffer, int size) override {
52*288bf522SAndroid Build Coastguard Worker return fwrite(buffer, size, 1, out_fp_) == 1;
53*288bf522SAndroid Build Coastguard Worker }
54*288bf522SAndroid Build Coastguard Worker
55*288bf522SAndroid Build Coastguard Worker private:
56*288bf522SAndroid Build Coastguard Worker FILE* out_fp_;
57*288bf522SAndroid Build Coastguard Worker };
58*288bf522SAndroid Build Coastguard Worker
59*288bf522SAndroid Build Coastguard Worker class ProtobufFileReader : public google::protobuf::io::CopyingInputStream {
60*288bf522SAndroid Build Coastguard Worker public:
ProtobufFileReader(FILE * in_fp)61*288bf522SAndroid Build Coastguard Worker explicit ProtobufFileReader(FILE* in_fp) : in_fp_(in_fp) {}
62*288bf522SAndroid Build Coastguard Worker
Read(void * buffer,int size)63*288bf522SAndroid Build Coastguard Worker int Read(void* buffer, int size) override { return fread(buffer, 1, size, in_fp_); }
64*288bf522SAndroid Build Coastguard Worker
65*288bf522SAndroid Build Coastguard Worker private:
66*288bf522SAndroid Build Coastguard Worker FILE* in_fp_;
67*288bf522SAndroid Build Coastguard Worker };
68*288bf522SAndroid Build Coastguard Worker
ToProtoExecutionType(CallChainExecutionType type)69*288bf522SAndroid Build Coastguard Worker static proto::Sample_CallChainEntry_ExecutionType ToProtoExecutionType(
70*288bf522SAndroid Build Coastguard Worker CallChainExecutionType type) {
71*288bf522SAndroid Build Coastguard Worker switch (type) {
72*288bf522SAndroid Build Coastguard Worker case CallChainExecutionType::NATIVE_METHOD:
73*288bf522SAndroid Build Coastguard Worker return proto::Sample_CallChainEntry_ExecutionType_NATIVE_METHOD;
74*288bf522SAndroid Build Coastguard Worker case CallChainExecutionType::INTERPRETED_JVM_METHOD:
75*288bf522SAndroid Build Coastguard Worker return proto::Sample_CallChainEntry_ExecutionType_INTERPRETED_JVM_METHOD;
76*288bf522SAndroid Build Coastguard Worker case CallChainExecutionType::JIT_JVM_METHOD:
77*288bf522SAndroid Build Coastguard Worker return proto::Sample_CallChainEntry_ExecutionType_JIT_JVM_METHOD;
78*288bf522SAndroid Build Coastguard Worker case CallChainExecutionType::ART_METHOD:
79*288bf522SAndroid Build Coastguard Worker return proto::Sample_CallChainEntry_ExecutionType_ART_METHOD;
80*288bf522SAndroid Build Coastguard Worker }
81*288bf522SAndroid Build Coastguard Worker CHECK(false) << "unexpected execution type";
82*288bf522SAndroid Build Coastguard Worker return proto::Sample_CallChainEntry_ExecutionType_NATIVE_METHOD;
83*288bf522SAndroid Build Coastguard Worker }
84*288bf522SAndroid Build Coastguard Worker
ProtoExecutionTypeToString(proto::Sample_CallChainEntry_ExecutionType type)85*288bf522SAndroid Build Coastguard Worker static const char* ProtoExecutionTypeToString(proto::Sample_CallChainEntry_ExecutionType type) {
86*288bf522SAndroid Build Coastguard Worker switch (type) {
87*288bf522SAndroid Build Coastguard Worker case proto::Sample_CallChainEntry_ExecutionType_NATIVE_METHOD:
88*288bf522SAndroid Build Coastguard Worker return "native_method";
89*288bf522SAndroid Build Coastguard Worker case proto::Sample_CallChainEntry_ExecutionType_INTERPRETED_JVM_METHOD:
90*288bf522SAndroid Build Coastguard Worker return "interpreted_jvm_method";
91*288bf522SAndroid Build Coastguard Worker case proto::Sample_CallChainEntry_ExecutionType_JIT_JVM_METHOD:
92*288bf522SAndroid Build Coastguard Worker return "jit_jvm_method";
93*288bf522SAndroid Build Coastguard Worker case proto::Sample_CallChainEntry_ExecutionType_ART_METHOD:
94*288bf522SAndroid Build Coastguard Worker return "art_method";
95*288bf522SAndroid Build Coastguard Worker }
96*288bf522SAndroid Build Coastguard Worker CHECK(false) << "unexpected execution type: " << type;
97*288bf522SAndroid Build Coastguard Worker return "";
98*288bf522SAndroid Build Coastguard Worker }
99*288bf522SAndroid Build Coastguard Worker
ProtoUnwindingErrorCodeToString(proto::Sample_UnwindingResult_ErrorCode error_code)100*288bf522SAndroid Build Coastguard Worker static const char* ProtoUnwindingErrorCodeToString(
101*288bf522SAndroid Build Coastguard Worker proto::Sample_UnwindingResult_ErrorCode error_code) {
102*288bf522SAndroid Build Coastguard Worker switch (error_code) {
103*288bf522SAndroid Build Coastguard Worker case proto::Sample_UnwindingResult::ERROR_NONE:
104*288bf522SAndroid Build Coastguard Worker return "ERROR_NONE";
105*288bf522SAndroid Build Coastguard Worker case proto::Sample_UnwindingResult::ERROR_UNKNOWN:
106*288bf522SAndroid Build Coastguard Worker return "ERROR_UNKNOWN";
107*288bf522SAndroid Build Coastguard Worker case proto::Sample_UnwindingResult::ERROR_NOT_ENOUGH_STACK:
108*288bf522SAndroid Build Coastguard Worker return "ERROR_NOT_ENOUGH_STACK";
109*288bf522SAndroid Build Coastguard Worker case proto::Sample_UnwindingResult::ERROR_MEMORY_INVALID:
110*288bf522SAndroid Build Coastguard Worker return "ERROR_MEMORY_INVALID";
111*288bf522SAndroid Build Coastguard Worker case proto::Sample_UnwindingResult::ERROR_UNWIND_INFO:
112*288bf522SAndroid Build Coastguard Worker return "ERROR_UNWIND_INFO";
113*288bf522SAndroid Build Coastguard Worker case proto::Sample_UnwindingResult::ERROR_INVALID_MAP:
114*288bf522SAndroid Build Coastguard Worker return "ERROR_INVALID_MAP";
115*288bf522SAndroid Build Coastguard Worker case proto::Sample_UnwindingResult::ERROR_MAX_FRAME_EXCEEDED:
116*288bf522SAndroid Build Coastguard Worker return "ERROR_MAX_FRAME_EXCEEDED";
117*288bf522SAndroid Build Coastguard Worker case proto::Sample_UnwindingResult::ERROR_REPEATED_FRAME:
118*288bf522SAndroid Build Coastguard Worker return "ERROR_REPEATED_FRAME";
119*288bf522SAndroid Build Coastguard Worker case proto::Sample_UnwindingResult::ERROR_INVALID_ELF:
120*288bf522SAndroid Build Coastguard Worker return "ERROR_INVALID_ELF";
121*288bf522SAndroid Build Coastguard Worker }
122*288bf522SAndroid Build Coastguard Worker }
123*288bf522SAndroid Build Coastguard Worker
124*288bf522SAndroid Build Coastguard Worker struct SampleEntry {
125*288bf522SAndroid Build Coastguard Worker uint64_t time;
126*288bf522SAndroid Build Coastguard Worker uint64_t period;
127*288bf522SAndroid Build Coastguard Worker uint32_t event_type_id;
128*288bf522SAndroid Build Coastguard Worker bool is_complete_callchain;
129*288bf522SAndroid Build Coastguard Worker std::vector<CallChainReportEntry> callchain;
130*288bf522SAndroid Build Coastguard Worker std::optional<UnwindingResult> unwinding_result;
131*288bf522SAndroid Build Coastguard Worker };
132*288bf522SAndroid Build Coastguard Worker
133*288bf522SAndroid Build Coastguard Worker struct ThreadId {
134*288bf522SAndroid Build Coastguard Worker uint32_t pid;
135*288bf522SAndroid Build Coastguard Worker uint32_t tid;
136*288bf522SAndroid Build Coastguard Worker
ThreadIdsimpleperf::__anon248605f60111::ThreadId137*288bf522SAndroid Build Coastguard Worker ThreadId(uint32_t pid, uint32_t tid) : pid(pid), tid(tid) {}
138*288bf522SAndroid Build Coastguard Worker
operator ==simpleperf::__anon248605f60111::ThreadId139*288bf522SAndroid Build Coastguard Worker bool operator==(const ThreadId& other) const { return pid == other.pid && tid == other.tid; }
140*288bf522SAndroid Build Coastguard Worker };
141*288bf522SAndroid Build Coastguard Worker
142*288bf522SAndroid Build Coastguard Worker struct ThreadIdHash {
operator ()simpleperf::__anon248605f60111::ThreadIdHash143*288bf522SAndroid Build Coastguard Worker size_t operator()(const ThreadId& thread_id) const noexcept {
144*288bf522SAndroid Build Coastguard Worker size_t seed = 0;
145*288bf522SAndroid Build Coastguard Worker HashCombine(seed, thread_id.pid);
146*288bf522SAndroid Build Coastguard Worker HashCombine(seed, thread_id.tid);
147*288bf522SAndroid Build Coastguard Worker return seed;
148*288bf522SAndroid Build Coastguard Worker }
149*288bf522SAndroid Build Coastguard Worker };
150*288bf522SAndroid Build Coastguard Worker
151*288bf522SAndroid Build Coastguard Worker struct ThreadData {
152*288bf522SAndroid Build Coastguard Worker std::string thread_name;
153*288bf522SAndroid Build Coastguard Worker std::queue<SampleEntry> stack_gap_samples;
154*288bf522SAndroid Build Coastguard Worker };
155*288bf522SAndroid Build Coastguard Worker
156*288bf522SAndroid Build Coastguard Worker class ReportSampleCommand : public Command {
157*288bf522SAndroid Build Coastguard Worker public:
ReportSampleCommand()158*288bf522SAndroid Build Coastguard Worker ReportSampleCommand()
159*288bf522SAndroid Build Coastguard Worker : Command(
160*288bf522SAndroid Build Coastguard Worker "report-sample", "report raw sample information in perf.data",
161*288bf522SAndroid Build Coastguard Worker // clang-format off
162*288bf522SAndroid Build Coastguard Worker "Usage: simpleperf report-sample [options]\n"
163*288bf522SAndroid Build Coastguard Worker "--dump-protobuf-report <file> Dump report file generated by\n"
164*288bf522SAndroid Build Coastguard Worker " `simpleperf report-sample --protobuf -o <file>`.\n"
165*288bf522SAndroid Build Coastguard Worker "-i <file> Specify path of record file, default is perf.data.\n"
166*288bf522SAndroid Build Coastguard Worker "-o report_file_name Set report file name. When --protobuf is used, default is\n"
167*288bf522SAndroid Build Coastguard Worker " report_sample.trace. Otherwise, default writes to stdout.\n"
168*288bf522SAndroid Build Coastguard Worker "--proguard-mapping-file <file> Add proguard mapping file to de-obfuscate symbols.\n"
169*288bf522SAndroid Build Coastguard Worker "--protobuf Use protobuf format in cmd_report_sample.proto to output\n"
170*288bf522SAndroid Build Coastguard Worker " samples.\n"
171*288bf522SAndroid Build Coastguard Worker "--remove-gaps MAX_GAP_LENGTH Ideally all callstacks are complete. But some may be broken\n"
172*288bf522SAndroid Build Coastguard Worker " for different reasons. To create a smooth view in Stack\n"
173*288bf522SAndroid Build Coastguard Worker " Chart, remove small gaps of broken callstacks. MAX_GAP_LENGTH\n"
174*288bf522SAndroid Build Coastguard Worker " is the max length of continuous broken-stack samples we want\n"
175*288bf522SAndroid Build Coastguard Worker " to remove. Default is 3.\n"
176*288bf522SAndroid Build Coastguard Worker "--remove-unknown-kernel-symbols Remove kernel callchains when kernel symbols are not\n"
177*288bf522SAndroid Build Coastguard Worker " available.\n"
178*288bf522SAndroid Build Coastguard Worker "--show-art-frames Show frames of internal methods in the ART Java interpreter.\n"
179*288bf522SAndroid Build Coastguard Worker "--show-callchain Show callchain with samples.\n"
180*288bf522SAndroid Build Coastguard Worker "--show-execution-type Show execution type of a method\n"
181*288bf522SAndroid Build Coastguard Worker "--symdir <dir> Look for files with symbols in a directory recursively.\n"
182*288bf522SAndroid Build Coastguard Worker "\n"
183*288bf522SAndroid Build Coastguard Worker "Sample filter options:\n"
184*288bf522SAndroid Build Coastguard Worker RECORD_FILTER_OPTION_HELP_MSG_FOR_REPORTING
185*288bf522SAndroid Build Coastguard Worker // clang-format on
186*288bf522SAndroid Build Coastguard Worker ),
187*288bf522SAndroid Build Coastguard Worker record_filename_("perf.data"),
188*288bf522SAndroid Build Coastguard Worker show_callchain_(false),
189*288bf522SAndroid Build Coastguard Worker use_protobuf_(false),
190*288bf522SAndroid Build Coastguard Worker report_fp_(nullptr),
191*288bf522SAndroid Build Coastguard Worker coded_os_(nullptr),
192*288bf522SAndroid Build Coastguard Worker sample_count_(0),
193*288bf522SAndroid Build Coastguard Worker lost_count_(0),
194*288bf522SAndroid Build Coastguard Worker trace_offcpu_(false),
195*288bf522SAndroid Build Coastguard Worker remove_unknown_kernel_symbols_(false),
196*288bf522SAndroid Build Coastguard Worker kernel_symbols_available_(false),
197*288bf522SAndroid Build Coastguard Worker callchain_report_builder_(thread_tree_),
198*288bf522SAndroid Build Coastguard Worker record_filter_(thread_tree_) {}
199*288bf522SAndroid Build Coastguard Worker
200*288bf522SAndroid Build Coastguard Worker bool Run(const std::vector<std::string>& args) override;
201*288bf522SAndroid Build Coastguard Worker
202*288bf522SAndroid Build Coastguard Worker private:
203*288bf522SAndroid Build Coastguard Worker bool ParseOptions(const std::vector<std::string>& args);
204*288bf522SAndroid Build Coastguard Worker bool DumpProtobufReport(const std::string& filename);
205*288bf522SAndroid Build Coastguard Worker bool OpenRecordFile();
206*288bf522SAndroid Build Coastguard Worker bool PrintMetaInfo();
207*288bf522SAndroid Build Coastguard Worker bool ProcessRecord(std::unique_ptr<Record> record);
208*288bf522SAndroid Build Coastguard Worker void UpdateThreadName(uint32_t pid, uint32_t tid);
209*288bf522SAndroid Build Coastguard Worker bool ProcessSampleRecord(const SampleRecord& r);
210*288bf522SAndroid Build Coastguard Worker bool ProcessSample(const ThreadEntry& thread, SampleEntry& sample);
211*288bf522SAndroid Build Coastguard Worker bool ReportSample(const ThreadId& thread_id, const SampleEntry& sample, size_t stack_gap_length);
212*288bf522SAndroid Build Coastguard Worker bool FinishReportSamples();
213*288bf522SAndroid Build Coastguard Worker bool PrintSampleInProtobuf(const ThreadId& thread_id, const SampleEntry& sample);
214*288bf522SAndroid Build Coastguard Worker void AddUnwindingResultInProtobuf(const UnwindingResult& unwinding_result,
215*288bf522SAndroid Build Coastguard Worker proto::Sample_UnwindingResult* proto_unwinding_result);
216*288bf522SAndroid Build Coastguard Worker bool ProcessSwitchRecord(Record* r);
217*288bf522SAndroid Build Coastguard Worker bool WriteRecordInProtobuf(proto::Record& proto_record);
218*288bf522SAndroid Build Coastguard Worker bool PrintLostSituationInProtobuf();
219*288bf522SAndroid Build Coastguard Worker bool PrintFileInfoInProtobuf();
220*288bf522SAndroid Build Coastguard Worker bool PrintThreadInfoInProtobuf();
221*288bf522SAndroid Build Coastguard Worker bool PrintSample(const ThreadId& thread_id, const SampleEntry& sample);
222*288bf522SAndroid Build Coastguard Worker void PrintLostSituation();
223*288bf522SAndroid Build Coastguard Worker
224*288bf522SAndroid Build Coastguard Worker std::string record_filename_;
225*288bf522SAndroid Build Coastguard Worker std::unique_ptr<RecordFileReader> record_file_reader_;
226*288bf522SAndroid Build Coastguard Worker std::string dump_protobuf_report_file_;
227*288bf522SAndroid Build Coastguard Worker bool show_callchain_;
228*288bf522SAndroid Build Coastguard Worker bool use_protobuf_;
229*288bf522SAndroid Build Coastguard Worker ThreadTree thread_tree_;
230*288bf522SAndroid Build Coastguard Worker std::string report_filename_;
231*288bf522SAndroid Build Coastguard Worker FILE* report_fp_;
232*288bf522SAndroid Build Coastguard Worker google::protobuf::io::CodedOutputStream* coded_os_;
233*288bf522SAndroid Build Coastguard Worker size_t sample_count_;
234*288bf522SAndroid Build Coastguard Worker size_t lost_count_;
235*288bf522SAndroid Build Coastguard Worker bool trace_offcpu_;
236*288bf522SAndroid Build Coastguard Worker std::vector<std::string> event_types_;
237*288bf522SAndroid Build Coastguard Worker bool remove_unknown_kernel_symbols_;
238*288bf522SAndroid Build Coastguard Worker bool kernel_symbols_available_;
239*288bf522SAndroid Build Coastguard Worker bool show_execution_type_ = false;
240*288bf522SAndroid Build Coastguard Worker CallChainReportBuilder callchain_report_builder_;
241*288bf522SAndroid Build Coastguard Worker std::unordered_map<ThreadId, ThreadData, ThreadIdHash> per_thread_data_;
242*288bf522SAndroid Build Coastguard Worker std::unique_ptr<UnwindingResultRecord> last_unwinding_result_;
243*288bf522SAndroid Build Coastguard Worker RecordFilter record_filter_;
244*288bf522SAndroid Build Coastguard Worker uint32_t max_remove_gap_length_ = 3;
245*288bf522SAndroid Build Coastguard Worker };
246*288bf522SAndroid Build Coastguard Worker
Run(const std::vector<std::string> & args)247*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::Run(const std::vector<std::string>& args) {
248*288bf522SAndroid Build Coastguard Worker // 1. Parse options.
249*288bf522SAndroid Build Coastguard Worker if (!ParseOptions(args)) {
250*288bf522SAndroid Build Coastguard Worker return false;
251*288bf522SAndroid Build Coastguard Worker }
252*288bf522SAndroid Build Coastguard Worker // 2. Prepare report fp.
253*288bf522SAndroid Build Coastguard Worker report_fp_ = stdout;
254*288bf522SAndroid Build Coastguard Worker std::unique_ptr<FILE, decltype(&fclose)> fp(nullptr, fclose);
255*288bf522SAndroid Build Coastguard Worker if (!report_filename_.empty()) {
256*288bf522SAndroid Build Coastguard Worker const char* open_mode = use_protobuf_ ? "wb" : "w";
257*288bf522SAndroid Build Coastguard Worker fp.reset(fopen(report_filename_.c_str(), open_mode));
258*288bf522SAndroid Build Coastguard Worker if (fp == nullptr) {
259*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "failed to open " << report_filename_;
260*288bf522SAndroid Build Coastguard Worker return false;
261*288bf522SAndroid Build Coastguard Worker }
262*288bf522SAndroid Build Coastguard Worker report_fp_ = fp.get();
263*288bf522SAndroid Build Coastguard Worker }
264*288bf522SAndroid Build Coastguard Worker
265*288bf522SAndroid Build Coastguard Worker // 3. Dump protobuf report.
266*288bf522SAndroid Build Coastguard Worker if (!dump_protobuf_report_file_.empty()) {
267*288bf522SAndroid Build Coastguard Worker return DumpProtobufReport(dump_protobuf_report_file_);
268*288bf522SAndroid Build Coastguard Worker }
269*288bf522SAndroid Build Coastguard Worker
270*288bf522SAndroid Build Coastguard Worker // 4. Open record file.
271*288bf522SAndroid Build Coastguard Worker if (!OpenRecordFile()) {
272*288bf522SAndroid Build Coastguard Worker return false;
273*288bf522SAndroid Build Coastguard Worker }
274*288bf522SAndroid Build Coastguard Worker if (use_protobuf_) {
275*288bf522SAndroid Build Coastguard Worker GOOGLE_PROTOBUF_VERIFY_VERSION;
276*288bf522SAndroid Build Coastguard Worker } else {
277*288bf522SAndroid Build Coastguard Worker thread_tree_.ShowMarkForUnknownSymbol();
278*288bf522SAndroid Build Coastguard Worker thread_tree_.ShowIpForUnknownSymbol();
279*288bf522SAndroid Build Coastguard Worker }
280*288bf522SAndroid Build Coastguard Worker
281*288bf522SAndroid Build Coastguard Worker // 5. Prepare protobuf output stream.
282*288bf522SAndroid Build Coastguard Worker std::unique_ptr<ProtobufFileWriter> protobuf_writer;
283*288bf522SAndroid Build Coastguard Worker std::unique_ptr<google::protobuf::io::CopyingOutputStreamAdaptor> protobuf_os;
284*288bf522SAndroid Build Coastguard Worker std::unique_ptr<google::protobuf::io::CodedOutputStream> protobuf_coded_os;
285*288bf522SAndroid Build Coastguard Worker if (use_protobuf_) {
286*288bf522SAndroid Build Coastguard Worker if (fprintf(report_fp_, "%s", PROT_FILE_MAGIC) != 10 ||
287*288bf522SAndroid Build Coastguard Worker fwrite(&PROT_FILE_VERSION, sizeof(uint16_t), 1, report_fp_) != 1u) {
288*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write magic/version";
289*288bf522SAndroid Build Coastguard Worker return false;
290*288bf522SAndroid Build Coastguard Worker }
291*288bf522SAndroid Build Coastguard Worker protobuf_writer.reset(new ProtobufFileWriter(report_fp_));
292*288bf522SAndroid Build Coastguard Worker protobuf_os.reset(new google::protobuf::io::CopyingOutputStreamAdaptor(protobuf_writer.get()));
293*288bf522SAndroid Build Coastguard Worker protobuf_coded_os.reset(new google::protobuf::io::CodedOutputStream(protobuf_os.get()));
294*288bf522SAndroid Build Coastguard Worker coded_os_ = protobuf_coded_os.get();
295*288bf522SAndroid Build Coastguard Worker }
296*288bf522SAndroid Build Coastguard Worker
297*288bf522SAndroid Build Coastguard Worker // 6. Read record file, and print samples online.
298*288bf522SAndroid Build Coastguard Worker if (!PrintMetaInfo()) {
299*288bf522SAndroid Build Coastguard Worker return false;
300*288bf522SAndroid Build Coastguard Worker }
301*288bf522SAndroid Build Coastguard Worker if (!record_file_reader_->ReadDataSection(
302*288bf522SAndroid Build Coastguard Worker [this](std::unique_ptr<Record> record) { return ProcessRecord(std::move(record)); })) {
303*288bf522SAndroid Build Coastguard Worker return false;
304*288bf522SAndroid Build Coastguard Worker }
305*288bf522SAndroid Build Coastguard Worker
306*288bf522SAndroid Build Coastguard Worker if (!FinishReportSamples()) {
307*288bf522SAndroid Build Coastguard Worker return false;
308*288bf522SAndroid Build Coastguard Worker }
309*288bf522SAndroid Build Coastguard Worker
310*288bf522SAndroid Build Coastguard Worker if (use_protobuf_) {
311*288bf522SAndroid Build Coastguard Worker if (!PrintLostSituationInProtobuf()) {
312*288bf522SAndroid Build Coastguard Worker return false;
313*288bf522SAndroid Build Coastguard Worker }
314*288bf522SAndroid Build Coastguard Worker if (!PrintFileInfoInProtobuf()) {
315*288bf522SAndroid Build Coastguard Worker return false;
316*288bf522SAndroid Build Coastguard Worker }
317*288bf522SAndroid Build Coastguard Worker if (!PrintThreadInfoInProtobuf()) {
318*288bf522SAndroid Build Coastguard Worker return false;
319*288bf522SAndroid Build Coastguard Worker }
320*288bf522SAndroid Build Coastguard Worker coded_os_->WriteLittleEndian32(0);
321*288bf522SAndroid Build Coastguard Worker if (coded_os_->HadError()) {
322*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "print protobuf report failed";
323*288bf522SAndroid Build Coastguard Worker return false;
324*288bf522SAndroid Build Coastguard Worker }
325*288bf522SAndroid Build Coastguard Worker protobuf_coded_os.reset(nullptr);
326*288bf522SAndroid Build Coastguard Worker } else {
327*288bf522SAndroid Build Coastguard Worker PrintLostSituation();
328*288bf522SAndroid Build Coastguard Worker fflush(report_fp_);
329*288bf522SAndroid Build Coastguard Worker }
330*288bf522SAndroid Build Coastguard Worker if (ferror(report_fp_) != 0) {
331*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "print report failed";
332*288bf522SAndroid Build Coastguard Worker return false;
333*288bf522SAndroid Build Coastguard Worker }
334*288bf522SAndroid Build Coastguard Worker return true;
335*288bf522SAndroid Build Coastguard Worker }
336*288bf522SAndroid Build Coastguard Worker
ParseOptions(const std::vector<std::string> & args)337*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::ParseOptions(const std::vector<std::string>& args) {
338*288bf522SAndroid Build Coastguard Worker OptionFormatMap option_formats = {
339*288bf522SAndroid Build Coastguard Worker {"--dump-protobuf-report", {OptionValueType::STRING, OptionType::SINGLE}},
340*288bf522SAndroid Build Coastguard Worker {"-i", {OptionValueType::STRING, OptionType::SINGLE}},
341*288bf522SAndroid Build Coastguard Worker {"-o", {OptionValueType::STRING, OptionType::SINGLE}},
342*288bf522SAndroid Build Coastguard Worker {"--proguard-mapping-file", {OptionValueType::STRING, OptionType::MULTIPLE}},
343*288bf522SAndroid Build Coastguard Worker {"--protobuf", {OptionValueType::NONE, OptionType::SINGLE}},
344*288bf522SAndroid Build Coastguard Worker {"--show-callchain", {OptionValueType::NONE, OptionType::SINGLE}},
345*288bf522SAndroid Build Coastguard Worker {"--remove-gaps", {OptionValueType::UINT, OptionType::SINGLE}},
346*288bf522SAndroid Build Coastguard Worker {"--remove-unknown-kernel-symbols", {OptionValueType::NONE, OptionType::SINGLE}},
347*288bf522SAndroid Build Coastguard Worker {"--show-art-frames", {OptionValueType::NONE, OptionType::SINGLE}},
348*288bf522SAndroid Build Coastguard Worker {"--show-execution-type", {OptionValueType::NONE, OptionType::SINGLE}},
349*288bf522SAndroid Build Coastguard Worker {"--symdir", {OptionValueType::STRING, OptionType::MULTIPLE}},
350*288bf522SAndroid Build Coastguard Worker };
351*288bf522SAndroid Build Coastguard Worker OptionFormatMap record_filter_options = GetRecordFilterOptionFormats(false);
352*288bf522SAndroid Build Coastguard Worker option_formats.insert(record_filter_options.begin(), record_filter_options.end());
353*288bf522SAndroid Build Coastguard Worker OptionValueMap options;
354*288bf522SAndroid Build Coastguard Worker std::vector<std::pair<OptionName, OptionValue>> ordered_options;
355*288bf522SAndroid Build Coastguard Worker if (!PreprocessOptions(args, option_formats, &options, &ordered_options, nullptr)) {
356*288bf522SAndroid Build Coastguard Worker return false;
357*288bf522SAndroid Build Coastguard Worker }
358*288bf522SAndroid Build Coastguard Worker options.PullStringValue("--dump-protobuf-report", &dump_protobuf_report_file_);
359*288bf522SAndroid Build Coastguard Worker options.PullStringValue("-i", &record_filename_);
360*288bf522SAndroid Build Coastguard Worker options.PullStringValue("-o", &report_filename_);
361*288bf522SAndroid Build Coastguard Worker for (const OptionValue& value : options.PullValues("--proguard-mapping-file")) {
362*288bf522SAndroid Build Coastguard Worker if (!callchain_report_builder_.AddProguardMappingFile(value.str_value)) {
363*288bf522SAndroid Build Coastguard Worker return false;
364*288bf522SAndroid Build Coastguard Worker }
365*288bf522SAndroid Build Coastguard Worker }
366*288bf522SAndroid Build Coastguard Worker use_protobuf_ = options.PullBoolValue("--protobuf");
367*288bf522SAndroid Build Coastguard Worker show_callchain_ = options.PullBoolValue("--show-callchain");
368*288bf522SAndroid Build Coastguard Worker if (!options.PullUintValue("--remove-gaps", &max_remove_gap_length_)) {
369*288bf522SAndroid Build Coastguard Worker return false;
370*288bf522SAndroid Build Coastguard Worker }
371*288bf522SAndroid Build Coastguard Worker remove_unknown_kernel_symbols_ = options.PullBoolValue("--remove-unknown-kernel-symbols");
372*288bf522SAndroid Build Coastguard Worker if (options.PullBoolValue("--show-art-frames")) {
373*288bf522SAndroid Build Coastguard Worker callchain_report_builder_.SetRemoveArtFrame(false);
374*288bf522SAndroid Build Coastguard Worker }
375*288bf522SAndroid Build Coastguard Worker show_execution_type_ = options.PullBoolValue("--show-execution-type");
376*288bf522SAndroid Build Coastguard Worker for (const OptionValue& value : options.PullValues("--symdir")) {
377*288bf522SAndroid Build Coastguard Worker if (!Dso::AddSymbolDir(value.str_value)) {
378*288bf522SAndroid Build Coastguard Worker return false;
379*288bf522SAndroid Build Coastguard Worker }
380*288bf522SAndroid Build Coastguard Worker }
381*288bf522SAndroid Build Coastguard Worker if (!record_filter_.ParseOptions(options)) {
382*288bf522SAndroid Build Coastguard Worker return false;
383*288bf522SAndroid Build Coastguard Worker }
384*288bf522SAndroid Build Coastguard Worker CHECK(options.values.empty());
385*288bf522SAndroid Build Coastguard Worker
386*288bf522SAndroid Build Coastguard Worker if (use_protobuf_ && report_filename_.empty()) {
387*288bf522SAndroid Build Coastguard Worker report_filename_ = "report_sample.trace";
388*288bf522SAndroid Build Coastguard Worker }
389*288bf522SAndroid Build Coastguard Worker return true;
390*288bf522SAndroid Build Coastguard Worker }
391*288bf522SAndroid Build Coastguard Worker
DumpProtobufReport(const std::string & filename)392*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::DumpProtobufReport(const std::string& filename) {
393*288bf522SAndroid Build Coastguard Worker GOOGLE_PROTOBUF_VERIFY_VERSION;
394*288bf522SAndroid Build Coastguard Worker std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(filename.c_str(), "rb"), fclose);
395*288bf522SAndroid Build Coastguard Worker if (fp == nullptr) {
396*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "failed to open " << filename;
397*288bf522SAndroid Build Coastguard Worker return false;
398*288bf522SAndroid Build Coastguard Worker }
399*288bf522SAndroid Build Coastguard Worker char magic[11] = {};
400*288bf522SAndroid Build Coastguard Worker if (fread(magic, 10, 1, fp.get()) != 1u || memcmp(magic, PROT_FILE_MAGIC, 10) != 0) {
401*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << filename << " isn't a file generated by report-sample command.";
402*288bf522SAndroid Build Coastguard Worker return false;
403*288bf522SAndroid Build Coastguard Worker }
404*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "magic: %s\n", magic);
405*288bf522SAndroid Build Coastguard Worker uint16_t version;
406*288bf522SAndroid Build Coastguard Worker if (fread(&version, sizeof(uint16_t), 1, fp.get()) != 1u || version != PROT_FILE_VERSION) {
407*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << filename << " doesn't have the expected version.";
408*288bf522SAndroid Build Coastguard Worker return false;
409*288bf522SAndroid Build Coastguard Worker }
410*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "version: %u\n", version);
411*288bf522SAndroid Build Coastguard Worker
412*288bf522SAndroid Build Coastguard Worker ProtobufFileReader protobuf_reader(fp.get());
413*288bf522SAndroid Build Coastguard Worker google::protobuf::io::CopyingInputStreamAdaptor adaptor(&protobuf_reader);
414*288bf522SAndroid Build Coastguard Worker google::protobuf::io::CodedInputStream coded_is(&adaptor);
415*288bf522SAndroid Build Coastguard Worker // map from file_id to max_symbol_id requested on the file.
416*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint32_t, int32_t> max_symbol_id_map;
417*288bf522SAndroid Build Coastguard Worker // files[file_id] is the number of symbols in the file.
418*288bf522SAndroid Build Coastguard Worker std::vector<uint32_t> files;
419*288bf522SAndroid Build Coastguard Worker uint32_t max_message_size = 64 * (1 << 20);
420*288bf522SAndroid Build Coastguard Worker coded_is.SetTotalBytesLimit(max_message_size);
421*288bf522SAndroid Build Coastguard Worker while (true) {
422*288bf522SAndroid Build Coastguard Worker uint32_t size;
423*288bf522SAndroid Build Coastguard Worker if (!coded_is.ReadLittleEndian32(&size)) {
424*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "failed to read " << filename;
425*288bf522SAndroid Build Coastguard Worker return false;
426*288bf522SAndroid Build Coastguard Worker }
427*288bf522SAndroid Build Coastguard Worker if (size == 0) {
428*288bf522SAndroid Build Coastguard Worker break;
429*288bf522SAndroid Build Coastguard Worker }
430*288bf522SAndroid Build Coastguard Worker // Handle files having large symbol table.
431*288bf522SAndroid Build Coastguard Worker if (size > max_message_size) {
432*288bf522SAndroid Build Coastguard Worker max_message_size = size;
433*288bf522SAndroid Build Coastguard Worker coded_is.SetTotalBytesLimit(max_message_size);
434*288bf522SAndroid Build Coastguard Worker }
435*288bf522SAndroid Build Coastguard Worker auto limit = coded_is.PushLimit(size);
436*288bf522SAndroid Build Coastguard Worker proto::Record proto_record;
437*288bf522SAndroid Build Coastguard Worker if (!proto_record.ParseFromCodedStream(&coded_is)) {
438*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "failed to read " << filename;
439*288bf522SAndroid Build Coastguard Worker return false;
440*288bf522SAndroid Build Coastguard Worker }
441*288bf522SAndroid Build Coastguard Worker coded_is.PopLimit(limit);
442*288bf522SAndroid Build Coastguard Worker if (proto_record.has_sample()) {
443*288bf522SAndroid Build Coastguard Worker auto& sample = proto_record.sample();
444*288bf522SAndroid Build Coastguard Worker static size_t sample_count = 0;
445*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "sample %zu:\n", ++sample_count);
446*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "event_type_id: %zu\n", sample.event_type_id());
447*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", sample.time());
448*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "event_count: %" PRIu64 "\n", sample.event_count());
449*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "thread_id: %d\n", sample.thread_id());
450*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "callchain:\n");
451*288bf522SAndroid Build Coastguard Worker for (int i = 0; i < sample.callchain_size(); ++i) {
452*288bf522SAndroid Build Coastguard Worker const proto::Sample_CallChainEntry& callchain = sample.callchain(i);
453*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "vaddr_in_file: %" PRIx64 "\n", callchain.vaddr_in_file());
454*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "file_id: %u\n", callchain.file_id());
455*288bf522SAndroid Build Coastguard Worker int32_t symbol_id = callchain.symbol_id();
456*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "symbol_id: %d\n", symbol_id);
457*288bf522SAndroid Build Coastguard Worker if (symbol_id < -1) {
458*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "unexpected symbol_id " << symbol_id;
459*288bf522SAndroid Build Coastguard Worker return false;
460*288bf522SAndroid Build Coastguard Worker }
461*288bf522SAndroid Build Coastguard Worker if (symbol_id != -1) {
462*288bf522SAndroid Build Coastguard Worker max_symbol_id_map[callchain.file_id()] =
463*288bf522SAndroid Build Coastguard Worker std::max(max_symbol_id_map[callchain.file_id()], symbol_id);
464*288bf522SAndroid Build Coastguard Worker }
465*288bf522SAndroid Build Coastguard Worker if (callchain.has_execution_type()) {
466*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "execution_type: %s\n",
467*288bf522SAndroid Build Coastguard Worker ProtoExecutionTypeToString(callchain.execution_type()));
468*288bf522SAndroid Build Coastguard Worker }
469*288bf522SAndroid Build Coastguard Worker }
470*288bf522SAndroid Build Coastguard Worker if (sample.has_unwinding_result()) {
471*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "unwinding_result:\n");
472*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "raw_error_code: %u\n",
473*288bf522SAndroid Build Coastguard Worker sample.unwinding_result().raw_error_code());
474*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "error_addr: 0x%" PRIx64 "\n",
475*288bf522SAndroid Build Coastguard Worker sample.unwinding_result().error_addr());
476*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "error_code: %s\n",
477*288bf522SAndroid Build Coastguard Worker ProtoUnwindingErrorCodeToString(sample.unwinding_result().error_code()));
478*288bf522SAndroid Build Coastguard Worker }
479*288bf522SAndroid Build Coastguard Worker } else if (proto_record.has_lost()) {
480*288bf522SAndroid Build Coastguard Worker auto& lost = proto_record.lost();
481*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "lost_situation:\n");
482*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "sample_count: %" PRIu64 "\n", lost.sample_count());
483*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "lost_count: %" PRIu64 "\n", lost.lost_count());
484*288bf522SAndroid Build Coastguard Worker } else if (proto_record.has_file()) {
485*288bf522SAndroid Build Coastguard Worker auto& file = proto_record.file();
486*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "file:\n");
487*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "id: %u\n", file.id());
488*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "path: %s\n", file.path().c_str());
489*288bf522SAndroid Build Coastguard Worker for (int i = 0; i < file.symbol_size(); ++i) {
490*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "symbol: %s\n", file.symbol(i).c_str());
491*288bf522SAndroid Build Coastguard Worker }
492*288bf522SAndroid Build Coastguard Worker for (int i = 0; i < file.mangled_symbol_size(); ++i) {
493*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "mangled_symbol: %s\n", file.mangled_symbol(i).c_str());
494*288bf522SAndroid Build Coastguard Worker }
495*288bf522SAndroid Build Coastguard Worker if (file.id() != files.size()) {
496*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "file id doesn't increase orderly, expected " << files.size() << ", really "
497*288bf522SAndroid Build Coastguard Worker << file.id();
498*288bf522SAndroid Build Coastguard Worker return false;
499*288bf522SAndroid Build Coastguard Worker }
500*288bf522SAndroid Build Coastguard Worker files.push_back(file.symbol_size());
501*288bf522SAndroid Build Coastguard Worker } else if (proto_record.has_thread()) {
502*288bf522SAndroid Build Coastguard Worker auto& thread = proto_record.thread();
503*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "thread:\n");
504*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "thread_id: %u\n", thread.thread_id());
505*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "process_id: %u\n", thread.process_id());
506*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "thread_name: %s\n", thread.thread_name().c_str());
507*288bf522SAndroid Build Coastguard Worker } else if (proto_record.has_meta_info()) {
508*288bf522SAndroid Build Coastguard Worker auto& meta_info = proto_record.meta_info();
509*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "meta_info:\n");
510*288bf522SAndroid Build Coastguard Worker for (int i = 0; i < meta_info.event_type_size(); ++i) {
511*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "event_type: %s\n", meta_info.event_type(i).c_str());
512*288bf522SAndroid Build Coastguard Worker }
513*288bf522SAndroid Build Coastguard Worker if (meta_info.has_app_package_name()) {
514*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "app_package_name: %s\n",
515*288bf522SAndroid Build Coastguard Worker meta_info.app_package_name().c_str());
516*288bf522SAndroid Build Coastguard Worker }
517*288bf522SAndroid Build Coastguard Worker if (meta_info.has_app_type()) {
518*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "app_type: %s\n", meta_info.app_type().c_str());
519*288bf522SAndroid Build Coastguard Worker }
520*288bf522SAndroid Build Coastguard Worker if (meta_info.has_android_sdk_version()) {
521*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "android_sdk_version: %s\n",
522*288bf522SAndroid Build Coastguard Worker meta_info.android_sdk_version().c_str());
523*288bf522SAndroid Build Coastguard Worker }
524*288bf522SAndroid Build Coastguard Worker if (meta_info.has_android_build_type()) {
525*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "android_build_type: %s\n",
526*288bf522SAndroid Build Coastguard Worker meta_info.android_build_type().c_str());
527*288bf522SAndroid Build Coastguard Worker }
528*288bf522SAndroid Build Coastguard Worker if (meta_info.has_trace_offcpu()) {
529*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "trace_offcpu: %s\n",
530*288bf522SAndroid Build Coastguard Worker meta_info.trace_offcpu() ? "true" : "false");
531*288bf522SAndroid Build Coastguard Worker }
532*288bf522SAndroid Build Coastguard Worker } else if (proto_record.has_context_switch()) {
533*288bf522SAndroid Build Coastguard Worker auto& context_switch = proto_record.context_switch();
534*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "context_switch:\n");
535*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "switch_on: %s\n",
536*288bf522SAndroid Build Coastguard Worker context_switch.switch_on() ? "true" : "false");
537*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", context_switch.time());
538*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "thread_id: %u\n", context_switch.thread_id());
539*288bf522SAndroid Build Coastguard Worker } else {
540*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "unexpected record type ";
541*288bf522SAndroid Build Coastguard Worker return false;
542*288bf522SAndroid Build Coastguard Worker }
543*288bf522SAndroid Build Coastguard Worker }
544*288bf522SAndroid Build Coastguard Worker for (auto pair : max_symbol_id_map) {
545*288bf522SAndroid Build Coastguard Worker if (pair.first >= files.size()) {
546*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "file_id(" << pair.first << ") >= file count (" << files.size() << ")";
547*288bf522SAndroid Build Coastguard Worker return false;
548*288bf522SAndroid Build Coastguard Worker }
549*288bf522SAndroid Build Coastguard Worker if (static_cast<uint32_t>(pair.second) >= files[pair.first]) {
550*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "symbol_id(" << pair.second << ") >= symbol count (" << files[pair.first]
551*288bf522SAndroid Build Coastguard Worker << ") in file_id( " << pair.first << ")";
552*288bf522SAndroid Build Coastguard Worker return false;
553*288bf522SAndroid Build Coastguard Worker }
554*288bf522SAndroid Build Coastguard Worker }
555*288bf522SAndroid Build Coastguard Worker return true;
556*288bf522SAndroid Build Coastguard Worker }
557*288bf522SAndroid Build Coastguard Worker
OpenRecordFile()558*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::OpenRecordFile() {
559*288bf522SAndroid Build Coastguard Worker record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
560*288bf522SAndroid Build Coastguard Worker if (record_file_reader_ == nullptr) {
561*288bf522SAndroid Build Coastguard Worker return false;
562*288bf522SAndroid Build Coastguard Worker }
563*288bf522SAndroid Build Coastguard Worker if (!record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_)) {
564*288bf522SAndroid Build Coastguard Worker return false;
565*288bf522SAndroid Build Coastguard Worker }
566*288bf522SAndroid Build Coastguard Worker auto& meta_info = record_file_reader_->GetMetaInfoFeature();
567*288bf522SAndroid Build Coastguard Worker if (auto it = meta_info.find("trace_offcpu"); it != meta_info.end()) {
568*288bf522SAndroid Build Coastguard Worker trace_offcpu_ = it->second == "true";
569*288bf522SAndroid Build Coastguard Worker if (trace_offcpu_) {
570*288bf522SAndroid Build Coastguard Worker std::string event_name = GetEventNameByAttr(record_file_reader_->AttrSection()[0].attr);
571*288bf522SAndroid Build Coastguard Worker if (!android::base::StartsWith(event_name, "cpu-clock") &&
572*288bf522SAndroid Build Coastguard Worker !android::base::StartsWith(event_name, "task-clock")) {
573*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "Recording file " << record_filename_ << " is no longer supported. "
574*288bf522SAndroid Build Coastguard Worker << "--trace-offcpu must be used with `-e cpu-clock` or `-e task-clock`.";
575*288bf522SAndroid Build Coastguard Worker return false;
576*288bf522SAndroid Build Coastguard Worker }
577*288bf522SAndroid Build Coastguard Worker }
578*288bf522SAndroid Build Coastguard Worker }
579*288bf522SAndroid Build Coastguard Worker if (auto it = meta_info.find("kernel_symbols_available"); it != meta_info.end()) {
580*288bf522SAndroid Build Coastguard Worker kernel_symbols_available_ = it->second == "true";
581*288bf522SAndroid Build Coastguard Worker }
582*288bf522SAndroid Build Coastguard Worker if (!record_filter_.CheckClock(record_file_reader_->GetClockId())) {
583*288bf522SAndroid Build Coastguard Worker return false;
584*288bf522SAndroid Build Coastguard Worker }
585*288bf522SAndroid Build Coastguard Worker for (const EventAttrWithId& attr : record_file_reader_->AttrSection()) {
586*288bf522SAndroid Build Coastguard Worker event_types_.push_back(GetEventNameByAttr(attr.attr));
587*288bf522SAndroid Build Coastguard Worker }
588*288bf522SAndroid Build Coastguard Worker return true;
589*288bf522SAndroid Build Coastguard Worker }
590*288bf522SAndroid Build Coastguard Worker
PrintMetaInfo()591*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::PrintMetaInfo() {
592*288bf522SAndroid Build Coastguard Worker auto& meta_info = record_file_reader_->GetMetaInfoFeature();
593*288bf522SAndroid Build Coastguard Worker
594*288bf522SAndroid Build Coastguard Worker auto get_meta_info_value = [&meta_info](const char* key) -> std::string {
595*288bf522SAndroid Build Coastguard Worker if (auto it = meta_info.find(key); it != meta_info.end()) {
596*288bf522SAndroid Build Coastguard Worker return it->second;
597*288bf522SAndroid Build Coastguard Worker }
598*288bf522SAndroid Build Coastguard Worker return "";
599*288bf522SAndroid Build Coastguard Worker };
600*288bf522SAndroid Build Coastguard Worker
601*288bf522SAndroid Build Coastguard Worker std::string app_package_name = get_meta_info_value("app_package_name");
602*288bf522SAndroid Build Coastguard Worker std::string app_type = get_meta_info_value("app_type");
603*288bf522SAndroid Build Coastguard Worker std::string android_sdk_version = get_meta_info_value("android_sdk_version");
604*288bf522SAndroid Build Coastguard Worker std::string android_build_type = get_meta_info_value("android_build_type");
605*288bf522SAndroid Build Coastguard Worker
606*288bf522SAndroid Build Coastguard Worker if (use_protobuf_) {
607*288bf522SAndroid Build Coastguard Worker proto::Record proto_record;
608*288bf522SAndroid Build Coastguard Worker proto::MetaInfo* proto_meta_info = proto_record.mutable_meta_info();
609*288bf522SAndroid Build Coastguard Worker for (auto& event_type : event_types_) {
610*288bf522SAndroid Build Coastguard Worker *(proto_meta_info->add_event_type()) = event_type;
611*288bf522SAndroid Build Coastguard Worker }
612*288bf522SAndroid Build Coastguard Worker if (!app_package_name.empty()) {
613*288bf522SAndroid Build Coastguard Worker proto_meta_info->set_app_package_name(app_package_name);
614*288bf522SAndroid Build Coastguard Worker }
615*288bf522SAndroid Build Coastguard Worker if (!app_type.empty()) {
616*288bf522SAndroid Build Coastguard Worker proto_meta_info->set_app_type(app_type);
617*288bf522SAndroid Build Coastguard Worker }
618*288bf522SAndroid Build Coastguard Worker if (!android_sdk_version.empty()) {
619*288bf522SAndroid Build Coastguard Worker proto_meta_info->set_android_sdk_version(android_sdk_version);
620*288bf522SAndroid Build Coastguard Worker }
621*288bf522SAndroid Build Coastguard Worker if (!android_build_type.empty()) {
622*288bf522SAndroid Build Coastguard Worker proto_meta_info->set_android_build_type(android_build_type);
623*288bf522SAndroid Build Coastguard Worker }
624*288bf522SAndroid Build Coastguard Worker proto_meta_info->set_trace_offcpu(trace_offcpu_);
625*288bf522SAndroid Build Coastguard Worker return WriteRecordInProtobuf(proto_record);
626*288bf522SAndroid Build Coastguard Worker }
627*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "meta_info:\n");
628*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "trace_offcpu: %s\n", trace_offcpu_ ? "true" : "false");
629*288bf522SAndroid Build Coastguard Worker for (auto& event_type : event_types_) {
630*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "event_type: %s\n", event_type.c_str());
631*288bf522SAndroid Build Coastguard Worker }
632*288bf522SAndroid Build Coastguard Worker if (!app_package_name.empty()) {
633*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "app_package_name: %s\n", app_package_name.c_str());
634*288bf522SAndroid Build Coastguard Worker }
635*288bf522SAndroid Build Coastguard Worker if (!app_type.empty()) {
636*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "app_type: %s\n", app_type.c_str());
637*288bf522SAndroid Build Coastguard Worker }
638*288bf522SAndroid Build Coastguard Worker if (!android_sdk_version.empty()) {
639*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "android_sdk_version: %s\n", android_sdk_version.c_str());
640*288bf522SAndroid Build Coastguard Worker }
641*288bf522SAndroid Build Coastguard Worker if (!android_build_type.empty()) {
642*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "android_build_type: %s\n", android_build_type.c_str());
643*288bf522SAndroid Build Coastguard Worker }
644*288bf522SAndroid Build Coastguard Worker return true;
645*288bf522SAndroid Build Coastguard Worker }
646*288bf522SAndroid Build Coastguard Worker
ProcessRecord(std::unique_ptr<Record> record)647*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::ProcessRecord(std::unique_ptr<Record> record) {
648*288bf522SAndroid Build Coastguard Worker thread_tree_.Update(*record);
649*288bf522SAndroid Build Coastguard Worker bool result = true;
650*288bf522SAndroid Build Coastguard Worker switch (record->type()) {
651*288bf522SAndroid Build Coastguard Worker case PERF_RECORD_SAMPLE: {
652*288bf522SAndroid Build Coastguard Worker result = ProcessSampleRecord(*static_cast<SampleRecord*>(record.get()));
653*288bf522SAndroid Build Coastguard Worker last_unwinding_result_.reset();
654*288bf522SAndroid Build Coastguard Worker break;
655*288bf522SAndroid Build Coastguard Worker }
656*288bf522SAndroid Build Coastguard Worker case SIMPLE_PERF_RECORD_UNWINDING_RESULT: {
657*288bf522SAndroid Build Coastguard Worker last_unwinding_result_.reset(static_cast<UnwindingResultRecord*>(record.release()));
658*288bf522SAndroid Build Coastguard Worker break;
659*288bf522SAndroid Build Coastguard Worker }
660*288bf522SAndroid Build Coastguard Worker case PERF_RECORD_LOST: {
661*288bf522SAndroid Build Coastguard Worker lost_count_ += static_cast<const LostRecord*>(record.get())->lost;
662*288bf522SAndroid Build Coastguard Worker break;
663*288bf522SAndroid Build Coastguard Worker }
664*288bf522SAndroid Build Coastguard Worker case PERF_RECORD_SWITCH:
665*288bf522SAndroid Build Coastguard Worker [[fallthrough]];
666*288bf522SAndroid Build Coastguard Worker case PERF_RECORD_SWITCH_CPU_WIDE: {
667*288bf522SAndroid Build Coastguard Worker result = ProcessSwitchRecord(record.get());
668*288bf522SAndroid Build Coastguard Worker break;
669*288bf522SAndroid Build Coastguard Worker }
670*288bf522SAndroid Build Coastguard Worker }
671*288bf522SAndroid Build Coastguard Worker return result;
672*288bf522SAndroid Build Coastguard Worker }
673*288bf522SAndroid Build Coastguard Worker
IsThreadStartPoint(CallChainReportEntry & entry)674*288bf522SAndroid Build Coastguard Worker static bool IsThreadStartPoint(CallChainReportEntry& entry) {
675*288bf522SAndroid Build Coastguard Worker // Android studio wants a clear call chain end to notify whether a call chain is complete.
676*288bf522SAndroid Build Coastguard Worker // For the main thread, the call chain ends at __libc_init in libc.so. For other threads,
677*288bf522SAndroid Build Coastguard Worker // the call chain ends at __start_thread in libc.so.
678*288bf522SAndroid Build Coastguard Worker // The call chain of the main thread can go beyond __libc_init, to _start (<= android O) or
679*288bf522SAndroid Build Coastguard Worker // _start_main (> android O).
680*288bf522SAndroid Build Coastguard Worker return entry.dso->FileName() == "libc.so" &&
681*288bf522SAndroid Build Coastguard Worker (strcmp(entry.symbol->Name(), "__libc_init") == 0 ||
682*288bf522SAndroid Build Coastguard Worker strcmp(entry.symbol->Name(), "__start_thread") == 0);
683*288bf522SAndroid Build Coastguard Worker }
684*288bf522SAndroid Build Coastguard Worker
ProcessSampleRecord(const SampleRecord & r)685*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::ProcessSampleRecord(const SampleRecord& r) {
686*288bf522SAndroid Build Coastguard Worker if (!record_filter_.Check(r)) {
687*288bf522SAndroid Build Coastguard Worker return true;
688*288bf522SAndroid Build Coastguard Worker }
689*288bf522SAndroid Build Coastguard Worker size_t kernel_ip_count;
690*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> ips = r.GetCallChain(&kernel_ip_count);
691*288bf522SAndroid Build Coastguard Worker if (kernel_ip_count > 0u && remove_unknown_kernel_symbols_ && !kernel_symbols_available_) {
692*288bf522SAndroid Build Coastguard Worker ips.erase(ips.begin(), ips.begin() + kernel_ip_count);
693*288bf522SAndroid Build Coastguard Worker kernel_ip_count = 0;
694*288bf522SAndroid Build Coastguard Worker }
695*288bf522SAndroid Build Coastguard Worker if (ips.empty()) {
696*288bf522SAndroid Build Coastguard Worker return true;
697*288bf522SAndroid Build Coastguard Worker }
698*288bf522SAndroid Build Coastguard Worker if (!show_callchain_) {
699*288bf522SAndroid Build Coastguard Worker ips.resize(1);
700*288bf522SAndroid Build Coastguard Worker kernel_ip_count = std::min(kernel_ip_count, static_cast<size_t>(1u));
701*288bf522SAndroid Build Coastguard Worker }
702*288bf522SAndroid Build Coastguard Worker const ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
703*288bf522SAndroid Build Coastguard Worker std::vector<CallChainReportEntry> callchain =
704*288bf522SAndroid Build Coastguard Worker callchain_report_builder_.Build(thread, ips, kernel_ip_count);
705*288bf522SAndroid Build Coastguard Worker
706*288bf522SAndroid Build Coastguard Worker bool complete_callchain = false;
707*288bf522SAndroid Build Coastguard Worker for (size_t i = 1; i < callchain.size(); i++) {
708*288bf522SAndroid Build Coastguard Worker // Stop at unknown callchain.
709*288bf522SAndroid Build Coastguard Worker if (thread_tree_.IsUnknownDso(callchain[i].dso)) {
710*288bf522SAndroid Build Coastguard Worker callchain.resize(i);
711*288bf522SAndroid Build Coastguard Worker break;
712*288bf522SAndroid Build Coastguard Worker }
713*288bf522SAndroid Build Coastguard Worker // Stop at thread start point. Because Android studio wants a clear call chain end.
714*288bf522SAndroid Build Coastguard Worker if (IsThreadStartPoint(callchain[i])) {
715*288bf522SAndroid Build Coastguard Worker complete_callchain = true;
716*288bf522SAndroid Build Coastguard Worker callchain.resize(i + 1);
717*288bf522SAndroid Build Coastguard Worker break;
718*288bf522SAndroid Build Coastguard Worker }
719*288bf522SAndroid Build Coastguard Worker }
720*288bf522SAndroid Build Coastguard Worker SampleEntry sample;
721*288bf522SAndroid Build Coastguard Worker sample.time = r.time_data.time;
722*288bf522SAndroid Build Coastguard Worker sample.period = r.period_data.period;
723*288bf522SAndroid Build Coastguard Worker sample.event_type_id = record_file_reader_->GetAttrIndexOfRecord(&r);
724*288bf522SAndroid Build Coastguard Worker sample.is_complete_callchain = complete_callchain;
725*288bf522SAndroid Build Coastguard Worker sample.callchain = std::move(callchain);
726*288bf522SAndroid Build Coastguard Worker // No need to add unwinding result for callchains fixed by callchain joiner.
727*288bf522SAndroid Build Coastguard Worker if (!complete_callchain && last_unwinding_result_) {
728*288bf522SAndroid Build Coastguard Worker sample.unwinding_result = last_unwinding_result_->unwinding_result;
729*288bf522SAndroid Build Coastguard Worker }
730*288bf522SAndroid Build Coastguard Worker
731*288bf522SAndroid Build Coastguard Worker return ProcessSample(*thread, sample);
732*288bf522SAndroid Build Coastguard Worker }
733*288bf522SAndroid Build Coastguard Worker
ProcessSample(const ThreadEntry & thread,SampleEntry & sample)734*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::ProcessSample(const ThreadEntry& thread, SampleEntry& sample) {
735*288bf522SAndroid Build Coastguard Worker ThreadId thread_id(thread.pid, thread.tid);
736*288bf522SAndroid Build Coastguard Worker ThreadData& data = per_thread_data_[thread_id];
737*288bf522SAndroid Build Coastguard Worker if (data.thread_name != thread.comm) {
738*288bf522SAndroid Build Coastguard Worker data.thread_name = thread.comm;
739*288bf522SAndroid Build Coastguard Worker }
740*288bf522SAndroid Build Coastguard Worker
741*288bf522SAndroid Build Coastguard Worker // If the sample has incomplete callchain, we push it to stack gap sample queue, to calculate
742*288bf522SAndroid Build Coastguard Worker // stack gap length later.
743*288bf522SAndroid Build Coastguard Worker if (!sample.is_complete_callchain) {
744*288bf522SAndroid Build Coastguard Worker data.stack_gap_samples.push(std::move(sample));
745*288bf522SAndroid Build Coastguard Worker return true;
746*288bf522SAndroid Build Coastguard Worker }
747*288bf522SAndroid Build Coastguard Worker // Otherwise, we can clean up stack gap sample queue and report the sample immediately.
748*288bf522SAndroid Build Coastguard Worker size_t gap_length = data.stack_gap_samples.size();
749*288bf522SAndroid Build Coastguard Worker while (!data.stack_gap_samples.empty()) {
750*288bf522SAndroid Build Coastguard Worker if (!ReportSample(thread_id, data.stack_gap_samples.front(), gap_length)) {
751*288bf522SAndroid Build Coastguard Worker return false;
752*288bf522SAndroid Build Coastguard Worker }
753*288bf522SAndroid Build Coastguard Worker data.stack_gap_samples.pop();
754*288bf522SAndroid Build Coastguard Worker }
755*288bf522SAndroid Build Coastguard Worker return ReportSample(thread_id, sample, 0);
756*288bf522SAndroid Build Coastguard Worker }
757*288bf522SAndroid Build Coastguard Worker
ReportSample(const ThreadId & thread_id,const SampleEntry & sample,size_t stack_gap_length)758*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::ReportSample(const ThreadId& thread_id, const SampleEntry& sample,
759*288bf522SAndroid Build Coastguard Worker size_t stack_gap_length) {
760*288bf522SAndroid Build Coastguard Worker // Remove samples within a stack gap <= max_remove_gap_length_.
761*288bf522SAndroid Build Coastguard Worker if (stack_gap_length > 0 && stack_gap_length <= max_remove_gap_length_) {
762*288bf522SAndroid Build Coastguard Worker return true;
763*288bf522SAndroid Build Coastguard Worker }
764*288bf522SAndroid Build Coastguard Worker sample_count_++;
765*288bf522SAndroid Build Coastguard Worker if (use_protobuf_) {
766*288bf522SAndroid Build Coastguard Worker return PrintSampleInProtobuf(thread_id, sample);
767*288bf522SAndroid Build Coastguard Worker }
768*288bf522SAndroid Build Coastguard Worker return PrintSample(thread_id, sample);
769*288bf522SAndroid Build Coastguard Worker }
770*288bf522SAndroid Build Coastguard Worker
FinishReportSamples()771*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::FinishReportSamples() {
772*288bf522SAndroid Build Coastguard Worker for (auto& p : per_thread_data_) {
773*288bf522SAndroid Build Coastguard Worker const auto& thread_id = p.first;
774*288bf522SAndroid Build Coastguard Worker auto& sample_queue = p.second.stack_gap_samples;
775*288bf522SAndroid Build Coastguard Worker size_t gap_length = sample_queue.size();
776*288bf522SAndroid Build Coastguard Worker while (!sample_queue.empty()) {
777*288bf522SAndroid Build Coastguard Worker if (!ReportSample(thread_id, sample_queue.front(), gap_length)) {
778*288bf522SAndroid Build Coastguard Worker return false;
779*288bf522SAndroid Build Coastguard Worker }
780*288bf522SAndroid Build Coastguard Worker sample_queue.pop();
781*288bf522SAndroid Build Coastguard Worker }
782*288bf522SAndroid Build Coastguard Worker }
783*288bf522SAndroid Build Coastguard Worker return true;
784*288bf522SAndroid Build Coastguard Worker }
785*288bf522SAndroid Build Coastguard Worker
PrintSampleInProtobuf(const ThreadId & thread_id,const SampleEntry & sample)786*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::PrintSampleInProtobuf(const ThreadId& thread_id,
787*288bf522SAndroid Build Coastguard Worker const SampleEntry& sample) {
788*288bf522SAndroid Build Coastguard Worker proto::Record proto_record;
789*288bf522SAndroid Build Coastguard Worker proto::Sample* proto_sample = proto_record.mutable_sample();
790*288bf522SAndroid Build Coastguard Worker proto_sample->set_time(sample.time);
791*288bf522SAndroid Build Coastguard Worker proto_sample->set_event_count(sample.period);
792*288bf522SAndroid Build Coastguard Worker proto_sample->set_thread_id(thread_id.tid);
793*288bf522SAndroid Build Coastguard Worker proto_sample->set_event_type_id(sample.event_type_id);
794*288bf522SAndroid Build Coastguard Worker
795*288bf522SAndroid Build Coastguard Worker for (const auto& node : sample.callchain) {
796*288bf522SAndroid Build Coastguard Worker proto::Sample_CallChainEntry* callchain = proto_sample->add_callchain();
797*288bf522SAndroid Build Coastguard Worker uint32_t file_id;
798*288bf522SAndroid Build Coastguard Worker if (!node.dso->GetDumpId(&file_id)) {
799*288bf522SAndroid Build Coastguard Worker file_id = node.dso->CreateDumpId();
800*288bf522SAndroid Build Coastguard Worker }
801*288bf522SAndroid Build Coastguard Worker int32_t symbol_id = -1;
802*288bf522SAndroid Build Coastguard Worker if (node.symbol != thread_tree_.UnknownSymbol()) {
803*288bf522SAndroid Build Coastguard Worker if (!node.symbol->GetDumpId(reinterpret_cast<uint32_t*>(&symbol_id))) {
804*288bf522SAndroid Build Coastguard Worker symbol_id = node.dso->CreateSymbolDumpId(node.symbol);
805*288bf522SAndroid Build Coastguard Worker }
806*288bf522SAndroid Build Coastguard Worker }
807*288bf522SAndroid Build Coastguard Worker callchain->set_vaddr_in_file(node.vaddr_in_file);
808*288bf522SAndroid Build Coastguard Worker callchain->set_file_id(file_id);
809*288bf522SAndroid Build Coastguard Worker callchain->set_symbol_id(symbol_id);
810*288bf522SAndroid Build Coastguard Worker if (show_execution_type_) {
811*288bf522SAndroid Build Coastguard Worker callchain->set_execution_type(ToProtoExecutionType(node.execution_type));
812*288bf522SAndroid Build Coastguard Worker }
813*288bf522SAndroid Build Coastguard Worker }
814*288bf522SAndroid Build Coastguard Worker if (sample.unwinding_result.has_value()) {
815*288bf522SAndroid Build Coastguard Worker AddUnwindingResultInProtobuf(sample.unwinding_result.value(),
816*288bf522SAndroid Build Coastguard Worker proto_sample->mutable_unwinding_result());
817*288bf522SAndroid Build Coastguard Worker }
818*288bf522SAndroid Build Coastguard Worker return WriteRecordInProtobuf(proto_record);
819*288bf522SAndroid Build Coastguard Worker }
820*288bf522SAndroid Build Coastguard Worker
AddUnwindingResultInProtobuf(const UnwindingResult & unwinding_result,proto::Sample_UnwindingResult * proto_unwinding_result)821*288bf522SAndroid Build Coastguard Worker void ReportSampleCommand::AddUnwindingResultInProtobuf(
822*288bf522SAndroid Build Coastguard Worker const UnwindingResult& unwinding_result,
823*288bf522SAndroid Build Coastguard Worker proto::Sample_UnwindingResult* proto_unwinding_result) {
824*288bf522SAndroid Build Coastguard Worker proto_unwinding_result->set_raw_error_code(unwinding_result.error_code);
825*288bf522SAndroid Build Coastguard Worker proto_unwinding_result->set_error_addr(unwinding_result.error_addr);
826*288bf522SAndroid Build Coastguard Worker proto::Sample_UnwindingResult_ErrorCode error_code;
827*288bf522SAndroid Build Coastguard Worker switch (unwinding_result.error_code) {
828*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_NONE:
829*288bf522SAndroid Build Coastguard Worker error_code = proto::Sample_UnwindingResult::ERROR_NONE;
830*288bf522SAndroid Build Coastguard Worker break;
831*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_MEMORY_INVALID: {
832*288bf522SAndroid Build Coastguard Worker // We dumped stack data in range [stack_start, stack_end) for dwarf unwinding.
833*288bf522SAndroid Build Coastguard Worker // If the failed-to-read memory addr is within [stack_end, stack_end + 128k], then
834*288bf522SAndroid Build Coastguard Worker // probably we didn't dump enough stack data.
835*288bf522SAndroid Build Coastguard Worker // 128k is a guess number. The size of stack used in one function layer is usually smaller
836*288bf522SAndroid Build Coastguard Worker // than it. And using a bigger value is more likely to be false positive.
837*288bf522SAndroid Build Coastguard Worker if (unwinding_result.error_addr >= unwinding_result.stack_end &&
838*288bf522SAndroid Build Coastguard Worker unwinding_result.error_addr <= unwinding_result.stack_end + 128 * 1024) {
839*288bf522SAndroid Build Coastguard Worker error_code = proto::Sample_UnwindingResult::ERROR_NOT_ENOUGH_STACK;
840*288bf522SAndroid Build Coastguard Worker } else {
841*288bf522SAndroid Build Coastguard Worker error_code = proto::Sample_UnwindingResult::ERROR_MEMORY_INVALID;
842*288bf522SAndroid Build Coastguard Worker }
843*288bf522SAndroid Build Coastguard Worker break;
844*288bf522SAndroid Build Coastguard Worker }
845*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_UNWIND_INFO:
846*288bf522SAndroid Build Coastguard Worker error_code = proto::Sample_UnwindingResult::ERROR_UNWIND_INFO;
847*288bf522SAndroid Build Coastguard Worker break;
848*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_INVALID_MAP:
849*288bf522SAndroid Build Coastguard Worker error_code = proto::Sample_UnwindingResult::ERROR_INVALID_MAP;
850*288bf522SAndroid Build Coastguard Worker break;
851*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_MAX_FRAMES_EXCEEDED:
852*288bf522SAndroid Build Coastguard Worker error_code = proto::Sample_UnwindingResult::ERROR_MAX_FRAME_EXCEEDED;
853*288bf522SAndroid Build Coastguard Worker break;
854*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_REPEATED_FRAME:
855*288bf522SAndroid Build Coastguard Worker error_code = proto::Sample_UnwindingResult::ERROR_REPEATED_FRAME;
856*288bf522SAndroid Build Coastguard Worker break;
857*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_INVALID_ELF:
858*288bf522SAndroid Build Coastguard Worker error_code = proto::Sample_UnwindingResult::ERROR_INVALID_ELF;
859*288bf522SAndroid Build Coastguard Worker break;
860*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_UNSUPPORTED:
861*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_THREAD_DOES_NOT_EXIST:
862*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_THREAD_TIMEOUT:
863*288bf522SAndroid Build Coastguard Worker case UnwindStackErrorCode::ERROR_SYSTEM_CALL:
864*288bf522SAndroid Build Coastguard Worker // These error_codes shouldn't happen in simpleperf's use of libunwindstack.
865*288bf522SAndroid Build Coastguard Worker error_code = proto::Sample_UnwindingResult::ERROR_UNKNOWN;
866*288bf522SAndroid Build Coastguard Worker break;
867*288bf522SAndroid Build Coastguard Worker default:
868*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "unknown unwinding error code: " << unwinding_result.error_code;
869*288bf522SAndroid Build Coastguard Worker error_code = proto::Sample_UnwindingResult::ERROR_UNKNOWN;
870*288bf522SAndroid Build Coastguard Worker break;
871*288bf522SAndroid Build Coastguard Worker }
872*288bf522SAndroid Build Coastguard Worker proto_unwinding_result->set_error_code(error_code);
873*288bf522SAndroid Build Coastguard Worker }
874*288bf522SAndroid Build Coastguard Worker
ProcessSwitchRecord(Record * r)875*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::ProcessSwitchRecord(Record* r) {
876*288bf522SAndroid Build Coastguard Worker bool switch_on = !(r->header.misc & PERF_RECORD_MISC_SWITCH_OUT);
877*288bf522SAndroid Build Coastguard Worker uint64_t time = r->Timestamp();
878*288bf522SAndroid Build Coastguard Worker uint32_t tid = r->sample_id.tid_data.tid;
879*288bf522SAndroid Build Coastguard Worker if (use_protobuf_) {
880*288bf522SAndroid Build Coastguard Worker proto::Record proto_record;
881*288bf522SAndroid Build Coastguard Worker proto::ContextSwitch* proto_switch = proto_record.mutable_context_switch();
882*288bf522SAndroid Build Coastguard Worker proto_switch->set_switch_on(switch_on);
883*288bf522SAndroid Build Coastguard Worker proto_switch->set_time(time);
884*288bf522SAndroid Build Coastguard Worker proto_switch->set_thread_id(tid);
885*288bf522SAndroid Build Coastguard Worker return WriteRecordInProtobuf(proto_record);
886*288bf522SAndroid Build Coastguard Worker }
887*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "context_switch:\n");
888*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "switch_on: %s\n", switch_on ? "true" : "false");
889*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", time);
890*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "thread_id: %u\n", tid);
891*288bf522SAndroid Build Coastguard Worker return true;
892*288bf522SAndroid Build Coastguard Worker }
893*288bf522SAndroid Build Coastguard Worker
WriteRecordInProtobuf(proto::Record & proto_record)894*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::WriteRecordInProtobuf(proto::Record& proto_record) {
895*288bf522SAndroid Build Coastguard Worker coded_os_->WriteLittleEndian32(static_cast<uint32_t>(proto_record.ByteSizeLong()));
896*288bf522SAndroid Build Coastguard Worker if (!proto_record.SerializeToCodedStream(coded_os_)) {
897*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "failed to write record to protobuf";
898*288bf522SAndroid Build Coastguard Worker return false;
899*288bf522SAndroid Build Coastguard Worker }
900*288bf522SAndroid Build Coastguard Worker return true;
901*288bf522SAndroid Build Coastguard Worker }
902*288bf522SAndroid Build Coastguard Worker
PrintLostSituationInProtobuf()903*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::PrintLostSituationInProtobuf() {
904*288bf522SAndroid Build Coastguard Worker proto::Record proto_record;
905*288bf522SAndroid Build Coastguard Worker proto::LostSituation* lost = proto_record.mutable_lost();
906*288bf522SAndroid Build Coastguard Worker lost->set_sample_count(sample_count_);
907*288bf522SAndroid Build Coastguard Worker lost->set_lost_count(lost_count_);
908*288bf522SAndroid Build Coastguard Worker return WriteRecordInProtobuf(proto_record);
909*288bf522SAndroid Build Coastguard Worker }
910*288bf522SAndroid Build Coastguard Worker
CompareDsoByDumpId(Dso * d1,Dso * d2)911*288bf522SAndroid Build Coastguard Worker static bool CompareDsoByDumpId(Dso* d1, Dso* d2) {
912*288bf522SAndroid Build Coastguard Worker uint32_t id1 = UINT_MAX;
913*288bf522SAndroid Build Coastguard Worker d1->GetDumpId(&id1);
914*288bf522SAndroid Build Coastguard Worker uint32_t id2 = UINT_MAX;
915*288bf522SAndroid Build Coastguard Worker d2->GetDumpId(&id2);
916*288bf522SAndroid Build Coastguard Worker return id1 < id2;
917*288bf522SAndroid Build Coastguard Worker }
918*288bf522SAndroid Build Coastguard Worker
PrintFileInfoInProtobuf()919*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::PrintFileInfoInProtobuf() {
920*288bf522SAndroid Build Coastguard Worker std::vector<Dso*> dsos = thread_tree_.GetAllDsos();
921*288bf522SAndroid Build Coastguard Worker std::sort(dsos.begin(), dsos.end(), CompareDsoByDumpId);
922*288bf522SAndroid Build Coastguard Worker for (Dso* dso : dsos) {
923*288bf522SAndroid Build Coastguard Worker uint32_t file_id;
924*288bf522SAndroid Build Coastguard Worker if (!dso->GetDumpId(&file_id)) {
925*288bf522SAndroid Build Coastguard Worker continue;
926*288bf522SAndroid Build Coastguard Worker }
927*288bf522SAndroid Build Coastguard Worker proto::Record proto_record;
928*288bf522SAndroid Build Coastguard Worker proto::File* file = proto_record.mutable_file();
929*288bf522SAndroid Build Coastguard Worker file->set_id(file_id);
930*288bf522SAndroid Build Coastguard Worker file->set_path(std::string{dso->GetReportPath()});
931*288bf522SAndroid Build Coastguard Worker const std::vector<Symbol>& symbols = dso->GetSymbols();
932*288bf522SAndroid Build Coastguard Worker std::vector<const Symbol*> dump_symbols;
933*288bf522SAndroid Build Coastguard Worker for (const auto& sym : symbols) {
934*288bf522SAndroid Build Coastguard Worker if (sym.HasDumpId()) {
935*288bf522SAndroid Build Coastguard Worker dump_symbols.push_back(&sym);
936*288bf522SAndroid Build Coastguard Worker }
937*288bf522SAndroid Build Coastguard Worker }
938*288bf522SAndroid Build Coastguard Worker std::sort(dump_symbols.begin(), dump_symbols.end(), Symbol::CompareByDumpId);
939*288bf522SAndroid Build Coastguard Worker
940*288bf522SAndroid Build Coastguard Worker for (const auto& sym : dump_symbols) {
941*288bf522SAndroid Build Coastguard Worker file->add_symbol(sym->DemangledName());
942*288bf522SAndroid Build Coastguard Worker file->add_mangled_symbol(sym->Name());
943*288bf522SAndroid Build Coastguard Worker }
944*288bf522SAndroid Build Coastguard Worker if (!WriteRecordInProtobuf(proto_record)) {
945*288bf522SAndroid Build Coastguard Worker return false;
946*288bf522SAndroid Build Coastguard Worker }
947*288bf522SAndroid Build Coastguard Worker }
948*288bf522SAndroid Build Coastguard Worker return true;
949*288bf522SAndroid Build Coastguard Worker }
950*288bf522SAndroid Build Coastguard Worker
PrintThreadInfoInProtobuf()951*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::PrintThreadInfoInProtobuf() {
952*288bf522SAndroid Build Coastguard Worker for (const auto& p : per_thread_data_) {
953*288bf522SAndroid Build Coastguard Worker const auto& thread_id = p.first;
954*288bf522SAndroid Build Coastguard Worker const auto& thread_data = p.second;
955*288bf522SAndroid Build Coastguard Worker proto::Record proto_record;
956*288bf522SAndroid Build Coastguard Worker proto::Thread* proto_thread = proto_record.mutable_thread();
957*288bf522SAndroid Build Coastguard Worker proto_thread->set_thread_id(thread_id.tid);
958*288bf522SAndroid Build Coastguard Worker proto_thread->set_process_id(thread_id.pid);
959*288bf522SAndroid Build Coastguard Worker proto_thread->set_thread_name(thread_data.thread_name);
960*288bf522SAndroid Build Coastguard Worker if (!WriteRecordInProtobuf(proto_record)) {
961*288bf522SAndroid Build Coastguard Worker return false;
962*288bf522SAndroid Build Coastguard Worker }
963*288bf522SAndroid Build Coastguard Worker }
964*288bf522SAndroid Build Coastguard Worker return true;
965*288bf522SAndroid Build Coastguard Worker }
966*288bf522SAndroid Build Coastguard Worker
PrintSample(const ThreadId & thread_id,const SampleEntry & sample)967*288bf522SAndroid Build Coastguard Worker bool ReportSampleCommand::PrintSample(const ThreadId& thread_id, const SampleEntry& sample) {
968*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "sample:\n");
969*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "event_type: %s\n", event_types_[sample.event_type_id].data());
970*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", sample.time);
971*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "event_count: %" PRIu64 "\n", sample.period);
972*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "thread_id: %d\n", thread_id.tid);
973*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "thread_name: %s\n",
974*288bf522SAndroid Build Coastguard Worker per_thread_data_[thread_id].thread_name.c_str());
975*288bf522SAndroid Build Coastguard Worker const auto& entries = sample.callchain;
976*288bf522SAndroid Build Coastguard Worker CHECK(!entries.empty());
977*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "vaddr_in_file: %" PRIx64 "\n", entries[0].vaddr_in_file);
978*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "file: %s\n", entries[0].dso->GetReportPath().data());
979*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "symbol: %s\n", entries[0].symbol->DemangledName());
980*288bf522SAndroid Build Coastguard Worker if (show_execution_type_) {
981*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "execution_type: %s\n",
982*288bf522SAndroid Build Coastguard Worker ProtoExecutionTypeToString(ToProtoExecutionType(entries[0].execution_type)));
983*288bf522SAndroid Build Coastguard Worker }
984*288bf522SAndroid Build Coastguard Worker
985*288bf522SAndroid Build Coastguard Worker if (entries.size() > 1u) {
986*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "callchain:\n");
987*288bf522SAndroid Build Coastguard Worker for (size_t i = 1u; i < entries.size(); ++i) {
988*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "vaddr_in_file: %" PRIx64 "\n", entries[i].vaddr_in_file);
989*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "file: %s\n", entries[i].dso->GetReportPath().data());
990*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "symbol: %s\n", entries[i].symbol->DemangledName());
991*288bf522SAndroid Build Coastguard Worker if (show_execution_type_) {
992*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 2, "execution_type: %s\n",
993*288bf522SAndroid Build Coastguard Worker ProtoExecutionTypeToString(ToProtoExecutionType(entries[i].execution_type)));
994*288bf522SAndroid Build Coastguard Worker }
995*288bf522SAndroid Build Coastguard Worker }
996*288bf522SAndroid Build Coastguard Worker }
997*288bf522SAndroid Build Coastguard Worker return true;
998*288bf522SAndroid Build Coastguard Worker }
999*288bf522SAndroid Build Coastguard Worker
PrintLostSituation()1000*288bf522SAndroid Build Coastguard Worker void ReportSampleCommand::PrintLostSituation() {
1001*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 0, "lost_situation:\n");
1002*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "sample_count: %" PRIu64 "\n", sample_count_);
1003*288bf522SAndroid Build Coastguard Worker FprintIndented(report_fp_, 1, "lost_count: %" PRIu64 "\n", lost_count_);
1004*288bf522SAndroid Build Coastguard Worker }
1005*288bf522SAndroid Build Coastguard Worker
1006*288bf522SAndroid Build Coastguard Worker } // namespace
1007*288bf522SAndroid Build Coastguard Worker
RegisterReportSampleCommand()1008*288bf522SAndroid Build Coastguard Worker void RegisterReportSampleCommand() {
1009*288bf522SAndroid Build Coastguard Worker RegisterCommand("report-sample",
1010*288bf522SAndroid Build Coastguard Worker [] { return std::unique_ptr<Command>(new ReportSampleCommand()); });
1011*288bf522SAndroid Build Coastguard Worker }
1012*288bf522SAndroid Build Coastguard Worker
1013*288bf522SAndroid Build Coastguard Worker } // namespace simpleperf
1014