mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
Add tracing annotations to absl::BlockingCounter
PiperOrigin-RevId: 656010740 Change-Id: I99ef6f18502a0cb2c363c805ae5f9a9a42bd3b41
This commit is contained in:
committed by
Copybara-Service
parent
9a0743ac27
commit
034f8d0598
@@ -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
|
||||
|
||||
@@ -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",
|
||||
@@ -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",
|
||||
|
||||
@@ -113,6 +113,7 @@ absl_cc_library(
|
||||
absl::stacktrace
|
||||
absl::symbolize
|
||||
absl::time
|
||||
absl::tracing_internal
|
||||
Threads::Threads
|
||||
PUBLIC
|
||||
)
|
||||
@@ -140,6 +141,7 @@ absl_cc_test(
|
||||
DEPS
|
||||
absl::synchronization
|
||||
absl::time
|
||||
absl::tracing_internal
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <atomic>
|
||||
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/internal/tracing.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
@@ -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;
|
||||
@@ -48,6 +50,8 @@ bool BlockingCounter::DecrementCount() {
|
||||
}
|
||||
|
||||
void BlockingCounter::Wait() {
|
||||
base_internal::TraceWait(this, TraceObjectKind());
|
||||
{
|
||||
MutexLock l(&this->lock_);
|
||||
|
||||
// only one thread may call Wait(). To support more than one thread,
|
||||
@@ -62,6 +66,8 @@ void BlockingCounter::Wait() {
|
||||
// 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
|
||||
} // namespace absl
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "absl/base/internal/tracing.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user