simpleperf: Fix BR_INST_RETIRED.NEAR_TAKEN for Intel Atom CPUs
Intel Atom CPUs use a different umask for BR_INST_RETIRED.NEAR_TAKEN,
as shown in
https://github.com/intel/perfmon/blob/main/scripts/perf/alderlake/pipeline.json#L303.
This patch detects Intel Atom CPUs and changes config when opening
perf event files on those CPUs.
Bug: 345410289
Test: run simpleperf manually
Test: run simpleperf_unit_test
Change-Id: Ic17bf663fa77c3fbd2df446ba941755a1cd51958
diff --git a/simpleperf/cmd_list.cpp b/simpleperf/cmd_list.cpp
index f6a474d..bd864a6 100644
--- a/simpleperf/cmd_list.cpp
+++ b/simpleperf/cmd_list.cpp
@@ -25,6 +25,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include "ETMRecorder.h"
#include "RegEx.h"
@@ -157,7 +158,11 @@
got_status = true;
}
} else if (model.arch == "x86") {
- if (event_type.limited_arch != model_name) {
+ std::string limited_arch = event_type.limited_arch;
+ if (auto pos = limited_arch.find(':'); pos != std::string::npos) {
+ limited_arch = limited_arch.substr(0, pos);
+ }
+ if (limited_arch != model_name) {
supported = false;
got_status = true;
}
@@ -196,10 +201,10 @@
return it->second;
}
#elif defined(__i386__) || defined(__x86_64__)
- if (model.x86_data.vendor_id == "GenuineIntel") {
+ if (android::base::StartsWith(model.x86_data.vendor_id, "GenuineIntel")) {
return "x86-intel";
}
- if (model.x86_data.vendor_id == "AuthenticAMD") {
+ if (android::base::StartsWith(model.x86_data.vendor_id, "AuthenticAMD")) {
return "x86-amd";
}
#endif // defined(__i386__) || defined(__x86_64__)
@@ -220,6 +225,12 @@
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
+#if defined(__i386__) || defined(__x86_64__)
+ std::set<int> atom_cpus = GetX86IntelAtomCpus();
+ if (atom_cpus.count(cpu) > 0) {
+ attr.config = event_type.GetIntelAtomCpuConfig();
+ }
+#endif // defined(__i386__) || defined(__x86_64__)
std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(
attr, test_thread_arg.tid, test_thread_arg.cpu, nullptr, event_type.name, false);
test_thread_arg.start = true;
diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp
index 316aee4..7921073 100644
--- a/simpleperf/environment.cpp
+++ b/simpleperf/environment.cpp
@@ -1101,6 +1101,7 @@
}
std::vector<CpuModel> ParseX86CpuModel(const std::vector<std::string>& lines) {
+ std::set<int> atom_cpus = GetX86IntelAtomCpus();
std::vector<CpuModel> cpu_models;
uint32_t processor = 0;
CpuModel model;
@@ -1112,6 +1113,9 @@
parsed |= 1;
} else if (name == "vendor_id") {
model.x86_data.vendor_id = value;
+ if (atom_cpus.count(static_cast<int>(processor)) > 0) {
+ model.x86_data.vendor_id += "-atom";
+ }
AddCpuModel(processor, model, cpu_models);
parsed = 0;
}
@@ -1181,4 +1185,13 @@
#endif
}
+std::set<int> GetX86IntelAtomCpus() {
+ std::string data;
+ if (!android::base::ReadFileToString("/sys/devices/cpu_atom/cpus", &data)) {
+ return {};
+ }
+ std::optional<std::set<int>> atom_cpus = GetCpusFromString(data);
+ return atom_cpus.has_value() ? atom_cpus.value() : std::set<int>();
+}
+
} // namespace simpleperf
diff --git a/simpleperf/environment.h b/simpleperf/environment.h
index 7d0d7f0..279f2ce 100644
--- a/simpleperf/environment.h
+++ b/simpleperf/environment.h
@@ -173,6 +173,7 @@
};
std::vector<CpuModel> GetCpuModels();
+std::set<int> GetX86IntelAtomCpus();
#endif // defined(__linux__)
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index 58f8250..5095739 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -666,8 +666,18 @@
// successfully or all failed to open.
EventFd* group_fd = nullptr;
for (auto& selection : group.selections) {
+#if defined(__i386__) || defined(__x86_64__)
+ perf_event_attr attr = selection.event_attr;
+ std::set<int> atom_cpus = GetX86IntelAtomCpus();
+ if (atom_cpus.count(cpu) > 0) {
+ attr.config = selection.event_type_modifier.event_type.GetIntelAtomCpuConfig();
+ }
+ std::unique_ptr<EventFd> event_fd =
+ EventFd::OpenEventFile(attr, tid, cpu, group_fd, selection.event_type_modifier.name, false);
+#else // defined(__i386__) || defined(__x86_64__)
std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(
selection.event_attr, tid, cpu, group_fd, selection.event_type_modifier.name, false);
+#endif // defined(__i386__) || defined(__x86_64__)
if (!event_fd) {
*failed_event_type = selection.event_type_modifier.name;
return false;
diff --git a/simpleperf/event_table.json b/simpleperf/event_table.json
index ddcbfbf..df17063 100644
--- a/simpleperf/event_table.json
+++ b/simpleperf/event_table.json
@@ -1045,7 +1045,7 @@
},
"x86-intel": {
"events": [
- ["0x20c4", "BR_INST_RETIRED.NEAR_TAKEN", "Taken branch instructions retired"]
+ ["0x20c4", "BR_INST_RETIRED.NEAR_TAKEN", "Taken branch instructions retired", "atom=0xc0c4"]
]
},
"x86-amd": {
diff --git a/simpleperf/event_table_generator.py b/simpleperf/event_table_generator.py
index d44cbb6..31f678b 100755
--- a/simpleperf/event_table_generator.py
+++ b/simpleperf/event_table_generator.py
@@ -189,7 +189,10 @@
number = int(event[0], 16)
name = event[1]
desc = event[2]
- self.events.append(RawEvent(number, name, desc, self.arch))
+ limited_arch = self.arch
+ if len(event) > 3:
+ limited_arch += ":" + event[3]
+ self.events.append(RawEvent(number, name, desc, limited_arch))
class RawEventGenerator:
@@ -210,7 +213,7 @@
lines = []
for event in events:
lines.append(gen_event_type_entry_str(event.name, 'PERF_TYPE_RAW', '0x%x' %
- event.number, event.desc, event.limited_arch))
+ event.number, event.desc, event.limited_arch))
return guard(''.join(lines))
lines_arm64 = generate_event_entries(self.arm64_data.events, self.add_arm_guard)
diff --git a/simpleperf/event_type.cpp b/simpleperf/event_type.cpp
index fef1a9f..d54ac27 100644
--- a/simpleperf/event_type.cpp
+++ b/simpleperf/event_type.cpp
@@ -463,6 +463,16 @@
return empty_result;
}
+uint64_t EventType::GetIntelAtomCpuConfig() const {
+ if (auto pos = limited_arch.find("atom="); pos != std::string::npos) {
+ uint64_t atom_config;
+ if (android::base::ParseUint(limited_arch.substr(pos + 5), &atom_config)) {
+ return atom_config;
+ }
+ }
+ return config;
+}
+
std::string ScopedEventTypes::BuildString(const std::vector<const EventType*>& event_types) {
std::string result;
for (auto type : event_types) {
diff --git a/simpleperf/event_type.h b/simpleperf/event_type.h
index d85f71d..8683dbb 100644
--- a/simpleperf/event_type.h
+++ b/simpleperf/event_type.h
@@ -58,6 +58,7 @@
bool IsTracepointEvent() const { return type == PERF_TYPE_TRACEPOINT; }
std::vector<int> GetPmuCpumask();
+ uint64_t GetIntelAtomCpuConfig() const;
std::string name;
uint32_t type;