diff options
author | Yabin Cui <yabinc@google.com> | 2023-11-16 16:34:01 -0800 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2023-11-16 16:41:26 -0800 |
commit | 5cc4e17654f6651aed599edf4ba1d62210f1e9be (patch) | |
tree | 4d60e879b242bae80b2491a9205a1b6f0955c786 | |
parent | d59010441b866ec457a75be58ce3871da7e8b0b9 (diff) | |
download | extras-5cc4e17654f6651aed599edf4ba1d62210f1e9be.tar.gz |
simpleperf: Add DebugRecord
DebugRecord is used to add debug strings in the recording file.
The debug strings can help debug failed unwinding cases.
Bug: 309868255
Test: run simpleperf_unit_test
Change-Id: Ie0e2c1abbb735bd10261af3ea332306a56222bfb
-rw-r--r-- | simpleperf/record.cpp | 36 | ||||
-rw-r--r-- | simpleperf/record.h | 17 | ||||
-rw-r--r-- | simpleperf/record_equal_test.h | 29 | ||||
-rw-r--r-- | simpleperf/record_test.cpp | 8 |
4 files changed, 78 insertions, 12 deletions
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp index 29e5d112..b9f03829 100644 --- a/simpleperf/record.cpp +++ b/simpleperf/record.cpp @@ -72,6 +72,7 @@ static std::string RecordTypeToString(int record_type) { {SIMPLE_PERF_RECORD_CALLCHAIN, "callchain"}, {SIMPLE_PERF_RECORD_UNWINDING_RESULT, "unwinding_result"}, {SIMPLE_PERF_RECORD_TRACING_DATA, "tracing_data"}, + {SIMPLE_PERF_RECORD_DEBUG, "debug"}, }; auto it = record_type_names.find(record_type); @@ -1603,6 +1604,38 @@ void UnwindingResultRecord::DumpData(size_t indent) const { } } +DebugRecord::DebugRecord(uint64_t time, const std::string& s) { + SetTypeAndMisc(SIMPLE_PERF_RECORD_DEBUG, 0); + uint32_t size = header_size() + sizeof(uint64_t) + Align(strlen(s.c_str()) + 1, sizeof(uint64_t)); + SetSize(size); + char* new_binary = new char[size]; + char* p = new_binary; + MoveToBinaryFormat(header, p); + MoveToBinaryFormat(time, p); + this->time = time; + this->s = p; + MoveToBinaryFormat(s.c_str(), strlen(s.c_str()) + 1, p); + CHECK_LE(p, new_binary + size); + UpdateBinary(new_binary); +} + +bool DebugRecord::Parse(const perf_event_attr&, char* p, char* end) { + if (!ParseHeader(p, end)) { + return false; + } + CHECK_SIZE_U64(p, end, 1); + MoveFromBinaryFormat(time, p); + if (memchr(p, '\0', end - p) == nullptr) { + return false; + } + s = p; + return true; +} + +void DebugRecord::DumpData(size_t indent) const { + PrintIndented(indent, "s %s\n", s); +} + bool UnknownRecord::Parse(const perf_event_attr&, char* p, char* end) { if (!ParseHeader(p, end)) { return false; @@ -1677,6 +1710,9 @@ std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, uint32 case SIMPLE_PERF_RECORD_TRACING_DATA: r.reset(new TracingDataRecord); break; + case SIMPLE_PERF_RECORD_DEBUG: + r.reset(new DebugRecord); + break; default: r.reset(new UnknownRecord); break; diff --git a/simpleperf/record.h b/simpleperf/record.h index 925eaaa0..92cc88c4 100644 --- a/simpleperf/record.h +++ b/simpleperf/record.h @@ -56,6 +56,7 @@ enum user_record_type { SIMPLE_PERF_RECORD_CALLCHAIN, SIMPLE_PERF_RECORD_UNWINDING_RESULT, SIMPLE_PERF_RECORD_TRACING_DATA, + SIMPLE_PERF_RECORD_DEBUG, }; // perf_event_header uses u16 to store record size. However, that is not @@ -671,6 +672,22 @@ struct UnwindingResultRecord : public Record { void DumpData(size_t indent) const override; }; +// Add a debug string in the recording file. +struct DebugRecord : public Record { + uint64_t time = 0; + char* s = nullptr; + + DebugRecord() {} + + DebugRecord(uint64_t time, const std::string& s); + + bool Parse(const perf_event_attr& attr, char* p, char* end) override; + uint64_t Timestamp() const override { return time; } + + protected: + void DumpData(size_t indent) const override; +}; + // UnknownRecord is used for unknown record types, it makes sure all unknown // records are not changed when modifying perf.data. struct UnknownRecord : public Record { diff --git a/simpleperf/record_equal_test.h b/simpleperf/record_equal_test.h index bd66415a..fce1a840 100644 --- a/simpleperf/record_equal_test.h +++ b/simpleperf/record_equal_test.h @@ -16,23 +16,28 @@ namespace simpleperf { -static void CheckMmapRecordDataEqual(const MmapRecord& r1, const MmapRecord& r2) { +static void CheckRecordDataEqual(const MmapRecord& r1, const MmapRecord& r2) { ASSERT_EQ(0, memcmp(r1.data, r2.data, sizeof(*r1.data))); ASSERT_STREQ(r1.filename, r2.filename); } -static void CheckCommRecordDataEqual(const CommRecord& r1, const CommRecord& r2) { +static void CheckRecordDataEqual(const CommRecord& r1, const CommRecord& r2) { ASSERT_EQ(0, memcmp(r1.data, r2.data, sizeof(*r1.data))); ASSERT_STREQ(r1.comm, r2.comm); } -static void CheckBuildIdRecordDataEqual(const BuildIdRecord& r1, const BuildIdRecord& r2) { +static void CheckRecordDataEqual(const BuildIdRecord& r1, const BuildIdRecord& r2) { ASSERT_EQ(r1.pid, r2.pid); ASSERT_EQ(r1.build_id, r2.build_id); ASSERT_STREQ(r1.filename, r2.filename); } -static void CheckSampleRecordDataEqual(const SampleRecord& r1, const SampleRecord& r2) { +static void CheckRecordDataEqual(const DebugRecord& r1, const DebugRecord& r2) { + ASSERT_EQ(r1.time, r2.time); + ASSERT_STREQ(r1.s, r2.s); +} + +static void CheckRecordDataEqual(const SampleRecord& r1, const SampleRecord& r2) { ASSERT_EQ(r1.sample_type, r2.sample_type); ASSERT_EQ(r1.read_format, r2.read_format); if (r1.sample_type & PERF_SAMPLE_IP) { @@ -95,20 +100,20 @@ static void CheckRecordEqual(const Record& r1, const Record& r2) { ASSERT_EQ(r1.misc(), r2.misc()); ASSERT_EQ(r1.size(), r2.size()); if (r1.type() == PERF_RECORD_SAMPLE) { - CheckSampleRecordDataEqual(static_cast<const SampleRecord&>(r1), - static_cast<const SampleRecord&>(r2)); + CheckRecordDataEqual(static_cast<const SampleRecord&>(r1), + static_cast<const SampleRecord&>(r2)); return; } ASSERT_EQ(0, memcmp(&r1.sample_id, &r2.sample_id, sizeof(r1.sample_id))); if (r1.type() == PERF_RECORD_MMAP) { - CheckMmapRecordDataEqual(static_cast<const MmapRecord&>(r1), - static_cast<const MmapRecord&>(r2)); + CheckRecordDataEqual(static_cast<const MmapRecord&>(r1), static_cast<const MmapRecord&>(r2)); } else if (r1.type() == PERF_RECORD_COMM) { - CheckCommRecordDataEqual(static_cast<const CommRecord&>(r1), - static_cast<const CommRecord&>(r2)); + CheckRecordDataEqual(static_cast<const CommRecord&>(r1), static_cast<const CommRecord&>(r2)); } else if (r1.type() == PERF_RECORD_BUILD_ID) { - CheckBuildIdRecordDataEqual(static_cast<const BuildIdRecord&>(r1), - static_cast<const BuildIdRecord&>(r2)); + CheckRecordDataEqual(static_cast<const BuildIdRecord&>(r1), + static_cast<const BuildIdRecord&>(r2)); + } else if (r1.type() == SIMPLE_PERF_RECORD_DEBUG) { + CheckRecordDataEqual(static_cast<const DebugRecord&>(r1), static_cast<const DebugRecord&>(r2)); } } diff --git a/simpleperf/record_test.cpp b/simpleperf/record_test.cpp index 20c9c18a..bca0b7ff 100644 --- a/simpleperf/record_test.cpp +++ b/simpleperf/record_test.cpp @@ -193,3 +193,11 @@ TEST_F(RecordTest, CommRecord) { ASSERT_EQ(r.sample_id.time_data.time, 4u); CheckRecordMatchBinary(r); } + +TEST_F(RecordTest, DebugRecord) { + DebugRecord r(1234, "hello"); + ASSERT_EQ(r.size() % sizeof(uint64_t), 0); + ASSERT_EQ(r.Timestamp(), 1234); + ASSERT_STREQ(r.s, "hello"); + CheckRecordMatchBinary(r); +} |