Commit f90c1176 authored by Etienne Pierre-doray's avatar Etienne Pierre-doray Committed by Commit Bot

[IO Hangs]: Annotate ScopedBlockingCall with activity tracker.

Record timestamp and location in ScopedBlockingCall to show up in hang dumps.
This is useful to investigate hangs related to IO & flush.

Bug: 1058194
Change-Id: Iee336ad9ec88a9b5d34a5d2e1a1e2a80c8248fc7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2091547
Commit-Queue: Etienne Pierre-Doray <etiennep@chromium.org>
Reviewed-by: default avatarBrian White <bcwhite@chromium.org>
Reviewed-by: default avatarGabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749648}
parent ead019c9
...@@ -1276,6 +1276,8 @@ class BASE_EXPORT ScopedActivity ...@@ -1276,6 +1276,8 @@ class BASE_EXPORT ScopedActivity
ALWAYS_INLINE ALWAYS_INLINE
ScopedActivity(uint8_t action, uint32_t id, int32_t info) ScopedActivity(uint8_t action, uint32_t id, int32_t info)
: ScopedActivity(GetProgramCounter(), action, id, info) {} : ScopedActivity(GetProgramCounter(), action, id, info) {}
ScopedActivity(Location from_here, uint8_t action, uint32_t id, int32_t info)
: ScopedActivity(from_here.program_counter(), action, id, info) {}
ScopedActivity() : ScopedActivity(0, 0, 0) {} ScopedActivity() : ScopedActivity(0, 0, 0) {}
// Changes the |action| and/or |info| of this activity on the stack. This // Changes the |action| and/or |info| of this activity on the stack. This
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/scoped_clear_last_error.h" #include "base/scoped_clear_last_error.h"
#include "base/threading/thread_local.h" #include "base/threading/thread_local.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -15,6 +16,10 @@ namespace base { ...@@ -15,6 +16,10 @@ namespace base {
namespace { namespace {
// The first 8 characters of sha1 of "ScopedBlockingCall".
// echo -n "ScopedBlockingCall" | sha1sum
constexpr uint32_t kActivityTrackerId = 0x11be9915;
LazyInstance<ThreadLocalPointer<internal::BlockingObserver>>::Leaky LazyInstance<ThreadLocalPointer<internal::BlockingObserver>>::Leaky
tls_blocking_observer = LAZY_INSTANCE_INITIALIZER; tls_blocking_observer = LAZY_INSTANCE_INITIALIZER;
...@@ -35,12 +40,14 @@ LazyInstance<ThreadLocalBoolean>::Leaky tls_construction_in_progress = ...@@ -35,12 +40,14 @@ LazyInstance<ThreadLocalBoolean>::Leaky tls_construction_in_progress =
namespace internal { namespace internal {
UncheckedScopedBlockingCall::UncheckedScopedBlockingCall( UncheckedScopedBlockingCall::UncheckedScopedBlockingCall(
const Location& from_here,
BlockingType blocking_type) BlockingType blocking_type)
: blocking_observer_(tls_blocking_observer.Get().Get()), : blocking_observer_(tls_blocking_observer.Get().Get()),
previous_scoped_blocking_call_(tls_last_scoped_blocking_call.Get().Get()), previous_scoped_blocking_call_(tls_last_scoped_blocking_call.Get().Get()),
is_will_block_(blocking_type == BlockingType::WILL_BLOCK || is_will_block_(blocking_type == BlockingType::WILL_BLOCK ||
(previous_scoped_blocking_call_ && (previous_scoped_blocking_call_ &&
previous_scoped_blocking_call_->is_will_block_)) { previous_scoped_blocking_call_->is_will_block_)),
scoped_activity_(from_here, 0, kActivityTrackerId, 0) {
tls_last_scoped_blocking_call.Get().Set(this); tls_last_scoped_blocking_call.Get().Set(this);
if (blocking_observer_) { if (blocking_observer_) {
...@@ -51,6 +58,14 @@ UncheckedScopedBlockingCall::UncheckedScopedBlockingCall( ...@@ -51,6 +58,14 @@ UncheckedScopedBlockingCall::UncheckedScopedBlockingCall(
blocking_observer_->BlockingTypeUpgraded(); blocking_observer_->BlockingTypeUpgraded();
} }
} }
if (scoped_activity_.IsRecorded()) {
// Also record the data for extended crash reporting.
const base::TimeTicks now = base::TimeTicks::Now();
auto& user_data = scoped_activity_.user_data();
user_data.SetUint("timestamp_us", now.since_origin().InMicroseconds());
user_data.SetUint("blocking_type", static_cast<uint64_t>(blocking_type));
}
} }
UncheckedScopedBlockingCall::~UncheckedScopedBlockingCall() { UncheckedScopedBlockingCall::~UncheckedScopedBlockingCall() {
...@@ -67,7 +82,7 @@ UncheckedScopedBlockingCall::~UncheckedScopedBlockingCall() { ...@@ -67,7 +82,7 @@ UncheckedScopedBlockingCall::~UncheckedScopedBlockingCall() {
ScopedBlockingCall::ScopedBlockingCall(const Location& from_here, ScopedBlockingCall::ScopedBlockingCall(const Location& from_here,
BlockingType blocking_type) BlockingType blocking_type)
: UncheckedScopedBlockingCall(blocking_type) { : UncheckedScopedBlockingCall(from_here, blocking_type) {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
DCHECK(!tls_construction_in_progress.Get().Get()); DCHECK(!tls_construction_in_progress.Get().Get());
tls_construction_in_progress.Get().Set(true); tls_construction_in_progress.Get().Set(true);
...@@ -91,7 +106,7 @@ namespace internal { ...@@ -91,7 +106,7 @@ namespace internal {
ScopedBlockingCallWithBaseSyncPrimitives:: ScopedBlockingCallWithBaseSyncPrimitives::
ScopedBlockingCallWithBaseSyncPrimitives(const Location& from_here, ScopedBlockingCallWithBaseSyncPrimitives(const Location& from_here,
BlockingType blocking_type) BlockingType blocking_type)
: UncheckedScopedBlockingCall(blocking_type) { : UncheckedScopedBlockingCall(from_here, blocking_type) {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
DCHECK(!tls_construction_in_progress.Get().Get()); DCHECK(!tls_construction_in_progress.Get().Get());
tls_construction_in_progress.Get().Set(true); tls_construction_in_progress.Get().Set(true);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define BASE_THREADING_SCOPED_BLOCKING_CALL_H #define BASE_THREADING_SCOPED_BLOCKING_CALL_H
#include "base/base_export.h" #include "base/base_export.h"
#include "base/debug/activity_tracker.h"
#include "base/location.h" #include "base/location.h"
#include "base/logging.h" #include "base/logging.h"
...@@ -35,7 +36,8 @@ class BlockingObserver; ...@@ -35,7 +36,8 @@ class BlockingObserver;
// ScopedBlockingCallWithBaseSyncPrimitives without assertions. // ScopedBlockingCallWithBaseSyncPrimitives without assertions.
class BASE_EXPORT UncheckedScopedBlockingCall { class BASE_EXPORT UncheckedScopedBlockingCall {
public: public:
explicit UncheckedScopedBlockingCall(BlockingType blocking_type); explicit UncheckedScopedBlockingCall(const Location& from_here,
BlockingType blocking_type);
~UncheckedScopedBlockingCall(); ~UncheckedScopedBlockingCall();
private: private:
...@@ -48,6 +50,8 @@ class BASE_EXPORT UncheckedScopedBlockingCall { ...@@ -48,6 +50,8 @@ class BASE_EXPORT UncheckedScopedBlockingCall {
// ScopedBlockingCall was instantiated. // ScopedBlockingCall was instantiated.
const bool is_will_block_; const bool is_will_block_;
base::debug::ScopedActivity scoped_activity_;
DISALLOW_COPY_AND_ASSIGN(UncheckedScopedBlockingCall); DISALLOW_COPY_AND_ASSIGN(UncheckedScopedBlockingCall);
}; };
......
...@@ -4,8 +4,10 @@ ...@@ -4,8 +4,10 @@
#include "chrome/browser/metrics/thread_watcher_report_hang.h" #include "chrome/browser/metrics/thread_watcher_report_hang.h"
#include "base/debug/activity_tracker.h"
#include "base/debug/debugger.h" #include "base/debug/debugger.h"
#include "base/debug/dump_without_crashing.h" #include "base/debug/dump_without_crashing.h"
#include "base/time/time.h"
namespace metrics { namespace metrics {
...@@ -15,6 +17,16 @@ namespace metrics { ...@@ -15,6 +17,16 @@ namespace metrics {
NOINLINE void ReportThreadHang() { NOINLINE void ReportThreadHang() {
volatile const char* inhibit_comdat = __func__; volatile const char* inhibit_comdat = __func__;
ALLOW_UNUSED_LOCAL(inhibit_comdat); ALLOW_UNUSED_LOCAL(inhibit_comdat);
// The first 8 characters of sha1 of "ReportThreadHang".
// echo -n "ReportThreadHang" | sha1sum
static constexpr uint32_t kActivityTrackerId = 0xceec103d;
base::debug::ScopedActivity scoped_activity(0, kActivityTrackerId, 0);
auto& user_data = scoped_activity.user_data();
const base::TimeTicks now = base::TimeTicks::Now();
user_data.SetUint("timestamp_us", now.since_origin().InMicroseconds());
#if defined(NDEBUG) #if defined(NDEBUG)
base::debug::DumpWithoutCrashing(); base::debug::DumpWithoutCrashing();
#else #else
......
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