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 "benchmark/benchmark.h"
13 #include "CartesianBenchmarks.h"
15 // Tests the full range of the value.
17 static std::array
<T
, 1000>
18 generate(std::uniform_int_distribution
<T
> distribution
= std::uniform_int_distribution
<T
>{
19 std::numeric_limits
<T
>::min(), std::numeric_limits
<T
>::max()}) {
20 std::mt19937 generator
;
21 std::array
<T
, 1000> result
;
22 std::generate_n(result
.begin(), result
.size(), [&] { return distribution(generator
); });
27 static void BM_Basic(benchmark::State
& state
) {
28 std::array data
{generate
<T
>()};
29 std::array
<char, 100> output
;
31 while (state
.KeepRunningBatch(data
.size()))
32 for (auto value
: data
)
33 benchmark::DoNotOptimize(std::format_to(output
.begin(), "{}", value
));
35 BENCHMARK_TEMPLATE(BM_Basic
, uint32_t);
36 BENCHMARK_TEMPLATE(BM_Basic
, int32_t);
37 BENCHMARK_TEMPLATE(BM_Basic
, uint64_t);
38 BENCHMARK_TEMPLATE(BM_Basic
, int64_t);
40 // Ideally the low values of a 128-bit value are all dispatched to a 64-bit routine.
42 static void BM_BasicLow(benchmark::State
& state
) {
43 using U
= std::conditional_t
<std::is_signed_v
<T
>, int64_t, uint64_t>;
45 generate
<T
>(std::uniform_int_distribution
<T
>{std::numeric_limits
<U
>::min(), std::numeric_limits
<U
>::max()})};
46 std::array
<char, 100> output
;
48 while (state
.KeepRunningBatch(data
.size()))
49 for (auto value
: data
)
50 benchmark::DoNotOptimize(std::format_to(output
.begin(), "{}", value
));
52 BENCHMARK_TEMPLATE(BM_BasicLow
, __uint128_t
);
53 BENCHMARK_TEMPLATE(BM_BasicLow
, __int128_t
);
55 BENCHMARK_TEMPLATE(BM_Basic
, __uint128_t
);
56 BENCHMARK_TEMPLATE(BM_Basic
, __int128_t
);
58 // *** Localization ***
59 enum class LocalizationE
{ False
, True
};
60 struct AllLocalizations
: EnumValuesAsTuple
<AllLocalizations
, LocalizationE
, 2> {
61 static constexpr const char* Names
[] = {"LocFalse", "LocTrue"};
64 template <LocalizationE E
>
65 struct Localization
{};
68 struct Localization
<LocalizationE::False
> {
69 static constexpr const char* fmt
= "";
73 struct Localization
<LocalizationE::True
> {
74 static constexpr const char* fmt
= "L";
85 struct AllBases
: EnumValuesAsTuple
<AllBases
, BaseE
, 5> {
86 static constexpr const char* Names
[] = {"BaseBin", "BaseOct", "BaseDec", "BaseHex", "BaseHexUpper"};
93 struct Base
<BaseE::Binary
> {
94 static constexpr const char* fmt
= "b";
98 struct Base
<BaseE::Octal
> {
99 static constexpr const char* fmt
= "o";
103 struct Base
<BaseE::Decimal
> {
104 static constexpr const char* fmt
= "d";
108 struct Base
<BaseE::Hex
> {
109 static constexpr const char* fmt
= "x";
113 struct Base
<BaseE::HexUpper
> {
114 static constexpr const char* fmt
= "X";
118 enum class TypeE
{ Int64
, Uint64
};
119 struct AllTypes
: EnumValuesAsTuple
<AllTypes
, TypeE
, 2> {
120 static constexpr const char* Names
[] = {"Int64", "Uint64"};
127 struct Type
<TypeE::Int64
> {
128 using type
= int64_t;
130 static std::array
<type
, 1000> make_data() { return generate
<type
>(); }
134 struct Type
<TypeE::Uint64
> {
135 using type
= uint64_t;
137 static std::array
<type
, 1000> make_data() { return generate
<type
>(); }
141 enum class AlignmentE
{ None
, Left
, Center
, Right
, ZeroPadding
};
142 struct AllAlignments
: EnumValuesAsTuple
<AllAlignments
, AlignmentE
, 5> {
143 static constexpr const char* Names
[] = {
144 "AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight", "ZeroPadding"};
147 template <AlignmentE E
>
151 struct Alignment
<AlignmentE::None
> {
152 static constexpr const char* fmt
= "";
156 struct Alignment
<AlignmentE::Left
> {
157 static constexpr const char* fmt
= "0<512";
161 struct Alignment
<AlignmentE::Center
> {
162 static constexpr const char* fmt
= "0^512";
166 struct Alignment
<AlignmentE::Right
> {
167 static constexpr const char* fmt
= "0>512";
171 struct Alignment
<AlignmentE::ZeroPadding
> {
172 static constexpr const char* fmt
= "0512";
175 template <class L
, class B
, class T
, class A
>
177 void run(benchmark::State
& state
) const {
178 std::array data
{Type
<T::value
>::make_data()};
179 std::array
<char, 512> output
;
181 while (state
.KeepRunningBatch(data
.size()))
182 for (auto value
: data
)
183 benchmark::DoNotOptimize(std::format_to(output
.begin(), std::string_view
{fmt
.data(), fmt
.size()}, value
));
186 std::string
name() const { return "Integral" + L::name() + B::name() + A::name() + T::name(); }
188 static constexpr std::string
make_fmt() {
189 return std::string("{:") + Alignment
<A::value
>::fmt
+ Localization
<L::value
>::fmt
+ Base
<B::value
>::fmt
+ "}";
192 static constexpr auto fmt
= []() {
193 constexpr size_t s
= make_fmt().size();
194 std::array
<char, s
> r
;
195 std::ranges::copy(make_fmt(), r
.begin());
200 int main(int argc
, char** argv
) {
201 benchmark::Initialize(&argc
, argv
);
202 if (benchmark::ReportUnrecognizedArguments(argc
, argv
))
205 makeCartesianProductBenchmark
<Integral
, AllLocalizations
, AllBases
, AllTypes
, AllAlignments
>();
207 benchmark::RunSpecifiedBenchmarks();