diff options
author | Yabin Cui <yabinc@google.com> | 2015-08-22 00:06:00 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-08-22 00:06:00 +0000 |
commit | cecefed0319e71eff228d641c3c8cdf2dc10f7f8 (patch) | |
tree | dfec44b751d4c6b0054facc4ba503cc760be6f29 /simpleperf | |
parent | 0e4ef2ff31805437bf4a67762c7873302bef0189 (diff) | |
parent | bea942d7f32002f90b42a8f5b28a774e5b6cb4c7 (diff) | |
download | extras-cecefed0319e71eff228d641c3c8cdf2dc10f7f8.tar.gz |
am bea942d7: Merge "Simpleperf: use OneTimeFreeAllocator to allocate symbol names."
* commit 'bea942d7f32002f90b42a8f5b28a774e5b6cb4c7':
Simpleperf: use OneTimeFreeAllocator to allocate symbol names.
Diffstat (limited to 'simpleperf')
-rw-r--r-- | simpleperf/callchain.cpp | 5 | ||||
-rw-r--r-- | simpleperf/cmd_report.cpp | 18 | ||||
-rw-r--r-- | simpleperf/dso.cpp | 61 | ||||
-rw-r--r-- | simpleperf/dso.h | 19 | ||||
-rw-r--r-- | simpleperf/record_file_test.cpp | 20 | ||||
-rw-r--r-- | simpleperf/utils.cpp | 27 | ||||
-rw-r--r-- | simpleperf/utils.h | 23 |
7 files changed, 125 insertions, 48 deletions
diff --git a/simpleperf/callchain.cpp b/simpleperf/callchain.cpp index c914d1e5..30932162 100644 --- a/simpleperf/callchain.cpp +++ b/simpleperf/callchain.cpp @@ -16,12 +16,15 @@ #include "callchain.h" +#include <string.h> + #include <queue> + #include <base/logging.h> #include "sample_tree.h" static bool MatchSampleByName(const SampleEntry* sample1, const SampleEntry* sample2) { - return (sample1->symbol->name == sample2->symbol->name); + return strcmp(sample1->symbol->Name(), sample2->symbol->Name()) == 0; } static size_t GetMatchingLengthInNode(const CallChainNode* node, diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp index 9c2f6062..7fee5168 100644 --- a/simpleperf/cmd_report.cpp +++ b/simpleperf/cmd_report.cpp @@ -179,12 +179,11 @@ class SymbolItem : public Displayable, public Comparable { } int Compare(const SampleEntry& sample1, const SampleEntry& sample2) const override { - return strcmp(sample1.symbol->GetDemangledName().c_str(), - sample2.symbol->GetDemangledName().c_str()); + return strcmp(sample1.symbol->DemangledName(), sample2.symbol->DemangledName()); } std::string Show(const SampleEntry& sample) const override { - return sample.symbol->GetDemangledName(); + return sample.symbol->DemangledName(); } }; @@ -215,12 +214,12 @@ class SymbolFromItem : public Displayable, public Comparable { } int Compare(const SampleEntry& sample1, const SampleEntry& sample2) const override { - return strcmp(sample1.branch_from.symbol->GetDemangledName().c_str(), - sample2.branch_from.symbol->GetDemangledName().c_str()); + return strcmp(sample1.branch_from.symbol->DemangledName(), + sample2.branch_from.symbol->DemangledName()); } std::string Show(const SampleEntry& sample) const override { - return sample.branch_from.symbol->GetDemangledName(); + return sample.branch_from.symbol->DemangledName(); } }; @@ -695,11 +694,10 @@ static void PrintCallGraphEntry(size_t depth, std::string prefix, double percentage = 100.0 * (node->period + node->children_period) / parent_period; percentage_s = android::base::StringPrintf("--%.2lf%%-- ", percentage); } - printf("%s%s%s\n", prefix.c_str(), percentage_s.c_str(), - node->chain[0]->symbol->GetDemangledName().c_str()); + printf("%s%s%s\n", prefix.c_str(), percentage_s.c_str(), node->chain[0]->symbol->DemangledName()); prefix.append(percentage_s.size(), ' '); for (size_t i = 1; i < node->chain.size(); ++i) { - printf("%s%s\n", prefix.c_str(), node->chain[i]->symbol->GetDemangledName().c_str()); + printf("%s%s\n", prefix.c_str(), node->chain[i]->symbol->DemangledName()); } for (size_t i = 0; i < node->children.size(); ++i) { @@ -711,7 +709,7 @@ static void PrintCallGraphEntry(size_t depth, std::string prefix, void ReportCommand::PrintCallGraph(const SampleEntry& sample) { std::string prefix = " "; printf("%s|\n", prefix.c_str()); - printf("%s-- %s\n", prefix.c_str(), sample.symbol->GetDemangledName().c_str()); + printf("%s-- %s\n", prefix.c_str(), sample.symbol->DemangledName()); prefix.append(3, ' '); for (size_t i = 0; i < sample.callchain.children.size(); ++i) { PrintCallGraphEntry(1, prefix, sample.callchain.children[i], sample.callchain.children_period, diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp index 0ac44640..ec4433e9 100644 --- a/simpleperf/dso.cpp +++ b/simpleperf/dso.cpp @@ -17,8 +17,11 @@ #include "dso.h" #include <stdlib.h> +#include <string.h> +#include <algorithm> #include <limits> +#include <vector> #include <base/logging.h> @@ -26,22 +29,32 @@ #include "read_elf.h" #include "utils.h" -const std::string& Symbol::GetDemangledName() const { - if (demangled_name_.empty()) { - demangled_name_ = Dso::Demangle(name); - } - return demangled_name_; +static OneTimeFreeAllocator symbol_name_allocator; + +Symbol::Symbol(const std::string& name, uint64_t addr, uint64_t len) + : addr(addr), + len(len), + name_(symbol_name_allocator.AllocateString(name)), + demangled_name_(nullptr) { } -bool SymbolComparator::operator()(const std::unique_ptr<Symbol>& symbol1, - const std::unique_ptr<Symbol>& symbol2) { - return symbol1->addr < symbol2->addr; +const char* Symbol::DemangledName() const { + if (demangled_name_ == nullptr) { + const std::string s = Dso::Demangle(name_); + if (s == name_) { + demangled_name_ = name_; + } else { + demangled_name_ = symbol_name_allocator.AllocateString(s); + } + } + return demangled_name_; } bool Dso::demangle_ = true; std::string Dso::symfs_dir_; std::string Dso::vmlinux_; std::unordered_map<std::string, BuildId> Dso::build_id_map_; +size_t Dso::dso_count_; void Dso::SetDemangle(bool demangle) { demangle_ = demangle; @@ -122,8 +135,21 @@ std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type, const std::string& dso_pat } Dso::Dso(DsoType type, const std::string& path) : type_(type), path_(path), is_loaded_(false) { + dso_count_++; +} + +Dso::~Dso() { + if (--dso_count_ == 0) { + symbol_name_allocator.Clear(); + } } +struct SymbolComparator { + bool operator()(const Symbol& symbol1, const Symbol& symbol2) { + return symbol1.addr < symbol2.addr; + } +}; + const Symbol* Dso::FindSymbol(uint64_t offset_in_dso) { if (!is_loaded_) { is_loaded_ = true; @@ -132,17 +158,13 @@ const Symbol* Dso::FindSymbol(uint64_t offset_in_dso) { return nullptr; } } - std::unique_ptr<Symbol> symbol(new Symbol{ - "", // name - offset_in_dso, // addr - 0, // len - }); - auto it = symbols_.upper_bound(symbol); + auto it = std::upper_bound(symbols_.begin(), symbols_.end(), Symbol("", offset_in_dso, 0), + SymbolComparator()); if (it != symbols_.begin()) { --it; - if ((*it)->addr <= offset_in_dso && (*it)->addr + (*it)->len > offset_in_dso) { - return (*it).get(); + if (it->addr <= offset_in_dso && it->addr + it->len > offset_in_dso) { + return &*it; } } return nullptr; @@ -162,6 +184,7 @@ bool Dso::Load() { break; } if (result) { + std::sort(symbols_.begin(), symbols_.end(), SymbolComparator()); FixupSymbolLength(); } return result; @@ -239,16 +262,16 @@ bool Dso::LoadElfFile() { } void Dso::InsertSymbol(const Symbol& symbol) { - symbols_.insert(std::unique_ptr<Symbol>(new Symbol(symbol))); + symbols_.push_back(symbol); } void Dso::FixupSymbolLength() { Symbol* prev_symbol = nullptr; for (auto& symbol : symbols_) { if (prev_symbol != nullptr && prev_symbol->len == 0) { - prev_symbol->len = symbol->addr - prev_symbol->addr; + prev_symbol->len = symbol.addr - prev_symbol->addr; } - prev_symbol = symbol.get(); + prev_symbol = &symbol; } if (prev_symbol != nullptr && prev_symbol->len == 0) { prev_symbol->len = std::numeric_limits<unsigned long long>::max() - prev_symbol->addr; diff --git a/simpleperf/dso.h b/simpleperf/dso.h index 148a47c8..b9553f30 100644 --- a/simpleperf/dso.h +++ b/simpleperf/dso.h @@ -18,7 +18,6 @@ #define SIMPLE_PERF_DSO_H_ #include <memory> -#include <set> #include <string> #include <unordered_map> #include <vector> @@ -26,21 +25,19 @@ #include "build_id.h" struct Symbol { - std::string name; uint64_t addr; uint64_t len; - Symbol(const std::string& name, uint64_t addr, uint64_t len) : name(name), addr(addr), len(len) { + Symbol(const std::string& name, uint64_t addr, uint64_t len); + const char* Name() const { + return name_; } - const std::string& GetDemangledName() const; + const char* DemangledName() const; private: - mutable std::string demangled_name_; -}; - -struct SymbolComparator { - bool operator()(const std::unique_ptr<Symbol>& symbol1, const std::unique_ptr<Symbol>& symbol2); + const char* name_; + mutable const char* demangled_name_; }; enum DsoType { @@ -62,6 +59,7 @@ struct Dso { static std::unique_ptr<Dso> CreateDso(DsoType dso_type, const std::string& dso_path = ""); + ~Dso(); const std::string& Path() const { return path_; } @@ -79,6 +77,7 @@ struct Dso { static std::string symfs_dir_; static std::string vmlinux_; static std::unordered_map<std::string, BuildId> build_id_map_; + static size_t dso_count_; Dso(DsoType type, const std::string& path); bool Load(); @@ -90,7 +89,7 @@ struct Dso { const DsoType type_; const std::string path_; - std::set<std::unique_ptr<Symbol>, SymbolComparator> symbols_; + std::vector<Symbol> symbols_; bool is_loaded_; }; diff --git a/simpleperf/record_file_test.cpp b/simpleperf/record_file_test.cpp index 73b90ba2..e2467a4f 100644 --- a/simpleperf/record_file_test.cpp +++ b/simpleperf/record_file_test.cpp @@ -17,6 +17,9 @@ #include <gtest/gtest.h> #include <string.h> + +#include <memory> + #include "environment.h" #include "event_attr.h" #include "event_type.h" @@ -37,15 +40,15 @@ class RecordFileTest : public ::testing::Test { std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType(event_type_str); ASSERT_TRUE(event_type_modifier != nullptr); perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type); - attrs_.push_back(attr); + attrs_.push_back(std::unique_ptr<perf_event_attr>(new perf_event_attr(attr))); AttrWithId attr_id; - attr_id.attr = &attrs_[attrs_.size() - 1]; + attr_id.attr = attrs_.back().get(); attr_id.ids.push_back(attrs_.size()); // Fake id. attr_ids_.push_back(attr_id); } std::string filename_; - std::vector<perf_event_attr> attrs_; + std::vector<std::unique_ptr<perf_event_attr>> attrs_; std::vector<AttrWithId> attr_ids_; }; @@ -59,8 +62,8 @@ TEST_F(RecordFileTest, smoke) { ASSERT_TRUE(writer->WriteAttrSection(attr_ids_)); // Write data section. - MmapRecord mmap_record = - CreateMmapRecord(attrs_[0], true, 1, 1, 0x1000, 0x2000, 0x3000, "mmap_record_example"); + MmapRecord mmap_record = CreateMmapRecord(*(attr_ids_[0].attr), true, 1, 1, 0x1000, 0x2000, + 0x3000, "mmap_record_example"); ASSERT_TRUE(writer->WriteData(mmap_record.BinaryFormat())); // Check data section that has been written. @@ -117,12 +120,13 @@ TEST_F(RecordFileTest, records_sorted_by_time) { // Write attr section. AddEventType("cpu-cycles"); - attrs_[0].sample_id_all = 1; - attrs_[0].sample_type |= PERF_SAMPLE_TIME; + attrs_[0]->sample_id_all = 1; + attrs_[0]->sample_type |= PERF_SAMPLE_TIME; ASSERT_TRUE(writer->WriteAttrSection(attr_ids_)); // Write data section. - MmapRecord r1 = CreateMmapRecord(attrs_[0], true, 1, 1, 0x100, 0x2000, 0x3000, "mmap_record1"); + MmapRecord r1 = + CreateMmapRecord(*(attr_ids_[0].attr), true, 1, 1, 0x100, 0x2000, 0x3000, "mmap_record1"); MmapRecord r2 = r1; MmapRecord r3 = r1; r1.sample_id.time_data.time = 2; diff --git a/simpleperf/utils.cpp b/simpleperf/utils.cpp index bca02bdc..ee95b091 100644 --- a/simpleperf/utils.cpp +++ b/simpleperf/utils.cpp @@ -23,8 +23,35 @@ #include <sys/stat.h> #include <unistd.h> +#include <algorithm> +#include <string> + #include <base/logging.h> +void OneTimeFreeAllocator::Clear() { + for (auto& p : v_) { + delete[] p; + } + v_.clear(); + cur_ = nullptr; + end_ = nullptr; +} + +const char* OneTimeFreeAllocator::AllocateString(const std::string& s) { + size_t size = s.size() + 1; + if (cur_ + size > end_) { + size_t alloc_size = std::max(size, unit_size_); + char* p = new char[alloc_size]; + v_.push_back(p); + cur_ = p; + end_ = p + alloc_size; + } + strcpy(cur_, s.c_str()); + const char* result = cur_; + cur_ += size; + return result; +} + void PrintIndented(size_t indent, const char* fmt, ...) { va_list ap; va_start(ap, fmt); diff --git a/simpleperf/utils.h b/simpleperf/utils.h index b91f77f7..4077c975 100644 --- a/simpleperf/utils.h +++ b/simpleperf/utils.h @@ -21,6 +21,7 @@ #include <stddef.h> #include <stdio.h> #include <stdlib.h> + #include <string> #include <vector> @@ -72,6 +73,28 @@ class SignalHandlerRegister { std::vector<std::pair<int, sig_t>> saved_signal_handlers_; }; +// OneTimeAllocator is used to allocate memory many times and free only once at the end. +// It reduces the cost to free each allocated memory. +class OneTimeFreeAllocator { + public: + OneTimeFreeAllocator(size_t unit_size = 8192u) + : unit_size_(unit_size), cur_(nullptr), end_(nullptr) { + } + + ~OneTimeFreeAllocator() { + Clear(); + } + + void Clear(); + const char* AllocateString(const std::string& s); + + private: + const size_t unit_size_; + std::vector<char*> v_; + char* cur_; + char* end_; +}; + template <class T> void MoveFromBinaryFormat(T& data, const char*& p) { data = *reinterpret_cast<const T*>(p); |