Simpleperf: remove dependency on global current_arch.
When running unit tests on arm64 devices:
[OK] ReportCommandTest.dwarf_callgraph
[OK] record_cmd.dwarf_callchain_sampling.
ERROR: can't unwind data recorded on a different architecture.
It is because ReportCommandtest.dwarf_callgraph opens a perf.data
recorded on x86_64, and changes current_arch. It causes a problem when
the test record_cmd.dwarf_callchain_sampling calls libbacktrace built
on aarch64. Athough it doesn't make the test fail, we should fix this.
Change-Id: I2cd70369a769ef2199cab2302b8b824369be0907
diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp
index 13f40d4..f19cfd3 100644
--- a/simpleperf/cmd_dumprecord.cpp
+++ b/simpleperf/cmd_dumprecord.cpp
@@ -39,7 +39,7 @@
: Command("dump", "dump perf record file",
"Usage: simpleperf dumprecord [options] [perf_record_file]\n"
" Dump different parts of a perf record file. Default file is perf.data.\n"),
- record_filename_("perf.data") {
+ record_filename_("perf.data"), record_file_arch_(GetBuildArch()) {
}
bool Run(const std::vector<std::string>& args);
@@ -53,6 +53,7 @@
std::string record_filename_;
std::unique_ptr<RecordFileReader> record_file_reader_;
+ ArchType record_file_arch_;
};
bool DumpRecordCommand::Run(const std::vector<std::string>& args) {
@@ -65,10 +66,12 @@
}
std::string arch = record_file_reader_->ReadFeatureString(FEAT_ARCH);
if (!arch.empty()) {
- if (!SetCurrentArch(arch)) {
+ record_file_arch_ = GetArchType(arch);
+ if (record_file_arch_ == ARCH_UNSUPPORTED) {
return false;
}
}
+ ScopedCurrentArch scoped_arch(record_file_arch_);
DumpFileHeader();
DumpAttrSection();
DumpDataSection();
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index f0a7cea..9166ae6 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -693,7 +693,7 @@
ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
RegSet regs = CreateRegSet(r.regs_user_data.reg_mask, r.regs_user_data.regs);
std::vector<char>& stack = r.stack_user_data.data;
- std::vector<uint64_t> unwind_ips = UnwindCallChain(*thread, regs, stack);
+ std::vector<uint64_t> unwind_ips = UnwindCallChain(GetBuildArch(), *thread, regs, stack);
r.callchain_data.ips.push_back(PERF_CONTEXT_USER);
r.callchain_data.ips.insert(r.callchain_data.ips.end(), unwind_ips.begin(), unwind_ips.end());
r.regs_user_data.abi = 0;
diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp
index a89be67..9f3e736 100644
--- a/simpleperf/cmd_report.cpp
+++ b/simpleperf/cmd_report.cpp
@@ -270,6 +270,7 @@
" --vmlinux <file>\n"
" Parse kernel symbols from <file>.\n"),
record_filename_("perf.data"),
+ record_file_arch_(GetBuildArch()),
use_branch_address_(false),
accumulate_callchain_(false),
print_callgraph_(false),
@@ -302,6 +303,7 @@
uint64_t parent_period, bool last);
std::string record_filename_;
+ ArchType record_file_arch_;
std::unique_ptr<RecordFileReader> record_file_reader_;
perf_event_attr event_attr_;
std::vector<std::unique_ptr<Displayable>> displayable_items_;
@@ -336,6 +338,7 @@
if (!ReadFeaturesFromRecordFile()) {
return false;
}
+ ScopedCurrentArch scoped_arch(record_file_arch_);
ReadSampleTreeFromRecordFile();
// 3. Show collected information.
@@ -565,7 +568,8 @@
RegSet regs = CreateRegSet(r.regs_user_data.reg_mask, r.regs_user_data.regs);
std::vector<char> stack(r.stack_user_data.data.begin(),
r.stack_user_data.data.begin() + r.stack_user_data.data.size());
- std::vector<uint64_t> unwind_ips = UnwindCallChain(*sample->thread, regs, stack);
+ std::vector<uint64_t> unwind_ips =
+ UnwindCallChain(ScopedCurrentArch::GetCurrentArch(), *sample->thread, regs, stack);
if (!unwind_ips.empty()) {
ips.push_back(PERF_CONTEXT_USER);
ips.insert(ips.end(), unwind_ips.begin(), unwind_ips.end());
@@ -633,7 +637,8 @@
std::string arch = record_file_reader_->ReadFeatureString(PerfFileFormat::FEAT_ARCH);
if (!arch.empty()) {
- if (!SetCurrentArch(arch)) {
+ record_file_arch_ = GetArchType(arch);
+ if (record_file_arch_ == ARCH_UNSUPPORTED) {
return false;
}
}
diff --git a/simpleperf/dwarf_unwind.cpp b/simpleperf/dwarf_unwind.cpp
index fd84feb..ae2e1a1 100644
--- a/simpleperf/dwarf_unwind.cpp
+++ b/simpleperf/dwarf_unwind.cpp
@@ -94,15 +94,15 @@
return ucontext;
}
-std::vector<uint64_t> UnwindCallChain(const ThreadEntry& thread, const RegSet& regs,
- const std::vector<char>& stack) {
+std::vector<uint64_t> UnwindCallChain(ArchType arch, const ThreadEntry& thread,
+ const RegSet& regs, const std::vector<char>& stack) {
std::vector<uint64_t> result;
- if (GetCurrentArch() != GetBuildArch()) {
+ if (arch != GetBuildArch()) {
LOG(ERROR) << "can't unwind data recorded on a different architecture";
return result;
}
uint64_t sp_reg_value;
- if (!GetSpRegValue(regs, &sp_reg_value)) {
+ if (!GetSpRegValue(regs, arch, &sp_reg_value)) {
LOG(ERROR) << "can't get sp reg value";
return result;
}
diff --git a/simpleperf/dwarf_unwind.h b/simpleperf/dwarf_unwind.h
index 671013e..4e3ffd1 100644
--- a/simpleperf/dwarf_unwind.h
+++ b/simpleperf/dwarf_unwind.h
@@ -23,7 +23,7 @@
struct ThreadEntry;
-std::vector<uint64_t> UnwindCallChain(const ThreadEntry& thread, const RegSet& regs,
+std::vector<uint64_t> UnwindCallChain(ArchType arch, const ThreadEntry& thread, const RegSet& regs,
const std::vector<char>& stack);
#endif // SIMPLE_PERF_DWARF_UNWIND_H_
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index d99966a..fad8b1e 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -45,7 +45,7 @@
perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
attr.exclude_callchain_user = 1;
- attr.sample_regs_user = GetSupportedRegMask();
+ attr.sample_regs_user = GetSupportedRegMask(GetBuildArch());
attr.sample_stack_user = 8192;
return IsEventAttrSupportedByKernel(attr);
}
@@ -166,7 +166,7 @@
selection.event_attr.sample_type |=
PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
selection.event_attr.exclude_callchain_user = 1;
- selection.event_attr.sample_regs_user = GetSupportedRegMask();
+ selection.event_attr.sample_regs_user = GetSupportedRegMask(GetBuildArch());
selection.event_attr.sample_stack_user = dump_stack_size;
}
return true;
diff --git a/simpleperf/nonlinux_support/nonlinux_support.cpp b/simpleperf/nonlinux_support/nonlinux_support.cpp
index a248995..7551d36 100644
--- a/simpleperf/nonlinux_support/nonlinux_support.cpp
+++ b/simpleperf/nonlinux_support/nonlinux_support.cpp
@@ -20,7 +20,8 @@
#include "dwarf_unwind.h"
#include "environment.h"
-std::vector<uint64_t> UnwindCallChain(const ThreadEntry&, const RegSet&, const std::vector<char>&) {
+std::vector<uint64_t> UnwindCallChain(ArchType, const ThreadEntry&, const RegSet&,
+ const std::vector<char>&) {
return std::vector<uint64_t>();
}
diff --git a/simpleperf/perf_regs.cpp b/simpleperf/perf_regs.cpp
index 1f29971..29d144e 100644
--- a/simpleperf/perf_regs.cpp
+++ b/simpleperf/perf_regs.cpp
@@ -21,30 +21,24 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-static ArchType current_arch = GetBuildArch();
+ArchType ScopedCurrentArch::current_arch = GetBuildArch();
-ArchType GetCurrentArch() {
- return current_arch;
-}
-
-bool SetCurrentArch(const std::string& arch) {
+ArchType GetArchType(const std::string& arch) {
if (arch == "x86" || arch == "i686") {
- current_arch = ARCH_X86_32;
+ return ARCH_X86_32;
} else if (arch == "x86_64") {
- current_arch = ARCH_X86_64;
+ return ARCH_X86_64;
} else if (arch == "aarch64") {
- current_arch = ARCH_ARM64;
+ return ARCH_ARM64;
} else if (android::base::StartsWith(arch, "arm")) {
- current_arch = ARCH_ARM;
- } else {
- LOG(ERROR) << "unsupported arch: " << arch;
- return false;
+ return ARCH_ARM;
}
- return true;
+ LOG(ERROR) << "unsupported arch: " << arch;
+ return ARCH_UNSUPPORTED;
}
-uint64_t GetSupportedRegMask() {
- switch (GetCurrentArch()) {
+uint64_t GetSupportedRegMask(ArchType arch) {
+ switch (arch) {
case ARCH_X86_32:
return ((1ULL << PERF_REG_X86_32_MAX) - 1);
case ARCH_X86_64:
@@ -78,10 +72,10 @@
{PERF_REG_ARM64_LR, "lr"}, {PERF_REG_ARM64_SP, "sp"}, {PERF_REG_ARM64_PC, "pc"},
};
-std::string GetRegName(size_t regno) {
+std::string GetRegName(size_t regno, ArchType arch) {
// Cast regno to int type to avoid -Werror=type-limits.
int reg = static_cast<int>(regno);
- switch (GetCurrentArch()) {
+ switch (arch) {
case ARCH_X86_64: {
if (reg >= PERF_REG_X86_R8 && reg <= PERF_REG_X86_R15) {
return android::base::StringPrintf("r%d", reg - PERF_REG_X86_R8 + 8);
@@ -133,18 +127,23 @@
return false;
}
-bool GetSpRegValue(const RegSet& regs, uint64_t* value) {
+bool GetSpRegValue(const RegSet& regs, ArchType arch, uint64_t* value) {
size_t regno;
-#if defined(__i386__)
- regno = PERF_REG_X86_SP;
-#elif defined(__x86_64__)
- regno = PERF_REG_X86_SP;
-#elif defined(__aarch64__)
- regno = PERF_REG_ARM64_SP;
-#elif defined(__arm__)
- regno = PERF_REG_ARM_SP;
-#else
- return false;
-#endif
+ switch (arch) {
+ case ARCH_X86_32:
+ regno = PERF_REG_X86_SP;
+ break;
+ case ARCH_X86_64:
+ regno = PERF_REG_X86_SP;
+ break;
+ case ARCH_ARM:
+ regno = PERF_REG_ARM_SP;
+ break;
+ case ARCH_ARM64:
+ regno = PERF_REG_ARM64_SP;
+ break;
+ default:
+ return false;
+ }
return GetRegValue(regs, regno, value);
}
diff --git a/simpleperf/perf_regs.h b/simpleperf/perf_regs.h
index 47451c0..9fc610f 100644
--- a/simpleperf/perf_regs.h
+++ b/simpleperf/perf_regs.h
@@ -55,12 +55,26 @@
#endif
}
-ArchType GetCurrentArch();
-bool SetCurrentArch(const std::string& arch);
+ArchType GetArchType(const std::string& arch);
+uint64_t GetSupportedRegMask(ArchType arch);
+std::string GetRegName(size_t regno, ArchType arch);
-uint64_t GetSupportedRegMask();
+class ScopedCurrentArch {
+ public:
+ ScopedCurrentArch(ArchType arch) : saved_arch(current_arch) {
+ current_arch = arch;
+ }
+ ~ScopedCurrentArch() {
+ current_arch = saved_arch;
+ }
+ static ArchType GetCurrentArch() {
+ return current_arch;
+ }
-std::string GetRegName(size_t regno);
+ private:
+ ArchType saved_arch;
+ static ArchType current_arch;
+};
struct RegSet {
uint64_t valid_mask;
@@ -70,6 +84,6 @@
RegSet CreateRegSet(uint64_t valid_mask, const std::vector<uint64_t>& valid_regs);
bool GetRegValue(const RegSet& regs, size_t regno, uint64_t* value);
-bool GetSpRegValue(const RegSet& regs, uint64_t* value);
+bool GetSpRegValue(const RegSet& regs, ArchType arch, uint64_t* value);
#endif // SIMPLE_PERF_PERF_REGS_H_
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp
index f9e220a..d97ba81 100644
--- a/simpleperf/record.cpp
+++ b/simpleperf/record.cpp
@@ -505,7 +505,8 @@
PrintIndented(indent, "user regs: abi=%" PRId64 "\n", regs_user_data.abi);
for (size_t i = 0, pos = 0; i < 64; ++i) {
if ((regs_user_data.reg_mask >> i) & 1) {
- PrintIndented(indent + 1, "reg (%s) 0x%016" PRIx64 "\n", GetRegName(i).c_str(),
+ PrintIndented(indent + 1, "reg (%s) 0x%016" PRIx64 "\n",
+ GetRegName(i, ScopedCurrentArch::GetCurrentArch()).c_str(),
regs_user_data.regs[pos++]);
}
}