Files
Nikolas Klauser 925f4f27b7 [libc++] Add an ABI flag to optimize mersenne_twister_engine (#206423)
Instead of updating the status array every time `operator()` is called,
we can instead update it once every time the entire array has been read.
That allows the compiler to vectorize the updating code, improving
performance.

Apple M4:
```
Benchmark                                     old      new    Difference    % Difference
----------------------------------------  -------  -------  ------------  --------------
std::mt19937::operator()                     1.39     0.65         -0.74         -53.26%
std::mt19937::operator()_(into_array)      172.92    80.69        -92.23         -53.34%
std::mt19937_64::operator()                  1.46     0.99         -0.47         -31.99%
std::mt19937_64::operator()_(into_array)   187.31   108.10        -79.21         -42.29%
```

Fixes #197221
2026-07-05 19:40:43 +02:00

63 lines
1.9 KiB
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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <random>
#include "benchmark/benchmark.h"
constexpr std::size_t MAX_BUFFER_LEN = 256;
constexpr std::size_t MAX_SEED_LEN = 16;
static void BM_SeedSeq_Generate(benchmark::State& state) {
std::array<std::uint32_t, MAX_BUFFER_LEN> buffer;
std::array<std::uint32_t, MAX_SEED_LEN> seeds;
{
std::random_device rd;
std::generate(std::begin(seeds), std::begin(seeds) + state.range(0), [&]() { return rd(); });
}
std::seed_seq seed(std::begin(seeds), std::begin(seeds) + state.range(0));
for (auto _ : state) {
seed.generate(std::begin(buffer), std::begin(buffer) + state.range(1));
}
}
BENCHMARK(BM_SeedSeq_Generate)->Ranges({{1, MAX_SEED_LEN}, {1, MAX_BUFFER_LEN}});
template <class Engine>
static void BM_engine(benchmark::State& state) {
Engine engine;
for (auto _ : state) {
benchmark::DoNotOptimize(engine());
}
}
BENCHMARK(BM_engine<std::mt19937_64>)->Name("std::mt19937_64::operator()");
BENCHMARK(BM_engine<std::mt19937>)->Name("std::mt19937::operator()");
template <class Engine>
static void BM_engine_array(benchmark::State& state) {
Engine engine;
typename Engine::result_type buffer[128];
for (auto _ : state) {
std::generate(std::begin(buffer), std::end(buffer), std::ref(engine));
benchmark::DoNotOptimize(buffer);
}
}
BENCHMARK(BM_engine_array<std::mt19937_64>)->Name("std::mt19937_64::operator() (into array)");
BENCHMARK(BM_engine_array<std::mt19937>)->Name("std::mt19937::operator() (into array)");
BENCHMARK_MAIN();