xref: /aosp_15_r20/system/extras/simpleperf/cmd_report_sample.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
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