summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2016-11-29 15:21:13 -0800
committerYabin Cui <yabinc@google.com>2016-11-29 15:21:13 -0800
commit5be914df7e842a052219a6ef4891ff3208373fc3 (patch)
tree4aa0c8e5b94d2cdd1e4dfa2caa7420cead3239ee
parentc11a58e7013e0f8cc59eb6eb02fe3366e625665a (diff)
downloadextras-5be914df7e842a052219a6ef4891ff3208373fc3.tar.gz
simpleperf: fix tests for dwarf callgraph unwinding.
32-bit simpleperf can't unwind a 64-bit `sleep` process in aarch64 environment. It makes following error in tests: simpleperf is built in arch arm, and can't do stack unwinding for arch arm64 So make the workload be able to start a process running callback function. By profiling that process, we can guarantee that 32-bit simpleperf is profiling a 32-bit process. Also fix a flaky test IOEventLoop.signal. Build 32-bit simpleperf_unit_test on 64-bit devices. Bug: http://b/33167911 Test: run simpleperf_unit_test. Change-Id: I82741dc5d90c73c1890f834d8e2a9188421a3828
-rw-r--r--simpleperf/Android.mk2
-rw-r--r--simpleperf/IOEventLoop_test.cpp7
-rw-r--r--simpleperf/cmd_record_test.cpp23
-rw-r--r--simpleperf/cmd_report_test.cpp5
-rw-r--r--simpleperf/cmd_stat_test.cpp10
-rw-r--r--simpleperf/workload.cpp49
-rw-r--r--simpleperf/workload.h13
7 files changed, 74 insertions, 35 deletions
diff --git a/simpleperf/Android.mk b/simpleperf/Android.mk
index 9addd060..e9939066 100644
--- a/simpleperf/Android.mk
+++ b/simpleperf/Android.mk
@@ -279,7 +279,7 @@ LOCAL_POST_LINK_CMD = \
$($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJCOPY) --add-section .testzipdata=$$TMP_FILE $(linked_module) && \
rm -f $$TMP_FILE
-LOCAL_MULTILIB := first
+LOCAL_MULTILIB := both
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(LLVM_DEVICE_BUILD_MK)
include $(BUILD_NATIVE_TEST)
diff --git a/simpleperf/IOEventLoop_test.cpp b/simpleperf/IOEventLoop_test.cpp
index 90bb4faf..dc7a4dad 100644
--- a/simpleperf/IOEventLoop_test.cpp
+++ b/simpleperf/IOEventLoop_test.cpp
@@ -18,6 +18,7 @@
#include <gtest/gtest.h>
+#include <atomic>
#include <chrono>
#include <thread>
@@ -105,13 +106,15 @@ TEST(IOEventLoop, signal) {
}
return true;
}));
- std::thread thread([]() {
- for (int i = 0; i < 100; ++i) {
+ std::atomic<bool> stop_thread(false);
+ std::thread thread([&]() {
+ while (!stop_thread) {
usleep(1000);
kill(getpid(), SIGINT);
}
});
ASSERT_TRUE(loop.RunLoop());
+ stop_thread = true;
thread.join();
ASSERT_EQ(100, count);
}
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index b863f019..35f330ef 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -141,10 +141,13 @@ TEST(record_cmd, system_wide_fp_callchain_sampling) {
TEST(record_cmd, dwarf_callchain_sampling) {
if (IsDwarfCallChainSamplingSupported()) {
- ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf"}));
- ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf,16384"}));
- ASSERT_FALSE(RunRecordCmd({"--call-graph", "dwarf,65536"}));
- ASSERT_TRUE(RunRecordCmd({"-g"}));
+ std::vector<std::unique_ptr<Workload>> workloads;
+ CreateProcesses(1, &workloads);
+ std::string pid = std::to_string(workloads[0]->GetPid());
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf"}));
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf,16384"}));
+ ASSERT_FALSE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf,65536"}));
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g"}));
} else {
GTEST_LOG_(INFO) << "This test does nothing as dwarf callchain sampling is "
"not supported on this device.";
@@ -172,7 +175,10 @@ TEST(record_cmd, no_unwind_option) {
TEST(record_cmd, post_unwind_option) {
if (IsDwarfCallChainSamplingSupported()) {
- ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf", "--post-unwind"}));
+ std::vector<std::unique_ptr<Workload>> workloads;
+ CreateProcesses(1, &workloads);
+ std::string pid = std::to_string(workloads[0]->GetPid());
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf", "--post-unwind"}));
} else {
GTEST_LOG_(INFO) << "This test does nothing as dwarf callchain sampling is "
"not supported on this device.";
@@ -291,11 +297,14 @@ TEST(record_cmd, dump_symbols) {
CheckDsoSymbolRecords(tmpfile.path, true, &success);
ASSERT_TRUE(success);
if (IsDwarfCallChainSamplingSupported()) {
- ASSERT_TRUE(RunRecordCmd({"-g"}, tmpfile.path));
+ std::vector<std::unique_ptr<Workload>> workloads;
+ CreateProcesses(1, &workloads);
+ std::string pid = std::to_string(workloads[0]->GetPid());
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g"}, tmpfile.path));
bool success;
CheckDsoSymbolRecords(tmpfile.path, false, &success);
ASSERT_TRUE(success);
- ASSERT_TRUE(RunRecordCmd({"-g", "--dump-symbols"}, tmpfile.path));
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g", "--dump-symbols"}, tmpfile.path));
CheckDsoSymbolRecords(tmpfile.path, true, &success);
ASSERT_TRUE(success);
}
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index 98190ee1..f34be5ca 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -446,9 +446,12 @@ static std::unique_ptr<Command> RecordCmd() {
TEST_F(ReportCommandTest, dwarf_callgraph) {
if (IsDwarfCallChainSamplingSupported()) {
+ std::vector<std::unique_ptr<Workload>> workloads;
+ CreateProcesses(1, &workloads);
+ std::string pid = std::to_string(workloads[0]->GetPid());
TemporaryFile tmp_file;
ASSERT_TRUE(
- RecordCmd()->Run({"-g", "-o", tmp_file.path, "sleep", SLEEP_SEC}));
+ RecordCmd()->Run({"-p", pid, "-g", "-o", tmp_file.path, "sleep", SLEEP_SEC}));
ReportRaw(tmp_file.path, {"-g"});
ASSERT_TRUE(success);
} else {
diff --git a/simpleperf/cmd_stat_test.cpp b/simpleperf/cmd_stat_test.cpp
index 25fcaf99..125f9386 100644
--- a/simpleperf/cmd_stat_test.cpp
+++ b/simpleperf/cmd_stat_test.cpp
@@ -55,9 +55,15 @@ TEST(stat_cmd, event_modifier) {
void CreateProcesses(size_t count,
std::vector<std::unique_ptr<Workload>>* workloads) {
workloads->clear();
+ // Create workloads run longer than profiling time.
+ auto function = []() {
+ while (true) {
+ for (volatile int i = 0; i < 10000; ++i);
+ usleep(1);
+ }
+ };
for (size_t i = 0; i < count; ++i) {
- // Create a workload runs longer than profiling time.
- auto workload = Workload::CreateWorkload({"sleep", "1000"});
+ auto workload = Workload::CreateWorkload(function);
ASSERT_TRUE(workload != nullptr);
ASSERT_TRUE(workload->Start());
workloads->push_back(std::move(workload));
diff --git a/simpleperf/workload.cpp b/simpleperf/workload.cpp
index 1d34c11a..dcb0e78a 100644
--- a/simpleperf/workload.cpp
+++ b/simpleperf/workload.cpp
@@ -25,7 +25,15 @@
#include <android-base/logging.h>
std::unique_ptr<Workload> Workload::CreateWorkload(const std::vector<std::string>& args) {
- std::unique_ptr<Workload> workload(new Workload(args));
+ std::unique_ptr<Workload> workload(new Workload(args, std::function<void ()>()));
+ if (workload != nullptr && workload->CreateNewProcess()) {
+ return workload;
+ }
+ return nullptr;
+}
+
+std::unique_ptr<Workload> Workload::CreateWorkload(const std::function<void ()>& function) {
+ std::unique_ptr<Workload> workload(new Workload(std::vector<std::string>(), function));
if (workload != nullptr && workload->CreateNewProcess()) {
return workload;
}
@@ -47,8 +55,6 @@ Workload::~Workload() {
}
}
-static void ChildProcessFn(std::vector<std::string>& args, int start_signal_fd, int exec_child_fd);
-
bool Workload::CreateNewProcess() {
CHECK_EQ(work_state_, NotYetCreateNewProcess);
@@ -78,7 +84,7 @@ bool Workload::CreateNewProcess() {
// In child process.
close(start_signal_pipe[1]);
close(exec_child_pipe[0]);
- ChildProcessFn(args_, start_signal_pipe[0], exec_child_pipe[1]);
+ ChildProcessFn(start_signal_pipe[0], exec_child_pipe[1]);
_exit(0);
}
// In parent process.
@@ -91,28 +97,33 @@ bool Workload::CreateNewProcess() {
return true;
}
-static void ChildProcessFn(std::vector<std::string>& args, int start_signal_fd, int exec_child_fd) {
+void Workload::ChildProcessFn(int start_signal_fd, int exec_child_fd) {
// Die if parent exits.
prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
- std::vector<char*> argv(args.size() + 1);
- for (size_t i = 0; i < args.size(); ++i) {
- argv[i] = &args[i][0];
- }
- argv[args.size()] = nullptr;
char start_signal = 0;
ssize_t nread = TEMP_FAILURE_RETRY(read(start_signal_fd, &start_signal, 1));
if (nread == 1 && start_signal == 1) {
close(start_signal_fd);
- execvp(argv[0], argv.data());
- // If execvp() succeed, we will not arrive here. But if it failed, we need to
- // report the failure to the parent process by writing 1 to exec_child_fd.
- int saved_errno = errno;
- char exec_child_failed = 1;
- TEMP_FAILURE_RETRY(write(exec_child_fd, &exec_child_failed, 1));
- close(exec_child_fd);
- errno = saved_errno;
- PLOG(ERROR) << "child process failed to execvp(" << argv[0] << ")";
+ if (child_proc_function_) {
+ close(exec_child_fd);
+ child_proc_function_();
+ } else {
+ char* argv[child_proc_args_.size() + 1];
+ for (size_t i = 0; i < child_proc_args_.size(); ++i) {
+ argv[i] = &child_proc_args_[i][0];
+ }
+ argv[child_proc_args_.size()] = nullptr;
+ execvp(argv[0], argv);
+ // If execvp() succeed, we will not arrive here. But if it failed, we need to
+ // report the failure to the parent process by writing 1 to exec_child_fd.
+ int saved_errno = errno;
+ char exec_child_failed = 1;
+ TEMP_FAILURE_RETRY(write(exec_child_fd, &exec_child_failed, 1));
+ close(exec_child_fd);
+ errno = saved_errno;
+ PLOG(ERROR) << "child process failed to execvp(" << argv[0] << ")";
+ }
} else {
PLOG(ERROR) << "child process failed to receive start_signal, nread = " << nread;
}
diff --git a/simpleperf/workload.h b/simpleperf/workload.h
index fa754b5a..2141830f 100644
--- a/simpleperf/workload.h
+++ b/simpleperf/workload.h
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <chrono>
+#include <functional>
#include <string>
#include <vector>
@@ -34,6 +35,7 @@ class Workload {
public:
static std::unique_ptr<Workload> CreateWorkload(const std::vector<std::string>& args);
+ static std::unique_ptr<Workload> CreateWorkload(const std::function<void ()>& function);
~Workload();
@@ -43,19 +45,24 @@ class Workload {
}
private:
- explicit Workload(const std::vector<std::string>& args)
+ explicit Workload(const std::vector<std::string>& args,
+ const std::function<void ()>& function)
: work_state_(NotYetCreateNewProcess),
- args_(args),
+ child_proc_args_(args),
+ child_proc_function_(function),
work_pid_(-1),
start_signal_fd_(-1),
exec_child_fd_(-1) {
}
bool CreateNewProcess();
+ void ChildProcessFn(int start_signal_fd, int exec_child_fd);
bool WaitChildProcess(bool wait_forever, bool is_child_killed);
WorkState work_state_;
- std::vector<std::string> args_;
+ // The child process either executes child_proc_args or run child_proc_function.
+ std::vector<std::string> child_proc_args_;
+ std::function<void ()> child_proc_function_;
pid_t work_pid_;
int start_signal_fd_; // The parent process writes 1 to start workload in the child process.
int exec_child_fd_; // The child process writes 1 to notify that execvp() failed.