Commit bb63788b by Martijn Vels Committed by Copybara-Service

Add tracing annotations to absl::Notification

PiperOrigin-RevId: 656188416
Change-Id: I43d901d99f8a4688406b8aab08bc2655a065af46
parent e342b7fc
...@@ -22,7 +22,7 @@ ABSL_NAMESPACE_BEGIN ...@@ -22,7 +22,7 @@ ABSL_NAMESPACE_BEGIN
namespace base_internal { namespace base_internal {
// Well known Abseil object types that have causality. // Well known Abseil object types that have causality.
enum class ObjectKind { kUnknown, kBlockingCounter }; enum class ObjectKind { kUnknown, kBlockingCounter, kNotification };
// `TraceWait` and `TraceContinue` record the start and end of a potentially // `TraceWait` and `TraceContinue` record the start and end of a potentially
// blocking wait operation on `object`. `object` typically represents a higher // blocking wait operation on `object`. `object` typically represents a higher
......
...@@ -324,6 +324,9 @@ cc_test( ...@@ -324,6 +324,9 @@ cc_test(
tags = ["no_test_lexan"], tags = ["no_test_lexan"],
deps = [ deps = [
":synchronization", ":synchronization",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:tracing_internal",
"//absl/time", "//absl/time",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
......
...@@ -112,6 +112,7 @@ absl_cc_library( ...@@ -112,6 +112,7 @@ absl_cc_library(
absl::raw_logging_internal absl::raw_logging_internal
absl::stacktrace absl::stacktrace
absl::symbolize absl::symbolize
absl::tracing_internal
absl::time absl::time
absl::tracing_internal absl::tracing_internal
Threads::Threads Threads::Threads
...@@ -217,8 +218,12 @@ absl_cc_test( ...@@ -217,8 +218,12 @@ absl_cc_test(
COPTS COPTS
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::base
absl::config
absl::core_headers
absl::synchronization absl::synchronization
absl::time absl::time
absl::tracing_internal
GTest::gmock_main GTest::gmock_main
) )
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <atomic> #include <atomic>
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/tracing.h"
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
#include "absl/time/time.h" #include "absl/time/time.h"
...@@ -24,6 +25,7 @@ namespace absl { ...@@ -24,6 +25,7 @@ namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
void Notification::Notify() { void Notification::Notify() {
base_internal::TraceSignal(this, TraceObjectKind());
MutexLock l(&this->mutex_); MutexLock l(&this->mutex_);
#ifndef NDEBUG #ifndef NDEBUG
...@@ -45,31 +47,37 @@ Notification::~Notification() { ...@@ -45,31 +47,37 @@ Notification::~Notification() {
} }
void Notification::WaitForNotification() const { void Notification::WaitForNotification() const {
base_internal::TraceWait(this, TraceObjectKind());
if (!HasBeenNotifiedInternal(&this->notified_yet_)) { if (!HasBeenNotifiedInternal(&this->notified_yet_)) {
this->mutex_.LockWhen(Condition(&HasBeenNotifiedInternal, this->mutex_.LockWhen(
&this->notified_yet_)); Condition(&HasBeenNotifiedInternal, &this->notified_yet_));
this->mutex_.Unlock(); this->mutex_.Unlock();
} }
base_internal::TraceContinue(this, TraceObjectKind());
} }
bool Notification::WaitForNotificationWithTimeout( bool Notification::WaitForNotificationWithTimeout(
absl::Duration timeout) const { absl::Duration timeout) const {
base_internal::TraceWait(this, TraceObjectKind());
bool notified = HasBeenNotifiedInternal(&this->notified_yet_); bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
if (!notified) { if (!notified) {
notified = this->mutex_.LockWhenWithTimeout( notified = this->mutex_.LockWhenWithTimeout(
Condition(&HasBeenNotifiedInternal, &this->notified_yet_), timeout); Condition(&HasBeenNotifiedInternal, &this->notified_yet_), timeout);
this->mutex_.Unlock(); this->mutex_.Unlock();
} }
base_internal::TraceContinue(notified ? this : nullptr, TraceObjectKind());
return notified; return notified;
} }
bool Notification::WaitForNotificationWithDeadline(absl::Time deadline) const { bool Notification::WaitForNotificationWithDeadline(absl::Time deadline) const {
base_internal::TraceWait(this, TraceObjectKind());
bool notified = HasBeenNotifiedInternal(&this->notified_yet_); bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
if (!notified) { if (!notified) {
notified = this->mutex_.LockWhenWithDeadline( notified = this->mutex_.LockWhenWithDeadline(
Condition(&HasBeenNotifiedInternal, &this->notified_yet_), deadline); Condition(&HasBeenNotifiedInternal, &this->notified_yet_), deadline);
this->mutex_.Unlock(); this->mutex_.Unlock();
} }
base_internal::TraceContinue(notified ? this : nullptr, TraceObjectKind());
return notified; return notified;
} }
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include <atomic> #include <atomic>
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/internal/tracing.h"
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
#include "absl/time/time.h" #include "absl/time/time.h"
...@@ -75,7 +76,11 @@ class Notification { ...@@ -75,7 +76,11 @@ class Notification {
// //
// Returns the value of the notification's internal "notified" state. // Returns the value of the notification's internal "notified" state.
ABSL_MUST_USE_RESULT bool HasBeenNotified() const { ABSL_MUST_USE_RESULT bool HasBeenNotified() const {
return HasBeenNotifiedInternal(&this->notified_yet_); if (HasBeenNotifiedInternal(&this->notified_yet_)) {
base_internal::TraceObserved(this, TraceObjectKind());
return true;
}
return false;
} }
// Notification::WaitForNotification() // Notification::WaitForNotification()
...@@ -108,6 +113,11 @@ class Notification { ...@@ -108,6 +113,11 @@ class Notification {
void Notify(); void Notify();
private: private:
// Convenience helper to reduce verbosity at call sites.
static inline constexpr base_internal::ObjectKind TraceObjectKind() {
return base_internal::ObjectKind::kNotification;
}
static inline bool HasBeenNotifiedInternal( static inline bool HasBeenNotifiedInternal(
const std::atomic<bool>* notified_yet) { const std::atomic<bool>* notified_yet) {
return notified_yet->load(std::memory_order_acquire); return notified_yet->load(std::memory_order_acquire);
......
...@@ -15,10 +15,15 @@ ...@@ -15,10 +15,15 @@
#include "absl/synchronization/notification.h" #include "absl/synchronization/notification.h"
#include <thread> // NOLINT(build/c++11) #include <thread> // NOLINT(build/c++11)
#include <tuple>
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/tracing.h"
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
...@@ -129,5 +134,93 @@ TEST(NotificationTest, SanityTest) { ...@@ -129,5 +134,93 @@ TEST(NotificationTest, SanityTest) {
BasicTests(true, &local_notification2); BasicTests(true, &local_notification2);
} }
#if ABSL_HAVE_ATTRIBUTE_WEAK
namespace base_internal {
namespace {
using TraceRecord = std::tuple<const void*, ObjectKind>;
thread_local TraceRecord tls_signal;
thread_local TraceRecord tls_wait;
thread_local TraceRecord tls_continue;
thread_local TraceRecord tls_observed;
} // namespace
// Strong extern "C" implementation.
extern "C" {
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(const void* object,
ObjectKind kind) {
tls_wait = {object, kind};
}
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(const void* object,
ObjectKind kind) {
tls_continue = {object, kind};
}
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(const void* object,
ObjectKind kind) {
tls_signal = {object, kind};
}
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceObserved)(const void* object,
ObjectKind kind) {
tls_observed = {object, kind};
}
} // extern "C"
TEST(NotificationTest, TracesNotify) {
Notification n;
tls_signal = {};
n.Notify();
EXPECT_EQ(tls_signal, TraceRecord(&n, ObjectKind::kNotification));
}
TEST(NotificationTest, TracesWaitForNotification) {
Notification n;
n.Notify();
tls_wait = tls_continue = {};
n.WaitForNotification();
EXPECT_EQ(tls_wait, TraceRecord(&n, ObjectKind::kNotification));
EXPECT_EQ(tls_continue, TraceRecord(&n, ObjectKind::kNotification));
}
TEST(NotificationTest, TracesWaitForNotificationWithTimeout) {
Notification n;
tls_wait = tls_continue = {};
n.WaitForNotificationWithTimeout(absl::Milliseconds(1));
EXPECT_EQ(tls_wait, TraceRecord(&n, ObjectKind::kNotification));
EXPECT_EQ(tls_continue, TraceRecord(nullptr, ObjectKind::kNotification));
n.Notify();
tls_wait = tls_continue = {};
n.WaitForNotificationWithTimeout(absl::Milliseconds(1));
EXPECT_EQ(tls_wait, TraceRecord(&n, ObjectKind::kNotification));
EXPECT_EQ(tls_continue, TraceRecord(&n, ObjectKind::kNotification));
}
TEST(NotificationTest, TracesHasBeenNotified) {
Notification n;
tls_observed = {};
ASSERT_FALSE(n.HasBeenNotified());
EXPECT_EQ(tls_observed, TraceRecord(nullptr, ObjectKind::kUnknown));
n.Notify();
tls_observed = {};
ASSERT_TRUE(n.HasBeenNotified());
EXPECT_EQ(tls_observed, TraceRecord(&n, ObjectKind::kNotification));
}
} // namespace base_internal
#endif // ABSL_HAVE_ATTRIBUTE_WEAK
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
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