1. Support parser multiple types of events in one perf file, distinguishes different event with suffix. 2. Support process functions with same name, distinguished by #file_name#func_name. (cherry picked from commit f1174d86a3aca3836adb2bff5e2f7a792b2cd3ed)
698 lines
28 KiB
Diff
698 lines
28 KiB
Diff
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<SymbolProfileMaps::iterator, bool> 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<string, ProfileMaps*> SymbolProfileMaps;
|
|
+ typedef std::multimap<std::string, ProfileMaps *> 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<string, int> 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 <string>
|
|
#include <utility>
|
|
|
|
+#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<uint64, uint64> Range;
|
|
typedef map<Range, uint64> RangeCountMap;
|
|
typedef pair<uint64, uint64> Branch;
|
|
typedef map<Branch, uint64> BranchCountMap;
|
|
+typedef map<string, AddressCountMap> 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<uint64> 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 <map>
|
|
#include <memory>
|
|
#include <set>
|
|
+#include <unordered_set>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
@@ -82,6 +83,9 @@ typedef std::map<uint32, ProfileInfo> PositionCountMap;
|
|
// callsite_location, callee_name
|
|
typedef std::pair<uint32, const char *> Callsite;
|
|
|
|
+// Map each event to its PositionCountMap.
|
|
+typedef std::map<string, PositionCountMap> 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<string> &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> addr2line_;
|
|
+ std::unordered_set<string> 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<uint64_t, std::string> 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
|
|
|