summaryrefslogtreecommitdiff
path: root/simpleperf/cmd_stat.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/cmd_stat.cpp')
-rw-r--r--simpleperf/cmd_stat.cpp194
1 files changed, 43 insertions, 151 deletions
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index 06f45187..31ab2a39 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -24,7 +24,6 @@
#include <chrono>
#include <set>
#include <string>
-#include <string_view>
#include <vector>
#include <android-base/file.h>
@@ -94,16 +93,6 @@ 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") {
@@ -127,49 +116,24 @@ struct CounterSummary {
}
}
}
-};
-static const std::unordered_map<std::string_view, std::pair<std::string_view, std::string_view>>
- COMMON_EVENT_RATE_MAP = {
- {"cache-misses", {"cache-references", "miss rate"}},
- {"branch-misses", {"branch-instructions", "miss rate"}},
-};
-
-static const std::unordered_map<std::string_view, std::pair<std::string_view, std::string_view>>
- ARM_EVENT_RATE_MAP = {
- // Refer to "D6.10.5 Meaningful ratios between common microarchitectural events" in ARMv8
- // specification.
- {"raw-l1i-cache-refill", {"raw-l1i-cache", "level 1 instruction cache refill rate"}},
- {"raw-l1i-tlb-refill", {"raw-l1i-tlb", "level 1 instruction TLB refill rate"}},
- {"raw-l1d-cache-refill", {"raw-l1d-cache", "level 1 data or unified cache refill rate"}},
- {"raw-l1d-tlb-refill", {"raw-l1d-tlb", "level 1 data or unified TLB refill rate"}},
- {"raw-l2d-cache-refill", {"raw-l2d-cache", "level 2 data or unified cache refill rate"}},
- {"raw-l2i-cache-refill", {"raw-l2i-cache", "level 2 instruction cache refill rate"}},
- {"raw-l3d-cache-refill", {"raw-l3d-cache", "level 3 data or unified cache refill rate"}},
- {"raw-l2d-tlb-refill", {"raw-l2d-tlb", "level 2 data or unified TLB refill rate"}},
- {"raw-l2i-tlb-refill", {"raw-l2i-tlb", "level 2 instruction TLB refill rate"}},
- {"raw-bus-access", {"raw-bus-cycles", "bus accesses per cycle"}},
- {"raw-ll-cache-miss", {"raw-ll-cache", "last level data or unified cache refill rate"}},
- {"raw-dtlb-walk", {"raw-l1d-tlb", "data TLB miss rate"}},
- {"raw-itlb-walk", {"raw-l1i-tlb", "instruction TLB miss rate"}},
- {"raw-ll-cache-miss-rd", {"raw-ll-cache-rd", "memory read operation miss rate"}},
- {"raw-remote-access-rd",
- {"raw-remote-access", "read accesses to another socket in a multi-socket system"}},
- // Refer to "Table K3-2 Relationship between REFILL events and associated access events" in
- // ARMv8 specification.
- {"raw-l1d-cache-refill-rd", {"raw-l1d-cache-rd", "level 1 cache refill rate, read"}},
- {"raw-l1d-cache-refill-wr", {"raw-l1d-cache-wr", "level 1 cache refill rate, write"}},
- {"raw-l1d-tlb-refill-rd", {"raw-l1d-tlb-rd", "level 1 TLB refill rate, read"}},
- {"raw-l1d-tlb-refill-wr", {"raw-l1d-tlb-wr", "level 1 TLB refill rate, write"}},
- {"raw-l2d-cache-refill-rd", {"raw-l2d-cache-rd", "level 2 data cache refill rate, read"}},
- {"raw-l2d-cache-refill-wr", {"raw-l2d-cache-wr", "level 2 data cache refill rate, write"}},
- {"raw-l2d-tlb-refill-rd", {"raw-l2d-tlb-rd", "level 2 data TLB refill rate, read"}},
+ 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);
+ }
};
class CounterSummaries {
public:
explicit CounterSummaries(bool csv) : csv_(csv) {}
- std::vector<CounterSummary>& Summaries() { return summaries_; }
+ void AddSummary(const CounterSummary& summary) {
+ summaries_.push_back(summary);
+ }
const CounterSummary* FindSummary(const std::string& type_name,
const std::string& modifier) {
@@ -193,8 +157,9 @@ class CounterSummaries {
const CounterSummary* other = FindSummary(s.type_name, "k");
if (other != nullptr && other->IsMonitoredAtTheSameTime(s)) {
if (FindSummary(s.type_name, "") == nullptr) {
- Summaries().emplace_back(s.type_name, "", s.group_id, s.count + other->count, s.scale,
- true, csv_);
+ AddSummary(CounterSummary(s.type_name, "", s.group_id,
+ s.count + other->count, s.scale, true,
+ csv_));
}
}
}
@@ -266,9 +231,31 @@ class CounterSummaries {
sap_mid);
}
}
- std::string rate_comment = GetRateComment(s, sap_mid);
- if (!rate_comment.empty()) {
- return rate_comment;
+ if (android::base::EndsWith(s.type_name, "-misses")) {
+ std::string other_name;
+ if (s.type_name == "cache-misses") {
+ other_name = "cache-references";
+ } else if (s.type_name == "branch-misses") {
+ other_name = "branch-instructions";
+ } else {
+ other_name =
+ s.type_name.substr(0, s.type_name.size() - strlen("-misses")) + "s";
+ }
+ const CounterSummary* other = FindSummary(other_name, s.modifier);
+ if (other != nullptr && other->IsMonitoredAtTheSameTime(s) &&
+ other->count != 0) {
+ double miss_rate = static_cast<double>(s.count) / other->count;
+ return android::base::StringPrintf("%lf%%%cmiss rate", miss_rate * 100,
+ sap_mid);
+ }
+ }
+ if (android::base::EndsWith(s.type_name, "-refill")) {
+ std::string other_name = s.type_name.substr(0, s.type_name.size() - strlen("-refill"));
+ const CounterSummary* other = FindSummary(other_name, s.modifier);
+ if (other != nullptr && other->IsMonitoredAtTheSameTime(s) && other->count != 0) {
+ double miss_rate = static_cast<double>(s.count) / other->count;
+ return android::base::StringPrintf("%f%%%cmiss rate", miss_rate * 100, sap_mid);
+ }
}
double running_time_in_sec;
if (!FindRunningTimeForSummary(s, &running_time_in_sec)) {
@@ -287,34 +274,6 @@ class CounterSummaries {
return android::base::StringPrintf("%.3lf%c/sec", rate, sap_mid);
}
- std::string GetRateComment(const CounterSummary& s, char sep) {
- std::string_view miss_event_name = s.type_name;
- std::string event_name;
- std::string rate_desc;
- if (auto it = COMMON_EVENT_RATE_MAP.find(miss_event_name); it != COMMON_EVENT_RATE_MAP.end()) {
- event_name = it->second.first;
- rate_desc = it->second.second;
- }
- if (event_name.empty() && (GetBuildArch() == ARCH_ARM || GetBuildArch() == ARCH_ARM64)) {
- if (auto it = ARM_EVENT_RATE_MAP.find(miss_event_name); it != ARM_EVENT_RATE_MAP.end()) {
- event_name = it->second.first;
- rate_desc = it->second.second;
- }
- }
- if (event_name.empty() && android::base::ConsumeSuffix(&miss_event_name, "-misses")) {
- event_name = std::string(miss_event_name) + "s";
- rate_desc = "miss rate";
- }
- if (!event_name.empty()) {
- const CounterSummary* other = FindSummary(event_name, s.modifier);
- if (other != nullptr && other->IsMonitoredAtTheSameTime(s) && other->count != 0) {
- double miss_rate = static_cast<double>(s.count) / other->count;
- return android::base::StringPrintf("%f%%%c%s", miss_rate * 100, sep, rate_desc.c_str());
- }
- }
- return "";
- }
-
bool FindRunningTimeForSummary(const CounterSummary& summary, double* running_time_in_sec) {
for (auto& s : summaries_) {
if ((s.type_name == "task-clock" || s.type_name == "cpu-clock") &&
@@ -331,48 +290,6 @@ 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()
@@ -417,14 +334,6 @@ 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.
@@ -473,7 +382,6 @@ 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) {
@@ -492,12 +400,6 @@ 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;
@@ -719,10 +621,6 @@ 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 {
@@ -802,7 +700,6 @@ 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];
@@ -827,9 +724,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.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.AddSummary(
+ CounterSummary(counters_info.event_name, counters_info.event_modifier,
+ counters_info.group_id, sum.value, scale, false, csv_));
}
summaries.AutoGenerateSummaries();
summaries.GenerateComments(duration_in_sec);
@@ -839,11 +736,6 @@ 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;
}