Commit e8ea622d authored by Clemens Backes's avatar Clemens Backes Committed by V8 LUCI CQ

[counters] Always provide a backing pointer

This avoids the {StatsCounter::lookup_done_} field by always
initializing the {StatsCounter::ptr_} field in {StatsCounter::GetPtr()}.
This makes the fast path for updating the counter value much simpler and
faster.

R=mlippautz@chromium.org

Bug: v8:12482
Change-Id: I89d094b15e0417bbfb302006de8eede0c200202d
Cq-Include-Trybots: luci.v8.try:v8_linux64_tsan_rel_ng
Cq-Include-Trybots: luci.v8.try:v8_linux64_ubsan_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3322768Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78314}
parent 76cbcce5
...@@ -24,8 +24,26 @@ void StatsTable::SetCounterFunction(CounterLookupCallback f) { ...@@ -24,8 +24,26 @@ void StatsTable::SetCounterFunction(CounterLookupCallback f) {
lookup_function_ = f; lookup_function_ = f;
} }
int* StatsCounter::FindLocationInStatsTable() const { namespace {
return counters_->FindLocation(name_); std::atomic<int> unused_counter_dump{0};
}
bool StatsCounter::Enabled() { return GetPtr() != &unused_counter_dump; }
std::atomic<int>* StatsCounter::SetupPtrFromStatsTable() {
// {Init} must have been called.
DCHECK_NOT_NULL(counters_);
DCHECK_NOT_NULL(name_);
int* location = counters_->FindLocation(name_);
std::atomic<int>* ptr =
location ? base::AsAtomicPtr(location) : &unused_counter_dump;
#ifdef DEBUG
std::atomic<int>* old_ptr = ptr_.exchange(ptr, std::memory_order_release);
DCHECK_IMPLIES(old_ptr, old_ptr == ptr);
#else
ptr_.store(ptr, std::memory_order_release);
#endif
return ptr;
} }
void Histogram::AddSample(int sample) { void Histogram::AddSample(int sample) {
......
...@@ -101,36 +101,24 @@ class StatsTable { ...@@ -101,36 +101,24 @@ class StatsTable {
// This class is thread-safe. // This class is thread-safe.
class StatsCounter { class StatsCounter {
public: public:
void Set(int value) { void Set(int value) { GetPtr()->store(value, std::memory_order_relaxed); }
if (std::atomic<int>* loc = GetPtr()) {
loc->store(value, std::memory_order_relaxed);
}
}
void Increment(int value = 1) { void Increment(int value = 1) {
if (std::atomic<int>* loc = GetPtr()) { GetPtr()->fetch_add(value, std::memory_order_relaxed);
loc->fetch_add(value, std::memory_order_relaxed);
}
} }
void Decrement(int value = 1) { void Decrement(int value = 1) {
if (std::atomic<int>* loc = GetPtr()) { GetPtr()->fetch_sub(value, std::memory_order_relaxed);
loc->fetch_sub(value, std::memory_order_relaxed);
}
} }
// Is this counter enabled? // Returns true if this counter is enabled (a lookup function was provided and
// Returns false if table is full. // it returned a non-null pointer).
bool Enabled() { return GetPtr() != nullptr; } V8_EXPORT_PRIVATE bool Enabled();
// Get the internal pointer to the counter. This is used // Get the internal pointer to the counter. This is used
// by the code generator to emit code that manipulates a // by the code generator to emit code that manipulates a
// given counter without calling the runtime system. // given counter without calling the runtime system.
std::atomic<int>* GetInternalPointer() { std::atomic<int>* GetInternalPointer() { return GetPtr(); }
std::atomic<int>* loc = GetPtr();
DCHECK_NOT_NULL(loc);
return loc;
}
private: private:
friend class Counters; friend class Counters;
...@@ -144,35 +132,22 @@ class StatsCounter { ...@@ -144,35 +132,22 @@ class StatsCounter {
name_ = name; name_ = name;
} }
V8_EXPORT_PRIVATE int* FindLocationInStatsTable() const; V8_NOINLINE V8_EXPORT_PRIVATE std::atomic<int>* SetupPtrFromStatsTable();
// Reset the cached internal pointer. // Reset the cached internal pointer.
void Reset() { void Reset() { ptr_.store(nullptr, std::memory_order_relaxed); }
lookup_done_.store(false, std::memory_order_release);
ptr_.store(nullptr, std::memory_order_release);
}
// Returns the cached address of this counter location. // Returns the cached address of this counter location.
std::atomic<int>* GetPtr() { std::atomic<int>* GetPtr() {
// {Init} must have been called.
DCHECK_NOT_NULL(counters_);
DCHECK_NOT_NULL(name_);
auto* ptr = ptr_.load(std::memory_order_acquire); auto* ptr = ptr_.load(std::memory_order_acquire);
if (V8_LIKELY(ptr)) return ptr; if (V8_LIKELY(ptr)) return ptr;
if (!lookup_done_.load(std::memory_order_acquire)) { return SetupPtrFromStatsTable();
ptr = base::AsAtomicPtr(FindLocationInStatsTable());
ptr_.store(ptr, std::memory_order_release);
lookup_done_.store(true, std::memory_order_release);
}
// Re-load after checking {lookup_done_}.
return ptr_.load(std::memory_order_acquire);
} }
Counters* counters_ = nullptr; Counters* counters_ = nullptr;
const char* name_ = nullptr; const char* name_ = nullptr;
// A pointer to an atomic, set atomically in {GetPtr}. // A pointer to an atomic, set atomically in {GetPtr}.
std::atomic<std::atomic<int>*> ptr_{nullptr}; std::atomic<std::atomic<int>*> ptr_{nullptr};
std::atomic<bool> lookup_done_{false};
}; };
// A Histogram represents a dynamically created histogram in the // A Histogram represents a dynamically created histogram in the
......
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