summaryrefslogtreecommitdiff
path: root/simpleperf
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2016-12-14 00:29:55 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-12-14 00:29:56 +0000
commit923268ef1e53edb06f088c11193e2214053d48df (patch)
tree860ed3a71701008fe72152a4ed938c31b702ca28 /simpleperf
parent88ff807ea265e293ca72204e0328f840966bbb93 (diff)
parent5f43fc4ac870b49542b4cf530a3729f9f1e0e9ab (diff)
downloadextras-923268ef1e53edb06f088c11193e2214053d48df.tar.gz
Merge "simpleperf: check monitored targets regularly."
Diffstat (limited to 'simpleperf')
-rw-r--r--simpleperf/cmd_record.cpp15
-rw-r--r--simpleperf/cmd_record_test.cpp24
-rw-r--r--simpleperf/cmd_stat.cpp11
-rw-r--r--simpleperf/cmd_stat_test.cpp23
-rw-r--r--simpleperf/environment.cpp4
-rw-r--r--simpleperf/environment.h1
-rw-r--r--simpleperf/event_selection_set.cpp34
-rw-r--r--simpleperf/event_selection_set.h20
8 files changed, 111 insertions, 21 deletions
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 2d1e0123..eb968d71 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -164,7 +164,7 @@ class RecordCommand : public Command {
start_sampling_time_in_ns_(0),
sample_record_count_(0),
lost_record_count_(0) {
- // Die if parent exits.
+ // Stop profiling if parent exits.
prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
}
@@ -252,6 +252,7 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
return false;
}
}
+ bool need_to_check_targets = false;
if (system_wide_collection_) {
event_selection_set_.AddMonitoredThreads({-1});
} else if (!event_selection_set_.HasMonitoredTarget()) {
@@ -263,6 +264,8 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
<< "No threads to monitor. Try `simpleperf help record` for help";
return false;
}
+ } else {
+ need_to_check_targets = true;
}
// 3. Open perf_event_files, create mapped buffers for perf_event_files.
@@ -281,15 +284,19 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
// 5. Create IOEventLoop and add read/signal/periodic Events.
IOEventLoop loop;
+ event_selection_set_.SetIOEventLoop(loop);
auto callback =
std::bind(&RecordCommand::ProcessRecord, this, std::placeholders::_1);
- if (!event_selection_set_.PrepareToReadMmapEventData(loop, callback)) {
+ if (!event_selection_set_.PrepareToReadMmapEventData(callback)) {
+ return false;
+ }
+ if (!event_selection_set_.HandleCpuHotplugEvents(cpus_)) {
return false;
}
- if (!event_selection_set_.HandleCpuHotplugEvents(loop, cpus_)) {
+ if (need_to_check_targets && !event_selection_set_.StopWhenNoMoreTargets()) {
return false;
}
- if (!loop.AddSignalEvents({SIGCHLD, SIGINT, SIGTERM},
+ if (!loop.AddSignalEvents({SIGCHLD, SIGINT, SIGTERM, SIGHUP},
[&]() { return loop.ExitLoop(); })) {
return false;
}
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index 35f330ef..28e2e9b1 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -18,9 +18,11 @@
#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
+#include <sys/syscall.h>
#include <map>
#include <memory>
+#include <thread>
#include "command.h"
#include "environment.h"
@@ -335,3 +337,25 @@ TEST(record_cmd, support_modifier_for_clock_events) {
}
}
}
+
+TEST(record_cmd, handle_SIGHUP) {
+ TemporaryFile tmpfile;
+ std::thread thread([]() {
+ sleep(1);
+ kill(getpid(), SIGHUP);
+ });
+ thread.detach();
+ ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "sleep", "1000000"}));
+}
+
+TEST(record_cmd, stop_when_no_more_targets) {
+ TemporaryFile tmpfile;
+ std::atomic<int> tid(0);
+ std::thread thread([&]() {
+ tid = syscall(__NR_gettid);
+ sleep(1);
+ });
+ thread.detach();
+ while (tid == 0);
+ ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "-t", std::to_string(tid)}));
+}
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index 06258f36..423fbffb 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -349,6 +349,7 @@ bool StatCommand::Run(const std::vector<std::string>& args) {
return false;
}
}
+ bool need_to_check_targets = false;
if (system_wide_collection_) {
event_selection_set_.AddMonitoredThreads({-1});
} else if (!event_selection_set_.HasMonitoredTarget()) {
@@ -360,6 +361,8 @@ bool StatCommand::Run(const std::vector<std::string>& args) {
<< "No threads to monitor. Try `simpleperf help stat` for help\n";
return false;
}
+ } else {
+ need_to_check_targets = true;
}
// 3. Open perf_event_files and output file if defined.
@@ -382,14 +385,18 @@ bool StatCommand::Run(const std::vector<std::string>& args) {
// 4. Create IOEventLoop and add signal/periodic Events.
IOEventLoop loop;
+ event_selection_set_.SetIOEventLoop(loop);
std::chrono::time_point<std::chrono::steady_clock> start_time;
std::vector<CountersInfo> counters;
if (system_wide_collection_ || (!cpus_.empty() && cpus_[0] != -1)) {
- if (!event_selection_set_.HandleCpuHotplugEvents(loop, cpus_)) {
+ if (!event_selection_set_.HandleCpuHotplugEvents(cpus_)) {
return false;
}
}
- if (!loop.AddSignalEvents({SIGCHLD, SIGINT, SIGTERM},
+ if (need_to_check_targets && !event_selection_set_.StopWhenNoMoreTargets()) {
+ return false;
+ }
+ if (!loop.AddSignalEvents({SIGCHLD, SIGINT, SIGTERM, SIGHUP},
[&]() { return loop.ExitLoop(); })) {
return false;
}
diff --git a/simpleperf/cmd_stat_test.cpp b/simpleperf/cmd_stat_test.cpp
index 125f9386..5aa1e3b5 100644
--- a/simpleperf/cmd_stat_test.cpp
+++ b/simpleperf/cmd_stat_test.cpp
@@ -19,6 +19,9 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
+#include <sys/syscall.h>
+
+#include <thread>
#include "command.h"
#include "get_test_data.h"
@@ -143,3 +146,23 @@ TEST(stat_cmd, no_modifier_for_clock_events) {
}
}
}
+
+TEST(stat_cmd, handle_SIGHUP) {
+ std::thread thread([]() {
+ sleep(1);
+ kill(getpid(), SIGHUP);
+ });
+ thread.detach();
+ ASSERT_TRUE(StatCmd()->Run({"sleep", "1000000"}));
+}
+
+TEST(stat_cmd, stop_when_no_more_targets) {
+ std::atomic<int> tid(0);
+ std::thread thread([&]() {
+ tid = syscall(__NR_gettid);
+ sleep(1);
+ });
+ thread.detach();
+ while (tid == 0);
+ ASSERT_TRUE(StatCmd()->Run({"-t", std::to_string(tid)}));
+}
diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp
index 3859de18..69f7c144 100644
--- a/simpleperf/environment.cpp
+++ b/simpleperf/environment.cpp
@@ -238,6 +238,10 @@ std::vector<pid_t> GetThreadsInProcess(pid_t pid) {
return result;
}
+bool IsThreadAlive(pid_t tid) {
+ return IsDir(android::base::StringPrintf("/proc/%d", tid));
+}
+
bool GetProcessForThread(pid_t tid, pid_t* pid) {
return ReadThreadNameAndPid(tid, nullptr, pid);
}
diff --git a/simpleperf/environment.h b/simpleperf/environment.h
index 3baaf752..5d9cee88 100644
--- a/simpleperf/environment.h
+++ b/simpleperf/environment.h
@@ -55,6 +55,7 @@ constexpr char DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID[] = "[kernel.kallsyms]";
bool GetKernelBuildId(BuildId* build_id);
bool GetModuleBuildId(const std::string& module_name, BuildId* build_id);
+bool IsThreadAlive(pid_t tid);
std::vector<pid_t> GetAllProcesses();
std::vector<pid_t> GetThreadsInProcess(pid_t pid);
bool GetProcessForThread(pid_t tid, pid_t* pid);
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index 6c45f150..038997fb 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -466,14 +466,13 @@ bool EventSelectionSet::MmapEventFiles(size_t mmap_pages, bool report_error) {
return true;
}
-bool EventSelectionSet::PrepareToReadMmapEventData(
- IOEventLoop& loop, const std::function<bool(Record*)>& callback) {
+bool EventSelectionSet::PrepareToReadMmapEventData(const std::function<bool(Record*)>& callback) {
// Add read Events for perf event files having mapped buffer.
for (auto& group : groups_) {
for (auto& selection : group) {
for (auto& event_fd : selection.event_fds) {
if (event_fd->HasMappedBuffer()) {
- if (!event_fd->StartPolling(loop, [this]() {
+ if (!event_fd->StartPolling(*loop_, [this]() {
return ReadMmapEventData();
})) {
return false;
@@ -482,7 +481,6 @@ bool EventSelectionSet::PrepareToReadMmapEventData(
}
}
}
- loop_ = &loop;
// Prepare record callback function.
record_callback_ = callback;
@@ -568,13 +566,12 @@ bool EventSelectionSet::FinishReadMmapEventData() {
return ReadMmapEventData();
}
-bool EventSelectionSet::HandleCpuHotplugEvents(
- IOEventLoop& loop, const std::vector<int>& monitored_cpus,
- double check_interval_in_sec) {
+bool EventSelectionSet::HandleCpuHotplugEvents(const std::vector<int>& monitored_cpus,
+ double check_interval_in_sec) {
monitored_cpus_.insert(monitored_cpus.begin(), monitored_cpus.end());
online_cpus_ = GetOnlineCpus();
- if (!loop.AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
- [&]() { return DetectCpuHotplugEvents(); })) {
+ if (!loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
+ [&]() { return DetectCpuHotplugEvents(); })) {
return false;
}
return true;
@@ -719,3 +716,22 @@ bool EventSelectionSet::CreateMappedBufferForCpu(int cpu) {
}
return true;
}
+
+bool EventSelectionSet::StopWhenNoMoreTargets(double check_interval_in_sec) {
+ return loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
+ [&]() { return CheckMonitoredTargets(); });
+}
+
+bool EventSelectionSet::CheckMonitoredTargets() {
+ for (const auto& tid : threads_) {
+ if (IsThreadAlive(tid)) {
+ return true;
+ }
+ }
+ for (const auto& pid : processes_) {
+ if (IsThreadAlive(pid)) {
+ return true;
+ }
+ }
+ return loop_->ExitLoop();
+}
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index b82b9177..8aca7840 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -32,6 +32,7 @@
#include "record.h"
constexpr double DEFAULT_PERIOD_TO_DETECT_CPU_HOTPLUG_EVENTS_IN_SEC = 0.5;
+constexpr double DEFAULT_PERIOD_TO_CHECK_MONITORED_TARGETS_IN_SEC = 1;
struct CounterInfo {
pid_t tid;
@@ -103,18 +104,24 @@ class EventSelectionSet {
return !processes_.empty() || !threads_.empty();
}
+ void SetIOEventLoop(IOEventLoop& loop) {
+ loop_ = &loop;
+ }
+
bool OpenEventFiles(const std::vector<int>& on_cpus);
bool ReadCounters(std::vector<CountersInfo>* counters);
bool MmapEventFiles(size_t min_mmap_pages, size_t max_mmap_pages);
- bool PrepareToReadMmapEventData(IOEventLoop& loop,
- const std::function<bool(Record*)>& callback);
+ bool PrepareToReadMmapEventData(const std::function<bool(Record*)>& callback);
bool FinishReadMmapEventData();
// If monitored_cpus is empty, monitor all cpus.
- bool HandleCpuHotplugEvents(
- IOEventLoop& loop, const std::vector<int>& monitored_cpus,
- double check_interval_in_sec =
- DEFAULT_PERIOD_TO_DETECT_CPU_HOTPLUG_EVENTS_IN_SEC);
+ bool HandleCpuHotplugEvents(const std::vector<int>& monitored_cpus,
+ double check_interval_in_sec =
+ DEFAULT_PERIOD_TO_DETECT_CPU_HOTPLUG_EVENTS_IN_SEC);
+
+ // Stop profiling if all monitored processes/threads don't exist.
+ bool StopWhenNoMoreTargets(double check_interval_in_sec =
+ DEFAULT_PERIOD_TO_CHECK_MONITORED_TARGETS_IN_SEC);
private:
struct EventSelection {
@@ -139,6 +146,7 @@ class EventSelectionSet {
bool HandleCpuOnlineEvent(int cpu);
bool HandleCpuOfflineEvent(int cpu);
bool CreateMappedBufferForCpu(int cpu);
+ bool CheckMonitoredTargets();
const bool for_stat_cmd_;