1767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui/* 2767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * Copyright (C) 2016 The Android Open Source Project 3767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * 4767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * Licensed under the Apache License, Version 2.0 (the "License"); 5767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * you may not use this file except in compliance with the License. 6767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * You may obtain a copy of the License at 7767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * 8767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * http://www.apache.org/licenses/LICENSE-2.0 9767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * 10767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * Unless required by applicable law or agreed to in writing, software 11767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * distributed under the License is distributed on an "AS IS" BASIS, 12767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * See the License for the specific language governing permissions and 14767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui * limitations under the License. 15767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui */ 16767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 17767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui#include <inttypes.h> 18767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 19767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui#include <memory> 20767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 2142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui#include "system/extras/simpleperf/report_sample.pb.h" 2242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 2342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui#include <google/protobuf/io/coded_stream.h> 2442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui#include <google/protobuf/io/zero_copy_stream_impl_lite.h> 2542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 26767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui#include "command.h" 27767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui#include "record_file.h" 28767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui#include "thread_tree.h" 29767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui#include "utils.h" 30767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 3142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cuinamespace proto = simpleperf_report_proto; 3242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 33767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cuinamespace { 34767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 3542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cuiclass ProtobufFileWriter : public google::protobuf::io::CopyingOutputStream { 3642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui public: 375674ed87431f2d9b05f4ec0c7f7c2e56e585c956Chih-Hung Hsieh explicit ProtobufFileWriter(FILE* out_fp) : out_fp_(out_fp) {} 3842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 3942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui bool Write(const void* buffer, int size) override { 4042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return fwrite(buffer, size, 1, out_fp_) == 1; 4142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 4242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 4342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui private: 4442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui FILE* out_fp_; 4542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui}; 4642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 4742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cuiclass ProtobufFileReader : public google::protobuf::io::CopyingInputStream { 4842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui public: 495674ed87431f2d9b05f4ec0c7f7c2e56e585c956Chih-Hung Hsieh explicit ProtobufFileReader(FILE* in_fp) : in_fp_(in_fp) {} 5042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 5142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui int Read(void* buffer, int size) override { 5242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return fread(buffer, 1, size, in_fp_); 5342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 5442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 5542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui private: 5642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui FILE* in_fp_; 5742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui}; 5842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 59767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cuiclass ReportSampleCommand : public Command { 60767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui public: 61767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui ReportSampleCommand() 62767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui : Command( 63767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui "report-sample", "report raw sample information in perf.data", 64767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui // clang-format off 65767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui"Usage: simpleperf report-sample [options]\n" 6642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui"--dump-protobuf-report <file>\n" 6742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui" Dump report file generated by\n" 6842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui" `simpleperf report-sample --protobuf -o <file>`.\n" 69767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui"-i <file> Specify path of record file, default is perf.data.\n" 70767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui"-o report_file_name Set report file name, default is stdout.\n" 7142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui"--protobuf Use protobuf format in report_sample.proto to output samples.\n" 7242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui" Need to set a report_file_name when using this option.\n" 73767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui"--show-callchain Print callchain samples.\n" 74767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui // clang-format on 75767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui ), 76767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui record_filename_("perf.data"), 77767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui show_callchain_(false), 7842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui use_protobuf_(false), 7942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui report_fp_(nullptr), 8042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui coded_os_(nullptr), 81587fb9b5b85e93a212586e6f98009860da0512edYabin Cui sample_count_(0), 8216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui lost_count_(0) {} 83767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 84767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui bool Run(const std::vector<std::string>& args) override; 85767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 86767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui private: 87767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui bool ParseOptions(const std::vector<std::string>& args); 8842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui bool DumpProtobufReport(const std::string& filename); 89767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui bool ProcessRecord(std::unique_ptr<Record> record); 90767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui bool PrintSampleRecordInProtobuf(const SampleRecord& record); 9198c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui bool GetCallEntry(const ThreadEntry* thread, bool in_kernel, uint64_t ip, bool omit_unknown_dso, 9298c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui uint64_t* pvaddr_in_file, uint32_t* pfile_id, int32_t* psymbol_id); 9398c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui bool GetCallEntry(const ThreadEntry* thread, bool in_kernel, uint64_t ip, bool omit_unknown_dso, 9498c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui uint64_t* pvaddr_in_file, Dso** pdso, const Symbol** psymbol); 9552190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui bool WriteRecordInProtobuf(proto::Record& proto_record); 96587fb9b5b85e93a212586e6f98009860da0512edYabin Cui bool PrintLostSituationInProtobuf(); 9716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui bool PrintFileInfoInProtobuf(); 9852190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui bool PrintThreadInfoInProtobuf(); 99767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui bool PrintSampleRecord(const SampleRecord& record); 100587fb9b5b85e93a212586e6f98009860da0512edYabin Cui void PrintLostSituation(); 101767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 102767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui std::string record_filename_; 103767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui std::unique_ptr<RecordFileReader> record_file_reader_; 10442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui std::string dump_protobuf_report_file_; 105767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui bool show_callchain_; 10642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui bool use_protobuf_; 107767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui ThreadTree thread_tree_; 108767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui std::string report_filename_; 109767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui FILE* report_fp_; 11042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui google::protobuf::io::CodedOutputStream* coded_os_; 111767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui size_t sample_count_; 112587fb9b5b85e93a212586e6f98009860da0512edYabin Cui size_t lost_count_; 113767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui}; 114767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 115767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cuibool ReportSampleCommand::Run(const std::vector<std::string>& args) { 116767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui // 1. Parse options. 117767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui if (!ParseOptions(args)) { 118767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return false; 119767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 12016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui // 2. Prepare report fp. 12116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui report_fp_ = stdout; 12216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui std::unique_ptr<FILE, decltype(&fclose)> fp(nullptr, fclose); 12316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (!report_filename_.empty()) { 12416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui const char* open_mode = "w"; 12516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (!dump_protobuf_report_file_.empty() && use_protobuf_) { 12616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui open_mode = "wb"; 12716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 12816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui fp.reset(fopen(report_filename_.c_str(), open_mode)); 12916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (fp == nullptr) { 13016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui PLOG(ERROR) << "failed to open " << report_filename_; 13116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui return false; 13216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 13316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui report_fp_ = fp.get(); 13416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 13516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui 13616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui // 3. Dump protobuf report. 13742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (!dump_protobuf_report_file_.empty()) { 13842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return DumpProtobufReport(dump_protobuf_report_file_); 13942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 14042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 14116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui // 4. Open record file. 142767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui record_file_reader_ = RecordFileReader::CreateInstance(record_filename_); 143767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui if (record_file_reader_ == nullptr) { 144767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return false; 145767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 146010b232198b1eab7c9fcba099a5565b03faba695Yabin Cui record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_); 147767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 14816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (use_protobuf_) { 14916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui GOOGLE_PROTOBUF_VERIFY_VERSION; 15016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } else { 15116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui thread_tree_.ShowMarkForUnknownSymbol(); 15216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui thread_tree_.ShowIpForUnknownSymbol(); 15316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 15416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui 15516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui // 5. Prepare protobuf output stream. 15642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui std::unique_ptr<ProtobufFileWriter> protobuf_writer; 15742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui std::unique_ptr<google::protobuf::io::CopyingOutputStreamAdaptor> protobuf_os; 15842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui std::unique_ptr<google::protobuf::io::CodedOutputStream> protobuf_coded_os; 15942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (use_protobuf_) { 16042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui protobuf_writer.reset(new ProtobufFileWriter(report_fp_)); 16142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui protobuf_os.reset(new google::protobuf::io::CopyingOutputStreamAdaptor( 16242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui protobuf_writer.get())); 16342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui protobuf_coded_os.reset( 16442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui new google::protobuf::io::CodedOutputStream(protobuf_os.get())); 16542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui coded_os_ = protobuf_coded_os.get(); 16642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 167767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 16816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui // 6. Read record file, and print samples online. 169767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui if (!record_file_reader_->ReadDataSection( 170767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui [this](std::unique_ptr<Record> record) { 171767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return ProcessRecord(std::move(record)); 172767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui })) { 173767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return false; 174767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 175767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 17642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (use_protobuf_) { 177587fb9b5b85e93a212586e6f98009860da0512edYabin Cui if (!PrintLostSituationInProtobuf()) { 178587fb9b5b85e93a212586e6f98009860da0512edYabin Cui return false; 179587fb9b5b85e93a212586e6f98009860da0512edYabin Cui } 18016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (!PrintFileInfoInProtobuf()) { 18116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui return false; 18216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 18352190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui if (!PrintThreadInfoInProtobuf()) { 18452190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui return false; 18552190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui } 18642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui coded_os_->WriteLittleEndian32(0); 18742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (coded_os_->HadError()) { 18842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui LOG(ERROR) << "print protobuf report failed"; 18942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return false; 19042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 19142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui protobuf_coded_os.reset(nullptr); 19242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } else { 193587fb9b5b85e93a212586e6f98009860da0512edYabin Cui PrintLostSituation(); 19442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui fflush(report_fp_); 19542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 196767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui if (ferror(report_fp_) != 0) { 197767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui PLOG(ERROR) << "print report failed"; 198767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return false; 199767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 200767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return true; 201767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui} 202767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 203767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cuibool ReportSampleCommand::ParseOptions(const std::vector<std::string>& args) { 204767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui for (size_t i = 0; i < args.size(); ++i) { 20542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (args[i] == "--dump-protobuf-report") { 20642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (!NextArgumentOrError(args, &i)) { 20742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return false; 20842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 20942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui dump_protobuf_report_file_ = args[i]; 21042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } else if (args[i] == "-i") { 211767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui if (!NextArgumentOrError(args, &i)) { 212767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return false; 213767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 214767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui record_filename_ = args[i]; 215767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } else if (args[i] == "-o") { 216767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui if (!NextArgumentOrError(args, &i)) { 217767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return false; 218767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 219767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui report_filename_ = args[i]; 22042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } else if (args[i] == "--protobuf") { 22142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui use_protobuf_ = true; 222767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } else if (args[i] == "--show-callchain") { 223767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui show_callchain_ = true; 224767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } else { 225767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui ReportUnknownOption(args, i); 226767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return false; 227767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 228767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 22942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 23042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (use_protobuf_ && report_filename_.empty()) { 23142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui LOG(ERROR) << "please specify a report filename to write protobuf data"; 23242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return false; 23342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 23442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return true; 23542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui} 23642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 23742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cuibool ReportSampleCommand::DumpProtobufReport(const std::string& filename) { 23842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui GOOGLE_PROTOBUF_VERIFY_VERSION; 23942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(filename.c_str(), "rb"), 24042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui fclose); 24142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (fp == nullptr) { 24242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui PLOG(ERROR) << "failed to open " << filename; 24342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return false; 24442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 24542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui ProtobufFileReader protobuf_reader(fp.get()); 24642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui google::protobuf::io::CopyingInputStreamAdaptor adaptor(&protobuf_reader); 24742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui google::protobuf::io::CodedInputStream coded_is(&adaptor); 24816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui // map from file_id to max_symbol_id requested on the file. 24916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui std::unordered_map<uint32_t, int32_t> max_symbol_id_map; 25016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui // files[file_id] is the number of symbols in the file. 25116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui std::vector<uint32_t> files; 25216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint32_t max_message_size = 64 * (1 << 20); 25316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint32_t warning_message_size = 512 * (1 << 20); 25416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui coded_is.SetTotalBytesLimit(max_message_size, warning_message_size); 25542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui while (true) { 25642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui uint32_t size; 25742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (!coded_is.ReadLittleEndian32(&size)) { 25842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui PLOG(ERROR) << "failed to read " << filename; 25942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return false; 26042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 26142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (size == 0) { 26242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui break; 26342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 26416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui // Handle files having large symbol table. 26516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (size > max_message_size) { 26616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui max_message_size = size; 26716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui coded_is.SetTotalBytesLimit(max_message_size, warning_message_size); 26816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 26942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui auto limit = coded_is.PushLimit(size); 27042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui proto::Record proto_record; 27142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (!proto_record.ParseFromCodedStream(&coded_is)) { 27242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui PLOG(ERROR) << "failed to read " << filename; 27342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return false; 27442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 27542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui coded_is.PopLimit(limit); 27616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (proto_record.has_sample()) { 277587fb9b5b85e93a212586e6f98009860da0512edYabin Cui auto& sample = proto_record.sample(); 278587fb9b5b85e93a212586e6f98009860da0512edYabin Cui static size_t sample_count = 0; 27916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 0, "sample %zu:\n", ++sample_count); 28016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", sample.time()); 28107ee9416bcaf6b1e2da2fadbc73995d27dbebb42Yabin Cui FprintIndented(report_fp_, 1, "event_count: %" PRIu64 "\n", sample.event_count()); 28216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 1, "thread_id: %d\n", sample.thread_id()); 28316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 1, "callchain:\n"); 28416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui for (int i = 0; i < sample.callchain_size(); ++i) { 28516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui const proto::Sample_CallChainEntry& callchain = sample.callchain(i); 28616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 2, "vaddr_in_file: %" PRIx64 "\n", 28716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui callchain.vaddr_in_file()); 28816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 2, "file_id: %u\n", callchain.file_id()); 28916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui int32_t symbol_id = callchain.symbol_id(); 29016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 2, "symbol_id: %d\n", symbol_id); 29116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (symbol_id < -1) { 29216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui LOG(ERROR) << "unexpected symbol_id " << symbol_id; 29316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui return false; 29416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 29516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (symbol_id != -1) { 29616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui max_symbol_id_map[callchain.file_id()] = 29716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui std::max(max_symbol_id_map[callchain.file_id()], symbol_id); 29816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 299587fb9b5b85e93a212586e6f98009860da0512edYabin Cui } 30016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } else if (proto_record.has_lost()) { 301587fb9b5b85e93a212586e6f98009860da0512edYabin Cui auto& lost = proto_record.lost(); 30216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 0, "lost_situation:\n"); 30316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 1, "sample_count: %" PRIu64 "\n", 30416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui lost.sample_count()); 30516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 1, "lost_count: %" PRIu64 "\n", 30616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui lost.lost_count()); 30716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } else if (proto_record.has_file()) { 30816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui auto& file = proto_record.file(); 30916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 0, "file:\n"); 31016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 1, "id: %u\n", file.id()); 31116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 1, "path: %s\n", file.path().c_str()); 31216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui for (int i = 0; i < file.symbol_size(); ++i) { 31316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 1, "symbol: %s\n", file.symbol(i).c_str()); 31416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 31516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (file.id() != files.size()) { 31616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui LOG(ERROR) << "file id doesn't increase orderly, expected " 31716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui << files.size() << ", really " << file.id(); 31816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui return false; 31916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 32016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui files.push_back(file.symbol_size()); 32152190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui } else if (proto_record.has_thread()) { 32252190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui auto& thread = proto_record.thread(); 32352190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui FprintIndented(report_fp_, 0, "thread:\n"); 32452190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui FprintIndented(report_fp_, 1, "thread_id: %u\n", thread.thread_id()); 32552190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui FprintIndented(report_fp_, 1, "process_id: %u\n", thread.process_id()); 32652190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui FprintIndented(report_fp_, 1, "thread_name: %s\n", thread.thread_name().c_str()); 327587fb9b5b85e93a212586e6f98009860da0512edYabin Cui } else { 32816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui LOG(ERROR) << "unexpected record type "; 32916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui return false; 33016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 33116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 33216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui for (auto pair : max_symbol_id_map) { 33316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (pair.first >= files.size()) { 33416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui LOG(ERROR) << "file_id(" << pair.first << ") >= file count (" 33516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui << files.size() << ")"; 33616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui return false; 33716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 33816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (static_cast<uint32_t>(pair.second) >= files[pair.first]) { 33916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui LOG(ERROR) << "symbol_id(" << pair.second << ") >= symbol count (" 34016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui << files[pair.first] << ") in file_id( " << pair.first << ")"; 34142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return false; 34242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 34342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 344767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return true; 345767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui} 346767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 347767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cuibool ReportSampleCommand::ProcessRecord(std::unique_ptr<Record> record) { 348767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui thread_tree_.Update(*record); 349767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui if (record->type() == PERF_RECORD_SAMPLE) { 350767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui sample_count_++; 35142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui auto& r = *static_cast<const SampleRecord*>(record.get()); 35242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (use_protobuf_) { 35342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return PrintSampleRecordInProtobuf(r); 35442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } else { 35542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return PrintSampleRecord(r); 35642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 357587fb9b5b85e93a212586e6f98009860da0512edYabin Cui } else if (record->type() == PERF_RECORD_LOST) { 358587fb9b5b85e93a212586e6f98009860da0512edYabin Cui lost_count_ += static_cast<const LostRecord*>(record.get())->lost; 35942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 36042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return true; 36142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui} 36242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 36342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cuibool ReportSampleCommand::PrintSampleRecordInProtobuf(const SampleRecord& r) { 36416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint64_t vaddr_in_file; 36516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint32_t file_id; 36616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui int32_t symbol_id; 36742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui proto::Record proto_record; 36842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui proto::Sample* sample = proto_record.mutable_sample(); 36942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui sample->set_time(r.time_data.time); 37007ee9416bcaf6b1e2da2fadbc73995d27dbebb42Yabin Cui sample->set_event_count(r.period_data.period); 37109dad97ae5110e9c706bba4b48e7aa8fb429d585Yabin Cui sample->set_thread_id(r.tid_data.tid); 37242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 37342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui bool in_kernel = r.InKernel(); 37442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui const ThreadEntry* thread = 37542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid); 37698c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui bool ret = GetCallEntry(thread, in_kernel, r.ip_data.ip, false, &vaddr_in_file, &file_id, 37798c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui &symbol_id); 37898c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui CHECK(ret); 37916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui proto::Sample_CallChainEntry* callchain = sample->add_callchain(); 38016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui callchain->set_vaddr_in_file(vaddr_in_file); 38116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui callchain->set_file_id(file_id); 38216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui callchain->set_symbol_id(symbol_id); 38342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui 384a447c0d5f1d5227af30c0cbb4320ad878bd78c43Yabin Cui if (show_callchain_ && (r.sample_type & PERF_SAMPLE_CALLCHAIN)) { 38542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui bool first_ip = true; 386190a848fb2d4f502372b2528c55ca1f520e90609Yabin Cui for (uint64_t i = 0; i < r.callchain_data.ip_nr; ++i) { 387190a848fb2d4f502372b2528c55ca1f520e90609Yabin Cui uint64_t ip = r.callchain_data.ips[i]; 38842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (ip >= PERF_CONTEXT_MAX) { 38942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui switch (ip) { 39042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui case PERF_CONTEXT_KERNEL: 39142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui in_kernel = true; 39242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui break; 39342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui case PERF_CONTEXT_USER: 39442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui in_kernel = false; 39542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui break; 39642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui default: 39742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex 39842c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui << ip << std::dec; 39942c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 40042c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } else { 40142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (first_ip) { 40242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui first_ip = false; 40342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui // Remove duplication with sample ip. 40442c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (ip == r.ip_data.ip) { 40542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui continue; 40642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 40742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 40898c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui if (!GetCallEntry(thread, in_kernel, ip, true, &vaddr_in_file, &file_id, &symbol_id)) { 40998c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui break; 41098c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui } 41142c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui callchain = sample->add_callchain(); 41216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui callchain->set_vaddr_in_file(vaddr_in_file); 41316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui callchain->set_file_id(file_id); 41416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui callchain->set_symbol_id(symbol_id); 41542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 41642c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 41742c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui } 41852190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui return WriteRecordInProtobuf(proto_record); 41952190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui} 42052190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui 42152190a377feeb1dccaae5034c51f0130c24dea09Yabin Cuibool ReportSampleCommand::WriteRecordInProtobuf(proto::Record& proto_record) { 42242c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui coded_os_->WriteLittleEndian32(proto_record.ByteSize()); 42342c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui if (!proto_record.SerializeToCodedStream(coded_os_)) { 42452190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui LOG(ERROR) << "failed to write record to protobuf"; 42542c8dc673e9edcfa9b315580cee2352c3db9f3e6Yabin Cui return false; 426767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 427767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return true; 428767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui} 429767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 43098c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cuibool ReportSampleCommand::GetCallEntry(const ThreadEntry* thread, 43116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui bool in_kernel, uint64_t ip, 43298c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui bool omit_unknown_dso, 43316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint64_t* pvaddr_in_file, 43416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint32_t* pfile_id, 43516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui int32_t* psymbol_id) { 43616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui Dso* dso; 43716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui const Symbol* symbol; 43898c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui if (!GetCallEntry(thread, in_kernel, ip, omit_unknown_dso, pvaddr_in_file, &dso, &symbol)) { 43998c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui return false; 44098c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui } 44116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (!dso->GetDumpId(pfile_id)) { 44216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui *pfile_id = dso->CreateDumpId(); 44316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 44416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (symbol != thread_tree_.UnknownSymbol()) { 44516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (!symbol->GetDumpId(reinterpret_cast<uint32_t*>(psymbol_id))) { 44616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui *psymbol_id = dso->CreateSymbolDumpId(symbol); 44716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 44816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } else { 44916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui *psymbol_id = -1; 45016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 45198c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui return true; 45216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui} 45316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui 45498c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cuibool ReportSampleCommand::GetCallEntry(const ThreadEntry* thread, 45516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui bool in_kernel, uint64_t ip, 45698c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui bool omit_unknown_dso, 45716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint64_t* pvaddr_in_file, Dso** pdso, 45816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui const Symbol** psymbol) { 45916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui const MapEntry* map = thread_tree_.FindMap(thread, ip, in_kernel); 46098c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui if (omit_unknown_dso && thread_tree_.IsUnknownDso(map->dso)) { 46198c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui return false; 46298c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui } 46316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui *psymbol = thread_tree_.FindSymbol(map, ip, pvaddr_in_file, pdso); 46416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui // If we can't find symbol, use the dso shown in the map. 46516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (*psymbol == thread_tree_.UnknownSymbol()) { 46616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui *pdso = map->dso; 46716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 46898c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui return true; 46916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui} 47016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui 471587fb9b5b85e93a212586e6f98009860da0512edYabin Cuibool ReportSampleCommand::PrintLostSituationInProtobuf() { 472587fb9b5b85e93a212586e6f98009860da0512edYabin Cui proto::Record proto_record; 473587fb9b5b85e93a212586e6f98009860da0512edYabin Cui proto::LostSituation* lost = proto_record.mutable_lost(); 474587fb9b5b85e93a212586e6f98009860da0512edYabin Cui lost->set_sample_count(sample_count_); 475587fb9b5b85e93a212586e6f98009860da0512edYabin Cui lost->set_lost_count(lost_count_); 47652190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui return WriteRecordInProtobuf(proto_record); 477587fb9b5b85e93a212586e6f98009860da0512edYabin Cui} 478587fb9b5b85e93a212586e6f98009860da0512edYabin Cui 47916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cuistatic bool CompareDsoByDumpId(Dso* d1, Dso* d2) { 48016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint32_t id1 = UINT_MAX; 48116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui d1->GetDumpId(&id1); 48216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint32_t id2 = UINT_MAX; 48316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui d2->GetDumpId(&id2); 48416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui return id1 < id2; 48516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui} 48616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui 48716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cuibool ReportSampleCommand::PrintFileInfoInProtobuf() { 48816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui std::vector<Dso*> dsos = thread_tree_.GetAllDsos(); 48916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui std::sort(dsos.begin(), dsos.end(), CompareDsoByDumpId); 49016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui for (Dso* dso : dsos) { 49116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint32_t file_id; 49216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (!dso->GetDumpId(&file_id)) { 49316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui continue; 49416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 49516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui proto::Record proto_record; 49616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui proto::File* file = proto_record.mutable_file(); 49716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui file->set_id(file_id); 49816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui file->set_path(dso->Path()); 49916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui const std::vector<Symbol>& symbols = dso->GetSymbols(); 50016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui std::vector<const Symbol*> dump_symbols; 50116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui for (const auto& sym : symbols) { 50216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui if (sym.HasDumpId()) { 50316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui dump_symbols.push_back(&sym); 50416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 50516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 506aba7e29f163b4a332a9d3fe9973d82c7d0db148fYabin Cui std::sort(dump_symbols.begin(), dump_symbols.end(), 507aba7e29f163b4a332a9d3fe9973d82c7d0db148fYabin Cui Symbol::CompareByDumpId); 50816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui 50916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui for (const auto& sym : dump_symbols) { 51016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui std::string* symbol = file->add_symbol(); 51116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui *symbol = sym->DemangledName(); 51216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 51352190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui if (!WriteRecordInProtobuf(proto_record)) { 51452190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui return false; 51552190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui } 51652190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui } 51752190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui return true; 51852190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui} 51952190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui 52052190a377feeb1dccaae5034c51f0130c24dea09Yabin Cuibool ReportSampleCommand::PrintThreadInfoInProtobuf() { 52152190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui std::vector<const ThreadEntry*> threads = thread_tree_.GetAllThreads(); 52252190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui auto compare_thread_id = [](const ThreadEntry* t1, const ThreadEntry* t2) { 52352190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui return t1->tid < t2->tid; 52452190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui }; 52552190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui std::sort(threads.begin(), threads.end(), compare_thread_id); 52652190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui for (auto& thread : threads) { 52752190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui proto::Record proto_record; 52852190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui proto::Thread* proto_thread = proto_record.mutable_thread(); 52952190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui proto_thread->set_thread_id(thread->tid); 53052190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui proto_thread->set_process_id(thread->pid); 53152190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui proto_thread->set_thread_name(thread->comm); 53252190a377feeb1dccaae5034c51f0130c24dea09Yabin Cui if (!WriteRecordInProtobuf(proto_record)) { 53316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui return false; 53416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 53516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui } 53616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui return true; 53716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui} 53816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui 539767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cuibool ReportSampleCommand::PrintSampleRecord(const SampleRecord& r) { 54016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui uint64_t vaddr_in_file; 54116501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui Dso* dso; 54216501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui const Symbol* symbol; 54316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui 544767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui FprintIndented(report_fp_, 0, "sample:\n"); 545767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", r.time_data.time); 54607ee9416bcaf6b1e2da2fadbc73995d27dbebb42Yabin Cui FprintIndented(report_fp_, 1, "event_count: %" PRIu64 "\n", r.period_data.period); 54709dad97ae5110e9c706bba4b48e7aa8fb429d585Yabin Cui FprintIndented(report_fp_, 1, "thread_id: %d\n", r.tid_data.tid); 54816501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui bool in_kernel = r.InKernel(); 54916501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui const ThreadEntry* thread = 55016501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid); 55198c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui bool ret = GetCallEntry(thread, in_kernel, r.ip_data.ip, false, &vaddr_in_file, &dso, &symbol); 55298c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui CHECK(ret); 55316501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 1, "vaddr_in_file: %" PRIx64 "\n", vaddr_in_file); 55416501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 1, "file: %s\n", dso->Path().c_str()); 555767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui FprintIndented(report_fp_, 1, "symbol: %s\n", symbol->DemangledName()); 556767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 557a447c0d5f1d5227af30c0cbb4320ad878bd78c43Yabin Cui if (show_callchain_ && (r.sample_type & PERF_SAMPLE_CALLCHAIN)) { 558767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui FprintIndented(report_fp_, 1, "callchain:\n"); 559767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui bool first_ip = true; 560190a848fb2d4f502372b2528c55ca1f520e90609Yabin Cui for (uint64_t i = 0; i < r.callchain_data.ip_nr; ++i) { 561190a848fb2d4f502372b2528c55ca1f520e90609Yabin Cui uint64_t ip = r.callchain_data.ips[i]; 562767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui if (ip >= PERF_CONTEXT_MAX) { 563767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui switch (ip) { 564767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui case PERF_CONTEXT_KERNEL: 565767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui in_kernel = true; 566767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui break; 567767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui case PERF_CONTEXT_USER: 568767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui in_kernel = false; 569767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui break; 570767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui default: 571767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex 572767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui << ip; 573767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 574767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } else { 575767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui if (first_ip) { 576767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui first_ip = false; 577767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui // Remove duplication with sample ip. 578767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui if (ip == r.ip_data.ip) { 579767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui continue; 580767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 581767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 58298c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui if (!GetCallEntry(thread, in_kernel, ip, true, &vaddr_in_file, &dso, &symbol)) { 58398c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui break; 58498c7584c1c6cb93ad3e0f66e2a6f1d6b2d8fb878Yabin Cui } 58516501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 2, "vaddr_in_file: %" PRIx64 "\n", 58616501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui vaddr_in_file); 58716501ffbd73483c498dde1ea4ad2670da7c9df55Yabin Cui FprintIndented(report_fp_, 2, "file: %s\n", dso->Path().c_str()); 588767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui FprintIndented(report_fp_, 2, "symbol: %s\n", symbol->DemangledName()); 589767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 590767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 591767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui } 592767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return true; 593767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui} 594767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 595587fb9b5b85e93a212586e6f98009860da0512edYabin Cuivoid ReportSampleCommand::PrintLostSituation() { 596587fb9b5b85e93a212586e6f98009860da0512edYabin Cui FprintIndented(report_fp_, 0, "lost_situation:\n"); 597587fb9b5b85e93a212586e6f98009860da0512edYabin Cui FprintIndented(report_fp_, 1, "sample_count: %" PRIu64 "\n", sample_count_); 598587fb9b5b85e93a212586e6f98009860da0512edYabin Cui FprintIndented(report_fp_, 1, "lost_count: %" PRIu64 "\n", sample_count_); 599587fb9b5b85e93a212586e6f98009860da0512edYabin Cui} 600587fb9b5b85e93a212586e6f98009860da0512edYabin Cui 601767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui} // namespace 602767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui 603767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cuivoid RegisterReportSampleCommand() { 604767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui RegisterCommand("report-sample", [] { 605767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui return std::unique_ptr<Command>(new ReportSampleCommand()); 606767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui }); 607767dd17947f1ae9dd3d02f738d442a23ed76f2f6Yabin Cui} 608