diff --git a/instruction_map.cc b/instruction_map.cc index 9342307..f460d67 100644 --- a/instruction_map.cc +++ b/instruction_map.cc @@ -29,7 +29,7 @@ InstructionMap::~InstructionMap() { } void InstructionMap::BuildPerFunctionInstructionMap( - const string &name, uint64 start_addr, uint64 end_addr) { + const string &name, uint64 start_addr, uint64 end_addr, bool is_repeat) { if (start_addr >= end_addr) { return; } @@ -39,7 +39,11 @@ void InstructionMap::BuildPerFunctionInstructionMap( inst_map_.insert(InstMap::value_type(addr, info)); if (info->source_stack.size() > 0) { symbol_map_->AddSourceCount(name, info->source_stack, 0, 1, - SymbolMap::MAX); + SymbolMap::MAX, std::string(), is_repeat); + for (const auto& event_name : symbol_map_->GetProcessingEventName()) { + symbol_map_->AddSourceCount(name, info->source_stack, 0, 1, + SymbolMap::MAX, event_name, is_repeat); + } } } } diff --git a/instruction_map.h b/instruction_map.h index 6a0a2bc..26287ee 100644 --- a/instruction_map.h +++ b/instruction_map.h @@ -53,8 +53,8 @@ class InstructionMap { } // Builds instruction map for a function. - void BuildPerFunctionInstructionMap(const string &name, uint64 start_addr, - uint64 end_addr); + void BuildPerFunctionInstructionMap(const std::string &name, + uint64 start_addr, uint64 end_addr, bool is_repeat); // Contains information about each instruction. struct InstInfo { diff --git a/profile.cc b/profile.cc index 95005f6..a306562 100644 --- a/profile.cc +++ b/profile.cc @@ -35,15 +35,19 @@ Profile::ProfileMaps *Profile::GetProfileMaps(uint64 addr) { uint64 start_addr, end_addr; if (symbol_map_->GetSymbolInfoByAddr(addr, &name, &start_addr, &end_addr)) { - std::pair ret = - symbol_profile_maps_.insert(SymbolProfileMaps::value_type(*name, NULL)); - if (ret.second) { - ret.first->second = new ProfileMaps(start_addr, end_addr); + uint32_t count = symbol_profile_maps_.count(*name); + if (count > 0) { + auto range = symbol_profile_maps_.equal_range(*name); + for (auto it = range.first; it != range.second; ++it) { + if (it->second->start_addr == start_addr) { + return it->second; + } + } } - return ret.first->second; - } else { - return NULL; + auto ret = symbol_profile_maps_.insert({*name, new ProfileMaps(start_addr, end_addr)}); + return ret->second; } + return NULL; } void Profile::AggregatePerFunctionProfile() { @@ -55,6 +59,16 @@ void Profile::AggregatePerFunctionProfile() { maps->address_count_map[addr_count.first + start] += addr_count.second; } } + /* annotate all event profile data from sample_reader_ */ + for (const auto &event_addr_count : sample_reader_->event_address_count_map()) { + for (const auto &addr_count : event_addr_count.second) { + ProfileMaps *maps = GetProfileMaps(addr_count.first + start); + if (maps != nullptr) { + maps->event_address_count_map[event_addr_count.first][addr_count.first + start] += + event_addr_count.second.at(addr_count.first); + } + } + } const RangeCountMap *range_map = &sample_reader_->range_count_map(); for (const auto &range_count : *range_map) { ProfileMaps *maps = GetProfileMaps(range_count.first.first + start); @@ -92,10 +106,11 @@ uint64 Profile::ProfileMaps::GetAggregatedCount() const { } void Profile::ProcessPerFunctionProfile(string func_name, - const ProfileMaps &maps) { + const ProfileMaps &maps, + bool is_repeat) { InstructionMap inst_map(addr2line_, symbol_map_); inst_map.BuildPerFunctionInstructionMap(func_name, maps.start_addr, - maps.end_addr); + maps.end_addr, is_repeat); AddressCountMap map; const AddressCountMap *map_ptr; @@ -117,21 +132,44 @@ void Profile::ProcessPerFunctionProfile(string func_name, map_ptr = &maps.address_count_map; } - for (const auto &address_count : *map_ptr) { - InstructionMap::InstMap::const_iterator iter = - inst_map.inst_map().find(address_count.first); - if (iter == inst_map.inst_map().end()) { - continue; - } - const InstructionMap::InstInfo *info = iter->second; - if (info == NULL) { - continue; + // For add SourceCount for each events. + if (!maps.event_address_count_map.empty()) { + for (const auto &event_address : maps.event_address_count_map) { + for (const auto &address_count : event_address.second) { + InstructionMap::InstMap::const_iterator iter = + inst_map.inst_map().find(address_count.first); + if (iter == inst_map.inst_map().end()) { + continue; + } + const InstructionMap::InstInfo *info = iter->second; + if (info == nullptr) { + continue; + } + if (info->source_stack.size() > 0) { + symbol_map_->AddSourceCount( + func_name, info->source_stack, + address_count.second * info->source_stack[0].DuplicationFactor(), 0, + SymbolMap::MAX, event_address.first, is_repeat); + } + } } - if (info->source_stack.size() > 0) { - symbol_map_->AddSourceCount( - func_name, info->source_stack, - address_count.second * info->source_stack[0].DuplicationFactor(), 0, - SymbolMap::MAX); + } else { + for (const auto &address_count : *map_ptr) { + InstructionMap::InstMap::const_iterator iter = + inst_map.inst_map().find(address_count.first); + if (iter == inst_map.inst_map().end()) { + continue; + } + const InstructionMap::InstInfo *info = iter->second; + if (info == NULL) { + continue; + } + if (info->source_stack.size() > 0) { + symbol_map_->AddSourceCount( + func_name, info->source_stack, + address_count.second * info->source_stack[0].DuplicationFactor(), 0, + SymbolMap::MAX, std::string(), is_repeat); + } } } @@ -178,8 +216,10 @@ void Profile::ComputeProfile() { // Traverse the symbol map to process the profiles. for (const auto &symbol_profile : symbol_profile_maps_) { - if (symbol_map_->ShouldEmit(symbol_profile.second->GetAggregatedCount())) - ProcessPerFunctionProfile(symbol_profile.first, *symbol_profile.second); + if (symbol_map_->ShouldEmit(symbol_profile.second->GetAggregatedCount())) { + bool is_repeat = symbol_profile_maps_.count(symbol_profile.first) > 1; + ProcessPerFunctionProfile(symbol_profile.first, *symbol_profile.second, is_repeat); + } } symbol_map_->Merge(); symbol_map_->ComputeWorkingSets(); diff --git a/profile.h b/profile.h index 810fb02..e851783 100644 --- a/profile.h +++ b/profile.h @@ -62,8 +62,10 @@ class Profile { AddressCountMap address_count_map; RangeCountMap range_count_map; BranchCountMap branch_count_map; + // Map events to Address count. + EventAddressCountMap event_address_count_map; }; - typedef map SymbolProfileMaps; + typedef std::multimap SymbolProfileMaps; // Returns the profile maps for a give function. ProfileMaps *GetProfileMaps(uint64 addr); @@ -74,7 +76,7 @@ class Profile { // Builds function level profile for specified function: // 1. Traverses all instructions to build instruction map. // 2. Unwinds the inline stack to add symbol count to each inlined symbol. - void ProcessPerFunctionProfile(string func_name, const ProfileMaps &map); + void ProcessPerFunctionProfile(string func_name, const ProfileMaps &map, bool is_repeat); const SampleReader *sample_reader_; const string binary_name_; diff --git a/profile_creator.cc b/profile_creator.cc index 80b0288..0189310 100644 --- a/profile_creator.cc +++ b/profile_creator.cc @@ -110,7 +110,16 @@ bool ProfileCreator::CreateProfile(const string &input_profile_name, if (!ReadSample(input_profile_name, profiler)) return false; if (!ComputeProfile(&symbol_map)) return false; } - bool ret = writer->WriteToFile(output_profile_name); + bool ret = true; + // The event_name_set stores target event name when processing more than one event in this perf.data, + // we can get the event name from event_name_set_ and write each event to it`s own profile. + if (!symbol_map.GetProcessingEventName().empty()) { + for (const auto &event_name : symbol_map.GetProcessingEventName()) { + ret &= writer->WriteToFile(output_profile_name + "." + event_name, event_name); + } + } else { + ret &= writer->WriteToFile(output_profile_name); + } return ret; } @@ -148,6 +157,11 @@ bool ProfileCreator::ComputeProfile(SymbolMap *symbol_map) { symbol_map, Addr2line::CreateWithSampledFunctions(binary_, &sampled_functions))) return false; + // Record sampled event name string. + // TODO: add set method instead of useing ref of local member. + for (const auto &event_name : sample_reader_->event_address_count_map()) { + symbol_map->GetProcessingEventName().insert(event_name.first); + } Profile profile(sample_reader_, binary_, symbol_map->get_addr2line(), symbol_map); profile.ComputeProfile(); diff --git a/profile_writer.cc b/profile_writer.cc index e9b9893..b6f888a 100644 --- a/profile_writer.cc +++ b/profile_writer.cc @@ -102,16 +102,30 @@ class SourceProfileLengther: public SymbolTraverser { class SourceProfileWriter: public SymbolTraverser { public: - static void Write(const SymbolMap &symbol_map, const StringIndexMap &map) { - SourceProfileWriter writer(map); + static void Write(const SymbolMap &symbol_map, const StringIndexMap &map, std::string target_event_name) { + // writer.Start() is a SymbolTraverser method, so we must record target_event_name in SourceProfileWriter. + SourceProfileWriter writer(map, target_event_name); writer.Start(symbol_map); } protected: virtual void Visit(const Symbol *node) { - gcov_write_unsigned(node->pos_counts.size()); + if (!target_event_name_.empty()) { + gcov_write_unsigned(node->event_pos_counts.count(target_event_name_) ? + node->event_pos_counts.find(target_event_name_)->second.size() : + 0); + } else { + gcov_write_unsigned(node->pos_counts.size()); + } gcov_write_unsigned(node->callsites.size()); - for (const auto &pos_count : node->pos_counts) { + // When event_pos_counts is empty, return to avoid accessing a nonexistent map. + if (!target_event_name_.empty() && !node->event_pos_counts.count(target_event_name_)) { + return; + } + const auto& pos_count_ref = !target_event_name_.empty() ? + node->event_pos_counts.find(target_event_name_)->second : + node->pos_counts; + for (const auto &pos_count : pos_count_ref) { gcov_write_unsigned(pos_count.first); gcov_write_unsigned(pos_count.second.target_map.size()); gcov_write_counter(pos_count.second.count); @@ -136,7 +150,10 @@ class SourceProfileWriter: public SymbolTraverser { } private: - explicit SourceProfileWriter(const StringIndexMap &map) : map_(map) {} + explicit SourceProfileWriter(const StringIndexMap &map, + const std::string target_event_name = std::string()) : + map_(map), + target_event_name_(target_event_name) {} int GetStringIndex(const string &str) { StringIndexMap::const_iterator ret = map_.find(str); @@ -145,10 +162,11 @@ class SourceProfileWriter: public SymbolTraverser { } const StringIndexMap &map_; + std::string target_event_name_; // Record event name to distinguish different events. DISALLOW_COPY_AND_ASSIGN(SourceProfileWriter); }; -void AutoFDOProfileWriter::WriteFunctionProfile() { +void AutoFDOProfileWriter::WriteFunctionProfile(std::string target_event_name) { typedef std::map StringIndexMap; // Map from a string to its index in this map. Providing a partial // ordering of all output strings. @@ -193,7 +211,7 @@ void AutoFDOProfileWriter::WriteFunctionProfile() { gcov_write_unsigned(GCOV_TAG_AFDO_FUNCTION); gcov_write_unsigned(length.length() + 1); gcov_write_unsigned(length.num_functions()); - SourceProfileWriter::Write(*symbol_map_, string_index_map); + SourceProfileWriter::Write(*symbol_map_, string_index_map, target_event_name); } void AutoFDOProfileWriter::WriteModuleGroup() { @@ -327,11 +345,11 @@ void AutoFDOProfileWriter::WriteWorkingSet() { } } -bool AutoFDOProfileWriter::WriteToFile(const string &output_filename) { +bool AutoFDOProfileWriter::WriteToFile(const string &output_filename, string event_name) { if (!WriteHeader(output_filename, output_filename + ".imports")) { return false; } - WriteFunctionProfile(); + WriteFunctionProfile(event_name); WriteModuleGroup(); WriteWorkingSet(); if (!WriteFinish()) { diff --git a/profile_writer.h b/profile_writer.h index f7d27e0..e1a4137 100644 --- a/profile_writer.h +++ b/profile_writer.h @@ -32,9 +32,10 @@ class ProfileWriter { explicit ProfileWriter() : symbol_map_(nullptr), module_map_(nullptr) {} virtual ~ProfileWriter() {} - virtual bool WriteToFile(const string &output_file) = 0; + virtual bool WriteToFile(const std::string &output_file, std::string event_name = std::string()) = 0; void setSymbolMap(const SymbolMap *symbol_map) { symbol_map_ = symbol_map; } void setModuleMap(const ModuleMap *module_map) { module_map_ = module_map; } + const SymbolMap * getSymbolMap() const { return symbol_map_;} void Dump(); protected: @@ -52,7 +53,7 @@ class AutoFDOProfileWriter : public ProfileWriter { explicit AutoFDOProfileWriter(uint32 gcov_version) : gcov_version_(gcov_version) {} - bool WriteToFile(const string &output_file) override; + bool WriteToFile(const string &output_file, std::string event_name = std::string()) override; private: // Opens the output file, and writes the header. @@ -100,7 +101,7 @@ class AutoFDOProfileWriter : public ProfileWriter { // callsite_offset_2: symbol profile // ... // callsite_offset_num_callsites: symbol profile - void WriteFunctionProfile(); + void WriteFunctionProfile(std::string target_event_name = std::string()); // Writes the module grouping info into the gcda file. This is stored // under the section tagged GCOV_TAG_MODULE_GROUPING: diff --git a/sample_reader.cc b/sample_reader.cc index 3071582..43a03cb 100644 --- a/sample_reader.cc +++ b/sample_reader.cc @@ -19,9 +19,13 @@ #include #include +#include "gflags/gflags.h" #include "base/logging.h" #include "third_party/perf_data_converter/src/quipper/perf_parser.h" +DEFINE_int32(sample_mapping_percentage_threshold, 95, + "when mapping perf sample events, at least this " + "percentage of them must be successfully mapped."); namespace { // Returns true if name equals full_name, or full_name is empty and name // matches re. @@ -201,6 +205,7 @@ bool TextSampleReaderWriter::IsFileExist() const { bool PerfDataSampleReader::Append(const string &profile_file) { quipper::PerfReader reader; quipper::PerfParser parser(&reader); + parser.set_sample_mapping_percentage_threshold(FLAGS_sample_mapping_percentage_threshold); if (!reader.ReadFile(profile_file) || !parser.ParseRawEvents()) { return false; } @@ -217,6 +222,13 @@ bool PerfDataSampleReader::Append(const string &profile_file) { } if (MatchBinary(event.dso_and_offset.dso_name(), focus_binary)) { address_count_map_[event.dso_and_offset.offset()]++; + // pmu event should be processed here, if event_name is not empty, it means there is at least + // two perf event in this perf.data, so we should record it into event_address_count_map_ for + // multiply event support. + auto &event_name = reader.GetEventNameFromId(event.event_ptr->sample_event().id()); + if (!event_name.empty()) { + event_address_count_map_[event_name][event.dso_and_offset.offset()]++; + } } if (event.branch_stack.size() > 0 && MatchBinary(event.branch_stack[0].to.dso_name(), focus_binary) && diff --git a/sample_reader.h b/sample_reader.h index 6932118..846f741 100644 --- a/sample_reader.h +++ b/sample_reader.h @@ -38,6 +38,7 @@ typedef pair Range; typedef map RangeCountMap; typedef pair Branch; typedef map BranchCountMap; +typedef map EventAddressCountMap; // Reads in the profile data, and represent it in address_count_map_. class SampleReader { @@ -59,6 +60,10 @@ class SampleReader { return branch_count_map_; } + const EventAddressCountMap &event_address_count_map() const { + return event_address_count_map_; + } + set GetSampledAddresses() const; // Returns the sample count for a given instruction. @@ -74,6 +79,7 @@ class SampleReader { address_count_map_.clear(); range_count_map_.clear(); branch_count_map_.clear(); + event_address_count_map_.clear(); } protected: @@ -84,6 +90,8 @@ class SampleReader { AddressCountMap address_count_map_; RangeCountMap range_count_map_; BranchCountMap branch_count_map_; + // Map each event and address count. + EventAddressCountMap event_address_count_map_; }; // Base class that reads in the profile from a sample data file. diff --git a/symbol_map.cc b/symbol_map.cc index ed048bf..233bbb2 100644 --- a/symbol_map.cc +++ b/symbol_map.cc @@ -326,11 +326,34 @@ void SymbolMap::AddSymbolEntryCount(const string &symbol_name, uint64 count) { Symbol *SymbolMap::TraverseInlineStack(const string &symbol_name, const SourceStack &src, - uint64 count) { + uint64 count, bool is_repeat) { if (src.empty()) return nullptr; - Symbol *symbol = map_.find(symbol_name)->second; - symbol->total_count += count; + Symbol *symbol = nullptr; const SourceInfo &info = src[src.size() - 1]; + if (!is_repeat) { + symbol = map_.find(symbol_name)->second; + } else { + // First old map should be removed + if (auto it = map_.find(symbol_name); it != map_.end() && it->second != nullptr) { + delete it->second; + map_.erase(it); + } + // Second use #file_name#func_name as new symbol_name + std::string new_func_name = "#" + std::string(info.file_name) + + "#" + symbol_name; + if (!map_.count(new_func_name)) { + symbol = new Symbol(); + map_.insert({new_func_name, symbol}); + } else { + symbol = map_.find(new_func_name)->second; + } + } + if (symbol == nullptr) { + LOG(FATAL) << "Build symbol map error! file/func_name:" << info.file_name << "/" + << symbol_name; + } + + symbol->total_count += count; if (symbol->info.file_name == NULL && info.file_name != NULL) { symbol->info.file_name = info.file_name; symbol->info.dir_name = info.dir_name; @@ -356,8 +379,9 @@ Symbol *SymbolMap::TraverseInlineStack(const string &symbol_name, void SymbolMap::AddSourceCount(const string &symbol_name, const SourceStack &src, uint64 count, uint64 num_inst, - Operation op) { - Symbol *symbol = TraverseInlineStack(symbol_name, src, count); + Operation op, string event_name, + bool is_repeat) { + Symbol *symbol = TraverseInlineStack(symbol_name, src, count, is_repeat); if (!symbol) return; uint32 offset = src[0].Offset(use_discriminator_encoding_); @@ -365,6 +389,13 @@ void SymbolMap::AddSourceCount(const string &symbol_name, if (count > symbol->pos_counts[offset].count) { symbol->pos_counts[offset].count = count; } + // symbol->pos_count is used for processing single event. If there is more + // than one processing event, event_name will not empty, so we need to record + // this sample in symbol->event_pos_counts. + if (!event_name.empty() && + count > symbol->event_pos_counts[event_name][offset].count) { + symbol->event_pos_counts[event_name][offset].count = count; + } } else if (op == SUM) { symbol->pos_counts[offset].count += count; } else { @@ -382,6 +413,12 @@ bool SymbolMap::AddIndirectCallTarget(const string &symbol_name, if (!symbol) return false; symbol->pos_counts[src[0].Offset(use_discriminator_encoding_)].target_map[ GetOriginalName(target.c_str())] = count; + if (!symbol->event_pos_counts.empty()) { + for (auto& pos_count : symbol->event_pos_counts) { + pos_count.second[src[0].Offset(use_discriminator_encoding_)].target_map[ + GetOriginalName(target.c_str())] = count; + } + } return true; } diff --git a/symbol_map.h b/symbol_map.h index fc3f470..1c73ae5 100644 --- a/symbol_map.h +++ b/symbol_map.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,9 @@ typedef std::map PositionCountMap; // callsite_location, callee_name typedef std::pair Callsite; +// Map each event to its PositionCountMap. +typedef std::map EventPositionCountMap; + struct CallsiteLess { bool operator()(const Callsite& c1, const Callsite& c2) const { if (c1.first != c2.first) @@ -108,12 +112,12 @@ class Symbol { // This constructor is used to create inlined symbol. Symbol(const char *name, const char *dir, const char *file, uint32 start) : info(SourceInfo(name, dir, file, start, 0, 0)), - total_count(0), head_count(0) {} + total_count(0), head_count(0), event_pos_counts() {} // This constructor is used to create aliased symbol. Symbol(const Symbol *src, const char *new_func_name) : info(src->info), total_count(src->total_count), - head_count(src->head_count) { + head_count(src->head_count), event_pos_counts() { info.func_name = new_func_name; } @@ -155,6 +159,8 @@ class Symbol { CallsiteMap callsites; // Map from source location to count and instruction number. PositionCountMap pos_counts; + // Map from event name to PositionCountMap + EventPositionCountMap event_pos_counts; }; // Maps function name to actual symbol. (Top level map). @@ -288,7 +294,9 @@ class SymbolMap { // num_inst: number of instructions that is mapped to the source. // op: operation used to calculate count (SUM or MAX). void AddSourceCount(const string &symbol, const SourceStack &source, - uint64 count, uint64 num_inst, Operation op); + uint64 count, uint64 num_inst, Operation op, + string event_name = string(), + bool is_repeat = false); // Adds the indirect call target to source stack. // symbol: name of the symbol in which source is located. @@ -303,7 +311,7 @@ class SymbolMap { // count to the total count in the inlined symbol. Returns the leaf symbol. If // the inline stack is empty, returns nullptr without any other updates. Symbol *TraverseInlineStack(const string &symbol, const SourceStack &source, - uint64 count); + uint64 count, bool is_repeat = false); // Updates function name, start_addr, end_addr of a function that has a // given address. Returns false if no such symbol exists. @@ -363,6 +371,11 @@ class SymbolMap { // Validates if the current symbol map is sane. bool Validate() const; + // Return a set of event name strings that appear in this perf.data. + std::unordered_set &GetProcessingEventName() { + return event_name_set_; + } + private: // Reads from the binary's elf section to build the symbol map. void BuildSymbolMap(); @@ -384,6 +397,7 @@ class SymbolMap { bool use_discriminator_encoding_; bool ignore_thresholds_; std::unique_ptr addr2line_; + std::unordered_set event_name_set_; /* working_set_[i] stores # of instructions that consumes i/NUM_GCOV_WORKING_SETS of total instruction counts. */ gcov_working_set_info working_set_[NUM_GCOV_WORKING_SETS]; diff --git a/third_party/perf_data_converter/src/quipper/perf_parser.cc b/third_party/perf_data_converter/src/quipper/perf_parser.cc index 0beef43..6755e5c 100644 --- a/third_party/perf_data_converter/src/quipper/perf_parser.cc +++ b/third_party/perf_data_converter/src/quipper/perf_parser.cc @@ -98,7 +98,7 @@ bool PerfParser::ParseRawEvents() { } parsed_events_.resize(write_index); - ProcessEvents(); + if (!ProcessEvents()) return false; if (!options_.discard_unused_events) return true; diff --git a/third_party/perf_data_converter/src/quipper/perf_parser.h b/third_party/perf_data_converter/src/quipper/perf_parser.h index 0910490..2ec734e 100644 --- a/third_party/perf_data_converter/src/quipper/perf_parser.h +++ b/third_party/perf_data_converter/src/quipper/perf_parser.h @@ -169,6 +169,13 @@ class PerfParser { // Pass in a struct containing various options. void set_options(const PerfParserOptions& options) { options_ = options; } + // Set sample_mapping_percentage_threshold to val. + void set_sample_mapping_percentage_threshold(int32_t val) { + if (val >= 0 && val <= 100) { + options_.sample_mapping_percentage_threshold = (float)val; + } + } + // Gets parsed event/sample info from raw event data. Stores pointers to the // raw events in an array of ParsedEvents. Does not own the raw events. It is // up to the user of this class to keep track of when these event pointers are diff --git a/third_party/perf_data_converter/src/quipper/perf_reader.cc b/third_party/perf_data_converter/src/quipper/perf_reader.cc index 7397db6..3012cd9 100644 --- a/third_party/perf_data_converter/src/quipper/perf_reader.cc +++ b/third_party/perf_data_converter/src/quipper/perf_reader.cc @@ -1073,6 +1073,12 @@ bool PerfReader::ReadEventDescMetadata(DataReader* data) { LOG(ERROR) << "Error reading ID value for attr #" << i; return false; } + // There may be multiple event id corresponding to the same event name, + // so save each {id, attr.name}. At the same time, this function + // only enters when there are multiple events in perf.data. + if (!event_id_name_map_.count(id)) { + event_id_name_map_.insert({id, attr.name}); + } } AddPerfFileAttr(attr); // The EVENT_DESC metadata is the newer replacement for the older event type diff --git a/third_party/perf_data_converter/src/quipper/perf_reader.h b/third_party/perf_data_converter/src/quipper/perf_reader.h index 7d91f99..3044a5a 100644 --- a/third_party/perf_data_converter/src/quipper/perf_reader.h +++ b/third_party/perf_data_converter/src/quipper/perf_reader.h @@ -130,6 +130,13 @@ class PerfReader { return proto_->string_metadata(); } + const string GetEventNameFromId(uint64_t id) const { + if (event_id_name_map_.count(id)) { + return event_id_name_map_.find(id)->second; + } + return std::string(); + } + uint64_t metadata_mask() const { return proto_->metadata_mask().Get(0); } private: @@ -304,6 +311,9 @@ class PerfReader { // file header, which may differ from the input file header, if any. struct perf_file_header out_header_; + // Map for record event id to name string + std::map event_id_name_map_; + DISALLOW_COPY_AND_ASSIGN(PerfReader); }; diff --git a/third_party/perf_data_converter/src/quipper/perf_serializer.cc b/third_party/perf_data_converter/src/quipper/perf_serializer.cc index 9653ab2..613189d 100644 --- a/third_party/perf_data_converter/src/quipper/perf_serializer.cc +++ b/third_party/perf_data_converter/src/quipper/perf_serializer.cc @@ -230,6 +230,11 @@ bool PerfSerializer::SerializeKernelEvent( case PERF_RECORD_LOST_SAMPLES: return SerializeLostSamplesEvent( event, event_proto->mutable_lost_samples_event()); + case PERF_RECORD_SWITCH: + case PERF_RECORD_SWITCH_CPU_WIDE: + case PERF_RECORD_NAMESPACES: + LOG(WARNING) << "Not support for autofdo v0.19, event type:" << event.header.type; + break; default: LOG(ERROR) << "Unknown event type: " << event.header.type; } -- 2.25.1