//===- PointerUnionBM.cpp - Benchmark for PointerUnion ---------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Benchmarks for PointerUnion operations with randomized data. // //===----------------------------------------------------------------------===// #include "benchmark/benchmark.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/Support/Casting.h" #include #include #include using namespace llvm; namespace llvm { namespace { // Aligned slot types with controlled NumLowBitsAvailable (3 low bits). template struct alignas(8) A8 { int data; }; template T &getSlot() { static T S{}; return S; } // Encodes a list of slot types for random fill. template struct TypeList {}; template void fillRandom(UnionT *Arr, size_t Count, TypeList) { constexpr size_t N = sizeof...(SlotTs); UnionT Variants[N] = {UnionT(&getSlot())...}; std::mt19937 Rng(42); std::uniform_int_distribution Dist(0, N - 1); for (size_t I = 0; I < Count; ++I) Arr[I] = Variants[Dist(Rng)]; } template void fillRandomWithNulls(UnionT *Arr, size_t Count, TypeList TL) { fillRandom(Arr, Count, TL); std::mt19937 Rng(123); // 50% null mix to exercise both null and non-null paths equally. std::bernoulli_distribution Coin(0.5); for (size_t I = 0; I < Count; ++I) if (Coin(Rng)) Arr[I] = nullptr; } // A8Types = TypeList, A8<1>, ..., A8>. // Used to generate randomized arrays with a uniform mix of N distinct types. template TypeList...> makeA8TypesImpl(std::index_sequence); template using A8Types = decltype(makeA8TypesImpl(std::make_index_sequence{})); template auto makePtrUnion(std::index_sequence) -> PointerUnion *...>; template using PtrUnion = decltype(makePtrUnion(std::make_index_sequence{})); // Isa: random type mix, uniform distribution (~1/N hit rate for each type). template static void BM_Isa(benchmark::State &State) { constexpr size_t Batch = 1024; std::vector Arr(Batch); fillRandom(Arr.data(), Batch, TL{}); benchmark::DoNotOptimize(Arr.data()); for (auto _ : State) { bool R = false; for (size_t I = 0; I < Batch; ++I) R ^= isa(Arr[I]); benchmark::DoNotOptimize(R); } State.SetItemsProcessed(State.iterations() * Batch); } // IsNull: random mix with ~50% nulls. template static void BM_IsNull(benchmark::State &State) { constexpr size_t Batch = 1024; std::vector Arr(Batch); fillRandomWithNulls(Arr.data(), Batch, TL{}); benchmark::DoNotOptimize(Arr.data()); for (auto _ : State) { bool R = false; for (size_t I = 0; I < Batch; ++I) R ^= Arr[I].isNull(); benchmark::DoNotOptimize(R); } State.SetItemsProcessed(State.iterations() * Batch); } } // namespace } // namespace llvm // Registration -- N = 2, 4, 8. BENCHMARK((BM_Isa, A8<0>, A8Types<2>>))->Name("Isa/PU/2/First"); BENCHMARK((BM_Isa, A8<1>, A8Types<2>>))->Name("Isa/PU/2/Last"); BENCHMARK((BM_Isa, A8<0>, A8Types<4>>))->Name("Isa/PU/4/First"); BENCHMARK((BM_Isa, A8<3>, A8Types<4>>))->Name("Isa/PU/4/Last"); BENCHMARK((BM_Isa, A8<0>, A8Types<8>>))->Name("Isa/PU/8/First"); BENCHMARK((BM_Isa, A8<7>, A8Types<8>>))->Name("Isa/PU/8/Last"); BENCHMARK((BM_IsNull, A8Types<2>>))->Name("IsNull/PU/2"); BENCHMARK((BM_IsNull, A8Types<4>>))->Name("IsNull/PU/4"); BENCHMARK((BM_IsNull, A8Types<8>>))->Name("IsNull/PU/8"); BENCHMARK_MAIN();