summaryrefslogtreecommitdiff
path: root/simpleperf
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2015-08-22 00:06:00 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2015-08-22 00:06:00 +0000
commitcecefed0319e71eff228d641c3c8cdf2dc10f7f8 (patch)
treedfec44b751d4c6b0054facc4ba503cc760be6f29 /simpleperf
parent0e4ef2ff31805437bf4a67762c7873302bef0189 (diff)
parentbea942d7f32002f90b42a8f5b28a774e5b6cb4c7 (diff)
downloadextras-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.cpp5
-rw-r--r--simpleperf/cmd_report.cpp18
-rw-r--r--simpleperf/dso.cpp61
-rw-r--r--simpleperf/dso.h19
-rw-r--r--simpleperf/record_file_test.cpp20
-rw-r--r--simpleperf/utils.cpp27
-rw-r--r--simpleperf/utils.h23
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);