From 6afc7e17d39ab294bdf625076777443a6b4c8e18 Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 17 Jun 2015 22:21:12 -0700 Subject: [PATCH] Simpleperf: add branch stack feature in perf.data. Also add the function to remove old perf.data. Bug: 19483574 Change-Id: I605bb637674d4674f95503a160de8c530fe87812 --- simpleperf/cmd_dumprecord.cpp | 2 +- simpleperf/cmd_record.cpp | 11 ++++-- simpleperf/record_file.cpp | 81 ++++++++++++++++++++++++++++--------------- simpleperf/record_file.h | 3 ++ simpleperf/utils.cpp | 16 +++++++++ simpleperf/utils.h | 1 + 6 files changed, 84 insertions(+), 30 deletions(-) diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp index 9245d18e..e5e239b5 100644 --- a/simpleperf/cmd_dumprecord.cpp +++ b/simpleperf/cmd_dumprecord.cpp @@ -134,7 +134,7 @@ static const std::string GetFeatureName(int feature) { {FEAT_EVENT_DESC, "event_desc"}, {FEAT_CPU_TOPOLOGY, "cpu_topology"}, {FEAT_NUMA_TOPOLOGY, "numa_topology"}, - {FEAT_BRANCH_STACK, "branck_stack"}, + {FEAT_BRANCH_STACK, "branch_stack"}, {FEAT_PMU_MAPPINGS, "pmu_mappings"}, {FEAT_GROUP_DESC, "group_desc"}, }; diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index 7cd7ec8e..2ceeed02 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -377,10 +377,17 @@ bool RecordCommand::DumpThreadCommAndMmaps() { } bool RecordCommand::DumpAdditionalFeatures() { - if (!record_file_writer_->WriteFeatureHeader(1)) { + size_t feature_count = (branch_sampling_ != 0 ? 2 : 1); + if (!record_file_writer_->WriteFeatureHeader(feature_count)) { return false; } - return DumpBuildIdFeature(); + if (!DumpBuildIdFeature()) { + return false; + } + if (branch_sampling_ != 0 && !record_file_writer_->WriteBranchStackFeature()) { + return false; + } + return true; } bool RecordCommand::DumpBuildIdFeature() { diff --git a/simpleperf/record_file.cpp b/simpleperf/record_file.cpp index 360d8423..2a7c6a14 100644 --- a/simpleperf/record_file.cpp +++ b/simpleperf/record_file.cpp @@ -35,6 +35,10 @@ using namespace PerfFileFormat; std::unique_ptr RecordFileWriter::CreateInstance( const std::string& filename, const perf_event_attr& event_attr, const std::vector>& event_fds) { + // Remove old perf.data to avoid file ownership problems. + if (!RemovePossibleFile(filename)) { + return nullptr; + } FILE* fp = fopen(filename.c_str(), "web+"); if (fp == nullptr) { PLOG(ERROR) << "failed to open record file '" << filename << "'"; @@ -191,16 +195,11 @@ bool RecordFileWriter::GetHitModules(std::vector* hit_kernel_module PLOG(ERROR) << "fflush() failed"; return false; } - if (fseek(record_fp_, 0, SEEK_END) == -1) { - PLOG(ERROR) << "fseek() failed"; + uint64_t file_size; + if (!SeekFileEnd(&file_size)) { return false; } - long file_size = ftell(record_fp_); - if (file_size == -1) { - PLOG(ERROR) << "ftell() failed"; - return false; - } - size_t mmap_len = file_size; + size_t mmap_len = static_cast(file_size); void* mmap_addr = mmap(nullptr, mmap_len, PROT_READ, MAP_SHARED, fileno(record_fp_), 0); if (mmap_addr == MAP_FAILED) { PLOG(ERROR) << "mmap() failed"; @@ -217,6 +216,20 @@ bool RecordFileWriter::GetHitModules(std::vector* hit_kernel_module return true; } +bool RecordFileWriter::SeekFileEnd(uint64_t* file_end) { + if (fseek(record_fp_, 0, SEEK_END) == -1) { + PLOG(ERROR) << "fseek() failed"; + return false; + } + long offset = ftell(record_fp_); + if (offset == -1) { + PLOG(ERROR) << "ftell() failed"; + return false; + } + *file_end = static_cast(offset); + return true; +} + bool RecordFileWriter::WriteFeatureHeader(size_t feature_count) { feature_count_ = feature_count; current_feature_index_ = 0; @@ -232,17 +245,10 @@ bool RecordFileWriter::WriteFeatureHeader(size_t feature_count) { } bool RecordFileWriter::WriteBuildIdFeature(const std::vector& build_id_records) { - if (current_feature_index_ >= feature_count_) { - return false; - } + CHECK_LT(current_feature_index_, feature_count_); // Always write features at the end of the file. - if (fseek(record_fp_, 0, SEEK_END) == -1) { - PLOG(ERROR) << "fseek() failed"; - return false; - } - long section_start = ftell(record_fp_); - if (section_start == -1) { - PLOG(ERROR) << "ftell() failed"; + uint64_t start_offset; + if (!SeekFileEnd(&start_offset)) { return false; } for (auto& record : build_id_records) { @@ -251,18 +257,41 @@ bool RecordFileWriter::WriteBuildIdFeature(const std::vector& bui return false; } } - long section_end = ftell(record_fp_); - if (section_end == -1) { + uint64_t end_offset; + if (!SeekFileEnd(&end_offset)) { return false; } - // Write feature section descriptor for build_id feature. + if (!ModifyFeatureSectionDescriptor(current_feature_index_, start_offset, + end_offset - start_offset)) { + return false; + } + ++current_feature_index_; + features_.push_back(FEAT_BUILD_ID); + return true; +} + +bool RecordFileWriter::WriteBranchStackFeature() { + CHECK_LT(current_feature_index_, feature_count_); + uint64_t start_offset; + if (!SeekFileEnd(&start_offset)) { + return false; + } + if (!ModifyFeatureSectionDescriptor(current_feature_index_, start_offset, 0)) { + return false; + } + ++current_feature_index_; + features_.push_back(FEAT_BRANCH_STACK); + return true; +} + +bool RecordFileWriter::ModifyFeatureSectionDescriptor(size_t feature_index, uint64_t offset, + uint64_t size) { SectionDesc desc; - desc.offset = section_start; - desc.size = section_end - section_start; + desc.offset = offset; + desc.size = size; uint64_t feature_offset = data_section_offset_ + data_section_size_; - if (fseek(record_fp_, feature_offset + current_feature_index_ * sizeof(SectionDesc), SEEK_SET) == - -1) { + if (fseek(record_fp_, feature_offset + feature_index * sizeof(SectionDesc), SEEK_SET) == -1) { PLOG(ERROR) << "fseek() failed"; return false; } @@ -270,8 +299,6 @@ bool RecordFileWriter::WriteBuildIdFeature(const std::vector& bui PLOG(ERROR) << "fwrite() failed"; return false; } - ++current_feature_index_; - features_.push_back(FEAT_BUILD_ID); return true; } diff --git a/simpleperf/record_file.h b/simpleperf/record_file.h index 694486c0..e217b3c2 100644 --- a/simpleperf/record_file.h +++ b/simpleperf/record_file.h @@ -52,6 +52,7 @@ class RecordFileWriter { bool WriteFeatureHeader(size_t feature_count); bool WriteBuildIdFeature(const std::vector& build_id_records); + bool WriteBranchStackFeature(); // Normally, Close() should be called after writing. But if something // wrong happens and we need to finish in advance, the destructor @@ -67,6 +68,8 @@ class RecordFileWriter { std::vector* hit_user_files); bool WriteFileHeader(); bool Write(const void* buf, size_t len); + bool SeekFileEnd(uint64_t* file_end); + bool ModifyFeatureSectionDescriptor(size_t feature_index, uint64_t offset, uint64_t size); const std::string filename_; FILE* record_fp_; diff --git a/simpleperf/utils.cpp b/simpleperf/utils.cpp index 5062504c..783bc8ff 100644 --- a/simpleperf/utils.cpp +++ b/simpleperf/utils.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -66,3 +67,18 @@ void GetEntriesInDir(const std::string& dirpath, std::vector* files } closedir(dir); } + +bool RemovePossibleFile(const std::string& filename) { + struct stat st; + if (stat(filename.c_str(), &st) == 0) { + if (!S_ISREG(st.st_mode)) { + LOG(ERROR) << filename << " is not a file."; + return false; + } + if (unlink(filename.c_str()) == -1) { + PLOG(ERROR) << "unlink(" << filename << ") failed"; + return false; + } + } + return true; +} diff --git a/simpleperf/utils.h b/simpleperf/utils.h index f54e698e..43c09be6 100644 --- a/simpleperf/utils.h +++ b/simpleperf/utils.h @@ -78,5 +78,6 @@ bool IsPowerOfTwo(uint64_t value); void GetEntriesInDir(const std::string& dirpath, std::vector* files, std::vector* subdirs); +bool RemovePossibleFile(const std::string& filename); #endif // SIMPLE_PERF_UTILS_H_ -- 2.11.0