Skip to content

Commit

Permalink
Add tracing annotations to absl::BlockingCounter
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 656010740
Change-Id: I99ef6f18502a0cb2c363c805ae5f9a9a42bd3b41
  • Loading branch information
martijnvels authored and copybara-github committed Jul 25, 2024
1 parent 9a0743a commit 034f8d0
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 17 deletions.
14 changes: 7 additions & 7 deletions absl/base/internal/tracing.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ABSL_NAMESPACE_BEGIN
namespace base_internal {

// Well known Abseil object types that have causality.
enum class ObjectKind { kUnknown };
enum class ObjectKind { kUnknown, kBlockingCounter };

// `TraceWait` and `TraceContinue` record the start and end of a potentially
// blocking wait operation on `object`. `object` typically represents a higher
Expand All @@ -47,14 +47,14 @@ void TraceObserved(const void* object, ObjectKind kind);
// ---------------------------------------------------------------------------
extern "C" {

void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(const void* object,
ObjectKind kind);
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(const void* object,
ObjectKind kind);
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(const void* object,
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(const void* object,
ObjectKind kind);
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceObserved)(const void* object,
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(const void* object,
ObjectKind kind);
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(const void* object,
ObjectKind kind);
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceObserved)(const void* object,
ObjectKind kind);

} // extern "C"

Expand Down
4 changes: 4 additions & 0 deletions absl/synchronization/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ cc_library(
"//absl/base:dynamic_annotations",
"//absl/base:malloc_internal",
"//absl/base:raw_logging_internal",
"//absl/base:tracing_internal",
"//absl/debugging:stacktrace",
"//absl/debugging:symbolize",
"//absl/time",
Expand Down Expand Up @@ -177,6 +178,9 @@ cc_test(
],
deps = [
":synchronization",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:tracing_internal",
"//absl/time",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
Expand Down
2 changes: 2 additions & 0 deletions absl/synchronization/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ absl_cc_library(
absl::stacktrace
absl::symbolize
absl::time
absl::tracing_internal
Threads::Threads
PUBLIC
)
Expand Down Expand Up @@ -140,6 +141,7 @@ absl_cc_test(
DEPS
absl::synchronization
absl::time
absl::tracing_internal
GTest::gmock_main
)

Expand Down
26 changes: 16 additions & 10 deletions absl/synchronization/blocking_counter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <atomic>

#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/tracing.h"

namespace absl {
ABSL_NAMESPACE_BEGIN
Expand All @@ -40,6 +41,7 @@ bool BlockingCounter::DecrementCount() {
ABSL_RAW_CHECK(count >= 0,
"BlockingCounter::DecrementCount() called too many times");
if (count == 0) {
base_internal::TraceSignal(this, TraceObjectKind());
MutexLock l(&lock_);
done_ = true;
return true;
Expand All @@ -48,19 +50,23 @@ bool BlockingCounter::DecrementCount() {
}

void BlockingCounter::Wait() {
MutexLock l(&this->lock_);
base_internal::TraceWait(this, TraceObjectKind());
{
MutexLock l(&this->lock_);

// only one thread may call Wait(). To support more than one thread,
// implement a counter num_to_exit, like in the Barrier class.
ABSL_RAW_CHECK(num_waiting_ == 0, "multiple threads called Wait()");
num_waiting_++;
// only one thread may call Wait(). To support more than one thread,
// implement a counter num_to_exit, like in the Barrier class.
ABSL_RAW_CHECK(num_waiting_ == 0, "multiple threads called Wait()");
num_waiting_++;

this->lock_.Await(Condition(IsDone, &this->done_));
this->lock_.Await(Condition(IsDone, &this->done_));

// At this point, we know that all threads executing DecrementCount
// will not touch this object again.
// Therefore, the thread calling this method is free to delete the object
// after we return from this method.
// At this point, we know that all threads executing DecrementCount
// will not touch this object again.
// Therefore, the thread calling this method is free to delete the object
// after we return from this method.
}
base_internal::TraceContinue(this, TraceObjectKind());
}

ABSL_NAMESPACE_END
Expand Down
6 changes: 6 additions & 0 deletions absl/synchronization/blocking_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <atomic>

#include "absl/base/internal/tracing.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"

Expand Down Expand Up @@ -89,6 +90,11 @@ class BlockingCounter {
void Wait();

private:
// Convenience helper to reduce verbosity at call sites.
static inline constexpr base_internal::ObjectKind TraceObjectKind() {
return base_internal::ObjectKind::kBlockingCounter;
}

Mutex lock_;
std::atomic<int> count_;
int num_waiting_ ABSL_GUARDED_BY(lock_);
Expand Down
66 changes: 66 additions & 0 deletions absl/synchronization/blocking_counter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
#include "absl/synchronization/blocking_counter.h"

#include <thread> // NOLINT(build/c++11)
#include <tuple>
#include <vector>

#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/tracing.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"

Expand Down Expand Up @@ -76,5 +80,67 @@ TEST(BlockingCounterTest, WaitNegativeInitialCount) {
#endif

} // namespace

#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;

} // 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};
}

} // extern "C"

TEST(BlockingCounterTest, TracesSignal) {
BlockingCounter counter(2);

tls_signal = {};
counter.DecrementCount();
EXPECT_EQ(tls_signal, TraceRecord(nullptr, ObjectKind::kUnknown));

tls_signal = {};
counter.DecrementCount();
EXPECT_EQ(tls_signal, TraceRecord(&counter, ObjectKind::kBlockingCounter));
}

TEST(BlockingCounterTest, TracesWaitContinue) {
BlockingCounter counter(1);
counter.DecrementCount();

tls_wait = {};
tls_continue = {};
counter.Wait();
EXPECT_EQ(tls_wait, TraceRecord(&counter, ObjectKind::kBlockingCounter));
EXPECT_EQ(tls_continue, TraceRecord(&counter, ObjectKind::kBlockingCounter));
}

} // namespace base_internal

#endif // ABSL_HAVE_ATTRIBUTE_WEAK

ABSL_NAMESPACE_END
} // namespace absl

0 comments on commit 034f8d0

Please sign in to comment.