Commit 8f241e77 by Evan Brown Committed by Copybara-Service

Store infoz on the heap instead of inline and store it only when we are sampling…

Store infoz on the heap instead of inline and store it only when we are sampling the current allocation.

PiperOrigin-RevId: 553847957
Change-Id: Idd131d0362bf36bd22d9bd20df54bd9ae50f0e28
parent 039d70f6
...@@ -137,18 +137,7 @@ class HashtablezInfoHandle { ...@@ -137,18 +137,7 @@ class HashtablezInfoHandle {
UnsampleSlow(info_); UnsampleSlow(info_);
} }
HashtablezInfoHandle(const HashtablezInfoHandle&) = delete; inline bool IsSampled() const { return ABSL_PREDICT_FALSE(info_ != nullptr); }
HashtablezInfoHandle& operator=(const HashtablezInfoHandle&) = delete;
HashtablezInfoHandle(HashtablezInfoHandle&& o) noexcept
: info_(absl::exchange(o.info_, nullptr)) {}
HashtablezInfoHandle& operator=(HashtablezInfoHandle&& o) noexcept {
if (ABSL_PREDICT_FALSE(info_ != nullptr)) {
UnsampleSlow(info_);
}
info_ = absl::exchange(o.info_, nullptr);
return *this;
}
inline void RecordStorageChanged(size_t size, size_t capacity) { inline void RecordStorageChanged(size_t size, size_t capacity) {
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return; if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
...@@ -198,6 +187,7 @@ class HashtablezInfoHandle { ...@@ -198,6 +187,7 @@ class HashtablezInfoHandle {
explicit HashtablezInfoHandle(std::nullptr_t) {} explicit HashtablezInfoHandle(std::nullptr_t) {}
inline void Unregister() {} inline void Unregister() {}
inline bool IsSampled() const { return false; }
inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {} inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {}
inline void RecordRehash(size_t /*total_probe_length*/) {} inline void RecordRehash(size_t /*total_probe_length*/) {}
inline void RecordReservation(size_t /*target_capacity*/) {} inline void RecordReservation(size_t /*target_capacity*/) {}
......
...@@ -42,16 +42,11 @@ namespace container_internal { ...@@ -42,16 +42,11 @@ namespace container_internal {
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
class HashtablezInfoHandlePeer { class HashtablezInfoHandlePeer {
public: public:
static bool IsSampled(const HashtablezInfoHandle& h) {
return h.info_ != nullptr;
}
static HashtablezInfo* GetInfo(HashtablezInfoHandle* h) { return h->info_; } static HashtablezInfo* GetInfo(HashtablezInfoHandle* h) { return h->info_; }
}; };
#else #else
class HashtablezInfoHandlePeer { class HashtablezInfoHandlePeer {
public: public:
static bool IsSampled(const HashtablezInfoHandle&) { return false; }
static HashtablezInfo* GetInfo(HashtablezInfoHandle*) { return nullptr; } static HashtablezInfo* GetInfo(HashtablezInfoHandle*) { return nullptr; }
}; };
#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
...@@ -267,7 +262,7 @@ TEST(HashtablezSamplerTest, Sample) { ...@@ -267,7 +262,7 @@ TEST(HashtablezSamplerTest, Sample) {
for (int i = 0; i < 1000000; ++i) { for (int i = 0; i < 1000000; ++i) {
HashtablezInfoHandle h = Sample(test_element_size); HashtablezInfoHandle h = Sample(test_element_size);
++total; ++total;
if (HashtablezInfoHandlePeer::IsSampled(h)) { if (h.IsSampled()) {
++num_sampled; ++num_sampled;
} }
sample_rate = static_cast<double>(num_sampled) / total; sample_rate = static_cast<double>(num_sampled) / total;
...@@ -294,6 +289,7 @@ TEST(HashtablezSamplerTest, Handle) { ...@@ -294,6 +289,7 @@ TEST(HashtablezSamplerTest, Handle) {
}); });
EXPECT_TRUE(found); EXPECT_TRUE(found);
h.Unregister();
h = HashtablezInfoHandle(); h = HashtablezInfoHandle();
found = false; found = false;
sampler.Iterate([&](const HashtablezInfo& h) { sampler.Iterate([&](const HashtablezInfo& h) {
......
...@@ -220,7 +220,7 @@ void DropDeletesWithoutResize(CommonFields& common, ...@@ -220,7 +220,7 @@ void DropDeletesWithoutResize(CommonFields& common,
void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size) { void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size) {
assert(IsFull(*it) && "erasing a dangling iterator"); assert(IsFull(*it) && "erasing a dangling iterator");
c.set_size(c.size() - 1); c.decrement_size();
const auto index = static_cast<size_t>(it - c.control()); const auto index = static_cast<size_t>(it - c.control());
const size_t index_before = (index - Group::kWidth) & c.capacity(); const size_t index_before = (index - Group::kWidth) & c.capacity();
const auto empty_after = Group(it).MaskEmpty(); const auto empty_after = Group(it).MaskEmpty();
...@@ -247,14 +247,15 @@ void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy, ...@@ -247,14 +247,15 @@ void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
ResetCtrl(c, policy.slot_size); ResetCtrl(c, policy.slot_size);
c.infoz().RecordStorageChanged(0, c.capacity()); c.infoz().RecordStorageChanged(0, c.capacity());
} else { } else {
// We need to record infoz before calling dealloc, which will unregister
// infoz.
c.infoz().RecordClearedReservation();
c.infoz().RecordStorageChanged(0, 0);
(*policy.dealloc)(c, policy); (*policy.dealloc)(c, policy);
c.set_control(EmptyGroup()); c.set_control(EmptyGroup());
c.set_generation_ptr(EmptyGeneration()); c.set_generation_ptr(EmptyGeneration());
c.set_slots(nullptr); c.set_slots(nullptr);
c.set_capacity(0); c.set_capacity(0);
c.infoz().RecordClearedReservation();
assert(c.size() == 0);
c.infoz().RecordStorageChanged(0, 0);
} }
} }
......
...@@ -524,13 +524,6 @@ TEST(Table, EmptyFunctorOptimization) { ...@@ -524,13 +524,6 @@ TEST(Table, EmptyFunctorOptimization) {
static_assert(std::is_empty<std::allocator<int>>::value, ""); static_assert(std::is_empty<std::allocator<int>>::value, "");
struct MockTable { struct MockTable {
void* infoz;
void* ctrl;
void* slots;
size_t size;
size_t capacity;
};
struct MockTableInfozDisabled {
void* ctrl; void* ctrl;
void* slots; void* slots;
size_t size; size_t size;
...@@ -555,9 +548,7 @@ TEST(Table, EmptyFunctorOptimization) { ...@@ -555,9 +548,7 @@ TEST(Table, EmptyFunctorOptimization) {
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code" #pragma clang diagnostic ignored "-Wunreachable-code"
#endif #endif
constexpr size_t mock_size = std::is_empty<HashtablezInfoHandle>() constexpr size_t mock_size = sizeof(MockTable);
? sizeof(MockTableInfozDisabled)
: sizeof(MockTable);
constexpr size_t generation_size = constexpr size_t generation_size =
SwisstableGenerationsEnabled() ? sizeof(GenerationData) : 0; SwisstableGenerationsEnabled() ? sizeof(GenerationData) : 0;
#if defined(__clang__) #if defined(__clang__)
......
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