summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2022-03-31 16:46:16 -0700
committerYabin Cui <yabinc@google.com>2022-03-31 17:03:59 -0700
commitc3cc93bbe0030a4ff53f17e07629a193cebad959 (patch)
treeec0c0dd02e68d1aa5a06949021fa0888e08b1195
parent1c3f6a483ea2746f2470e886dacd76f30b834156 (diff)
downloadextras-c3cc93bbe0030a4ff53f17e07629a193cebad959.tar.gz
simpleperf: raise priority of stop recording events.
Simpleperf main thread handles several events, like processing records from record read thread, periodically checking JIT debug file updates, etc. Some events may take significant time to finish, and slow down reaction to stop recording events. To alleviate it, this CL raises priority of stop recording events. So they only need to wait for the currently running event. Bug: 227220328 Test: run simpleperf_unit_test Change-Id: Ib0160fe1da6d81cae8e71f25a5870d320706d2a9
-rw-r--r--simpleperf/IOEventLoop.cpp32
-rw-r--r--simpleperf/IOEventLoop.h24
-rw-r--r--simpleperf/IOEventLoop_test.cpp42
-rw-r--r--simpleperf/cmd_monitor.cpp9
-rw-r--r--simpleperf/cmd_record.cpp11
5 files changed, 92 insertions, 26 deletions
diff --git a/simpleperf/IOEventLoop.cpp b/simpleperf/IOEventLoop.cpp
index 06bdd713..239fff97 100644
--- a/simpleperf/IOEventLoop.cpp
+++ b/simpleperf/IOEventLoop.cpp
@@ -84,6 +84,10 @@ bool IOEventLoop::EnsureInit() {
return false;
}
event_config_free(cfg);
+ if (event_base_priority_init(ebase_, 2) != 0) {
+ LOG(ERROR) << "event_base_priority_init failed";
+ return false;
+ }
}
if (ebase_ == nullptr) {
LOG(ERROR) << "failed to create event_base";
@@ -110,39 +114,44 @@ static bool MakeFdNonBlocking(int fd) {
return true;
}
-IOEventRef IOEventLoop::AddReadEvent(int fd, const std::function<bool()>& callback) {
+IOEventRef IOEventLoop::AddReadEvent(int fd, const std::function<bool()>& callback,
+ IOEventPriority priority) {
if (!MakeFdNonBlocking(fd)) {
return nullptr;
}
- return AddEvent(fd, EV_READ | EV_PERSIST, nullptr, callback);
+ return AddEvent(fd, EV_READ | EV_PERSIST, nullptr, callback, priority);
}
-IOEventRef IOEventLoop::AddWriteEvent(int fd, const std::function<bool()>& callback) {
+IOEventRef IOEventLoop::AddWriteEvent(int fd, const std::function<bool()>& callback,
+ IOEventPriority priority) {
if (!MakeFdNonBlocking(fd)) {
return nullptr;
}
- return AddEvent(fd, EV_WRITE | EV_PERSIST, nullptr, callback);
+ return AddEvent(fd, EV_WRITE | EV_PERSIST, nullptr, callback, priority);
}
-bool IOEventLoop::AddSignalEvent(int sig, const std::function<bool()>& callback) {
- return AddEvent(sig, EV_SIGNAL | EV_PERSIST, nullptr, callback) != nullptr;
+bool IOEventLoop::AddSignalEvent(int sig, const std::function<bool()>& callback,
+ IOEventPriority priority) {
+ return AddEvent(sig, EV_SIGNAL | EV_PERSIST, nullptr, callback, priority) != nullptr;
}
-bool IOEventLoop::AddSignalEvents(std::vector<int> sigs, const std::function<bool()>& callback) {
+bool IOEventLoop::AddSignalEvents(std::vector<int> sigs, const std::function<bool()>& callback,
+ IOEventPriority priority) {
for (auto sig : sigs) {
- if (!AddSignalEvent(sig, callback)) {
+ if (!AddSignalEvent(sig, callback, priority)) {
return false;
}
}
return true;
}
-IOEventRef IOEventLoop::AddPeriodicEvent(timeval duration, const std::function<bool()>& callback) {
- return AddEvent(-1, EV_PERSIST, &duration, callback);
+IOEventRef IOEventLoop::AddPeriodicEvent(timeval duration, const std::function<bool()>& callback,
+ IOEventPriority priority) {
+ return AddEvent(-1, EV_PERSIST, &duration, callback, priority);
}
IOEventRef IOEventLoop::AddEvent(int fd_or_sig, int16_t events, timeval* timeout,
- const std::function<bool()>& callback) {
+ const std::function<bool()>& callback, IOEventPriority priority) {
if (!EnsureInit()) {
return nullptr;
}
@@ -152,6 +161,7 @@ IOEventRef IOEventLoop::AddEvent(int fd_or_sig, int16_t events, timeval* timeout
LOG(ERROR) << "event_new() failed";
return nullptr;
}
+ event_priority_set(e->e, priority);
if (event_add(e->e, timeout) != 0) {
LOG(ERROR) << "event_add() failed";
return nullptr;
diff --git a/simpleperf/IOEventLoop.h b/simpleperf/IOEventLoop.h
index 0bbbbd01..1578a4d0 100644
--- a/simpleperf/IOEventLoop.h
+++ b/simpleperf/IOEventLoop.h
@@ -32,6 +32,12 @@ namespace simpleperf {
struct IOEvent;
typedef IOEvent* IOEventRef;
+enum IOEventPriority {
+ // Lower value means higher priority.
+ IOEventHighPriority = 0,
+ IOEventLowPriority = 1,
+};
+
// IOEventLoop is a class wrapper of libevent, it monitors events happened,
// and calls the corresponding callbacks. Possible events are: file ready to
// read, file ready to write, signal happens, periodic timer timeout.
@@ -46,22 +52,27 @@ class IOEventLoop {
// Register a read Event, so [callback] is called when [fd] can be read
// without blocking. If registered successfully, return the reference
// to control the Event, otherwise return nullptr.
- IOEventRef AddReadEvent(int fd, const std::function<bool()>& callback);
+ IOEventRef AddReadEvent(int fd, const std::function<bool()>& callback,
+ IOEventPriority priority = IOEventLowPriority);
// Register a write Event, so [callback] is called when [fd] can be written
// without blocking.
- IOEventRef AddWriteEvent(int fd, const std::function<bool()>& callback);
+ IOEventRef AddWriteEvent(int fd, const std::function<bool()>& callback,
+ IOEventPriority priority = IOEventLowPriority);
// Register a signal Event, so [callback] is called each time signal [sig]
// happens.
- bool AddSignalEvent(int sig, const std::function<bool()>& callback);
+ bool AddSignalEvent(int sig, const std::function<bool()>& callback,
+ IOEventPriority priority = IOEventLowPriority);
// Register a vector of signal Events.
- bool AddSignalEvents(std::vector<int> sigs, const std::function<bool()>& callback);
+ bool AddSignalEvents(std::vector<int> sigs, const std::function<bool()>& callback,
+ IOEventPriority priority = IOEventLowPriority);
// Register a periodic Event, so [callback] is called periodically every
// [duration].
- IOEventRef AddPeriodicEvent(timeval duration, const std::function<bool()>& callback);
+ IOEventRef AddPeriodicEvent(timeval duration, const std::function<bool()>& callback,
+ IOEventPriority priority = IOEventLowPriority);
// Run a loop polling for Events. It only exits when ExitLoop() is called
// in a callback function of registered Events.
@@ -81,7 +92,8 @@ class IOEventLoop {
private:
bool EnsureInit();
IOEventRef AddEvent(int fd_or_sig, int16_t events, timeval* timeout,
- const std::function<bool()>& callback);
+ const std::function<bool()>& callback,
+ IOEventPriority priority = IOEventLowPriority);
static void EventCallbackFn(int, int16_t, void*);
event_base* ebase_;
diff --git a/simpleperf/IOEventLoop_test.cpp b/simpleperf/IOEventLoop_test.cpp
index 09f64522..658fe820 100644
--- a/simpleperf/IOEventLoop_test.cpp
+++ b/simpleperf/IOEventLoop_test.cpp
@@ -250,3 +250,45 @@ TEST(IOEventLoop, exit_before_loop) {
IOEventLoop loop;
ASSERT_TRUE(loop.ExitLoop());
}
+
+TEST(IOEventLoop, priority) {
+ int low_priority_fd[2];
+ ASSERT_EQ(0, pipe(low_priority_fd));
+ int high_priority_fd[2];
+ ASSERT_EQ(0, pipe(high_priority_fd));
+
+ IOEventLoop loop;
+ int count = 0;
+
+ ASSERT_NE(nullptr, loop.AddReadEvent(
+ low_priority_fd[0],
+ [&]() {
+ char c;
+ read(low_priority_fd[0], &c, 1);
+ CHECK_EQ(count, 1);
+ count++;
+ return loop.ExitLoop();
+ },
+ IOEventLowPriority));
+
+ ASSERT_NE(nullptr, loop.AddReadEvent(
+ high_priority_fd[0],
+ [&]() {
+ char c;
+ read(high_priority_fd[0], &c, 1);
+ CHECK_EQ(count, 0);
+ count++;
+ return true;
+ },
+ IOEventHighPriority));
+
+ char c;
+ CHECK_EQ(write(low_priority_fd[1], &c, 1), 1);
+ CHECK_EQ(write(high_priority_fd[1], &c, 1), 1);
+ ASSERT_TRUE(loop.RunLoop());
+ ASSERT_EQ(2, count);
+ for (int i = 0; i < 2; i++) {
+ close(low_priority_fd[i]);
+ close(high_priority_fd[i]);
+ }
+}
diff --git a/simpleperf/cmd_monitor.cpp b/simpleperf/cmd_monitor.cpp
index 355f9d51..d81ccfea 100644
--- a/simpleperf/cmd_monitor.cpp
+++ b/simpleperf/cmd_monitor.cpp
@@ -266,21 +266,22 @@ bool MonitorCommand::PrepareMonitoring() {
// 5. Add read/signal/periodic Events.
IOEventLoop* loop = event_selection_set_.GetIOEventLoop();
auto exit_loop_callback = [loop]() { return loop->ExitLoop(); };
- if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM}, exit_loop_callback)) {
+ if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM}, exit_loop_callback, IOEventHighPriority)) {
return false;
}
// Only add an event for SIGHUP if we didn't inherit SIG_IGN (e.g. from
// nohup).
if (!SignalIsIgnored(SIGHUP)) {
- if (!loop->AddSignalEvent(SIGHUP, exit_loop_callback)) {
+ if (!loop->AddSignalEvent(SIGHUP, exit_loop_callback, IOEventHighPriority)) {
return false;
}
}
if (duration_in_sec_ != 0) {
- if (!loop->AddPeriodicEvent(SecondToTimeval(duration_in_sec_),
- [loop]() { return loop->ExitLoop(); })) {
+ if (!loop->AddPeriodicEvent(
+ SecondToTimeval(duration_in_sec_), [loop]() { return loop->ExitLoop(); },
+ IOEventHighPriority)) {
return false;
}
}
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 1c53dc1c..35cab822 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -629,25 +629,26 @@ bool RecordCommand::PrepareRecording(Workload* workload) {
}
IOEventLoop* loop = event_selection_set_.GetIOEventLoop();
auto exit_loop_callback = [loop]() { return loop->ExitLoop(); };
- if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM}, exit_loop_callback)) {
+ if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM}, exit_loop_callback, IOEventHighPriority)) {
return false;
}
// Only add an event for SIGHUP if we didn't inherit SIG_IGN (e.g. from nohup).
if (!SignalIsIgnored(SIGHUP)) {
- if (!loop->AddSignalEvent(SIGHUP, exit_loop_callback)) {
+ if (!loop->AddSignalEvent(SIGHUP, exit_loop_callback, IOEventHighPriority)) {
return false;
}
}
if (stop_signal_fd_ != -1) {
- if (!loop->AddReadEvent(stop_signal_fd_, exit_loop_callback)) {
+ if (!loop->AddReadEvent(stop_signal_fd_, exit_loop_callback, IOEventHighPriority)) {
return false;
}
}
if (duration_in_sec_ != 0) {
- if (!loop->AddPeriodicEvent(SecondToTimeval(duration_in_sec_),
- [loop]() { return loop->ExitLoop(); })) {
+ if (!loop->AddPeriodicEvent(
+ SecondToTimeval(duration_in_sec_), [loop]() { return loop->ExitLoop(); },
+ IOEventHighPriority)) {
return false;
}
}