diff options
author | Yabin Cui <yabinc@google.com> | 2019-09-19 23:15:42 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2019-09-19 23:15:42 +0000 |
commit | 9ad7a2597ff93810cb9635c947732274a36f9212 (patch) | |
tree | 4798a6f1af9925453a38582b36e5d89f4ec6b00e | |
parent | 15f2323247ecfe0acc344cb4d4e305ae9d0faf0e (diff) | |
parent | fad7bbea296a376139bddf8d3991a41b9d763409 (diff) | |
download | extras-9ad7a2597ff93810cb9635c947732274a36f9212.tar.gz |
Merge "simpleperf: output text format for autofdo in inject cmd."
-rw-r--r-- | simpleperf/cmd_inject.cpp | 80 | ||||
-rw-r--r-- | simpleperf/cmd_inject_test.cpp | 18 | ||||
-rw-r--r-- | simpleperf/utils.h | 10 |
3 files changed, 101 insertions, 7 deletions
diff --git a/simpleperf/cmd_inject.cpp b/simpleperf/cmd_inject.cpp index e14e32f0..9cf40b93 100644 --- a/simpleperf/cmd_inject.cpp +++ b/simpleperf/cmd_inject.cpp @@ -23,20 +23,39 @@ #include "command.h" #include "record_file.h" #include "thread_tree.h" +#include "utils.h" using namespace simpleperf; namespace { +using AddrPair = std::pair<uint64_t, uint64_t>; + +struct AddrPairHash { + size_t operator()(const AddrPair& ap) const noexcept { + size_t seed = 0; + HashCombine(seed, ap.first); + HashCombine(seed, ap.second); + return seed; + } +}; + +struct BinaryInfo { + std::unordered_map<AddrPair, uint64_t, AddrPairHash> range_count_map; + std::unordered_map<AddrPair, uint64_t, AddrPairHash> branch_count_map; +}; + class InjectCommand : public Command { public: InjectCommand() : Command("inject", "convert etm instruction tracing data into instr ranges", // clang-format off "Usage: simpleperf inject [options]\n" +"--binary binary_name Generate data only for binaries containing binary_name.\n" "-i <file> input perf.data, generated by recording cs-etm event type.\n" " Default is perf.data.\n" "-o <file> output file. Default is perf_inject.data.\n" +" The output is in text format accepted by AutoFDO.\n" "--dump-etm type1,type2,... Dump etm data. A type is one of raw, packet and element.\n" "--symdir <dir> Look for binaries in a directory recursively.\n" // clang-format on @@ -60,6 +79,7 @@ class InjectCommand : public Command { if (!record_file_reader_->ReadDataSection([this](auto r) { return ProcessRecord(r.get()); })) { return false; } + PostProcess(); output_fp_.reset(nullptr); return true; } @@ -67,7 +87,12 @@ class InjectCommand : public Command { private: bool ParseOptions(const std::vector<std::string>& args) { for (size_t i = 0; i < args.size(); i++) { - if (args[i] == "-i") { + if (args[i] == "--binary") { + if (!NextArgumentOrError(args, &i)) { + return false; + } + binary_name_filter_ = args[i]; + } else if (args[i] == "-i") { if (!NextArgumentOrError(args, &i)) { return false; } @@ -122,14 +147,52 @@ class InjectCommand : public Command { } void ProcessInstrRange(const ETMInstrRange& instr_range) { - fprintf(output_fp_.get(), - "dso %s, [0x%" PRIx64 "-0x%" PRIx64 "], branch_to 0x%" PRIx64 ", taken %" PRIu64 - ", not_taken %" PRIu64 "\n", - instr_range.dso->GetDebugFilePath().c_str(), instr_range.start_addr, - instr_range.end_addr, instr_range.branch_to_addr, instr_range.branch_taken_count, - instr_range.branch_not_taken_count); + if (instr_range.dso->GetDebugFilePath().find(binary_name_filter_) == std::string::npos) { + return; + } + auto& binary = binary_map_[instr_range.dso->GetDebugFilePath()]; + binary.range_count_map[AddrPair(instr_range.start_addr, instr_range.end_addr)] += + instr_range.branch_taken_count + instr_range.branch_not_taken_count; + if (instr_range.branch_taken_count > 0) { + binary.branch_count_map[AddrPair(instr_range.end_addr, instr_range.branch_to_addr)] += + instr_range.branch_taken_count; + } } + void PostProcess() { + for (const auto& pair : binary_map_) { + const std::string& binary_path = pair.first; + const BinaryInfo& binary = pair.second; + + // Write range_count_map. + fprintf(output_fp_.get(), "%zu\n", binary.range_count_map.size()); + for (const auto& pair2 : binary.range_count_map) { + const AddrPair& addr_range = pair2.first; + uint64_t count = pair2.second; + + fprintf(output_fp_.get(), "%" PRIx64 "-%" PRIx64 ":%" PRIu64 "\n", addr_range.first, + addr_range.second, count); + } + + // Write addr_count_map. + fprintf(output_fp_.get(), "0\n"); + + // Write branch_count_map. + fprintf(output_fp_.get(), "%zu\n", binary.branch_count_map.size()); + for (const auto& pair2 : binary.branch_count_map) { + const AddrPair& branch = pair2.first; + uint64_t count = pair2.second; + + fprintf(output_fp_.get(), "%" PRIx64 "->%" PRIx64 ":%" PRIu64 "\n", branch.first, + branch.second, count); + } + + // Write the binary path in comment. + fprintf(output_fp_.get(), "// %s\n\n", binary_path.c_str()); + } + } + + std::string binary_name_filter_; std::string input_filename_ = "perf.data"; std::string output_filename_ = "perf_inject.data"; ThreadTree thread_tree_; @@ -138,6 +201,9 @@ class InjectCommand : public Command { std::unique_ptr<ETMDecoder> etm_decoder_; std::vector<uint8_t> aux_data_buffer_; std::unique_ptr<FILE, decltype(&fclose)> output_fp_; + + // Store results for AutoFDO. + std::unordered_map<std::string, BinaryInfo> binary_map_; }; } // namespace diff --git a/simpleperf/cmd_inject_test.cpp b/simpleperf/cmd_inject_test.cpp index 473f04f7..3401360d 100644 --- a/simpleperf/cmd_inject_test.cpp +++ b/simpleperf/cmd_inject_test.cpp @@ -32,3 +32,21 @@ TEST(cmd_inject, smoke) { // Test that we can find instr range in etm_test_loop binary. ASSERT_NE(data.find("etm_test_loop"), std::string::npos); } + +TEST(cmd_inject, binary_option) { + // Test that data for etm_test_loop is generated when selected by --binary. + TemporaryFile tmpfile; + ASSERT_TRUE(InjectCmd()->Run({"--symdir", GetTestDataDir() + "etm", "-i", + GetTestData(PERF_DATA_ETM_TEST_LOOP), "--binary", "etm_test_loop", + "-o", tmpfile.path})); + std::string data; + ASSERT_TRUE(android::base::ReadFileToString(tmpfile.path, &data)); + ASSERT_NE(data.find("etm_test_loop"), std::string::npos); + + // Test that data for etm_test_loop isn't generated when not selected by --binary. + ASSERT_TRUE(InjectCmd()->Run({"--symdir", GetTestDataDir() + "etm", "-i", + GetTestData(PERF_DATA_ETM_TEST_LOOP), "--binary", + "no_etm_test_loop", "-o", tmpfile.path})); + ASSERT_TRUE(android::base::ReadFileToString(tmpfile.path, &data)); + ASSERT_EQ(data.find("etm_test_loop"), std::string::npos); +} diff --git a/simpleperf/utils.h b/simpleperf/utils.h index 3ca8f5cf..872e191d 100644 --- a/simpleperf/utils.h +++ b/simpleperf/utils.h @@ -163,4 +163,14 @@ timeval SecondToTimeval(double time_in_sec); std::string GetSimpleperfVersion(); +namespace { + +// from boost::hash_combine +template <typename T> +void HashCombine(size_t& seed, const T& val) { + seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + +} // namespace + #endif // SIMPLE_PERF_UTILS_H_ |