summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2019-07-17 16:59:48 -0700
committerYabin Cui <yabinc@google.com>2019-07-19 11:48:08 -0700
commit724d848bae89aed1462c18f130ef5858e78773f8 (patch)
tree777a05e2cfc2b4d001f99bf6ad8203b3f416c653
parent193ca49c16231dc5511e74f2d925c53166db3021 (diff)
downloadextras-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.cpp62
-rw-r--r--simpleperf/ETMRecorder.h10
-rw-r--r--simpleperf/cmd_record.cpp15
-rw-r--r--simpleperf/cmd_record_test.cpp17
-rw-r--r--simpleperf/record.cpp52
-rw-r--r--simpleperf/record.h36
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;