Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / benchmarks / formatter_int.bench.cpp
blob7cd794a4d4d6670a6be5829e78df3f1c5154e857
1 //===----------------------------------------------------------------------===//
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
8 #include <array>
9 #include <format>
10 #include <random>
12 #include "CartesianBenchmarks.h"
13 #include "benchmark/benchmark.h"
15 // Tests the full range of the value.
16 template <class T>
17 static std::array<T, 1000> generate(std::uniform_int_distribution<T> distribution = std::uniform_int_distribution<T>{
18 std::numeric_limits<T>::min(), std::numeric_limits<T>::max()}) {
19 std::mt19937 generator;
20 std::array<T, 1000> result;
21 std::generate_n(result.begin(), result.size(), [&] { return distribution(generator); });
22 return result;
25 template <class T>
26 static void BM_Basic(benchmark::State& state) {
27 std::array data{generate<T>()};
28 std::array<char, 100> output;
30 while (state.KeepRunningBatch(data.size()))
31 for (auto value : data)
32 benchmark::DoNotOptimize(std::format_to(output.begin(), "{}", value));
34 BENCHMARK_TEMPLATE(BM_Basic, uint32_t);
35 BENCHMARK_TEMPLATE(BM_Basic, int32_t);
36 BENCHMARK_TEMPLATE(BM_Basic, uint64_t);
37 BENCHMARK_TEMPLATE(BM_Basic, int64_t);
39 // Ideally the low values of a 128-bit value are all dispatched to a 64-bit routine.
40 template <class T>
41 static void BM_BasicLow(benchmark::State& state) {
42 using U = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
43 std::array data{
44 generate<T>(std::uniform_int_distribution<T>{std::numeric_limits<U>::min(), std::numeric_limits<U>::max()})};
45 std::array<char, 100> output;
47 while (state.KeepRunningBatch(data.size()))
48 for (auto value : data)
49 benchmark::DoNotOptimize(std::format_to(output.begin(), "{}", value));
51 BENCHMARK_TEMPLATE(BM_BasicLow, __uint128_t);
52 BENCHMARK_TEMPLATE(BM_BasicLow, __int128_t);
54 BENCHMARK_TEMPLATE(BM_Basic, __uint128_t);
55 BENCHMARK_TEMPLATE(BM_Basic, __int128_t);
57 // *** Localization ***
58 enum class LocalizationE { False, True };
59 struct AllLocalizations : EnumValuesAsTuple<AllLocalizations, LocalizationE, 2> {
60 static constexpr const char* Names[] = {"LocFalse", "LocTrue"};
63 template <LocalizationE E>
64 struct Localization {};
66 template <>
67 struct Localization<LocalizationE::False> {
68 static constexpr const char* fmt = "";
71 template <>
72 struct Localization<LocalizationE::True> {
73 static constexpr const char* fmt = "L";
76 // *** Base ***
77 enum class BaseE {
78 Binary,
79 Octal,
80 Decimal,
81 Hex,
82 HexUpper,
84 struct AllBases : EnumValuesAsTuple<AllBases, BaseE, 5> {
85 static constexpr const char* Names[] = {"BaseBin", "BaseOct", "BaseDec", "BaseHex", "BaseHexUpper"};
88 template <BaseE E>
89 struct Base {};
91 template <>
92 struct Base<BaseE::Binary> {
93 static constexpr const char* fmt = "b";
96 template <>
97 struct Base<BaseE::Octal> {
98 static constexpr const char* fmt = "o";
101 template <>
102 struct Base<BaseE::Decimal> {
103 static constexpr const char* fmt = "d";
106 template <>
107 struct Base<BaseE::Hex> {
108 static constexpr const char* fmt = "x";
111 template <>
112 struct Base<BaseE::HexUpper> {
113 static constexpr const char* fmt = "X";
116 // *** Types ***
117 enum class TypeE { Int64, Uint64 };
118 struct AllTypes : EnumValuesAsTuple<AllTypes, TypeE, 2> {
119 static constexpr const char* Names[] = {"Int64", "Uint64"};
122 template <TypeE E>
123 struct Type {};
125 template <>
126 struct Type<TypeE::Int64> {
127 using type = int64_t;
129 static std::array<type, 1000> make_data() { return generate<type>(); }
132 template <>
133 struct Type<TypeE::Uint64> {
134 using type = uint64_t;
136 static std::array<type, 1000> make_data() { return generate<type>(); }
139 // *** Alignment ***
140 enum class AlignmentE { None, Left, Center, Right, ZeroPadding };
141 struct AllAlignments : EnumValuesAsTuple<AllAlignments, AlignmentE, 5> {
142 static constexpr const char* Names[] = {
143 "AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight", "ZeroPadding"};
146 template <AlignmentE E>
147 struct Alignment {};
149 template <>
150 struct Alignment<AlignmentE::None> {
151 static constexpr const char* fmt = "";
154 template <>
155 struct Alignment<AlignmentE::Left> {
156 static constexpr const char* fmt = "0<512";
159 template <>
160 struct Alignment<AlignmentE::Center> {
161 static constexpr const char* fmt = "0^512";
164 template <>
165 struct Alignment<AlignmentE::Right> {
166 static constexpr const char* fmt = "0>512";
169 template <>
170 struct Alignment<AlignmentE::ZeroPadding> {
171 static constexpr const char* fmt = "0512";
174 template <class L, class B, class T, class A>
175 struct Integral {
176 void run(benchmark::State& state) const {
177 std::array data{Type<T::value>::make_data()};
178 std::array<char, 512> output;
180 while (state.KeepRunningBatch(data.size()))
181 for (auto value : data)
182 benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value));
185 std::string name() const { return "Integral" + L::name() + B::name() + A::name() + T::name(); }
187 static constexpr std::string make_fmt() {
188 return std::string("{:") + Alignment<A::value>::fmt + Localization<L::value>::fmt + Base<B::value>::fmt + "}";
191 static constexpr auto fmt = []() {
192 constexpr size_t s = make_fmt().size();
193 std::array<char, s> r;
194 std::ranges::copy(make_fmt(), r.begin());
195 return r;
196 }();
199 int main(int argc, char** argv) {
200 benchmark::Initialize(&argc, argv);
201 if (benchmark::ReportUnrecognizedArguments(argc, argv))
202 return 1;
204 makeCartesianProductBenchmark<Integral, AllLocalizations, AllBases, AllTypes, AllAlignments>();
206 benchmark::RunSpecifiedBenchmarks();