Add a trace event for the duration of ScopedBlockingCalls
This helps identify sections of a trace event that were blocked on external
dependencies and shed some light on the "descheduled" portion of an event.
This CL is non-trivial for 3 reasons:
1) This new TRACE_EVENT kicks off tracing earlier than before in some
configurations. This means that main() of basic utilities all of a sudden
needed AtExitManagers (first patch set of this CL). But that then spread out
to many main()'s and was painful. Since the Singleton is only required in
tracing to know whether it's enabled : this CL specializes
Singleton/TraceEventETWExport to avoid instantiating the instance only to
notice it's not enabled (guaranteed default state).
2) We do not want tracing events while a thread is idle (i.e. when it's
sleeping on its own WaitableEvent/ConditionVariable while waiting for more
tasks). Ideally we simply wouldn't record the trace event when it's not
nested within another event but tracing doesn't have a notion of "current
event depth". As such this CL opts for a declarative model where owners of
the few WaitableEvents/ConditionVariables used to sleep-while-idle can flag
those as irrelevant for tracing.
3) Possibility of reentrancy if the trace event macros perform a blocking
call themselves. Added DCHECKs to confirm this doesn't occur (was
initial suspected cause of CrOS+amd64 only failures but it kept
failing despite that and this feature had to be disabled there..)
Bonus:
* Singleton::GetIfExists() avoids instantiating TraceEventETWExport
when switches::kTraceExportEventsToETW isn't present.
* The declarative model brought forth by (2) also enables not instantiating
debug::ScopedEventWaitActivity objects while a thread is merely sleeping.
This will avoid polluting crash metadata with wait-acitvity for sleeping
threads.
* In a follow-up CL we will be able to remove
base::internal::ScopedClearBlockingObserverForTesting which was previously
necessary specifically to avoid a situation in TaskScheduler unit tests
where WaitableEvents used for the test logic would instantiate
ScopedBlockingCalls and interfere with the very logic under test.
(not done in this one as it's large enough on its own)
Bug: 899897, 902514
Change-Id: I93b63e83ac6bd9e5e9d4e29a9b86c62c73738835
Reviewed-on: https://chromium-review.googlesource.com/c/1305891
Commit-Queue: Gabriel Charette <[email protected]>
Reviewed-by: danakj <[email protected]>
Reviewed-by: François Doray <[email protected]>
Reviewed-by: Peter Kasting <[email protected]>
Reviewed-by: Charlie Harrison <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Reviewed-by: Misha Efimov <[email protected]>
Cr-Commit-Position: refs/heads/master@{#605966}
diff --git a/base/synchronization/waitable_event.h b/base/synchronization/waitable_event.h
index 836adc0..31a36aa 100644
--- a/base/synchronization/waitable_event.h
+++ b/base/synchronization/waitable_event.h
@@ -113,6 +113,14 @@
HANDLE handle() const { return handle_.Get(); }
#endif
+ // Declares that this WaitableEvent will only ever be used by a thread that is
+ // idle at the bottom of its stack and waiting for work (in particular, it is
+ // not synchronously waiting on this event before resuming ongoing work). This
+ // is useful to avoid telling base-internals that this thread is "blocked"
+ // when it's merely idle and ready to do work. As such, this is only expected
+ // to be used by thread and thread pool impls.
+ void declare_only_used_while_idle() { waiting_is_blocking_ = false; }
+
// Wait, synchronously, on multiple events.
// waitables: an array of WaitableEvent pointers
// count: the number of elements in @waitables
@@ -276,6 +284,10 @@
scoped_refptr<WaitableEventKernel> kernel_;
#endif
+ // Whether a thread invoking Wait() on this WaitableEvent should be considered
+ // blocked as opposed to idle (and potentially replaced if part of a pool).
+ bool waiting_is_blocking_ = true;
+
DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
};