scoped_blocking_call_internal.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
  5. #define BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
  6. #include "base/base_export.h"
  7. #include "base/callback_forward.h"
  8. #include "base/debug/activity_tracker.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/memory/ref_counted.h"
  11. #include "base/synchronization/lock.h"
  12. #include "base/thread_annotations.h"
  13. #include "base/time/time.h"
  14. #include "base/types/strong_alias.h"
  15. #include "third_party/abseil-cpp/absl/types/optional.h"
  16. namespace base {
  17. // Forward-declare types from scoped_blocking_call.h to break cyclic dependency.
  18. enum class BlockingType;
  19. using IOJankReportingCallback = RepeatingCallback<void(int, int)>;
  20. using OnlyObservedThreadsForTest =
  21. StrongAlias<class OnlyObservedThreadsTag, bool>;
  22. void BASE_EXPORT EnableIOJankMonitoringForProcess(IOJankReportingCallback,
  23. OnlyObservedThreadsForTest);
  24. // Implementation details of types in scoped_blocking_call.h and classes for a
  25. // few key //base types to observe and react to blocking calls.
  26. namespace internal {
  27. // Interface for an observer to be informed when a thread enters or exits
  28. // the scope of ScopedBlockingCall objects.
  29. class BASE_EXPORT BlockingObserver {
  30. public:
  31. virtual ~BlockingObserver() = default;
  32. // Invoked when a ScopedBlockingCall is instantiated on the observed thread
  33. // where there wasn't an existing ScopedBlockingCall.
  34. virtual void BlockingStarted(BlockingType blocking_type) = 0;
  35. // Invoked when a WILL_BLOCK ScopedBlockingCall is instantiated on the
  36. // observed thread where there was a MAY_BLOCK ScopedBlockingCall but not a
  37. // WILL_BLOCK ScopedBlockingCall.
  38. virtual void BlockingTypeUpgraded() = 0;
  39. // Invoked when the last ScopedBlockingCall on the observed thread is
  40. // destroyed.
  41. virtual void BlockingEnded() = 0;
  42. };
  43. // Registers |blocking_observer| on the current thread. It is invalid to call
  44. // this on a thread where there is an active ScopedBlockingCall.
  45. BASE_EXPORT void SetBlockingObserverForCurrentThread(
  46. BlockingObserver* blocking_observer);
  47. BASE_EXPORT void ClearBlockingObserverForCurrentThread();
  48. // An IOJankMonitoringWindow instruments 1-minute of runtime. Any I/O jank > 1
  49. // second happening during that period will be reported to it. It will then
  50. // report via the IOJankReportingCallback in |reporting_callback_storage()| if
  51. // it's non-null. https://bit.ly/chrome-io-jank-metric.
  52. class BASE_EXPORT IOJankMonitoringWindow
  53. : public RefCountedThreadSafe<IOJankMonitoringWindow> {
  54. public:
  55. explicit IOJankMonitoringWindow(TimeTicks start_time);
  56. IOJankMonitoringWindow(const IOJankMonitoringWindow&) = delete;
  57. IOJankMonitoringWindow& operator=(const IOJankMonitoringWindow&) = delete;
  58. // Cancels monitoring and clears this class' static state.
  59. static void CancelMonitoringForTesting();
  60. class ScopedMonitoredCall {
  61. public:
  62. // Stores a ref to the current IOJankMonitoringWindow if monitoring is
  63. // active, keeping it alive at least until the monitored call completes or
  64. // Cancel() is invoked.
  65. ScopedMonitoredCall();
  66. // Reports to |assigned_jank_window_| if it's non-null.
  67. ~ScopedMonitoredCall();
  68. ScopedMonitoredCall(const ScopedMonitoredCall&) = delete;
  69. ScopedMonitoredCall& operator=(const ScopedMonitoredCall&) = delete;
  70. // Cancels monitoring of this call.
  71. void Cancel();
  72. private:
  73. TimeTicks call_start_;
  74. scoped_refptr<IOJankMonitoringWindow> assigned_jank_window_;
  75. };
  76. static constexpr TimeDelta kIOJankInterval = Seconds(1);
  77. static constexpr TimeDelta kMonitoringWindow = Minutes(1);
  78. static constexpr TimeDelta kTimeDiscrepancyTimeout = kIOJankInterval * 10;
  79. static constexpr int kNumIntervals = kMonitoringWindow / kIOJankInterval;
  80. // kIOJankIntervals must integrally fill kMonitoringWindow
  81. static_assert((kMonitoringWindow % kIOJankInterval).is_zero(), "");
  82. // Cancelation is simple because it can only affect the current window.
  83. static_assert(kTimeDiscrepancyTimeout < kMonitoringWindow, "");
  84. private:
  85. friend class base::RefCountedThreadSafe<IOJankMonitoringWindow>;
  86. friend void base::EnableIOJankMonitoringForProcess(
  87. IOJankReportingCallback,
  88. OnlyObservedThreadsForTest);
  89. // No-op if reporting_callback_storage() is null (i.e. unless
  90. // EnableIOJankMonitoringForProcess() was called).
  91. // When reporting_callback_storage() is non-null : Ensures that there's an
  92. // active IOJankMonitoringWindow for Now(), connects it via |next_| to the
  93. // previous IOJankMonitoringWindow to let ScopedMonitoredCalls that span
  94. // multiple windows report to each window they cover. In the event that Now()
  95. // is farther ahead than expected (> 10s), the previous window is |canceled_|
  96. // as it was likely interrupted by a system sleep and a new
  97. // IOJankMonitoringWindow chain is started from Now(). In all cases, returns a
  98. // live reference to the current (old or new) IOJankMonitoringWindow as a
  99. // helper so callers that need it don't need to re-acquire
  100. // current_jank_window_lock() after calling this.
  101. // |recent_now| is a recent sampling of TimeTicks::Now(), avoids
  102. // double-sampling Now() from most callers.
  103. static scoped_refptr<IOJankMonitoringWindow> MonitorNextJankWindowIfNecessary(
  104. TimeTicks recent_now);
  105. // An IOJankMonitoringWindow is destroyed when all refs to it are gone, i.e.:
  106. // 1) The window it covers has elapsed and MonitorNextJankWindowIfNecessary()
  107. // has replaced it.
  108. // 2) All pending ScopedMonitoredCall's in their range have completed
  109. // (including the ones that transitively have it in their |next_| chain).
  110. ~IOJankMonitoringWindow();
  111. // Called from ~ScopedMonitoredCall().
  112. void OnBlockingCallCompleted(TimeTicks call_start, TimeTicks call_end);
  113. // Helper for OnBlockingCallCompleted(). Records |num_janky_intervals|
  114. // starting at |local_jank_start_index|. Having this logic separately helps
  115. // sane management of |intervals_lock_| when recursive calls through |next_|
  116. // pointers are necessary.
  117. void AddJank(int local_jank_start_index, int num_janky_intervals);
  118. static Lock& current_jank_window_lock();
  119. static scoped_refptr<IOJankMonitoringWindow>& current_jank_window_storage()
  120. EXCLUSIVE_LOCKS_REQUIRED(current_jank_window_lock());
  121. // Storage for callback used to report monitoring results.
  122. // NullCallback if monitoring was not enabled for this process.
  123. static IOJankReportingCallback& reporting_callback_storage()
  124. EXCLUSIVE_LOCKS_REQUIRED(current_jank_window_lock());
  125. Lock intervals_lock_;
  126. size_t intervals_jank_count_[kNumIntervals] GUARDED_BY(intervals_lock_) = {};
  127. const TimeTicks start_time_;
  128. // Set only once per window, in MonitorNextJankWindowIfNecessary(). Any read
  129. // of this value must be ordered after that call in memory and in time.
  130. scoped_refptr<IOJankMonitoringWindow> next_;
  131. // Set to true if ~IOJankMonitoringWindow() shouldn't record metrics.
  132. // Modifications of this variable must be synchronized with each other and
  133. // happen-before ~IOJankMonitoringWindow().
  134. bool canceled_ = false;
  135. };
  136. // Common implementation class for both ScopedBlockingCall and
  137. // ScopedBlockingCallWithBaseSyncPrimitives without assertions.
  138. class BASE_EXPORT UncheckedScopedBlockingCall {
  139. public:
  140. enum class BlockingCallType {
  141. kRegular,
  142. kBaseSyncPrimitives,
  143. };
  144. explicit UncheckedScopedBlockingCall(const Location& from_here,
  145. BlockingType blocking_type,
  146. BlockingCallType blocking_call_type);
  147. UncheckedScopedBlockingCall(const UncheckedScopedBlockingCall&) = delete;
  148. UncheckedScopedBlockingCall& operator=(const UncheckedScopedBlockingCall&) =
  149. delete;
  150. ~UncheckedScopedBlockingCall();
  151. private:
  152. const raw_ptr<BlockingObserver> blocking_observer_;
  153. // Previous ScopedBlockingCall instantiated on this thread.
  154. const raw_ptr<UncheckedScopedBlockingCall> previous_scoped_blocking_call_;
  155. // Whether the BlockingType of the current thread was WILL_BLOCK after this
  156. // ScopedBlockingCall was instantiated.
  157. const bool is_will_block_;
  158. base::debug::ScopedActivity scoped_activity_;
  159. // Non-nullopt for non-nested blocking calls of type MAY_BLOCK on foreground
  160. // threads which we monitor for I/O jank.
  161. absl::optional<IOJankMonitoringWindow::ScopedMonitoredCall> monitored_call_;
  162. };
  163. } // namespace internal
  164. } // namespace base
  165. #endif // BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_