brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · 77c067e Raw
262 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710 11#include <format>12 13#include <array>14#include <bit>15#include <cmath>16#include <limits>17#include <random>18#include <string>19 20#include "../CartesianBenchmarks.h"21#include "benchmark/benchmark.h"22 23// *** Localization ***24enum class LocalizationE { False, True };25struct AllLocalizations : EnumValuesAsTuple<AllLocalizations, LocalizationE, 2> {26  static constexpr const char* Names[] = {"LocFalse", "LocTrue"};27};28 29template <LocalizationE E>30struct Localization {};31 32template <>33struct Localization<LocalizationE::False> {34  static constexpr const char* fmt = "";35};36 37template <>38struct Localization<LocalizationE::True> {39  static constexpr const char* fmt = "L";40};41 42// *** Types ***43enum class TypeE { Float, Double, LongDouble };44// TODO FMT Set to 3 after to_chars has long double suport.45struct AllTypes : EnumValuesAsTuple<AllTypes, TypeE, 2> {46  static constexpr const char* Names[] = {"Float", "Double", "LongDouble"};47};48 49template <TypeE E>50struct Type {};51 52template <>53struct Type<TypeE::Float> {54  using type = float;55};56 57template <>58struct Type<TypeE::Double> {59  using type = double;60};61 62template <>63struct Type<TypeE::LongDouble> {64  using type = long double;65};66 67// *** Values ***68enum class ValueE { Inf, Random };69struct AllValues : EnumValuesAsTuple<AllValues, ValueE, 2> {70  static constexpr const char* Names[] = {"Inf", "Random"};71};72 73template <ValueE E>74struct Value {};75 76template <>77struct Value<ValueE::Inf> {78  template <class F>79  static std::array<F, 1000> make_data() {80    std::array<F, 1000> result;81    std::fill(result.begin(), result.end(), -std::numeric_limits<F>::infinity());82    return result;83  }84};85 86template <>87struct Value<ValueE::Random> {88  template <class F>89  static std::array<F, 1000> make_data() {90    std::random_device seed;91    std::mt19937 generator(seed());92    std::uniform_int_distribution<std::conditional_t<sizeof(F) == sizeof(uint32_t), uint32_t, uint64_t>> distribution;93 94    std::array<F, 1000> result;95    std::generate(result.begin(), result.end(), [&] {96      while (true) {97        auto val = std::bit_cast<F>(distribution(generator));98        if (std::isfinite(val))99          return val;100      }101    });102    return result;103  }104};105 106// *** Display Type ***107enum class DisplayTypeE {108  Default,109  Hex,110  Scientific,111  Fixed,112  General,113};114struct AllDisplayTypes : EnumValuesAsTuple<AllDisplayTypes, DisplayTypeE, 5> {115  static constexpr const char* Names[] = {116      "DisplayDefault", "DisplayHex", "DisplayScientific", "DisplayFixed", "DisplayGeneral"};117};118 119template <DisplayTypeE E>120struct DisplayType {};121 122template <>123struct DisplayType<DisplayTypeE::Default> {124  static constexpr const char* fmt = "";125};126 127template <>128struct DisplayType<DisplayTypeE::Hex> {129  static constexpr const char* fmt = "a";130};131 132template <>133struct DisplayType<DisplayTypeE::Scientific> {134  static constexpr const char* fmt = "e";135};136 137template <>138struct DisplayType<DisplayTypeE::Fixed> {139  static constexpr const char* fmt = "f";140};141 142template <>143struct DisplayType<DisplayTypeE::General> {144  static constexpr const char* fmt = "g";145};146 147// *** Alignment ***148enum class AlignmentE { None, Left, Center, Right, ZeroPadding };149struct AllAlignments : EnumValuesAsTuple<AllAlignments, AlignmentE, 5> {150  static constexpr const char* Names[] = {151      "AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight", "ZeroPadding"};152};153 154template <AlignmentE E>155struct Alignment {};156 157template <>158struct Alignment<AlignmentE::None> {159  static constexpr const char* fmt = "";160};161 162template <>163struct Alignment<AlignmentE::Left> {164  // Width > PrecisionE::Huge165  static constexpr const char* fmt = "0<17500";166};167 168template <>169struct Alignment<AlignmentE::Center> {170  // Width > PrecisionE::Huge171  static constexpr const char* fmt = "0^17500";172};173 174template <>175struct Alignment<AlignmentE::Right> {176  // Width > PrecisionE::Huge177  static constexpr const char* fmt = "0>17500";178};179 180template <>181struct Alignment<AlignmentE::ZeroPadding> {182  // Width > PrecisionE::Huge183  static constexpr const char* fmt = "017500";184};185 186enum class PrecisionE { None, Zero, Small, Huge };187struct AllPrecisions : EnumValuesAsTuple<AllPrecisions, PrecisionE, 4> {188  static constexpr const char* Names[] = {"PrecNone", "PrecZero", "PrecSmall", "PrecHuge"};189};190 191template <PrecisionE E>192struct Precision {};193 194template <>195struct Precision<PrecisionE::None> {196  static constexpr const char* fmt = "";197};198 199template <>200struct Precision<PrecisionE::Zero> {201  static constexpr const char* fmt = ".0";202};203 204template <>205struct Precision<PrecisionE::Small> {206  static constexpr const char* fmt = ".10";207};208 209template <>210struct Precision<PrecisionE::Huge> {211  // The maximum precision for a minimal sub normal long double is +/- 0x1p-16494.212  // This value is always larger than that value forcing the trailing zero path213  // to be executed.214  static constexpr const char* fmt = ".17000";215};216 217template <class L, class DT, class T, class V, class A, class P>218struct FloatingPoint {219  using F = typename Type<T::value>::type;220 221  void run(benchmark::State& state) const {222    std::array<F, 1000> data{Value<V::value>::template make_data<F>()};223    std::array<char, 20'000> output;224 225    while (state.KeepRunningBatch(1000))226      for (F value : data)227        benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value));228  }229 230  std::string name() const {231    return "FloatingPoint" + L::name() + DT::name() + T::name() + V::name() + A::name() + P::name();232  }233 234  static constexpr std::string make_fmt() {235    return std::string("{:") + Alignment<A::value>::fmt + Precision<P::value>::fmt + Localization<L::value>::fmt +236           DisplayType<DT::value>::fmt + "}";237  }238 239  static constexpr auto fmt = []() {240    constexpr size_t s = make_fmt().size();241    std::array<char, s> r;242    std::ranges::copy(make_fmt(), r.begin());243    return r;244  }();245};246 247int main(int argc, char** argv) {248  benchmark::Initialize(&argc, argv);249  if (benchmark::ReportUnrecognizedArguments(argc, argv))250    return 1;251 252  makeCartesianProductBenchmark<FloatingPoint,253                                AllLocalizations,254                                AllDisplayTypes,255                                AllTypes,256                                AllValues,257                                AllAlignments,258                                AllPrecisions>();259 260  benchmark::RunSpecifiedBenchmarks();261}262