diff options
Diffstat (limited to 'absl/container/internal')
-rw-r--r-- | absl/container/internal/hashtablez_force_sampling.cc | 24 | ||||
-rw-r--r-- | absl/container/internal/hashtablez_force_sampling_test.cc | 60 | ||||
-rw-r--r-- | absl/container/internal/hashtablez_sampler.cc | 16 | ||||
-rw-r--r-- | absl/container/internal/hashtablez_sampler.h | 16 | ||||
-rw-r--r-- | absl/container/internal/hashtablez_sampler_force_weak_definition.cc | 27 | ||||
-rw-r--r-- | absl/container/internal/hashtablez_sampler_test.cc | 25 | ||||
-rw-r--r-- | absl/container/internal/raw_hash_set.h | 2 |
7 files changed, 168 insertions, 2 deletions
diff --git a/absl/container/internal/hashtablez_force_sampling.cc b/absl/container/internal/hashtablez_force_sampling.cc new file mode 100644 index 000000000000..868976ec5240 --- /dev/null +++ b/absl/container/internal/hashtablez_force_sampling.cc @@ -0,0 +1,24 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/container/internal/hashtablez_sampler.h" + +namespace absl { +namespace container_internal { + +// See hashtablez_sampler.h for details. +extern "C" const bool kAbslContainerInternalSampleEverything = true; + +} // namespace container_internal +} // namespace absl diff --git a/absl/container/internal/hashtablez_force_sampling_test.cc b/absl/container/internal/hashtablez_force_sampling_test.cc new file mode 100644 index 000000000000..9ff1046a9ad3 --- /dev/null +++ b/absl/container/internal/hashtablez_force_sampling_test.cc @@ -0,0 +1,60 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <cstddef> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/container/internal/hashtablez_sampler.h" + +namespace absl { +namespace container_internal { + +class HashtablezInfoHandlePeer { + public: + static bool IsSampled(const HashtablezInfoHandle& h) { + return h.info_ != nullptr; + } +}; + +namespace { + +bool samples[3]{true, true, true}; + +// We do this test in a global object to test that this works even before main. +struct Global { + Global() { + // By default it is sampled. + samples[0] = HashtablezInfoHandlePeer::IsSampled(Sample()); + + // Even with a large parameter, it is sampled. + SetHashtablezSampleParameter(100); + samples[1] = HashtablezInfoHandlePeer::IsSampled(Sample()); + + // Even if we turn it off, it is still sampled. + SetHashtablezEnabled(false); + samples[2] = HashtablezInfoHandlePeer::IsSampled(Sample()); + } +} global; + +TEST(kAbslContainerInternalSampleEverything, Works) { + EXPECT_THAT(samples, testing::Each(true)); + EXPECT_TRUE(kAbslContainerInternalSampleEverything); + // One more after main() + EXPECT_TRUE(HashtablezInfoHandlePeer::IsSampled(Sample())); +} + +} // namespace +} // namespace container_internal +} // namespace absl diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc index 1ba9564513e2..7c411140be49 100644 --- a/absl/container/internal/hashtablez_sampler.cc +++ b/absl/container/internal/hashtablez_sampler.cc @@ -116,6 +116,11 @@ HashtablezSampler& HashtablezSampler::Global() { return *sampler; } +HashtablezSampler::DisposeCallback HashtablezSampler::SetDisposeCallback( + DisposeCallback f) { + return dispose_.exchange(f, std::memory_order_relaxed); +} + HashtablezInfo::HashtablezInfo() { PrepareForSampling(); } HashtablezInfo::~HashtablezInfo() = default; @@ -138,7 +143,7 @@ void HashtablezInfo::PrepareForSampling() { } HashtablezSampler::HashtablezSampler() - : dropped_samples_(0), size_estimate_(0), all_(nullptr) { + : dropped_samples_(0), size_estimate_(0), all_(nullptr), dispose_(nullptr) { absl::MutexLock l(&graveyard_.init_mu); graveyard_.dead = &graveyard_; } @@ -161,6 +166,10 @@ void HashtablezSampler::PushNew(HashtablezInfo* sample) { } void HashtablezSampler::PushDead(HashtablezInfo* sample) { + if (auto* dispose = dispose_.load(std::memory_order_relaxed)) { + dispose(*sample); + } + absl::MutexLock graveyard_lock(&graveyard_.init_mu); absl::MutexLock sample_lock(&sample->init_mu); sample->dead = graveyard_.dead; @@ -220,6 +229,11 @@ int64_t HashtablezSampler::Iterate( } HashtablezInfo* SampleSlow(int64_t* next_sample) { + if (kAbslContainerInternalSampleEverything) { + *next_sample = 1; + return HashtablezSampler::Global().Register(); + } + bool first = *next_sample < 0; *next_sample = GetGeometricVariable( g_hashtablez_sample_parameter.load(std::memory_order_relaxed)); diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h index c42f1842ffe7..126a0ade431e 100644 --- a/absl/container/internal/hashtablez_sampler.h +++ b/absl/container/internal/hashtablez_sampler.h @@ -183,6 +183,13 @@ class HashtablezSampler { // Unregisters the sample. void Unregister(HashtablezInfo* sample); + // The dispose callback will be called on all samples the moment they are + // being unregistered. Only affects samples that are unregistered after the + // callback has been set. + // Returns the previous callback. + using DisposeCallback = void (*)(const HashtablezInfo&); + DisposeCallback SetDisposeCallback(DisposeCallback f); + // Iterates over all the registered `StackInfo`s. Returning the number of // samples that have been dropped. int64_t Iterate(const std::function<void(const HashtablezInfo& stack)>& f); @@ -222,6 +229,8 @@ class HashtablezSampler { // std::atomic<HashtablezInfo*> all_; HashtablezInfo graveyard_; + + std::atomic<DisposeCallback> dispose_; }; // Enables or disables sampling for Swiss tables. @@ -233,6 +242,13 @@ void SetHashtablezSampleParameter(int32_t rate); // Sets a soft max for the number of samples that will be kept. void SetHashtablezMaxSamples(int32_t max); +// Configuration override. +// This allows process-wide sampling without depending on order of +// initialization of static storage duration objects. +// The definition of this constant is weak, which allows us to inject a +// different value for it at link time. +extern "C" const bool kAbslContainerInternalSampleEverything; + } // namespace container_internal } // namespace absl diff --git a/absl/container/internal/hashtablez_sampler_force_weak_definition.cc b/absl/container/internal/hashtablez_sampler_force_weak_definition.cc new file mode 100644 index 000000000000..38a3f2601c08 --- /dev/null +++ b/absl/container/internal/hashtablez_sampler_force_weak_definition.cc @@ -0,0 +1,27 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/container/internal/hashtablez_sampler.h" + +#include "absl/base/attributes.h" + +namespace absl { +namespace container_internal { + +// See hashtablez_sampler.h for details. +extern "C" ABSL_ATTRIBUTE_WEAK const bool + kAbslContainerInternalSampleEverything = false; + +} // namespace container_internal +} // namespace absl diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc index 31e7641a1222..f9ee941a015c 100644 --- a/absl/container/internal/hashtablez_sampler_test.cc +++ b/absl/container/internal/hashtablez_sampler_test.cc @@ -302,6 +302,31 @@ TEST(HashtablezSamplerTest, MultiThreaded) { stop.Notify(); } +TEST(HashtablezSamplerTest, Callback) { + HashtablezSampler sampler; + + auto* info1 = Register(&sampler, 1); + auto* info2 = Register(&sampler, 2); + + static const HashtablezInfo* expected; + + auto callback = [](const HashtablezInfo& info) { + // We can't use `info` outside of this callback because the object will be + // disposed as soon as we return from here. + EXPECT_EQ(&info, expected); + }; + + // Set the callback. + EXPECT_EQ(sampler.SetDisposeCallback(callback), nullptr); + expected = info1; + sampler.Unregister(info1); + + // Unset the callback. + EXPECT_EQ(callback, sampler.SetDisposeCallback(nullptr)); + expected = nullptr; // no more calls. + sampler.Unregister(info2); +} + } // namespace } // namespace container_internal } // namespace absl diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 8f6469fff7f3..8e3fa02d7e42 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -1035,7 +1035,7 @@ class raw_hash_set { size_t capacity() const { return capacity_; } size_t max_size() const { return (std::numeric_limits<size_t>::max)(); } - void clear() { + ABSL_ATTRIBUTE_REINITIALIZES void clear() { // Iterating over this container is O(bucket_count()). When bucket_count() // is much greater than size(), iteration becomes prohibitively expensive. // For clear() it is more important to reuse the allocated array when the |