perfetto: change watchdog to monitor guardrails when explicitly started
Bug: 73051936
Change-Id: I7e9c2a07225dbe382556b8669e249a1f6012e8f6
diff --git a/include/perfetto/base/watchdog.h b/include/perfetto/base/watchdog.h
index 610328e..8bfb4df 100644
--- a/include/perfetto/base/watchdog.h
+++ b/include/perfetto/base/watchdog.h
@@ -55,6 +55,10 @@
// returned handle is not destroyed before this point.
Timer CreateFatalTimer(uint32_t ms);
+ // Starts the watchdog thread which monitors the memory and CPU usage
+ // of the program.
+ void Start();
+
// Sets a limit on the memory (defined as the RSS) used by the program
// averaged over the last |window_ms| milliseconds. If |kb| is 0, any
// existing limit is removed.
@@ -118,15 +122,6 @@
// Main method for the watchdog thread.
void ThreadMain();
- // Change whether the thread is running or not based on resource limits.
- void UpdateThreadStateUnlocked();
-
- // Starts the thread if not already started.
- void StartThreadUnlocked();
-
- // Quits the thread if not already quit.
- void QuitThreadUnlocked();
-
// Check each type of resource every |polling_interval_ms_| miillis.
void CheckMemory(uint64_t rss_bytes);
void CheckCpu(uint64_t cpu_time);
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index c8d5f87..e0297ca 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -26,7 +26,7 @@
"thread_checker.cc",
"unix_task_runner.cc",
]
- if (is_linux || is_android) {
+ if (!build_with_chromium && (is_linux || is_android)) {
sources += [ "watchdog.cc" ]
}
if (is_debug) {
@@ -103,7 +103,7 @@
"utils_unittest.cc",
"weak_ptr_unittest.cc",
]
- if (is_linux || is_android) {
+ if (!build_with_chromium && (is_linux || is_android)) {
sources += [ "watchdog_unittest.cc" ]
}
}
diff --git a/src/base/watchdog.cc b/src/base/watchdog.cc
index df6ebd1..97ece02 100644
--- a/src/base/watchdog.cc
+++ b/src/base/watchdog.cc
@@ -50,10 +50,26 @@
: polling_interval_ms_(polling_interval_ms) {}
Watchdog::~Watchdog() {
- QuitThreadUnlocked();
+ if (!thread_.joinable()) {
+ PERFETTO_DCHECK(quit_);
+ return;
+ }
+
+ {
+ std::lock_guard<std::mutex> guard(mutex_);
+ PERFETTO_DCHECK(!quit_);
+ quit_ = true;
+ }
+ exit_signal_.notify_one();
+ thread_.join();
}
Watchdog* Watchdog::GetInstance() {
+#if PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
+ // Ensure that it is impossible to use watchdog on a Chromium build.
+ PERFETTO_CHECK(false);
+#endif
+
static Watchdog* watchdog = new Watchdog(kDefaultPollingInterval);
return watchdog;
}
@@ -62,33 +78,43 @@
return Watchdog::Timer(ms);
}
-void Watchdog::SetMemoryLimit(uint32_t bytes, uint32_t window_ms) {
- {
- // Update the fields under the lock.
- std::lock_guard<std::mutex> guard(mutex_);
+void Watchdog::Start() {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (thread_.joinable()) {
+ PERFETTO_DCHECK(!quit_);
+ } else {
+ PERFETTO_DCHECK(quit_);
- PERFETTO_CHECK(IsMultipleOf(window_ms, polling_interval_ms_) || bytes == 0);
-
- size_t size = bytes == 0 ? 0 : window_ms / polling_interval_ms_ + 1;
- memory_window_bytes_.Reset(size);
- memory_limit_bytes_ = bytes;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // Kick the thread to start running but only on Android or Linux.
+ quit_ = false;
+ thread_ = std::thread(&Watchdog::ThreadMain, this);
+#endif
}
- UpdateThreadStateUnlocked();
+}
+
+void Watchdog::SetMemoryLimit(uint32_t bytes, uint32_t window_ms) {
+ // Update the fields under the lock.
+ std::lock_guard<std::mutex> guard(mutex_);
+
+ PERFETTO_CHECK(IsMultipleOf(window_ms, polling_interval_ms_) || bytes == 0);
+
+ size_t size = bytes == 0 ? 0 : window_ms / polling_interval_ms_ + 1;
+ memory_window_bytes_.Reset(size);
+ memory_limit_bytes_ = bytes;
}
void Watchdog::SetCpuLimit(uint32_t percentage, uint32_t window_ms) {
- {
- std::lock_guard<std::mutex> guard(mutex_);
+ std::lock_guard<std::mutex> guard(mutex_);
- PERFETTO_CHECK(percentage <= 100);
- PERFETTO_CHECK(IsMultipleOf(window_ms, polling_interval_ms_) ||
- percentage == 0);
+ PERFETTO_CHECK(percentage <= 100);
+ PERFETTO_CHECK(IsMultipleOf(window_ms, polling_interval_ms_) ||
+ percentage == 0);
- size_t size = percentage == 0 ? 0 : window_ms / polling_interval_ms_ + 1;
- cpu_window_time_ticks_.Reset(size);
- cpu_limit_percentage_ = percentage;
- }
- UpdateThreadStateUnlocked();
+ size_t size = percentage == 0 ? 0 : window_ms / polling_interval_ms_ + 1;
+ cpu_window_time_ticks_.Reset(size);
+ cpu_limit_percentage_ = percentage;
}
void Watchdog::ThreadMain() {
@@ -166,48 +192,6 @@
}
}
-void Watchdog::UpdateThreadStateUnlocked() {
- if (cpu_limit_percentage_ > 0 || memory_limit_bytes_ > 0) {
- StartThreadUnlocked();
- } else if (cpu_limit_percentage_ == 0 && memory_limit_bytes_ == 0) {
- QuitThreadUnlocked();
- }
-}
-
-void Watchdog::StartThreadUnlocked() {
- if (thread_.joinable()) {
-#if PERFETTO_DCHECK_IS_ON()
- std::lock_guard<std::mutex> guard(mutex_);
- PERFETTO_DCHECK(!quit_);
-#endif
- } else {
- // Don't need to lock because thread is not running.
- PERFETTO_DCHECK(quit_);
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- // Kick the thread to start running but only on Android or Linux.
- quit_ = false;
- thread_ = std::thread(&Watchdog::ThreadMain, this);
-#endif
- }
-}
-
-void Watchdog::QuitThreadUnlocked() {
- if (thread_.joinable()) {
- {
- std::lock_guard<std::mutex> guard(mutex_);
- PERFETTO_DCHECK(!quit_);
- quit_ = true;
- }
- exit_signal_.notify_one();
- thread_.join();
- thread_ = std::thread();
- } else {
- PERFETTO_DCHECK(quit_);
- }
-}
-
uint32_t Watchdog::WindowTimeForRingBuffer(const WindowedInterval& window) {
return static_cast<uint32_t>(window.size() - 1) * polling_interval_ms_;
}
diff --git a/src/base/watchdog_unittest.cc b/src/base/watchdog_unittest.cc
index 36a4b87..d383735 100644
--- a/src/base/watchdog_unittest.cc
+++ b/src/base/watchdog_unittest.cc
@@ -69,6 +69,7 @@
TestWatchdog watchdog(5);
watchdog.SetMemoryLimit(8 * 1024 * 1024, 25);
+ watchdog.Start();
// Sleep so that the watchdog has some time to pick it up.
usleep(1000 * 1000);
@@ -81,6 +82,7 @@
{
TestWatchdog watchdog(1);
watchdog.SetCpuLimit(10, 25);
+ watchdog.Start();
volatile int x = 0;
while (true) {
x++;