scoped_blocking_call_internal.h 7.8 KB

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