summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2019-08-20 17:18:49 -0700
committerandroid-build-merger <android-build-merger@google.com>2019-08-20 17:18:49 -0700
commit5507a26a7c8dd819b201bbb0d516084eb05c9247 (patch)
treec6bd93aeb365e59354f88f54ca4a44d96285216a
parentb6d4993018c56422871744c579dedca45fdf3ff8 (diff)
parent5ff5b91fdc0b07bebaaecd76e47d5c57571ca5ad (diff)
downloadextras-5507a26a7c8dd819b201bbb0d516084eb05c9247.tar.gz
Merge "simpleperf: add --use-devfreq-counters option."
am: 5ff5b91fdc Change-Id: I6f741f3981256dafb9713684bda6a3d8ec2f6182
-rw-r--r--simpleperf/cmd_stat.cpp102
-rw-r--r--simpleperf/cmd_stat_test.cpp8
2 files changed, 91 insertions, 19 deletions
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index bc047cb8..06f45187 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -94,6 +94,16 @@ struct CounterSummary {
return type_name + ":" + modifier;
}
+ bool IsMonitoredAllTheTime() const {
+ // If an event runs all the time it is enabled (by not sharing hardware
+ // counters with other events), the scale of its summary is usually within
+ // [1, 1 + 1e-5]. By setting SCALE_ERROR_LIMIT to 1e-5, We can identify
+ // events monitored all the time in most cases while keeping the report
+ // error rate <= 1e-5.
+ constexpr double SCALE_ERROR_LIMIT = 1e-5;
+ return (fabs(scale - 1.0) < SCALE_ERROR_LIMIT);
+ }
+
private:
std::string ReadableCountValue(bool csv) {
if (type_name == "cpu-clock" || type_name == "task-clock") {
@@ -117,16 +127,6 @@ struct CounterSummary {
}
}
}
-
- bool IsMonitoredAllTheTime() const {
- // If an event runs all the time it is enabled (by not sharing hardware
- // counters with other events), the scale of its summary is usually within
- // [1, 1 + 1e-5]. By setting SCALE_ERROR_LIMIT to 1e-5, We can identify
- // events monitored all the time in most cases while keeping the report
- // error rate <= 1e-5.
- constexpr double SCALE_ERROR_LIMIT = 1e-5;
- return (fabs(scale - 1.0) < SCALE_ERROR_LIMIT);
- }
};
static const std::unordered_map<std::string_view, std::pair<std::string_view, std::string_view>>
@@ -169,9 +169,7 @@ static const std::unordered_map<std::string_view, std::pair<std::string_view, st
class CounterSummaries {
public:
explicit CounterSummaries(bool csv) : csv_(csv) {}
- void AddSummary(const CounterSummary& summary) {
- summaries_.push_back(summary);
- }
+ std::vector<CounterSummary>& Summaries() { return summaries_; }
const CounterSummary* FindSummary(const std::string& type_name,
const std::string& modifier) {
@@ -195,9 +193,8 @@ class CounterSummaries {
const CounterSummary* other = FindSummary(s.type_name, "k");
if (other != nullptr && other->IsMonitoredAtTheSameTime(s)) {
if (FindSummary(s.type_name, "") == nullptr) {
- AddSummary(CounterSummary(s.type_name, "", s.group_id,
- s.count + other->count, s.scale, true,
- csv_));
+ Summaries().emplace_back(s.type_name, "", s.group_id, s.count + other->count, s.scale,
+ true, csv_);
}
}
}
@@ -334,6 +331,48 @@ class CounterSummaries {
bool csv_;
};
+// devfreq may use performance counters to calculate memory latency (as in
+// drivers/devfreq/arm-memlat-mon.c). Hopefully we can get more available counters by asking devfreq
+// to not use the memory latency governor temporarily.
+class DevfreqCounters {
+ public:
+ bool Use() {
+ if (!IsRoot()) {
+ LOG(ERROR) << "--use-devfreq-counters needs root permission to set devfreq governors";
+ return false;
+ }
+ std::string devfreq_dir = "/sys/class/devfreq/";
+ for (auto& name : GetSubDirs(devfreq_dir)) {
+ std::string governor_path = devfreq_dir + name + "/governor";
+ if (IsRegularFile(governor_path)) {
+ std::string governor;
+ if (!android::base::ReadFileToString(governor_path, &governor)) {
+ LOG(ERROR) << "failed to read " << governor_path;
+ return false;
+ }
+ governor = android::base::Trim(governor);
+ if (governor == "mem_latency") {
+ if (!android::base::WriteStringToFile("performance", governor_path)) {
+ PLOG(ERROR) << "failed to write " << governor_path;
+ return false;
+ }
+ mem_latency_governor_paths_.emplace_back(std::move(governor_path));
+ }
+ }
+ }
+ return true;
+ }
+
+ ~DevfreqCounters() {
+ for (auto& path : mem_latency_governor_paths_) {
+ android::base::WriteStringToFile("mem_latency", path);
+ }
+ }
+
+ private:
+ std::vector<std::string> mem_latency_governor_paths_;
+};
+
class StatCommand : public Command {
public:
StatCommand()
@@ -378,6 +417,14 @@ class StatCommand : public Command {
"-o output_filename Write report to output_filename instead of standard output.\n"
"-p pid1,pid2,... Stat events on existing processes. Mutually exclusive with -a.\n"
"-t tid1,tid2,... Stat events on existing threads. Mutually exclusive with -a.\n"
+#if defined(__ANDROID__)
+"--use-devfreq-counters On devices with Qualcomm SOCs, some hardware counters may be used\n"
+" to monitor memory latency (in drivers/devfreq/arm-memlat-mon.c),\n"
+" making fewer counters available to users. This option asks devfreq\n"
+" to temporarily release counters by replacing memory-latency governor\n"
+" with performance governor. It affects memory latency during profiling,\n"
+" and may cause wedged power if simpleperf is killed in between.\n"
+#endif
"--verbose Show result in verbose mode.\n"
#if 0
// Below options are only used internally and shouldn't be visible to the public.
@@ -426,6 +473,7 @@ class StatCommand : public Command {
std::string app_package_name_;
bool in_app_context_;
android::base::unique_fd stop_signal_fd_;
+ bool use_devfreq_counters_ = false;
};
bool StatCommand::Run(const std::vector<std::string>& args) {
@@ -444,6 +492,12 @@ bool StatCommand::Run(const std::vector<std::string>& args) {
output_filename_, !event_selection_set_.GetTracepointEvents().empty());
}
}
+ DevfreqCounters devfreq_counters;
+ if (use_devfreq_counters_) {
+ if (!devfreq_counters.Use()) {
+ return false;
+ }
+ }
if (event_selection_set_.empty()) {
if (!AddDefaultMeasuredEventTypes()) {
return false;
@@ -665,6 +719,10 @@ bool StatCommand::ParseOptions(const std::vector<std::string>& args,
if (!SetTracepointEventsFilePath(args[i])) {
return false;
}
+#if defined(__ANDROID__)
+ } else if (args[i] == "--use-devfreq-counters") {
+ use_devfreq_counters_ = true;
+#endif
} else if (args[i] == "--verbose") {
verbose_mode_ = true;
} else {
@@ -744,6 +802,7 @@ bool StatCommand::ShowCounters(const std::vector<CountersInfo>& counters,
}
}
+ bool counters_always_available = true;
CounterSummaries summaries(csv_);
for (size_t i = 0; i < counters.size(); ++i) {
const CountersInfo& counters_info = counters[i];
@@ -768,9 +827,9 @@ bool StatCommand::ShowCounters(const std::vector<CountersInfo>& counters,
if (sum.time_running < sum.time_enabled && sum.time_running != 0) {
scale = static_cast<double>(sum.time_enabled) / sum.time_running;
}
- summaries.AddSummary(
- CounterSummary(counters_info.event_name, counters_info.event_modifier,
- counters_info.group_id, sum.value, scale, false, csv_));
+ summaries.Summaries().emplace_back(counters_info.event_name, counters_info.event_modifier,
+ counters_info.group_id, sum.value, scale, false, csv_);
+ counters_always_available &= summaries.Summaries().back().IsMonitoredAllTheTime();
}
summaries.AutoGenerateSummaries();
summaries.GenerateComments(duration_in_sec);
@@ -780,6 +839,11 @@ bool StatCommand::ShowCounters(const std::vector<CountersInfo>& counters,
fprintf(fp, "Total test time,%lf,seconds,\n", duration_in_sec);
else
fprintf(fp, "\nTotal test time: %lf seconds.\n", duration_in_sec);
+
+ if (!counters_always_available) {
+ LOG(WARNING) << "Some hardware counters are not always available (scale < 100%). "
+ << "Try --use-devfreq-counters if on a rooted device.";
+ }
return true;
}
diff --git a/simpleperf/cmd_stat_test.cpp b/simpleperf/cmd_stat_test.cpp
index ecc7404e..3668cb91 100644
--- a/simpleperf/cmd_stat_test.cpp
+++ b/simpleperf/cmd_stat_test.cpp
@@ -303,3 +303,11 @@ TEST(stat_cmd, app_option_for_profileable_app) {
TEST_REQUIRE_APPS();
TestStatingApps("com.android.simpleperf.profileable");
}
+
+TEST(stat_cmd, use_devfreq_counters_option) {
+#if defined(__ANDROID__)
+ TEST_IN_ROOT(StatCmd()->Run({"--use-devfreq-counters", "sleep", "0.1"}));
+#else
+ GTEST_LOG_(INFO) << "This test tests an option only available on Android.";
+#endif
+}