diff options
author | Yabin Cui <yabinc@google.com> | 2019-07-17 16:59:48 -0700 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2019-07-19 11:48:08 -0700 |
commit | 724d848bae89aed1462c18f130ef5858e78773f8 (patch) | |
tree | 777a05e2cfc2b4d001f99bf6ad8203b3f416c653 | |
parent | 193ca49c16231dc5511e74f2d925c53166db3021 (diff) | |
download | extras-724d848bae89aed1462c18f130ef5858e78773f8.tar.gz |
simpleperf: add PERF_RECORD_AUXTRACE_INFO record.
PERF_RECORD_AUXTRACE_INFO is used to record etm configurations on device.
Make its content the same as in linux perf.
Bug: 135204414
Test: run simpleperf_unit_test.
Change-Id: I5d32cbe22acbc690d2ba47473ff344241982a0c3
-rw-r--r-- | simpleperf/ETMRecorder.cpp | 62 | ||||
-rw-r--r-- | simpleperf/ETMRecorder.h | 10 | ||||
-rw-r--r-- | simpleperf/cmd_record.cpp | 15 | ||||
-rw-r--r-- | simpleperf/cmd_record_test.cpp | 17 | ||||
-rw-r--r-- | simpleperf/record.cpp | 52 | ||||
-rw-r--r-- | simpleperf/record.h | 36 |
6 files changed, 178 insertions, 14 deletions
diff --git a/simpleperf/ETMRecorder.cpp b/simpleperf/ETMRecorder.cpp index 0da803f5..9752da86 100644 --- a/simpleperf/ETMRecorder.cpp +++ b/simpleperf/ETMRecorder.cpp @@ -32,8 +32,15 @@ namespace simpleperf { -static constexpr uint64_t ETM4_CFG_CTXTID = 1ULL << 6; -static constexpr uint64_t ETM4_CFG_TS = 1ULL << 11; +static constexpr bool ETM_RECORD_TIMESTAMP = false; + +// Config bits from include/linux/coresight-pmu.h in the kernel +// For etm_event_config: +static constexpr int ETM_OPT_CTXTID = 14; +static constexpr int ETM_OPT_TS = 28; +// For etm_config_reg: +static constexpr int ETM4_CFG_BIT_CTXTID = 6; +static constexpr int ETM4_CFG_BIT_TS = 11; static const std::string ETM_DIR = "/sys/bus/event_source/devices/cs_etm/"; @@ -127,7 +134,7 @@ bool ETMRecorder::ReadEtmInfo() { ReadValueInEtmDir(name + "/trcidr/trcidr1", &cpu_info.trcidr1) && ReadValueInEtmDir(name + "/trcidr/trcidr2", &cpu_info.trcidr2) && ReadValueInEtmDir(name + "/trcidr/trcidr8", &cpu_info.trcidr8) && - ReadValueInEtmDir(name + "/trcidr/trcidr9", &cpu_info.trcidr9) && + ReadValueInEtmDir(name + "/mgmt/trcauthstatus", &cpu_info.trcauthstatus) && ReadValueInEtmDir(name + "/mgmt/trctraceid", &cpu_info.trctraceid); if (!success) { return false; @@ -150,15 +157,50 @@ bool ETMRecorder::FindSinkConfig() { void ETMRecorder::SetEtmPerfEventAttr(perf_event_attr* attr) { CHECK(etm_supported_); - attr->config |= ETM4_CFG_CTXTID; - bool ts_supported = true; - for (auto& p : etm_info_) { - ts_supported &= p.second.IsTimestampSupported(); + BuildEtmConfig(); + attr->config = etm_event_config_; + attr->config2 = sink_config_; +} + +void ETMRecorder::BuildEtmConfig() { + if (etm_event_config_ == 0) { + etm_event_config_ |= 1ULL << ETM_OPT_CTXTID; + etm_config_reg_ |= 1U << ETM4_CFG_BIT_CTXTID; + + if (ETM_RECORD_TIMESTAMP) { + bool ts_supported = true; + for (auto& p : etm_info_) { + ts_supported &= p.second.IsTimestampSupported(); + } + if (ts_supported) { + etm_event_config_ |= 1ULL << ETM_OPT_TS; + etm_config_reg_ |= 1U << ETM4_CFG_BIT_TS; + } + } } - if (ts_supported) { - attr->config |= ETM4_CFG_TS; +} + +AuxTraceInfoRecord ETMRecorder::CreateAuxTraceInfoRecord() { + AuxTraceInfoRecord::DataType data; + memset(&data, 0, sizeof(data)); + data.aux_type = AuxTraceInfoRecord::AUX_TYPE_ETM; + data.nr_cpu = etm_info_.size(); + data.pmu_type = GetEtmEventType(); + std::vector<AuxTraceInfoRecord::ETM4Info> etm4_v(etm_info_.size()); + size_t pos = 0; + for (auto& p : etm_info_) { + auto& e = etm4_v[pos++]; + e.magic = AuxTraceInfoRecord::MAGIC_ETM4; + e.cpu = p.first; + e.trcconfigr = etm_config_reg_; + e.trctraceidr = p.second.trctraceid; + e.trcidr0 = p.second.trcidr0; + e.trcidr1 = p.second.trcidr1; + e.trcidr2 = p.second.trcidr2; + e.trcidr8 = p.second.trcidr8; + e.trcauthstatus = p.second.trcauthstatus; } - attr->config2 = sink_config_; + return AuxTraceInfoRecord(data, etm4_v); } } // namespace simpleperf
\ No newline at end of file diff --git a/simpleperf/ETMRecorder.h b/simpleperf/ETMRecorder.h index f4c57378..ba31d83a 100644 --- a/simpleperf/ETMRecorder.h +++ b/simpleperf/ETMRecorder.h @@ -22,6 +22,7 @@ #include <memory> #include "event_type.h" +#include "record.h" #include "perf_event.h" namespace simpleperf { @@ -31,7 +32,7 @@ struct ETMPerCpu { uint32_t trcidr1; uint32_t trcidr2; uint32_t trcidr8; - uint32_t trcidr9; + uint32_t trcauthstatus; uint32_t trctraceid; int GetMajorVersion() const; @@ -54,14 +55,21 @@ class ETMRecorder { std::unique_ptr<EventType> BuildEventType(); bool CheckEtmSupport(); void SetEtmPerfEventAttr(perf_event_attr* attr); + AuxTraceInfoRecord CreateAuxTraceInfoRecord(); private: bool ReadEtmInfo(); bool FindSinkConfig(); + void BuildEtmConfig(); int event_type_ = 0; bool etm_supported_ = false; + // select ETR device, setting in perf_event_attr->config2 uint32_t sink_config_ = 0; + // select etm options (timestamp, context_id, ...), setting in perf_event_attr->config + uint64_t etm_event_config_ = 0; + // record etm options in AuxTraceInfoRecord + uint32_t etm_config_reg_ = 0; std::map<int, ETMPerCpu> etm_info_; }; diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index de4ac42a..834b33fb 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -40,6 +40,7 @@ #include "CallChainJoiner.h" #include "command.h" #include "environment.h" +#include "ETMRecorder.h" #include "event_selection_set.h" #include "event_type.h" #include "IOEventLoop.h" @@ -282,6 +283,7 @@ class RecordCommand : public Command { bool DumpKernelMaps(); bool DumpUserSpaceMaps(); bool DumpProcessMaps(pid_t pid, const std::unordered_set<pid_t>& tids); + bool DumpAuxTraceInfo(); bool ProcessRecord(Record* record); bool ShouldOmitRecord(Record* record); bool DumpMapsForRecord(Record* record); @@ -1044,7 +1046,8 @@ bool RecordCommand::CreateAndInitRecordFile() { } // Use first perf_event_attr and first event id to dump mmap and comm records. dumping_attr_id_ = event_selection_set_.GetEventAttrWithId()[0]; - return DumpKernelSymbol() && DumpTracingData() && DumpKernelMaps() && DumpUserSpaceMaps(); + return DumpKernelSymbol() && DumpTracingData() && DumpKernelMaps() && DumpUserSpaceMaps() && + DumpAuxTraceInfo(); } std::unique_ptr<RecordFileWriter> RecordCommand::CreateRecordFile( @@ -1210,6 +1213,16 @@ bool RecordCommand::ProcessRecord(Record* record) { return SaveRecordWithoutUnwinding(record); } +bool RecordCommand::DumpAuxTraceInfo() { + for (auto& event_type : event_selection_set_.GetEvents()) { + if (event_type->name == "cs-etm") { + AuxTraceInfoRecord auxtrace_info = ETMRecorder::GetInstance().CreateAuxTraceInfoRecord(); + return ProcessRecord(&auxtrace_info); + } + } + return true; +} + template <typename MmapRecordType> bool MapOnlyExistInMemory(MmapRecordType* record) { return !record->InKernel() && MappedFileOnlyExistInMemory(record->filename); diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp index 39cf496d..f4759ef0 100644 --- a/simpleperf/cmd_record_test.cpp +++ b/simpleperf/cmd_record_test.cpp @@ -807,7 +807,20 @@ TEST(record_cmd, no_cut_samples_option) { } TEST(record_cmd, cs_etm_event) { - if (ETMRecorder::GetInstance().CheckEtmSupport()) { - ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm"})); + if (!ETMRecorder::GetInstance().CheckEtmSupport()) { + GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device"; + return; } + TemporaryFile tmpfile; + ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm"}, tmpfile.path)); + std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path); + ASSERT_TRUE(reader); + bool has_auxtrace_info = false; + ASSERT_TRUE(reader->ReadDataSection([&](std::unique_ptr<Record> r) { + if (r->type() == PERF_RECORD_AUXTRACE_INFO) { + has_auxtrace_info = true; + } + return true; + })); + ASSERT_TRUE(has_auxtrace_info); }
\ No newline at end of file diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp index 2d684a8a..f45fe7c7 100644 --- a/simpleperf/record.cpp +++ b/simpleperf/record.cpp @@ -45,6 +45,7 @@ static std::string RecordTypeToString(int record_type) { {PERF_RECORD_BUILD_ID, "build_id"}, {PERF_RECORD_MMAP2, "mmap2"}, {PERF_RECORD_TRACING_DATA, "tracing_data"}, + {PERF_RECORD_AUXTRACE_INFO, "auxtrace_info"}, {SIMPLE_PERF_RECORD_KERNEL_SYMBOL, "kernel_symbol"}, {SIMPLE_PERF_RECORD_DSO, "dso"}, {SIMPLE_PERF_RECORD_SYMBOL, "symbol"}, @@ -910,6 +911,55 @@ BuildIdRecord::BuildIdRecord(bool in_kernel, pid_t pid, const BuildId& build_id, UpdateBinary(new_binary); } +AuxTraceInfoRecord::AuxTraceInfoRecord(char* p) : Record(p) { + const char* end = p + size(); + p += header_size(); + data = reinterpret_cast<DataType*>(p); + CHECK_EQ(data->aux_type, AUX_TYPE_ETM); + CHECK_EQ(data->version, 0); + for (uint32_t i = 0; i < data->nr_cpu; ++i) { + CHECK_EQ(data->etm4_info[i].magic, MAGIC_ETM4); + } + p += sizeof(DataType) + data->nr_cpu * sizeof(ETM4Info); + CHECK_EQ(p, end); +} + +AuxTraceInfoRecord::AuxTraceInfoRecord(const DataType& data, + const std::vector<ETM4Info>& etm4_info) { + SetTypeAndMisc(PERF_RECORD_AUXTRACE_INFO, 0); + SetSize(header_size() + sizeof(DataType) + sizeof(ETM4Info) * etm4_info.size()); + char* new_binary = new char[size()]; + char* p = new_binary; + MoveToBinaryFormat(header, p); + this->data = reinterpret_cast<DataType*>(p); + MoveToBinaryFormat(data, p); + for (auto& etm4 : etm4_info) { + MoveToBinaryFormat(etm4, p); + } + UpdateBinary(new_binary); +} + +void AuxTraceInfoRecord::DumpData(size_t indent) const { + PrintIndented(indent, "aux_type %u\n", data->aux_type); + PrintIndented(indent, "version %" PRIu64 "\n", data->version); + PrintIndented(indent, "nr_cpu %u\n", data->nr_cpu); + PrintIndented(indent, "pmu_type %u\n", data->pmu_type); + PrintIndented(indent, "snapshot %" PRIu64 "\n", data->snapshot); + indent++; + for (int i = 0; i < data->nr_cpu; i++) { + const ETM4Info& e = data->etm4_info[i]; + PrintIndented(indent, "magic 0x%" PRIx64 "\n", e.magic); + PrintIndented(indent, "cpu %" PRIu64 "\n", e.cpu); + PrintIndented(indent, "trcconfigr 0x%" PRIx64 "\n", e.trcconfigr); + PrintIndented(indent, "trctraceidr 0x%" PRIx64 "\n", e.trctraceidr); + PrintIndented(indent, "trcidr0 0x%" PRIx64 "\n", e.trcidr0); + PrintIndented(indent, "trcidr1 0x%" PRIx64 "\n", e.trcidr1); + PrintIndented(indent, "trcidr2 0x%" PRIx64 "\n", e.trcidr2); + PrintIndented(indent, "trcidr8 0x%" PRIx64 "\n", e.trcidr8); + PrintIndented(indent, "trcauthstatus 0x%" PRIx64 "\n", e.trcauthstatus); + } +} + KernelSymbolRecord::KernelSymbolRecord(char* p) : Record(p) { const char* end = p + size(); p += header_size(); @@ -1211,6 +1261,8 @@ std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, uint32 return std::unique_ptr<Record>(new SampleRecord(attr, p)); case PERF_RECORD_TRACING_DATA: return std::unique_ptr<Record>(new TracingDataRecord(p)); + case PERF_RECORD_AUXTRACE_INFO: + return std::unique_ptr<Record>(new AuxTraceInfoRecord(p)); case SIMPLE_PERF_RECORD_KERNEL_SYMBOL: return std::unique_ptr<Record>(new KernelSymbolRecord(p)); case SIMPLE_PERF_RECORD_DSO: diff --git a/simpleperf/record.h b/simpleperf/record.h index adde3f44..23a7652b 100644 --- a/simpleperf/record.h +++ b/simpleperf/record.h @@ -40,6 +40,8 @@ enum user_record_type { PERF_RECORD_BUILD_ID, PERF_RECORD_FINISHED_ROUND, + PERF_RECORD_AUXTRACE_INFO = 70, + SIMPLE_PERF_RECORD_TYPE_START = 32768, SIMPLE_PERF_RECORD_KERNEL_SYMBOL, // TODO: remove DsoRecord and SymbolRecord. @@ -438,6 +440,40 @@ struct BuildIdRecord : public Record { void DumpData(size_t indent) const override; }; +struct AuxTraceInfoRecord : public Record { + // magic values to be compatible with linux perf + static const uint32_t AUX_TYPE_ETM = 3; + static const uint64_t MAGIC_ETM4 = 0x4040404040404040ULL; + + struct ETM4Info { + uint64_t magic; + uint64_t cpu; + uint64_t trcconfigr; + uint64_t trctraceidr; + uint64_t trcidr0; + uint64_t trcidr1; + uint64_t trcidr2; + uint64_t trcidr8; + uint64_t trcauthstatus; + }; + + struct DataType { + uint32_t aux_type; + uint32_t reserved; + uint64_t version; + uint32_t nr_cpu; + uint32_t pmu_type; + uint64_t snapshot; + ETM4Info etm4_info[0]; + }* data; + + explicit AuxTraceInfoRecord(char* p); + AuxTraceInfoRecord(const DataType& data, const std::vector<ETM4Info>& etm4_info); + + protected: + void DumpData(size_t indent) const override; +}; + struct KernelSymbolRecord : public Record { uint32_t kallsyms_size; const char* kallsyms; |