Merge "Snap for 4892329 from 65e3f75117faf1c57f322ec9e3f1cb291347a585 to nougat-mr1-cts-release" into nougat-mr1-cts-release
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index 8780cfc..21eb884 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -16,10 +16,12 @@
 
 #include <gtest/gtest.h>
 
+#include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/test_utils.h>
 
 #include <memory>
+#include <regex>
 
 #include "command.h"
 #include "environment.h"
@@ -49,16 +51,19 @@
 }
 
 TEST(record_cmd, no_options) {
+  TEST_REQUIRE_HW_COUNTER();
   ASSERT_TRUE(RunRecordCmd({}));
 }
 
 TEST(record_cmd, system_wide_option) {
+  TEST_REQUIRE_HW_COUNTER();
   if (IsRoot()) {
     ASSERT_TRUE(RunRecordCmd({"-a"}));
   }
 }
 
 TEST(record_cmd, sample_period_option) {
+  TEST_REQUIRE_HW_COUNTER();
   ASSERT_TRUE(RunRecordCmd({"-c", "100000"}));
 }
 
@@ -67,16 +72,19 @@
 }
 
 TEST(record_cmd, freq_option) {
+  TEST_REQUIRE_HW_COUNTER();
   ASSERT_TRUE(RunRecordCmd({"-f", "99"}));
   ASSERT_TRUE(RunRecordCmd({"-F", "99"}));
 }
 
 TEST(record_cmd, output_file_option) {
+  TEST_REQUIRE_HW_COUNTER();
   TemporaryFile tmpfile;
   ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, dump_kernel_mmap) {
+  TEST_REQUIRE_HW_COUNTER();
   TemporaryFile tmpfile;
   ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
@@ -97,6 +105,7 @@
 }
 
 TEST(record_cmd, dump_build_id_feature) {
+  TEST_REQUIRE_HW_COUNTER();
   TemporaryFile tmpfile;
   ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
@@ -113,6 +122,7 @@
 }
 
 TEST(record_cmd, branch_sampling) {
+  TEST_REQUIRE_HW_COUNTER();
   if (IsBranchSamplingSupported()) {
     ASSERT_TRUE(RunRecordCmd({"-b"}));
     ASSERT_TRUE(RunRecordCmd({"-j", "any,any_call,any_ret,ind_call"}));
@@ -126,14 +136,34 @@
 }
 
 TEST(record_cmd, event_modifier) {
+  TEST_REQUIRE_HW_COUNTER();
   ASSERT_TRUE(RunRecordCmd({"-e", "cpu-cycles:u"}));
 }
 
 TEST(record_cmd, fp_callchain_sampling) {
+  TEST_REQUIRE_HW_COUNTER();
   ASSERT_TRUE(RunRecordCmd({"--call-graph", "fp"}));
 }
 
+bool HasHardwareCounter() {
+  static int has_hw_counter = -1;
+  if (has_hw_counter == -1) {
+    has_hw_counter = 1;
+#if defined(__arm__)
+    std::string cpu_info;
+    if (android::base::ReadFileToString("/proc/cpuinfo", &cpu_info)) {
+      std::string hardware = GetHardwareFromCpuInfo(cpu_info);
+      if (std::regex_search(hardware, std::regex(R"(i\.MX6.*Quad)"))) {
+        has_hw_counter = 0;
+      }
+    }
+#endif
+  }
+  return has_hw_counter == 1;
+}
+
 TEST(record_cmd, dwarf_callchain_sampling) {
+  TEST_REQUIRE_HW_COUNTER();
   if (IsDwarfCallChainSamplingSupported()) {
     ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf"}));
     ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf,16384"}));
@@ -145,6 +175,7 @@
 }
 
 TEST(record_cmd, no_unwind_option) {
+  TEST_REQUIRE_HW_COUNTER();
   if (IsDwarfCallChainSamplingSupported()) {
     ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf", "--no-unwind"}));
   } else {
@@ -155,6 +186,7 @@
 }
 
 TEST(record_cmd, post_unwind_option) {
+  TEST_REQUIRE_HW_COUNTER();
   if (IsDwarfCallChainSamplingSupported()) {
     ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf", "--post-unwind"}));
   } else {
@@ -167,6 +199,7 @@
 }
 
 TEST(record_cmd, existing_processes) {
+  TEST_REQUIRE_HW_COUNTER();
   std::vector<std::unique_ptr<Workload>> workloads;
   CreateProcesses(2, &workloads);
   std::string pid_list =
@@ -175,6 +208,7 @@
 }
 
 TEST(record_cmd, existing_threads) {
+  TEST_REQUIRE_HW_COUNTER();
   std::vector<std::unique_ptr<Workload>> workloads;
   CreateProcesses(2, &workloads);
   // Process id can also be used as thread id in linux.
@@ -185,15 +219,18 @@
 }
 
 TEST(record_cmd, no_monitored_threads) {
+  TEST_REQUIRE_HW_COUNTER();
   ASSERT_FALSE(RecordCmd()->Run({""}));
 }
 
 TEST(record_cmd, more_than_one_event_types) {
+  TEST_REQUIRE_HW_COUNTER();
   ASSERT_TRUE(RunRecordCmd({"-e", "cpu-cycles,cpu-clock"}));
   ASSERT_TRUE(RunRecordCmd({"-e", "cpu-cycles", "-e", "cpu-clock"}));
 }
 
 TEST(record_cmd, mmap_page_option) {
+  TEST_REQUIRE_HW_COUNTER();
   ASSERT_TRUE(RunRecordCmd({"-m", "1"}));
   ASSERT_FALSE(RunRecordCmd({"-m", "0"}));
   ASSERT_FALSE(RunRecordCmd({"-m", "7"}));
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index bcf8b6e..a98b75f 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -268,6 +268,7 @@
 }
 
 TEST_F(ReportCommandTest, dwarf_callgraph) {
+  TEST_REQUIRE_HW_COUNTER();
   if (IsDwarfCallChainSamplingSupported()) {
     TemporaryFile tmp_file;
     ASSERT_TRUE(RecordCmd()->Run({"-g", "-o", tmp_file.path, "sleep", SLEEP_SEC}));
diff --git a/simpleperf/cmd_stat_test.cpp b/simpleperf/cmd_stat_test.cpp
index 8786d8d..6bf57dd 100644
--- a/simpleperf/cmd_stat_test.cpp
+++ b/simpleperf/cmd_stat_test.cpp
@@ -51,6 +51,7 @@
 }
 
 TEST(stat_cmd, event_modifier) {
+  TEST_REQUIRE_HW_COUNTER();
   ASSERT_TRUE(StatCmd()->Run({"-e", "cpu-cycles:u,cpu-cycles:k", "sleep", "1"}));
 }
 
diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp
index a73aa1c..4266932 100644
--- a/simpleperf/environment.cpp
+++ b/simpleperf/environment.cpp
@@ -491,3 +491,16 @@
   }
   return true;
 }
+
+std::string GetHardwareFromCpuInfo(const std::string& cpu_info) {
+  for (auto& line : android::base::Split(cpu_info, "\n")) {
+    size_t pos = line.find(':');
+    if (pos != std::string::npos) {
+      std::string key = android::base::Trim(line.substr(0, pos));
+      if (key == "Hardware") {
+        return android::base::Trim(line.substr(pos + 1));
+      }
+    }
+  }
+  return "";
+}
diff --git a/simpleperf/environment.h b/simpleperf/environment.h
index 0b565ea..241619e 100644
--- a/simpleperf/environment.h
+++ b/simpleperf/environment.h
@@ -82,4 +82,6 @@
 bool CheckPerfEventLimit();
 bool GetMaxSampleFrequency(uint64_t* max_sample_freq);
 
+std::string GetHardwareFromCpuInfo(const std::string& cpu_info);
+
 #endif  // SIMPLE_PERF_ENVIRONMENT_H_
diff --git a/simpleperf/environment_test.cpp b/simpleperf/environment_test.cpp
index 6bca7b8..ea59ee5 100644
--- a/simpleperf/environment_test.cpp
+++ b/simpleperf/environment_test.cpp
@@ -72,3 +72,10 @@
   ASSERT_FALSE(ProcessKernelSymbols(
       tempfile.path, std::bind(&KernelSymbolsMatch, std::placeholders::_1, expected_symbol)));
 }
+
+TEST(environment, GetHardwareFromCpuInfo) {
+  std::string cpu_info = "CPU revision : 10\n\n"
+      "Hardware : Symbol i.MX6 Freeport_Plat Quad/DualLite (Device Tree)\n";
+  ASSERT_EQ("Symbol i.MX6 Freeport_Plat Quad/DualLite (Device Tree)",
+            GetHardwareFromCpuInfo(cpu_info));
+}
diff --git a/simpleperf/test_util.h b/simpleperf/test_util.h
index cfbe493..64d3922 100644
--- a/simpleperf/test_util.h
+++ b/simpleperf/test_util.h
@@ -26,3 +26,12 @@
 
 void ParseSymbol(const ElfFileSymbol& symbol, std::map<std::string, ElfFileSymbol>* symbols);
 void CheckElfFileSymbols(const std::map<std::string, ElfFileSymbol>& symbols);
+
+bool HasHardwareCounter();
+#define TEST_REQUIRE_HW_COUNTER() \
+  do { \
+    if (!HasHardwareCounter()) { \
+      GTEST_LOG_(INFO) << "Skip this test as the machine doesn't have hardware PMU counters."; \
+      return; \
+    } \
+  } while (0)