2222
2323#include < folly/Benchmark.h>
2424#include < folly/concurrency/AtomicSharedPtr.h>
25+ #include < folly/container/Enumerate.h>
26+ #include < folly/container/F14Set.h>
2527#include < folly/portability/GFlags.h>
2628
2729using namespace folly ;
@@ -250,8 +252,8 @@ BENCHMARK_DRAW_LINE();
250252// / fragment the memory and scatter hprec allocations across cachelines with no
251253// / consistent stride, if hprecs are allocated separately and linked together
252254template <template <typename > class Atom >
253- FOLLY_NOINLINE static void grow_scattered_hprec_list (
254- hazptr_domain<Atom>& domain, size_t hprec_count) {
255+ FOLLY_NOINLINE static std::vector<hazptr_holder<Atom>>
256+ grow_scattered_hprec_list ( hazptr_domain<Atom>& domain, size_t hprec_count) {
255257 using hprec_layout = aligned_storage_for_t <hazptr_rec<std::atomic>>;
256258
257259 std::vector<hazptr_holder<Atom>> holders;
@@ -272,10 +274,13 @@ FOLLY_NOINLINE static void grow_scattered_hprec_list(
272274 // / create hazard pointer, which possibly allocates its hprec
273275 holders.emplace_back (make_hazard_pointer (domain));
274276 }
277+
278+ return holders;
275279}
276280
277281// / benchmark hazptr domain cleanup with various hprec-sequence sizes
278- void hazptr_cleanup_empty_with_hprec_seq (size_t iters, size_t hprec_count) {
282+ static void hazptr_cleanup_empty_with_hprec_seq (
283+ size_t iters, size_t hprec_count) {
279284 BenchmarkSuspender braces;
280285
281286 hazptr_domain<> domain;
@@ -302,6 +307,62 @@ BENCHMARK_PARAM(hazptr_cleanup_empty_with_hprec_seq, 65536)
302307BENCHMARK_PARAM(hazptr_cleanup_empty_with_hprec_seq, 262144 )
303308BENCHMARK_PARAM(hazptr_cleanup_empty_with_hprec_seq, 1048576 )
304309
310+ BENCHMARK_DRAW_LINE();
311+
312+ // / benchmark hazptr domain cleanup with sqrt(N) protected pointers
313+ // / selected uniformly at random from N hprecs
314+ static void hazptr_cleanup_sqrt_with_hprec_seq (
315+ size_t iters, size_t hprec_count) {
316+ BenchmarkSuspender braces;
317+
318+ size_t protected_count = static_cast <size_t >(std::sqrt (hprec_count));
319+
320+ // / create sqrt(N) objects to protect
321+ std::vector<std::unique_ptr<TestObj>> protected_objects;
322+ protected_objects.reserve (protected_count);
323+ for (size_t i = 0 ; i < protected_count; ++i) {
324+ protected_objects.push_back (std::make_unique<TestObj>(i));
325+ }
326+
327+ // / select sqrt(N) holders uniformly at random to protect objects
328+ std::mt19937_64 rng;
329+ std::uniform_int_distribution<size_t > dist (0 , hprec_count - 1 );
330+ folly::F14FastSet<size_t > protected_indices;
331+ protected_indices.reserve (protected_count);
332+ while (protected_indices.size () < protected_count) {
333+ protected_indices.insert (dist (rng));
334+ }
335+
336+ hazptr_domain<> domain;
337+ auto holders = grow_scattered_hprec_list (domain, hprec_count);
338+
339+ // / protect the objects using the randomly selected holders
340+ for (auto [objidx, hpidx] : enumerate(protected_indices)) {
341+ std::atomic<TestObj*> ptr{protected_objects[objidx].get ()};
342+ holders[hpidx].protect (ptr);
343+ }
344+
345+ braces.dismissing ([&] {
346+ while (iters--) {
347+ auto * obj = new TestObj (iters);
348+ obj->retire (domain);
349+ domain.cleanup (); // calls load_hazptr_vals on possibly-scattered hprecs
350+ }
351+ });
352+ }
353+
354+ BENCHMARK_PARAM (hazptr_cleanup_sqrt_with_hprec_seq, 1 )
355+ BENCHMARK_PARAM(hazptr_cleanup_sqrt_with_hprec_seq, 4 )
356+ BENCHMARK_PARAM(hazptr_cleanup_sqrt_with_hprec_seq, 16 )
357+ BENCHMARK_PARAM(hazptr_cleanup_sqrt_with_hprec_seq, 64 )
358+ BENCHMARK_PARAM(hazptr_cleanup_sqrt_with_hprec_seq, 256 )
359+ BENCHMARK_PARAM(hazptr_cleanup_sqrt_with_hprec_seq, 1024 )
360+ BENCHMARK_PARAM(hazptr_cleanup_sqrt_with_hprec_seq, 4096 )
361+ BENCHMARK_PARAM(hazptr_cleanup_sqrt_with_hprec_seq, 16384 )
362+ BENCHMARK_PARAM(hazptr_cleanup_sqrt_with_hprec_seq, 65536 )
363+ BENCHMARK_PARAM(hazptr_cleanup_sqrt_with_hprec_seq, 262144 )
364+ BENCHMARK_PARAM(hazptr_cleanup_sqrt_with_hprec_seq, 1048576 )
365+
305366int main(int argc, char * argv[]) {
306367 folly::gflags::ParseCommandLineFlags (&argc, &argv, true );
307368 runBenchmarks ();
0 commit comments