summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--simpleperf/cmd_list.cpp16
-rw-r--r--simpleperf/cmd_record.cpp4
-rw-r--r--simpleperf/cmd_stat.cpp4
-rw-r--r--simpleperf/environment.cpp63
-rw-r--r--simpleperf/environment.h2
5 files changed, 86 insertions, 3 deletions
diff --git a/simpleperf/cmd_list.cpp b/simpleperf/cmd_list.cpp
index b6bf817c..273a8037 100644
--- a/simpleperf/cmd_list.cpp
+++ b/simpleperf/cmd_list.cpp
@@ -22,6 +22,7 @@
#include <android-base/logging.h>
#include "command.h"
+#include "environment.h"
#include "event_attr.h"
#include "event_fd.h"
#include "event_type.h"
@@ -30,9 +31,14 @@ static void PrintEventTypesOfType(uint32_t type, const std::string& type_name,
const std::vector<EventType>& event_types) {
printf("List of %s:\n", type_name.c_str());
for (auto& event_type : event_types) {
- if (event_type.type == type &&
- IsEventAttrSupportedByKernel(CreateDefaultPerfEventAttr(event_type))) {
- printf(" %s\n", event_type.name.c_str());
+ if (event_type.type == type) {
+ perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
+ // Exclude kernel to list supported events even when
+ // /proc/sys/kernel/perf_event_paranoid is 2.
+ attr.exclude_kernel = 1;
+ if (IsEventAttrSupportedByKernel(attr)) {
+ printf(" %s\n", event_type.name.c_str());
+ }
}
}
printf("\n");
@@ -50,6 +56,10 @@ class ListCommand : public Command {
};
bool ListCommand::Run(const std::vector<std::string>& args) {
+ if (!CheckPerfEventLimit()) {
+ return false;
+ }
+
static std::map<std::string, std::pair<int, std::string>> type_map = {
{"hw", {PERF_TYPE_HARDWARE, "hardware events"}},
{"sw", {PERF_TYPE_SOFTWARE, "software events"}},
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 83f60e73..48255fad 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -191,6 +191,10 @@ class RecordCommand : public Command {
};
bool RecordCommand::Run(const std::vector<std::string>& args) {
+ if (!CheckPerfEventLimit()) {
+ return false;
+ }
+
// 1. Parse options, and use default measured event type if not given.
std::vector<std::string> workload_args;
if (!ParseOptions(args, &workload_args)) {
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index f477abfd..dca7ed05 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -101,6 +101,10 @@ class StatCommand : public Command {
};
bool StatCommand::Run(const std::vector<std::string>& args) {
+ if (!CheckPerfEventLimit()) {
+ return false;
+ }
+
// 1. Parse options, and use default measured event types if not given.
std::vector<std::string> workload_args;
if (!ParseOptions(args, &workload_args)) {
diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp
index 578c1b16..798d08dc 100644
--- a/simpleperf/environment.cpp
+++ b/simpleperf/environment.cpp
@@ -31,6 +31,10 @@
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
+#if defined(__ANDROID__)
+#include <sys/system_properties.h>
+#endif
+
#include "read_elf.h"
#include "utils.h"
@@ -385,3 +389,62 @@ bool GetExecPath(std::string* exec_path) {
*exec_path = path;
return true;
}
+
+/*
+ * perf event paranoia level:
+ * -1 - not paranoid at all
+ * 0 - disallow raw tracepoint access for unpriv
+ * 1 - disallow cpu events for unpriv
+ * 2 - disallow kernel profiling for unpriv
+ * 3 - disallow user profiling for unpriv
+ */
+static bool ReadPerfEventParanoid(int* value) {
+ std::string s;
+ if (!android::base::ReadFileToString("/proc/sys/kernel/perf_event_paranoid", &s)) {
+ PLOG(ERROR) << "failed to read /proc/sys/kernel/perf_event_paranoid";
+ return false;
+ }
+ s = android::base::Trim(s);
+ if (!android::base::ParseInt(s.c_str(), value)) {
+ PLOG(ERROR) << "failed to parse /proc/sys/kernel/perf_event_paranoid: " << s;
+ return false;
+ }
+ return true;
+}
+
+static const char* GetLimitLevelDescription(int limit_level) {
+ switch (limit_level) {
+ case -1: return "unlimited";
+ case 0: return "disallowing raw tracepoint access for unpriv";
+ case 1: return "disallowing cpu events for unpriv";
+ case 2: return "disallowing kernel profiling for unpriv";
+ case 3: return "disallowing user profiling for unpriv";
+ default: return "unknown level";
+ }
+}
+
+bool CheckPerfEventLimit() {
+ int limit_level;
+ if (!ReadPerfEventParanoid(&limit_level)) {
+ return false;
+ }
+ if (limit_level <= 1) {
+ return true;
+ }
+#if defined(__ANDROID__)
+ // Try to enable perf_event_paranoid by setprop security.perf_harden=0.
+ if (__system_property_set("security.perf_harden", "0") == 0) {
+ sleep(1);
+ if (ReadPerfEventParanoid(&limit_level) && limit_level <= 1) {
+ return true;
+ }
+ }
+ LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level
+ << ", " << GetLimitLevelDescription(limit_level) << ".";
+ LOG(WARNING) << "Try using `adb shell setprop security.perf_harden 0` to allow profiling.";
+#else
+ LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level
+ << ", " << GetLimitLevelDescription(limit_level) << ".";
+#endif
+ return true;
+}
diff --git a/simpleperf/environment.h b/simpleperf/environment.h
index cb44ebe3..b8eac610 100644
--- a/simpleperf/environment.h
+++ b/simpleperf/environment.h
@@ -69,4 +69,6 @@ bool GetValidThreadsFromThreadString(const std::string& tid_str, std::set<pid_t>
bool GetExecPath(std::string* exec_path);
+bool CheckPerfEventLimit();
+
#endif // SIMPLE_PERF_ENVIRONMENT_H_