Merge "Simpleperf: add separate cpu_hotplug_test." am: 8460573b13
am: ef3f6278f2

* commit 'ef3f6278f2505ef3ae0e24f236b7a14f9ba2d472':
  Simpleperf: add separate cpu_hotplug_test.
diff --git a/simpleperf/Android.mk b/simpleperf/Android.mk
index ac16655..7335adf 100644
--- a/simpleperf/Android.mk
+++ b/simpleperf/Android.mk
@@ -194,7 +194,6 @@
   cmd_record_test.cpp \
   cmd_report_test.cpp \
   cmd_stat_test.cpp \
-  cpu_offline_test.cpp \
   environment_test.cpp \
   read_elf_test.cpp \
   record_file_test.cpp \
@@ -248,4 +247,37 @@
 include $(BUILD_HOST_NATIVE_TEST)
 endif
 
+
+# simpleperf_cpu_hotplug_test
+# =========================================================
+simpleperf_cpu_hotplug_test_src_files := \
+  gtest_main.cpp \
+  cpu_hotplug_test.cpp \
+
+# simpleperf_cpu_hotplug_test target
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_target)
+LOCAL_SRC_FILES := $(simpleperf_cpu_hotplug_test_src_files)
+LOCAL_WHOLE_STATIC_LIBRARIES := libsimpleperf
+LOCAL_SHARED_LIBRARIES := $(simpleperf_shared_libraries_target)
+LOCAL_MULTILIB := first
+LOCAL_MODULE := simpleperf_cpu_hotplug_test
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_NATIVE_TEST)
+
+# simpleperf_cpu_hotplug_test linux host
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_host_linux)
+LOCAL_SRC_FILES := $(simpleperf_cpu_hotplug_test_src_files)
+LOCAL_WHOLE_STATIC_LIBRARIES := libsimpleperf
+LOCAL_SHARED_LIBRARIES := $(simpleperf_shared_libraries_host_linux)
+LOCAL_MULTILIB := first
+LOCAL_MODULE := simpleperf_cpu_hotplug_test
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_HOST_NATIVE_TEST)
+endif
+
 include $(call first-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 5431041..a6ca9ff 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -55,6 +55,9 @@
   signaled = true;
 }
 
+// Used in cpu-hotplug test.
+bool system_wide_perf_event_open_failed = false;
+
 class RecordCommand : public Command {
  public:
   RecordCommand()
@@ -212,6 +215,7 @@
   //    for perf_event_files.
   if (system_wide_collection_) {
     if (!event_selection_set_.OpenEventFilesForCpus(cpus_)) {
+      system_wide_perf_event_open_failed = true;
       return false;
     }
   } else {
diff --git a/simpleperf/cpu_offline_test.cpp b/simpleperf/cpu_hotplug_test.cpp
similarity index 84%
rename from simpleperf/cpu_offline_test.cpp
rename to simpleperf/cpu_hotplug_test.cpp
index 311767d..68d4ea7 100644
--- a/simpleperf/cpu_offline_test.cpp
+++ b/simpleperf/cpu_hotplug_test.cpp
@@ -139,16 +139,11 @@
 };
 
 static void CpuToggleThread(CpuToggleThreadArg* arg) {
-  // Wait until a record command is running.
-  sleep(1);
   while (!arg->end_flag) {
-    SetCpuOnline(arg->toggle_cpu, false);
-    sleep(1);
-    if (arg->end_flag) {
-      break;
-    }
     SetCpuOnline(arg->toggle_cpu, true);
     sleep(1);
+    SetCpuOnline(arg->toggle_cpu, false);
+    sleep(1);
   }
 }
 
@@ -159,7 +154,12 @@
     std::string cpu_str = android::base::StringPrintf("%d", record_cpu);
     std::string record_duration_str = android::base::StringPrintf("%d", record_duration_in_second);
     bool ret = RecordCmd()->Run({"-a", "--cpu", cpu_str, "sleep", record_duration_str});
-    exit(ret ? 0 : 1);
+    extern bool system_wide_perf_event_open_failed;
+    // It is not an error if perf_event_open failed because of cpu-hotplug.
+    if (!ret && !system_wide_perf_event_open_failed) {
+      exit(1);
+    }
+    exit(0);
   }
   int timeout = record_duration_in_second + 10;
   auto end_time = std::chrono::steady_clock::now() + std::chrono::seconds(timeout);
@@ -192,22 +192,32 @@
     GTEST_LOG_(INFO) << "This test does nothing, because there is only one cpu in the system.";
     return;
   }
-
-  const size_t TEST_ITERATION_COUNT = 20u;
-  const int TEST_DURATION_IN_SECOND = 9;
-  for (size_t i = 0; i < TEST_ITERATION_COUNT; ++i) {
-    int test_cpu = GetCpuCount() - 1;
-    SetCpuOnline(test_cpu, true);
-    CpuToggleThreadArg cpu_toggle_arg;
-    cpu_toggle_arg.toggle_cpu = test_cpu;
-    cpu_toggle_arg.end_flag = false;
-    std::thread cpu_toggle_thread(CpuToggleThread, &cpu_toggle_arg);
-
-    ASSERT_TRUE(RecordInChildProcess(test_cpu, TEST_DURATION_IN_SECOND));
-    cpu_toggle_arg.end_flag = true;
-    cpu_toggle_thread.join();
-    GTEST_LOG_(INFO) << "Finish test iteration " << (i + 1) << " successfully.";
+  for (int i = 1; i < GetCpuCount(); ++i) {
+    if (!IsCpuOnline(i)) {
+      SetCpuOnline(i, true);
+    }
   }
+  // Start cpu hotplugger.
+  int test_cpu = GetCpuCount() - 1;
+  CpuToggleThreadArg cpu_toggle_arg;
+  cpu_toggle_arg.toggle_cpu = test_cpu;
+  cpu_toggle_arg.end_flag = false;
+  std::thread cpu_toggle_thread(CpuToggleThread, &cpu_toggle_arg);
+
+  const std::chrono::hours test_duration(10);  // Test for 10 hours.
+  const double RECORD_DURATION_IN_SEC = 2.9;
+  const double SLEEP_DURATION_IN_SEC = 1.3;
+
+  auto end_time = std::chrono::steady_clock::now() + test_duration;
+  size_t iterations = 0;
+  while (std::chrono::steady_clock::now() < end_time) {
+    iterations++;
+    GTEST_LOG_(INFO) << "Test for " << iterations << " times.";
+    ASSERT_TRUE(RecordInChildProcess(test_cpu, RECORD_DURATION_IN_SEC));
+    usleep(static_cast<useconds_t>(SLEEP_DURATION_IN_SEC * 1e6));
+  }
+  cpu_toggle_arg.end_flag = true;
+  cpu_toggle_thread.join();
 }
 
 static std::unique_ptr<EventFd> OpenHardwareEventOnCpu(int cpu) {