summaryrefslogtreecommitdiff
path: root/simpleperf
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2016-08-24 23:36:28 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-08-24 23:36:28 +0000
commita903cc9b9ce63b281e42a9c019f8d9873f00877f (patch)
tree2f10f63b401719b5fcc390529ba7be826aeb8cee /simpleperf
parent4d269c7593dec6758580e91ad1e71cf221d81aa9 (diff)
parent08e7b325f13aba02ce3a79251c32dfd2dd0db482 (diff)
downloadextras-a903cc9b9ce63b281e42a9c019f8d9873f00877f.tar.gz
Merge "simpleperf: improve cpu_hotplug_test."
Diffstat (limited to 'simpleperf')
-rw-r--r--simpleperf/cpu_hotplug_test.cpp157
1 files changed, 147 insertions, 10 deletions
diff --git a/simpleperf/cpu_hotplug_test.cpp b/simpleperf/cpu_hotplug_test.cpp
index 56962b16..166ec3a7 100644
--- a/simpleperf/cpu_hotplug_test.cpp
+++ b/simpleperf/cpu_hotplug_test.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <unistd.h>
#if defined(__BIONIC__)
#include <sys/system_properties.h>
@@ -36,6 +37,9 @@
#include "event_type.h"
#include "utils.h"
+static auto test_duration_for_long_tests = std::chrono::seconds(120);
+static auto cpu_hotplug_interval = std::chrono::microseconds(1000);
+
#if defined(__BIONIC__)
class ScopedMpdecisionKiller {
public:
@@ -66,14 +70,14 @@ class ScopedMpdecisionKiller {
int ret = __system_property_set("ctl.stop", "mpdecision");
CHECK_EQ(0, ret);
// Need to wait until mpdecision is actually stopped.
- usleep(500000);
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
CHECK(!IsMpdecisionRunning());
}
void EnableMpdecision() {
int ret = __system_property_set("ctl.start", "mpdecision");
CHECK_EQ(0, ret);
- usleep(500000);
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
CHECK(IsMpdecisionRunning());
}
@@ -139,7 +143,7 @@ static bool SetCpuOnline(int cpu, bool online) {
LOG(ERROR) << "setting cpu " << cpu << (online ? " online" : " offline") << " seems not to take effect";
return false;
}
- usleep(1000);
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
return true;
}
@@ -199,7 +203,9 @@ struct CpuToggleThreadArg {
static void CpuToggleThread(CpuToggleThreadArg* arg) {
while (!arg->end_flag) {
CHECK(SetCpuOnline(arg->toggle_cpu, true));
+ std::this_thread::sleep_for(cpu_hotplug_interval);
CHECK(SetCpuOnline(arg->toggle_cpu, false));
+ std::this_thread::sleep_for(cpu_hotplug_interval);
}
}
@@ -227,11 +233,21 @@ TEST(cpu_offline, offline_while_recording) {
attr.disabled = 0;
attr.enable_on_exec = 0;
- const std::chrono::minutes test_duration(2); // Test for 2 minutes.
- auto end_time = std::chrono::steady_clock::now() + test_duration;
+ auto start_time = std::chrono::steady_clock::now();
+ auto cur_time = start_time;
+ auto end_time = std::chrono::steady_clock::now() + test_duration_for_long_tests;
+ auto report_step = std::chrono::seconds(15);
size_t iterations = 0;
- while (std::chrono::steady_clock::now() < end_time) {
+ while (cur_time < end_time) {
+ if (cur_time + report_step < std::chrono::steady_clock::now()) {
+ // Report test time.
+ auto diff = std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::steady_clock::now() - start_time);
+ GTEST_LOG_(INFO) << "Have Tested " << (diff.count() / 60.0) << " minutes.";
+ cur_time = std::chrono::steady_clock::now();
+ }
+
std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(attr, -1, test_cpu, nullptr, false);
if (event_fd == nullptr) {
// Failed to open because the test_cpu is offline.
@@ -268,18 +284,28 @@ TEST(cpu_offline, offline_while_ioctl_enable) {
attr.disabled = 1;
attr.enable_on_exec = 0;
- const std::chrono::minutes test_duration(2); // Test for 2 minutes.
- auto end_time = std::chrono::steady_clock::now() + test_duration;
+ auto start_time = std::chrono::steady_clock::now();
+ auto cur_time = start_time;
+ auto end_time = std::chrono::steady_clock::now() + test_duration_for_long_tests;
+ auto report_step = std::chrono::seconds(15);
size_t iterations = 0;
- while (std::chrono::steady_clock::now() < end_time) {
+ while (cur_time < end_time) {
+ if (cur_time + report_step < std::chrono::steady_clock::now()) {
+ // Report test time.
+ auto diff = std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::steady_clock::now() - start_time);
+ GTEST_LOG_(INFO) << "Have Tested " << (diff.count() / 60.0) << " minutes.";
+ cur_time = std::chrono::steady_clock::now();
+
+ }
std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(attr, -1, test_cpu, nullptr, false);
if (event_fd == nullptr) {
// Failed to open because the test_cpu is offline.
continue;
}
// Wait a little for the event to be installed on test_cpu's perf context.
- usleep(1000);
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
ASSERT_TRUE(event_fd->EnableEvent());
iterations++;
GTEST_LOG_(INFO) << "Test offline while ioctl(PERF_EVENT_IOC_ENABLE) for " << iterations << " times.";
@@ -288,6 +314,91 @@ TEST(cpu_offline, offline_while_ioctl_enable) {
cpu_toggle_thread.join();
}
+struct CpuSpinThreadArg {
+ int spin_cpu;
+ std::atomic<pid_t> tid;
+ std::atomic<bool> end_flag;
+};
+
+static void CpuSpinThread(CpuSpinThreadArg* arg) {
+ arg->tid = syscall(__NR_gettid);
+ while (!arg->end_flag) {
+ cpu_set_t mask;
+ CPU_ZERO(&mask);
+ CPU_SET(arg->spin_cpu, &mask);
+ // If toggle_cpu is offline, setaffinity fails. So call it in a loop to
+ // make sure current thread mostly runs on toggle_cpu.
+ sched_setaffinity(arg->tid, sizeof(mask), &mask);
+ }
+}
+
+// http://b/28086229.
+TEST(cpu_offline, offline_while_user_process_profiling) {
+ ScopedMpdecisionKiller scoped_mpdecision_killer;
+ CpuOnlineRestorer cpuonline_restorer;
+ // Start cpu hotpluger.
+ int test_cpu;
+ if (!FindAHotpluggableCpu(&test_cpu)) {
+ return;
+ }
+ 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);
+
+ // Start cpu spinner.
+ CpuSpinThreadArg cpu_spin_arg;
+ cpu_spin_arg.spin_cpu = test_cpu;
+ cpu_spin_arg.tid = 0;
+ cpu_spin_arg.end_flag = false;
+ std::thread cpu_spin_thread(CpuSpinThread, &cpu_spin_arg);
+ while (cpu_spin_arg.tid == 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+
+ std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles");
+ ASSERT_TRUE(event_type_modifier != nullptr);
+ perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
+ // Enable profiling in perf_event_open system call.
+ attr.disabled = 0;
+ attr.enable_on_exec = 0;
+
+ auto start_time = std::chrono::steady_clock::now();
+ auto cur_time = start_time;
+ auto end_time = start_time + test_duration_for_long_tests;
+ auto report_step = std::chrono::seconds(15);
+ size_t iterations = 0;
+
+ while (cur_time < end_time) {
+ if (cur_time + report_step < std::chrono::steady_clock::now()) {
+ auto diff = std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::steady_clock::now() - start_time);
+ GTEST_LOG_(INFO) << "Have Tested " << (diff.count() / 60.0) << " minutes.";
+ cur_time = std::chrono::steady_clock::now();
+ }
+ // Test if the cpu pmu is still usable.
+ ASSERT_TRUE(EventFd::OpenEventFile(attr, 0, -1, nullptr, true) != nullptr);
+
+ std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(attr, cpu_spin_arg.tid,
+ test_cpu, nullptr, false);
+ if (event_fd == nullptr) {
+ // Failed to open because the test_cpu is offline.
+ continue;
+ }
+ // profile for a while.
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ iterations++;
+ GTEST_LOG_(INFO) << "Test offline while user process profiling for " << iterations << " times.";
+ }
+ cpu_toggle_arg.end_flag = true;
+ cpu_toggle_thread.join();
+ cpu_spin_arg.end_flag = true;
+ cpu_spin_thread.join();
+ // Check if the cpu-cycle event is still available on test_cpu.
+ ASSERT_TRUE(SetCpuOnline(test_cpu, true));
+ ASSERT_TRUE(EventFd::OpenEventFile(attr, -1, test_cpu, nullptr, true) != nullptr);
+}
+
// http://b/19863147.
TEST(cpu_offline, offline_while_recording_on_another_cpu) {
ScopedMpdecisionKiller scoped_mpdecision_killer;
@@ -320,6 +431,32 @@ TEST(cpu_offline, offline_while_recording_on_another_cpu) {
}
int main(int argc, char** argv) {
+ for (int i = 1; i < argc; ++i) {
+ if (strcmp(argv[i], "--help") == 0) {
+ printf("--long_test_duration <second> Set test duration for long tests. Default is 120s.\n");
+ printf("--cpu_hotplug_interval <microseconds> Set cpu hotplug interval. Default is 1000us.\n");
+ } else if (strcmp(argv[i], "--long_test_duration") == 0) {
+ if (i + 1 < argc) {
+ int second_count = atoi(argv[i+1]);
+ if (second_count <= 0) {
+ fprintf(stderr, "Invalid arg for --long_test_duration.\n");
+ return 1;
+ }
+ test_duration_for_long_tests = std::chrono::seconds(second_count);
+ i++;
+ }
+ } else if (strcmp(argv[i], "--cpu_hotplug_interval") == 0) {
+ if (i + 1 < argc) {
+ int microsecond_count = atoi(argv[i+1]);
+ if (microsecond_count <= 0) {
+ fprintf(stderr, "Invalid arg for --cpu_hotplug_interval\n");
+ return 1;
+ }
+ cpu_hotplug_interval = std::chrono::microseconds(microsecond_count);
+ i++;
+ }
+ }
+ }
InitLogging(argv, android::base::StderrLogger);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();