summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--simpleperf/cmd_dumprecord.cpp18
-rw-r--r--simpleperf/cmd_record.cpp9
-rw-r--r--simpleperf/cmd_record_test.cpp10
-rw-r--r--simpleperf/main.cpp5
-rw-r--r--simpleperf/record_file.h2
-rw-r--r--simpleperf/record_file_format.h70
-rw-r--r--simpleperf/record_file_reader.cpp17
-rw-r--r--simpleperf/record_file_test.cpp26
-rw-r--r--simpleperf/record_file_writer.cpp22
-rw-r--r--simpleperf/utils.cpp7
-rw-r--r--simpleperf/utils.h2
11 files changed, 152 insertions, 36 deletions
diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp
index 191d641c..2ce5295d 100644
--- a/simpleperf/cmd_dumprecord.cpp
+++ b/simpleperf/cmd_dumprecord.cpp
@@ -49,7 +49,7 @@ class DumpRecordCommand : public Command {
void DumpFileHeader();
void DumpAttrSection();
void DumpDataSection();
- void DumpFeatureSection();
+ bool DumpFeatureSection();
std::string record_filename_;
std::unique_ptr<RecordFileReader> record_file_reader_;
@@ -75,7 +75,9 @@ bool DumpRecordCommand::Run(const std::vector<std::string>& args) {
DumpFileHeader();
DumpAttrSection();
DumpDataSection();
- DumpFeatureSection();
+ if (!DumpFeatureSection()) {
+ return false;
+ }
return true;
}
@@ -180,7 +182,7 @@ void DumpRecordCommand::DumpDataSection() {
}, false);
}
-void DumpRecordCommand::DumpFeatureSection() {
+bool DumpRecordCommand::DumpFeatureSection() {
std::map<int, SectionDesc> section_map = record_file_reader_->FeatureSectionDescriptors();
for (const auto& pair : section_map) {
int feature = pair.first;
@@ -220,8 +222,18 @@ void DumpRecordCommand::DumpFeatureSection() {
symbol.addr, symbol.addr + symbol.len);
}
}
+ } else if (feature == FEAT_META_INFO) {
+ std::unordered_map<std::string, std::string> info_map;
+ if (!record_file_reader_->ReadMetaInfoFeature(&info_map)) {
+ return false;
+ }
+ PrintIndented(1, "meta_info:\n");
+ for (auto& pair : info_map) {
+ PrintIndented(2, "%s = %s\n", pair.first.c_str(), pair.second.c_str());
+ }
}
}
+ return true;
}
void RegisterDumpRecordCommand() {
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 3376af06..78e0a95d 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -941,7 +941,7 @@ bool RecordCommand::DumpAdditionalFeatures(
return false;
}
- size_t feature_count = 4;
+ size_t feature_count = 5;
if (branch_sampling_) {
feature_count++;
}
@@ -984,6 +984,13 @@ bool RecordCommand::DumpAdditionalFeatures(
!record_file_writer_->WriteBranchStackFeature()) {
return false;
}
+
+ std::unordered_map<std::string, std::string> info_map;
+ info_map["simpleperf_version"] = GetSimpleperfVersion();
+ if (!record_file_writer_->WriteMetaInfoFeature(info_map)) {
+ return false;
+ }
+
if (!record_file_writer_->EndWriteFeatures()) {
return false;
}
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index 85bbe34b..ec0605a4 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -428,3 +428,13 @@ TEST(record_cmd, start_profiling_fd_option) {
close(read_fd);
ASSERT_EQ("STARTED", s);
}
+
+TEST(record_cmd, record_meta_info_feature) {
+ TemporaryFile tmpfile;
+ ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
+ std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
+ ASSERT_TRUE(reader != nullptr);
+ std::unordered_map<std::string, std::string> info_map;
+ ASSERT_TRUE(reader->ReadMetaInfoFeature(&info_map));
+ ASSERT_NE(info_map.find("simpleperf_version"), info_map.end());
+}
diff --git a/simpleperf/main.cpp b/simpleperf/main.cpp
index 07b0e4b3..ae3e6292 100644
--- a/simpleperf/main.cpp
+++ b/simpleperf/main.cpp
@@ -24,8 +24,6 @@
#include "command.h"
#include "utils.h"
-constexpr int SIMPLEPERF_VERSION = 1;
-
int main(int argc, char** argv) {
android::base::InitLogging(argv, android::base::StderrLogger);
std::vector<std::string> args;
@@ -46,8 +44,7 @@ int main(int argc, char** argv) {
return 1;
}
} else if (strcmp(argv[i], "--version") == 0) {
- LOG(INFO) << "Simpleperf version " << SIMPLEPERF_VERSION << ", revision "
- << SIMPLEPERF_REVISION;
+ LOG(INFO) << "Simpleperf version " << GetSimpleperfVersion();
return 0;
} else {
args.push_back(argv[i]);
diff --git a/simpleperf/record_file.h b/simpleperf/record_file.h
index 51d4f437..32c91fa4 100644
--- a/simpleperf/record_file.h
+++ b/simpleperf/record_file.h
@@ -56,6 +56,7 @@ class RecordFileWriter {
uint32_t file_type,
uint64_t min_vaddr,
const std::vector<const Symbol*>& symbols);
+ bool WriteMetaInfoFeature(const std::unordered_map<std::string, std::string>& info_map);
bool EndWriteFeatures();
// Normally, Close() should be called after writing. But if something
@@ -148,6 +149,7 @@ class RecordFileReader {
bool ReadFileFeature(size_t& read_pos, std::string* file_path,
uint32_t* file_type, uint64_t* min_vaddr,
std::vector<Symbol>* symbols);
+ bool ReadMetaInfoFeature(std::unordered_map<std::string, std::string>* info_map);
void LoadBuildIdAndFileFeatures(ThreadTree& thread_tree);
diff --git a/simpleperf/record_file_format.h b/simpleperf/record_file_format.h
index efa000cf..f9ed6f32 100644
--- a/simpleperf/record_file_format.h
+++ b/simpleperf/record_file_format.h
@@ -19,34 +19,47 @@
#include "perf_event.h"
-// The file structure of perf.data:
-// file_header
-// id_section
-// attr section
-// data section
-// feature section
-//
-// The feature section has the following structure:
-// a section descriptor array, each element contains the section information of one add_feature.
-// data section of feature 1
-// data section of feature 2
-// ....
-
-// file feature section:
-// file_struct files[];
-//
-// struct file_struct {
-// uint32_t size; // size of rest fields in file_struct
-// char file_path[];
-// uint32_t file_type;
-// uint64_t min_vaddr;
-// uint32_t symbol_count;
-// struct {
-// uint64_t start_vaddr;
-// uint32_t len;
-// char symbol_name[];
-// } symbol_table;
-// };
+/*
+The file structure of perf.data:
+ file_header
+ id_section
+ attr section
+ data section
+ feature section
+
+The feature section has the following structure:
+ a section descriptor array, each element contains the section information of one add_feature.
+ data section of feature 1
+ data section of feature 2
+ ....
+
+file feature section:
+ file_struct files[];
+
+ struct file_struct {
+ uint32_t size; // size of rest fields in file_struct
+ char file_path[];
+ uint32_t file_type;
+ uint64_t min_vaddr;
+ uint32_t symbol_count;
+ struct {
+ uint64_t start_vaddr;
+ uint32_t len;
+ char symbol_name[];
+ } symbol_table;
+ };
+
+meta_info feature section:
+ meta_info infos[];
+
+ struct meta_info {
+ char key[];
+ char value[];
+ };
+ keys in meta_info feature section include:
+ simpleperf_version,
+
+*/
namespace PerfFileFormat {
@@ -74,6 +87,7 @@ enum {
FEAT_SIMPLEPERF_START = 128,
FEAT_FILE = FEAT_SIMPLEPERF_START,
+ FEAT_META_INFO,
FEAT_MAX_NUM = 256,
};
diff --git a/simpleperf/record_file_reader.cpp b/simpleperf/record_file_reader.cpp
index 0fdb6ddc..67f35bea 100644
--- a/simpleperf/record_file_reader.cpp
+++ b/simpleperf/record_file_reader.cpp
@@ -434,6 +434,23 @@ bool RecordFileReader::ReadFileFeature(size_t& read_pos,
return true;
}
+bool RecordFileReader::ReadMetaInfoFeature(std::unordered_map<std::string, std::string>* info_map) {
+ std::vector<char> buf;
+ if (!ReadFeatureSection(FEAT_META_INFO, &buf)) {
+ return false;
+ }
+ const char* p = buf.data();
+ const char* end = buf.data() + buf.size();
+ while (p < end) {
+ const char* key = p;
+ const char* value = key + strlen(key) + 1;
+ CHECK(value < end);
+ (*info_map)[p] = value;
+ p = value + strlen(value) + 1;
+ }
+ return true;
+}
+
void RecordFileReader::LoadBuildIdAndFileFeatures(ThreadTree& thread_tree) {
std::vector<BuildIdRecord> records = ReadBuildIdFeature();
std::vector<std::pair<std::string, BuildId>> build_ids;
diff --git a/simpleperf/record_file_test.cpp b/simpleperf/record_file_test.cpp
index 4fe725b9..530611e8 100644
--- a/simpleperf/record_file_test.cpp
+++ b/simpleperf/record_file_test.cpp
@@ -157,3 +157,29 @@ TEST_F(RecordFileTest, record_more_than_one_attr) {
ASSERT_EQ(attrs[i].ids, attr_ids_[i].ids);
}
}
+
+TEST_F(RecordFileTest, write_meta_info_feature_section) {
+ // Write to a record file.
+ std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
+ ASSERT_TRUE(writer != nullptr);
+ AddEventType("cpu-cycles");
+ ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
+
+ // Write meta_info feature section.
+ ASSERT_TRUE(writer->BeginWriteFeatures(1));
+ std::unordered_map<std::string, std::string> info_map;
+ for (int i = 0; i < 100; ++i) {
+ std::string s = std::to_string(i);
+ info_map[s] = s + s;
+ }
+ ASSERT_TRUE(writer->WriteMetaInfoFeature(info_map));
+ ASSERT_TRUE(writer->EndWriteFeatures());
+ ASSERT_TRUE(writer->Close());
+
+ // Read from a record file.
+ std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
+ ASSERT_TRUE(reader != nullptr);
+ std::unordered_map<std::string, std::string> read_info_map;
+ ASSERT_TRUE(reader->ReadMetaInfoFeature(&read_info_map));
+ ASSERT_EQ(read_info_map, info_map);
+}
diff --git a/simpleperf/record_file_writer.cpp b/simpleperf/record_file_writer.cpp
index fe62ab58..083a7462 100644
--- a/simpleperf/record_file_writer.cpp
+++ b/simpleperf/record_file_writer.cpp
@@ -328,6 +328,28 @@ bool RecordFileWriter::WriteFileFeature(const std::string& file_path,
return WriteFeatureEnd(FEAT_FILE);
}
+bool RecordFileWriter::WriteMetaInfoFeature(
+ const std::unordered_map<std::string, std::string>& info_map) {
+ uint32_t size = 0u;
+ for (auto& pair : info_map) {
+ size += pair.first.size() + 1;
+ size += pair.second.size() + 1;
+ }
+ std::vector<char> buf(size);
+ char* p = buf.data();
+ for (auto& pair : info_map) {
+ MoveToBinaryFormat(pair.first.c_str(), pair.first.size() + 1, p);
+ MoveToBinaryFormat(pair.second.c_str(), pair.second.size() + 1, p);
+ }
+ if (!WriteFeatureBegin(FEAT_META_INFO)) {
+ return false;
+ }
+ if (!Write(buf.data(), buf.size())) {
+ return false;
+ }
+ return WriteFeatureEnd(FEAT_META_INFO);
+}
+
bool RecordFileWriter::WriteFeatureBegin(int feature) {
auto it = features_.find(feature);
if (it == features_.end()) {
diff --git a/simpleperf/utils.cpp b/simpleperf/utils.cpp
index 62a8b63c..1dbe078e 100644
--- a/simpleperf/utils.cpp
+++ b/simpleperf/utils.cpp
@@ -31,6 +31,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <7zCrc.h>
#include <Xz.h>
@@ -337,3 +338,9 @@ timeval SecondToTimeval(double time_in_sec) {
tv.tv_usec = static_cast<int>((time_in_sec - tv.tv_sec) * 1000000);
return tv;
}
+
+constexpr int SIMPLEPERF_VERSION = 1;
+
+std::string GetSimpleperfVersion() {
+ return android::base::StringPrintf("%d.%s", SIMPLEPERF_VERSION, SIMPLEPERF_REVISION);
+}
diff --git a/simpleperf/utils.h b/simpleperf/utils.h
index fc21a99f..775fd5c4 100644
--- a/simpleperf/utils.h
+++ b/simpleperf/utils.h
@@ -169,4 +169,6 @@ uint64_t ConvertBytesToValue(const char* bytes, uint32_t size);
timeval SecondToTimeval(double time_in_sec);
+std::string GetSimpleperfVersion();
+
#endif // SIMPLE_PERF_UTILS_H_