123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
- #define BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
- #include "base/base_export.h"
- #include "base/debug/activity_tracker.h"
- #include "base/macros.h"
- #include "base/memory/ref_counted.h"
- #include "base/optional.h"
- #include "base/synchronization/lock.h"
- #include "base/thread_annotations.h"
- #include "base/time/time.h"
- namespace base {
- // Forward-declare types from scoped_blocking_call.h to break cyclic dependency.
- enum class BlockingType;
- using IOJankReportingCallback = RepeatingCallback<void(int, int)>;
- void BASE_EXPORT EnableIOJankMonitoringForProcess(IOJankReportingCallback);
- // Implementation details of types in scoped_blocking_call.h and classes for a
- // few key //base types to observe and react to blocking calls.
- namespace internal {
- // Interface for an observer to be informed when a thread enters or exits
- // the scope of ScopedBlockingCall objects.
- class BASE_EXPORT BlockingObserver {
- public:
- virtual ~BlockingObserver() = default;
- // Invoked when a ScopedBlockingCall is instantiated on the observed thread
- // where there wasn't an existing ScopedBlockingCall.
- virtual void BlockingStarted(BlockingType blocking_type) = 0;
- // Invoked when a WILL_BLOCK ScopedBlockingCall is instantiated on the
- // observed thread where there was a MAY_BLOCK ScopedBlockingCall but not a
- // WILL_BLOCK ScopedBlockingCall.
- virtual void BlockingTypeUpgraded() = 0;
- // Invoked when the last ScopedBlockingCall on the observed thread is
- // destroyed.
- virtual void BlockingEnded() = 0;
- };
- // Registers |blocking_observer| on the current thread. It is invalid to call
- // this on a thread where there is an active ScopedBlockingCall.
- BASE_EXPORT void SetBlockingObserverForCurrentThread(
- BlockingObserver* blocking_observer);
- BASE_EXPORT void ClearBlockingObserverForCurrentThread();
- // An IOJankMonitoringWindow instruments 1-minute of runtime. Any I/O jank > 1
- // second happening during that period will be reported to it. It will then
- // report via the IOJankReportingCallback in |reporting_callback_storage()| if
- // it's non-null. https://bit.ly/chrome-io-jank-metric.
- class BASE_EXPORT IOJankMonitoringWindow
- : public RefCountedThreadSafe<IOJankMonitoringWindow> {
- public:
- explicit IOJankMonitoringWindow(TimeTicks start_time);
- IOJankMonitoringWindow(const IOJankMonitoringWindow&) = delete;
- IOJankMonitoringWindow& operator=(const IOJankMonitoringWindow&) = delete;
- // Cancels monitoring and clears this class' static state.
- static void CancelMonitoringForTesting();
- class ScopedMonitoredCall {
- public:
- // Stores a ref to the current IOJankMonitoringWindow if monitoring is
- // active, keeping it alive at least until the monitored call completes or
- // Cancel() is invoked.
- ScopedMonitoredCall();
- // Reports to |assigned_jank_window_| if it's non-null.
- ~ScopedMonitoredCall();
- ScopedMonitoredCall(const ScopedMonitoredCall&) = delete;
- ScopedMonitoredCall& operator=(const ScopedMonitoredCall&) = delete;
- // Cancels monitoring of this call.
- void Cancel();
- private:
- const TimeTicks call_start_;
- scoped_refptr<IOJankMonitoringWindow> assigned_jank_window_;
- };
- static constexpr TimeDelta kIOJankInterval = TimeDelta::FromSeconds(1);
- static constexpr TimeDelta kMonitoringWindow = TimeDelta::FromMinutes(1);
- static constexpr TimeDelta kTimeDiscrepancyTimeout = kIOJankInterval * 10;
- static constexpr int kNumIntervals = kMonitoringWindow / kIOJankInterval;
- private:
- friend class base::RefCountedThreadSafe<IOJankMonitoringWindow>;
- friend void base::EnableIOJankMonitoringForProcess(IOJankReportingCallback);
- // No-op if reporting_callback_storage() is null (i.e. unless
- // EnableIOJankMonitoringForProcess() was called).
- // When reporting_callback_storage() is non-null : Ensures that there's an
- // active IOJankMonitoringWindow for Now(), connects it via |next_| to the
- // previous IOJankMonitoringWindow to let ScopedMonitoredCalls that span
- // multiple windows report to each window they cover. In the event that Now()
- // is farther ahead than expected (> 10s), the previous window is |canceled_|
- // as it was likely interrupted by a system sleep and a new
- // IOJankMonitoringWindow chain is started from Now(). In all cases, returns a
- // live reference to the current (old or new) IOJankMonitoringWindow as a
- // helper so callers that need it don't need to re-acquire
- // current_jank_window_lock() after calling this.
- // |recent_now| is a recent sampling of TimeTicks::Now(), avoids
- // double-sampling Now() from most callers.
- static scoped_refptr<IOJankMonitoringWindow> MonitorNextJankWindowIfNecessary(
- TimeTicks recent_now);
- // An IOJankMonitoringWindow is destroyed when all refs to it are gone, i.e.:
- // 1) The window it covers has elapsed and MonitorNextJankWindowIfNecessary()
- // has replaced it.
- // 2) All pending ScopedMonitoredCall's in their range have completed
- // (including the ones that transitively have it in their |next_| chain).
- ~IOJankMonitoringWindow();
- // Called from ~ScopedMonitoredCall().
- void OnBlockingCallCompleted(TimeTicks call_start, TimeTicks call_end);
- // Helper for OnBlockingCallCompleted(). Records |num_janky_intervals|
- // starting at |local_jank_start_index|. Having this logic separately helps
- // sane management of |intervals_lock_| when recursive calls through |next_|
- // pointers are necessary.
- void AddJank(int local_jank_start_index, int num_janky_intervals);
- static Lock& current_jank_window_lock();
- static scoped_refptr<IOJankMonitoringWindow>& current_jank_window_storage()
- EXCLUSIVE_LOCKS_REQUIRED(current_jank_window_lock());
- // Storage for callback used to report monitoring results.
- // NullCallback if monitoring was not enabled for this process.
- static IOJankReportingCallback& reporting_callback_storage()
- EXCLUSIVE_LOCKS_REQUIRED(current_jank_window_lock());
- Lock intervals_lock_;
- size_t intervals_jank_count_[kNumIntervals] GUARDED_BY(intervals_lock_) = {};
- const TimeTicks start_time_;
- // Set only once per window, in MonitorNextJankWindowIfNecessary(). Any read
- // of this value must be ordered after that call in memory and in time.
- scoped_refptr<IOJankMonitoringWindow> next_;
- // Set to true if ~IOJankMonitoringWindow() shouldn't record metrics.
- // Modifications of this variable must be synchronized with each other and
- // happen-before ~IOJankMonitoringWindow().
- bool canceled_ = false;
- };
- // Common implementation class for both ScopedBlockingCall and
- // ScopedBlockingCallWithBaseSyncPrimitives without assertions.
- class BASE_EXPORT UncheckedScopedBlockingCall {
- public:
- enum class BlockingCallType {
- kRegular,
- kBaseSyncPrimitives,
- };
- explicit UncheckedScopedBlockingCall(const Location& from_here,
- BlockingType blocking_type,
- BlockingCallType blocking_call_type);
- ~UncheckedScopedBlockingCall();
- private:
- BlockingObserver* const blocking_observer_;
- // Previous ScopedBlockingCall instantiated on this thread.
- UncheckedScopedBlockingCall* const previous_scoped_blocking_call_;
- // Whether the BlockingType of the current thread was WILL_BLOCK after this
- // ScopedBlockingCall was instantiated.
- const bool is_will_block_;
- base::debug::ScopedActivity scoped_activity_;
- // Non-nullopt for non-nested blocking calls of type MAY_BLOCK on foreground
- // threads which we monitor for I/O jank.
- Optional<IOJankMonitoringWindow::ScopedMonitoredCall> monitored_call_;
- DISALLOW_COPY_AND_ASSIGN(UncheckedScopedBlockingCall);
- };
- } // namespace internal
- } // namespace base
- #endif // BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
|