Commit 69f885bc authored by OlivierLi's avatar OlivierLi Committed by Commit Bot

Introduce experiment params for EnableHangWatcher trial.

This allows selective activation of hang watching on the different
supported threads.

Bug: 1034046
Change-Id: Iac18db82d162cc88b4ca78134b74cfec96340e33
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2288196Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Commit-Queue: Oliver Li <olivierli@chromium.org>
Cr-Commit-Position: refs/heads/master@{#792386}
parent 3aee95e1
......@@ -184,6 +184,15 @@ void ThreadControllerWithMessagePumpImpl::InitializeThreadTaskRunnerHandle() {
power_monitor_.BindToCurrentThread();
}
void ThreadControllerWithMessagePumpImpl::MaybeStartHangWatchScope() {
// Nested runloops are covered by the parent loop hang watch scope.
// TODO(crbug/1034046): Provide more granular scoping that reuses the parent
// scope deadline.
if (main_thread_only().runloop_count == 1 && base::HangWatcher::IsEnabled()) {
hang_watch_scope_.emplace(base::HangWatchScope::kDefaultHangWatchTime);
}
}
scoped_refptr<SingleThreadTaskRunner>
ThreadControllerWithMessagePumpImpl::GetDefaultTaskRunner() {
base::internal::CheckedAutoLock lock(task_runner_lock_);
......@@ -216,13 +225,7 @@ ThreadControllerWithMessagePumpImpl::GetAssociatedThread() const {
}
void ThreadControllerWithMessagePumpImpl::BeforeDoInternalWork() {
// Nested runloops are covered by the parent loop hang watch scope.
// TODO(crbug/1034046): Provide more granular scoping that reuses the parent
// scope deadline.
if (main_thread_only().runloop_count == 1) {
hang_watch_scope_.emplace(base::HangWatchScope::kDefaultHangWatchTime);
}
MaybeStartHangWatchScope();
work_id_provider_->IncrementWorkId();
}
......@@ -241,12 +244,7 @@ void ThreadControllerWithMessagePumpImpl::BeforeWait() {
MessagePump::Delegate::NextWorkInfo
ThreadControllerWithMessagePumpImpl::DoWork() {
// Nested runloops are covered by the parent loop hang watch scope.
// TODO(crbug/1034046): Provide more granular scoping that reuses the parent
// scope deadline.
if (main_thread_only().runloop_count == 1) {
hang_watch_scope_.emplace(base::HangWatchScope::kDefaultHangWatchTime);
}
MaybeStartHangWatchScope();
work_deduplicator_.OnWorkStarted();
LazyNow continuation_lazy_now(time_source_);
......@@ -369,12 +367,7 @@ TimeDelta ThreadControllerWithMessagePumpImpl::DoWorkImpl(
bool ThreadControllerWithMessagePumpImpl::DoIdleWork() {
TRACE_EVENT0("sequence_manager", "SequenceManager::DoIdleWork");
// Nested runloops are covered by the parent loop hang watch scope.
// TODO(crbug/1034046): Provide more granular scoping that reuses the parent
// scope deadline.
if (main_thread_only().runloop_count == 1) {
hang_watch_scope_.emplace(base::HangWatchScope::kDefaultHangWatchTime);
}
MaybeStartHangWatchScope();
work_id_provider_->IncrementWorkId();
#if defined(OS_WIN)
......
......@@ -153,6 +153,10 @@ class BASE_EXPORT ThreadControllerWithMessagePumpImpl
return main_thread_only_;
}
// Instantiate a HangWatchScope to cover the current work if hang
// watching is activated via finch and the current loop is not nested.
void MaybeStartHangWatchScope();
// TODO(altimin): Merge with the one in SequenceManager.
scoped_refptr<AssociatedThreadId> associated_thread_;
MainThreadOnly main_thread_only_;
......
......@@ -304,7 +304,7 @@ void WorkerThread::RunWorker() {
// Background threads can take an arbitrary amount of time to complete, do not
// watch them for hangs. Ignore priority boosting for now.
const bool watch_for_hangs =
base::HangWatcher::GetInstance() != nullptr &&
base::HangWatcher::IsThreadPoolHangWatchingEnabled() &&
GetDesiredThreadPriority() != ThreadPriority::BACKGROUND;
// If this process has a HangWatcher register this thread for watching.
......
......@@ -14,6 +14,7 @@
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/no_destructor.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/lock.h"
......@@ -28,14 +29,21 @@
namespace base {
// static
constexpr base::Feature HangWatcher::kEnableHangWatcher{
"EnableHangWatcher", base::FEATURE_DISABLED_BY_DEFAULT};
constexpr base::Feature kEnableHangWatcher{"EnableHangWatcher",
base::FEATURE_DISABLED_BY_DEFAULT};
constexpr base::FeatureParam<bool> kHangWatchIOThread{
&kEnableHangWatcher, "hang_watch_io_thread", false};
constexpr base::FeatureParam<bool> kHangWatchThreadPool{
&kEnableHangWatcher, "hang_watch_threadpool", false};
constexpr base::TimeDelta HangWatchScope::kDefaultHangWatchTime =
base::TimeDelta::FromSeconds(10);
namespace {
HangWatcher* g_instance = nullptr;
std::atomic<bool> g_use_hang_watcher{false};
std::atomic<bool> g_hang_watch_workers{false};
std::atomic<bool> g_hang_watch_io_thread{false};
}
constexpr const char* kThreadName = "HangWatcher";
......@@ -106,6 +114,38 @@ HangWatchScope::~HangWatchScope() {
// and that went undetected by the HangWatcher.
}
void HangWatcher::InitializeOnMainThread() {
DCHECK(!g_use_hang_watcher);
DCHECK(!g_hang_watch_workers);
DCHECK(!g_hang_watch_io_thread);
g_use_hang_watcher.store(base::FeatureList::IsEnabled(kEnableHangWatcher),
std::memory_order_relaxed);
// If hang watching is disabled as a whole there is no need to read the
// params.
if (g_use_hang_watcher.load(std::memory_order_relaxed)) {
g_hang_watch_workers.store(kHangWatchThreadPool.Get(),
std::memory_order_relaxed);
g_hang_watch_io_thread.store(kHangWatchIOThread.Get(),
std::memory_order_relaxed);
}
}
// static
bool HangWatcher::IsEnabled() {
return g_use_hang_watcher.load(std::memory_order_relaxed);
}
// static
bool HangWatcher::IsThreadPoolHangWatchingEnabled() {
return g_hang_watch_workers.load(std::memory_order_relaxed);
}
bool HangWatcher::IsIOThreadHangWatchingEnabled() {
return g_hang_watch_io_thread.load(std::memory_order_relaxed);
}
HangWatcher::HangWatcher()
: monitor_period_(kMonitoringPeriod),
should_monitor_(WaitableEvent::ResetPolicy::AUTOMATIC),
......
......@@ -14,7 +14,6 @@
#include "base/callback_forward.h"
#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
#include "base/feature_list.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "base/threading/platform_thread.h"
......@@ -87,7 +86,6 @@ class BASE_EXPORT HangWatchScope {
// within a single process. This instance must outlive all monitored threads.
class BASE_EXPORT HangWatcher : public DelegateSimpleThread::Delegate {
public:
static const base::Feature kEnableHangWatcher;
// The first invocation of the constructor will set the global instance
// accessible through GetInstance(). This means that only one instance can
......@@ -103,6 +101,16 @@ class BASE_EXPORT HangWatcher : public DelegateSimpleThread::Delegate {
// Returns a non-owning pointer to the global HangWatcher instance.
static HangWatcher* GetInstance();
// Initializes HangWatcher. Must be called once on the main thread during
// startup while single-threaded.
static void InitializeOnMainThread();
// Thread safe functions to verify if hang watching is activated. If called
// before InitializeOnMainThread returns the default value which is false.
static bool IsEnabled();
static bool IsThreadPoolHangWatchingEnabled();
static bool IsIOThreadHangWatchingEnabled();
// Sets up the calling thread to be monitored for threads. Returns a
// ScopedClosureRunner that unregisters the thread. This closure has to be
// called from the registered thread before it's joined.
......
......@@ -21,6 +21,7 @@
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/task/sequence_manager/thread_controller_power_monitor.h"
#include "base/threading/hang_watcher.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event_impl.h"
......@@ -633,6 +634,8 @@ void ChromeMainDelegate::PostFieldTrialInitialization() {
base::sequence_manager::internal::ThreadControllerPowerMonitor::
InitializeOnMainThread();
#endif
base::HangWatcher::InitializeOnMainThread();
}
bool ChromeMainDelegate::BasicStartupComplete(int* exit_code) {
......
......@@ -1549,7 +1549,7 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
// Two different types of hang detection cannot run at the same time or they
// would interfere with each other.
if (!base::FeatureList::IsEnabled(base::HangWatcher::kEnableHangWatcher)) {
if (!base::HangWatcher::IsEnabled()) {
// Start watching all browser threads for responsiveness.
ThreadWatcherList::StartWatchingAll(parsed_command_line());
}
......
......@@ -44,6 +44,7 @@
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/threading/hang_watcher.h"
#include "base/trace_event/trace_event.h"
#include "components/discardable_memory/service/discardable_shared_memory_manager.h"
#include "components/download/public/common/download_task_runner.h"
......@@ -928,7 +929,7 @@ int ContentMainRunnerImpl::RunServiceManager(MainFunctionParams& main_params,
// The hang watcher needs to be started once the feature list is available
// but before the IO thread is started.
if (base::FeatureList::IsEnabled(base::HangWatcher::kEnableHangWatcher)) {
if (base::HangWatcher::IsEnabled()) {
hang_watcher_ = new base::HangWatcher();
hang_watcher_->Start();
ANNOTATE_LEAKING_OBJECT_PTR(hang_watcher_);
......
......@@ -135,7 +135,7 @@ NOINLINE void BrowserProcessSubThread::IOThreadRun(base::RunLoop* run_loop) {
// Register the IO thread for hang watching before it starts running and set
// up a closure to automatically unregister it when Run() returns.
base::ScopedClosureRunner unregister_thread_closure;
if (base::FeatureList::IsEnabled(base::HangWatcher::kEnableHangWatcher)) {
if (base::HangWatcher::IsIOThreadHangWatchingEnabled()) {
unregister_thread_closure =
base::HangWatcher::GetInstance()->RegisterThread();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment