/* * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SUBCOMMAND_REPORT_H #define SUBCOMMAND_REPORT_H #include #include #include #include #include #include #include #include #include #include "perf_file_reader.h" #if HAVE_PROTOBUF #include "report_protobuf_file.h" #endif #include "debug_logger.h" #include "option.h" #include "perf_event_record.h" #include "report.h" #include "report_json_file.h" #include "subcommand.h" #include "symbols_file.h" #include "utilities.h" #include "virtual_runtime.h" namespace OHOS { namespace Developtools { namespace HiPerf { class SubCommandReport : public SubCommand { public: SubCommandReport() // clang-format off : SubCommand("report", "report sampling information from perf.data format file", "Usage: hiperf report [options]\n" " The default options are same as :\n" " -i perf.data --sort comm,pid,tid,dso,func\n" " --symbol-dir \n" " use symbols path to find symbols.\n" " separate the paths with commas.\n" " --limit-percent \n" " only show heat percent limit content.\n" " -s / --call-stack\n" " show the unwind callstack\n" " --call-stack-limit-percent \n" " only show the callstack heat percent limit content.\n" " --proto\n" " show protobuf content in the save file name.\n" " default file name is perf.data.\n" " --json\n" " report in json format.\n" " default file name is perf.data.\n" " --diff \n" " show the diff result from -i to -diff .\n" " example: \"report -i a.data --diff b.data\"\n" " --branch\n" " show the branch from address instead of ip address\n" " -- [,keyname2][,...]\n" " select able keys: comms,pids,tids,dsos,funcs,from_dsos,from_funcs\n" " example: --comms hiperf\n" " --sort [,key2][,...]\n" " Choose some keywords.\n" " These keywords will be used for sorting.\n" " Only selected keywords will appear in the report.\n" "\n" " pid -- process id\n" " tid -- thread id\n" " comm -- thread name (can be changed for same thread)\n" " dso -- like dso name , or elf path\n" " func -- function name in the symbols\n" "\n" " in branch mode:\n" " from_dso -- branched from dso or elf\n" " from_func -- branched from function\n" " dso -- means branched to dso or elf\n" " func -- means branched to function\n" " -i \n" " perf data file to report, default is perf.data\n" " -o \n" " report file name. if empty will use stdout print\n" " --hide_count\n" " will not show count in report\n" "\n" ), recordFile_ {"perf.data", ""} // default file path is perf.data // clang-format on { } bool OnSubCommand(std::vector &args) override; bool ParseOption(std::vector &args) override; void DumpOptions(void) const override; static bool RegisterSubCommandReport(void); bool RecordCallBack(std::unique_ptr record); ~SubCommandReport(); private: void ProcessSample(std::unique_ptr &); void BroadcastSample(std::unique_ptr &); bool VerifyOption(); bool VerifyDisplayOption(); // load bool PrepareOutput(); bool LoadPerfData(); void ProcessFeaturesData(); void LoadEventConfigData(); void LoadAttrSection(); void LoadEventDesc(); void ProcessSymbolsData(); void LoadPerfDataCompleted(); bool OutputReport(); bool OutputStd(); // prefdata bool showCallStack_ = false; bool diffMode_ = false; // create record file reader pointer std::unique_ptr recordFileReader_; std::vector symbolsPaths_; // report file name , if empty will use stdout std::string reportFile_; // for diff report enum RecordIndex { FIRST = 0, SECOND = 1, MAX = 2, CURRENT = -1 } index_ = FIRST; std::string recordFile_[MAX]; ReportOption reportOption_; Report report_[MAX] = {reportOption_, reportOption_}; inline Report &GetReport(RecordIndex index = CURRENT, int configId = 0) { if (index == CURRENT) { return report_[index_]; } else { return report_[index]; } } std::vector configNames_; std::set cpuOffids_; const std::string cpuOffEventName = "sched:sched_switch"; bool cpuOffMode_ = false; std::map> prevSampleCache_; void FlushCacheRecord(); // in debug mode we will output some more debug info bool debug_ = false; bool branch_ = false; bool jsonFormat_ = false; FILE *output_ = nullptr; std::unique_ptr reportJsonFile_ = nullptr; bool protobufFormat_ = false; #if HAVE_PROTOBUF std::unique_ptr protobufOutputFileWriter_ = nullptr; void UpdateReportInfo(); #endif friend class SubCommandReportTest; FRIEND_TEST(SubCommandReportTest, TestLoadPerfData); FRIEND_TEST(SubCommandReportTest, TestOutputReport); FRIEND_TEST(SubCommandReportTest, TestOutputStd); FRIEND_TEST(SubCommandReportTest, TestVerifyOption); FRIEND_TEST(SubCommandReportTest, TestVerifyDisplayOption); FRIEND_TEST(SubCommandReportTest, TestPrepareConsole); FRIEND_TEST(SubCommandReportTest, TestPrepareConsole); }; } // namespace HiPerf } // namespace Developtools } // namespace OHOS #endif // SUBCOMMAND_REPORT_H