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
6 //===----------------------------------------------------------------------===//
12 #include "CartesianBenchmarks.h"
13 #include "benchmark/benchmark.h"
15 // Tests the full range of the value.
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
); });
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.
41 static void BM_BasicLow(benchmark::State
& state
) {
42 using U
= std::conditional_t
<std::is_signed_v
<T
>, int64_t, uint64_t>;
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
{};
67 struct Localization
<LocalizationE::False
> {
68 static constexpr const char* fmt
= "";
72 struct Localization
<LocalizationE::True
> {
73 static constexpr const char* fmt
= "L";
84 struct AllBases
: EnumValuesAsTuple
<AllBases
, BaseE
, 5> {
85 static constexpr const char* Names
[] = {"BaseBin", "BaseOct", "BaseDec", "BaseHex", "BaseHexUpper"};
92 struct Base
<BaseE::Binary
> {
93 static constexpr const char* fmt
= "b";
97 struct Base
<BaseE::Octal
> {
98 static constexpr const char* fmt
= "o";
102 struct Base
<BaseE::Decimal
> {
103 static constexpr const char* fmt
= "d";
107 struct Base
<BaseE::Hex
> {
108 static constexpr const char* fmt
= "x";
112 struct Base
<BaseE::HexUpper
> {
113 static constexpr const char* fmt
= "X";
117 enum class TypeE
{ Int64
, Uint64
};
118 struct AllTypes
: EnumValuesAsTuple
<AllTypes
, TypeE
, 2> {
119 static constexpr const char* Names
[] = {"Int64", "Uint64"};
126 struct Type
<TypeE::Int64
> {
127 using type
= int64_t;
129 static std::array
<type
, 1000> make_data() { return generate
<type
>(); }
133 struct Type
<TypeE::Uint64
> {
134 using type
= uint64_t;
136 static std::array
<type
, 1000> make_data() { return generate
<type
>(); }
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
>
150 struct Alignment
<AlignmentE::None
> {
151 static constexpr const char* fmt
= "";
155 struct Alignment
<AlignmentE::Left
> {
156 static constexpr const char* fmt
= "0<512";
160 struct Alignment
<AlignmentE::Center
> {
161 static constexpr const char* fmt
= "0^512";
165 struct Alignment
<AlignmentE::Right
> {
166 static constexpr const char* fmt
= "0>512";
170 struct Alignment
<AlignmentE::ZeroPadding
> {
171 static constexpr const char* fmt
= "0512";
174 template <class L
, class B
, class T
, class A
>
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());
199 int main(int argc
, char** argv
) {
200 benchmark::Initialize(&argc
, argv
);
201 if (benchmark::ReportUnrecognizedArguments(argc
, argv
))
204 makeCartesianProductBenchmark
<Integral
, AllLocalizations
, AllBases
, AllTypes
, AllAlignments
>();
206 benchmark::RunSpecifiedBenchmarks();