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