30#ifndef ANKERL_NANOBENCH_H_INCLUDED 
   31#define ANKERL_NANOBENCH_H_INCLUDED 
   34#define ANKERL_NANOBENCH_VERSION_MAJOR 4   
   35#define ANKERL_NANOBENCH_VERSION_MINOR 3   
   36#define ANKERL_NANOBENCH_VERSION_PATCH 11  
   46#include <unordered_map>  
   49#define ANKERL_NANOBENCH(x) ANKERL_NANOBENCH_PRIVATE_##x() 
   51#define ANKERL_NANOBENCH_PRIVATE_CXX() __cplusplus 
   52#define ANKERL_NANOBENCH_PRIVATE_CXX98() 199711L 
   53#define ANKERL_NANOBENCH_PRIVATE_CXX11() 201103L 
   54#define ANKERL_NANOBENCH_PRIVATE_CXX14() 201402L 
   55#define ANKERL_NANOBENCH_PRIVATE_CXX17() 201703L 
   57#if ANKERL_NANOBENCH(CXX) >= ANKERL_NANOBENCH(CXX17) 
   58#    define ANKERL_NANOBENCH_PRIVATE_NODISCARD() [[nodiscard]] 
   60#    define ANKERL_NANOBENCH_PRIVATE_NODISCARD() 
   64#    define ANKERL_NANOBENCH_PRIVATE_IGNORE_PADDED_PUSH() \ 
   65        _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wpadded\"")
 
   66#    define ANKERL_NANOBENCH_PRIVATE_IGNORE_PADDED_POP() _Pragma("clang diagnostic pop")
 
   68#    define ANKERL_NANOBENCH_PRIVATE_IGNORE_PADDED_PUSH() 
   69#    define ANKERL_NANOBENCH_PRIVATE_IGNORE_PADDED_POP() 
   73#    define ANKERL_NANOBENCH_PRIVATE_IGNORE_EFFCPP_PUSH() _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Weffc++\"")
 
   74#    define ANKERL_NANOBENCH_PRIVATE_IGNORE_EFFCPP_POP() _Pragma("GCC diagnostic pop")
 
   76#    define ANKERL_NANOBENCH_PRIVATE_IGNORE_EFFCPP_PUSH() 
   77#    define ANKERL_NANOBENCH_PRIVATE_IGNORE_EFFCPP_POP() 
   80#if defined(ANKERL_NANOBENCH_LOG_ENABLED) 
   82#    define ANKERL_NANOBENCH_LOG(x)                                                 \ 
   84            std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << x << std::endl; \
 
   87#    define ANKERL_NANOBENCH_LOG(x) \ 
   92#define ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS() 0 
   93#if defined(__linux__) && !defined(ANKERL_NANOBENCH_DISABLE_PERF_COUNTERS) 
   94#    include <linux/version.h> 
   95#    if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) 
   98#        undef ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS 
   99#        define ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS() 1 
  103#if defined(__clang__) 
  104#    define ANKERL_NANOBENCH_NO_SANITIZE(...) __attribute__((no_sanitize(__VA_ARGS__))) 
  106#    define ANKERL_NANOBENCH_NO_SANITIZE(...) 
  110#    define ANKERL_NANOBENCH_PRIVATE_NOINLINE() __declspec(noinline) 
  112#    define ANKERL_NANOBENCH_PRIVATE_NOINLINE() __attribute__((noinline)) 
  117#if defined(__GNUC__) && __GNUC__ < 5 
  118#    define ANKERL_NANOBENCH_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__) 
  120#    define ANKERL_NANOBENCH_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value 
  125#define ANKERL_NANOBENCH_PRIVATE_NOEXCEPT_STRING_MOVE() std::is_nothrow_move_assignable<std::string>::value 
  132using Clock = std::conditional<std::chrono::high_resolution_clock::is_steady, std::chrono::high_resolution_clock,
 
  133                               std::chrono::steady_clock>::type;
 
  291void render(std::string 
const& mustacheTemplate, 
Bench const& bench, std::ostream& 
out);
 
  301void render(
char const* mustacheTemplate, std::vector<Result> 
const& results, std::ostream& 
out);
 
  302void render(std::string 
const& mustacheTemplate, std::vector<Result> 
const& results, std::ostream& 
out);
 
  316char const* 
csv() noexcept;
 
  359#if ANKERL_NANOBENCH(PERF_COUNTERS) 
  360class LinuxPerformanceCounters;
 
  388    std::string mBenchmarkTitle = 
"benchmark";                               
 
  389    std::string mBenchmarkName = 
"noname";                                   
 
  390    std::string mUnit = 
"op";                                                
 
  392    double mComplexityN = -1.0;                                              
 
  393    size_t mNumEpochs = 11;                                                  
 
  394    size_t mClockResolutionMultiple = 
static_cast<size_t>(1000);             
 
  395    std::chrono::nanoseconds mMaxEpochTime = std::chrono::milliseconds(100); 
 
  396    std::chrono::nanoseconds mMinEpochTime = std::chrono::milliseconds(1);   
 
  397    uint64_t mMinEpochIterations{1};                                         
 
  399    uint64_t mEpochIterations{0};                                          
 
  400    uint64_t mWarmup = 0;                                                  
 
  401    std::ostream* mOut = 
nullptr;                                          
 
  402    std::chrono::duration<double> mTimeUnit = std::chrono::nanoseconds{1}; 
 
  403    std::string mTimeUnitName = 
"ns";                                      
 
  404    bool mShowPerformanceCounters = 
true;                                  
 
  405    bool mIsRelative = 
false;                                              
 
  406    std::unordered_map<std::string, std::string> mContext{};               
 
  467    std::vector<std::vector<double>> mNameToMeasurements{};
 
  495    static constexpr uint64_t(min)();
 
  496    static constexpr uint64_t(max)();
 
  512    Rng& operator=(
Rng&&) noexcept = default;
 
  513    ~
Rng() noexcept = default;
 
  540    explicit 
Rng(uint64_t seed) noexcept;
 
  541    Rng(uint64_t x, uint64_t y) noexcept;
 
  556    inline uint64_t operator()() noexcept;
 
  574    inline uint32_t bounded(uint32_t range) noexcept;
 
  585    inline 
double uniform01() noexcept;
 
  594    template <typename Container>
 
  595    void shuffle(Container& container) noexcept;
 
  606    static constexpr uint64_t 
rotl(uint64_t x, 
unsigned k) noexcept;
 
  658    template <typename Op>
 
  660    Bench& run(
char const* benchmarkName, Op&& op);
 
  662    template <typename Op>
 
  664    Bench& run(
std::
string const& benchmarkName, Op&& op);
 
  670    template <typename Op>
 
  679    Bench& title(
char const* benchmarkTitle);
 
  704    Bench& context(
char const* variableName, 
char const* variableValue);
 
  705    Bench& context(
std::
string const& variableName, 
std::
string const& variableValue);
 
  726    template <typename T>
 
  727    Bench& batch(T b) noexcept;
 
  751    Bench& timeUnit(
std::chrono::duration<
double> const& tu, 
std::
string const& tuName);
 
  753    ANKERL_NANOBENCH(NODISCARD) 
std::chrono::duration<
double> const& timeUnit() const noexcept;
 
  785    Bench& clockResolutionMultiple(
size_t multiple) noexcept;
 
  803    Bench& epochs(
size_t numEpochs) noexcept;
 
  816    Bench& maxEpochTime(
std::chrono::nanoseconds t) noexcept;
 
  829    Bench& minEpochTime(
std::chrono::nanoseconds t) noexcept;
 
  842    Bench& minEpochIterations(uint64_t numIters) noexcept;
 
  851    Bench& epochIterations(uint64_t numIters) noexcept;
 
  863    Bench& warmup(uint64_t numWarmupIters) noexcept;
 
  883    Bench& relative(
bool isRelativeEnabled) noexcept;
 
  914    template <typename Arg>
 
  931    template <typename T>
 
  932    Bench& complexityN(T n) noexcept;
 
  991    template <typename Op>
 
  992    BigO complexityBigO(
char const* 
name, Op op) const;
 
  994    template <typename Op>
 
  995    BigO complexityBigO(
std::
string const& 
name, Op op) const;
 
 1012    std::vector<Result> mResults{};
 
 1022template <
typename Arg>
 
 1027#if defined(_MSC_VER) 
 1028void doNotOptimizeAwaySink(
void const*);
 
 1030template <
typename T>
 
 1038template <
typename T>
 
 1041    asm volatile(
"" : : 
"r,m"(val) : 
"memory");
 
 1044template <
typename T>
 
 1046#    if defined(__clang__) 
 1048    asm volatile(
"" : 
"+r,m"(val) : : 
"memory");
 
 1051    asm volatile(
"" : 
"+m,r"(val) : : 
"memory");
 
 1098#if ANKERL_NANOBENCH(PERF_COUNTERS) 
 1099    LinuxPerformanceCounters* mPc = 
nullptr;
 
 1115    template <
typename Op>
 
 1117        for (
auto& rangeMeasure : 
data) {
 
 1118            rangeMeasure.first = op(rangeMeasure.first);
 
 1125    template <
typename Op>
 
 1127        : 
BigO(bigOName, mapRangeMeasure(rangeMeasure, rangeToN)) {}
 
 1129    template <
typename Op>
 
 1131        : 
BigO(
std::move(bigOName), mapRangeMeasure(rangeMeasure, rangeToN)) {}
 
 1143    double mNormalizedRootMeanSquare{};
 
 1146std::ostream& 
operator<<(std::ostream& os, std::vector<ankerl::nanobench::BigO> 
const& bigOs);
 
 1154namespace nanobench {
 
 1161    return (std::numeric_limits<uint64_t>::max)();
 
 1165uint64_t 
Rng::operator()() noexcept {
 
 1168    mX = UINT64_C(15241094284759029579) * mY;
 
 1169    mY = 
rotl(mY - x, 27);
 
 1175uint32_t 
Rng::bounded(uint32_t range) noexcept {
 
 1176    uint64_t 
const r32 = 
static_cast<uint32_t
>(operator()());
 
 1177    auto multiresult = r32 * range;
 
 1178    return static_cast<uint32_t
>(multiresult >> 32U);
 
 1182    auto i = (UINT64_C(0x3ff) << 52U) | (
operator()() >> 12U);
 
 1186    std::memcpy(&d, &i, 
sizeof(
double));
 
 1190template <
typename Container>
 
 1192    auto i = container.size();
 
 1195        auto n = operator()();
 
 1197        auto b1 = 
static_cast<decltype(i)
>((
static_cast<uint32_t
>(n) * 
static_cast<uint64_t
>(i)) >> 32U);
 
 1198        swap(container[--i], container[b1]);
 
 1200        auto b2 = 
static_cast<decltype(i)
>(((n >> 32U) * 
static_cast<uint64_t
>(i)) >> 32U);
 
 1201        swap(container[--i], container[b2]);
 
 1206constexpr uint64_t 
Rng::
rotl(uint64_t x, 
unsigned k) noexcept {
 
 1207    return (x << 
k) | (x >> (64U - 
k));
 
 1210template <
typename Op>
 
 1217    while (
auto n = iterationLogic.numIters()) {
 
 1219        Clock::time_point 
const before = Clock::now();
 
 1223        Clock::time_point 
const after = Clock::now();
 
 1225        pc.updateResults(iterationLogic.numIters());
 
 1226        iterationLogic.
add(after - before, pc);
 
 1233template <
typename Op>
 
 1235    name(benchmarkName);
 
 1236    return run(std::forward<Op>(op));
 
 1239template <
typename Op>
 
 1241    name(benchmarkName);
 
 1242    return run(std::forward<Op>(op));
 
 1245template <
typename Op>
 
 1250template <
typename Op>
 
 1257template <
typename T>
 
 1259    mConfig.mBatch = 
static_cast<double>(b);
 
 1264template <
typename T>
 
 1266    mConfig.mComplexityN = 
static_cast<double>(n);
 
 1271template <
typename Arg>
 
 1278template <
typename Arg>
 
 1285#if defined(_MSC_VER) 
 1286template <
typename T>
 
 1288    doNotOptimizeAwaySink(&val);
 
 1297#if defined(ANKERL_NANOBENCH_IMPLEMENT) 
 1303#    include <algorithm>  
 1313#    include <stdexcept>  
 1315#    if defined(__linux__) 
 1318#    if ANKERL_NANOBENCH(PERF_COUNTERS) 
 1321#        include <linux/perf_event.h> 
 1322#        include <sys/ioctl.h> 
 1323#        include <sys/syscall.h> 
 1329namespace nanobench {
 
 1340class StreamStateRestorer;
 
 1342class MarkDownColumn;
 
 1353namespace nanobench {
 
 1355uint64_t splitMix64(uint64_t& state) 
noexcept;
 
 1360template <
typename T>
 
 1361inline double d(T t) 
noexcept {
 
 1362    return static_cast<double>(
t);
 
 1364inline double d(Clock::duration duration) 
noexcept {
 
 1365    return std::chrono::duration_cast<std::chrono::duration<double>>(duration).
count();
 
 1369inline Clock::duration clockResolution() noexcept;
 
 1373namespace templates {
 
 1375char const* 
csv() noexcept {
 
 1376    return R
"DELIM("title";"name";"unit";"batch";"elapsed";"error %";"instructions";"branches";"branch misses";"total" 
 1377{{#result}}"{{title}}";"{{name}}";"{{unit}}";{{batch}};{{median(elapsed)}};{{medianAbsolutePercentError(elapsed)}};{{median(instructions)}};{{median(branchinstructions)}};{{median(branchmisses)}};{{sumProduct(iterations, elapsed)}} 
 1382    return R
"DELIM(<html> 
 1385    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> 
 1389    <div id="myDiv"></div> 
 1394                y: [{{#measurement}}{{elapsed}}{{^-last}}, {{/last}}{{/measurement}}], 
 1398        var title = '{{title}}'; 
 1400        data = data.map(a => Object.assign(a, { boxpoints: 'all', pointpos: 0, type: 'box' })); 
 1401        var layout = { title: { text: title }, showlegend: false, yaxis: { title: 'time per unit', rangemode: 'tozero', autorange: true } }; Plotly.newPlot('myDiv', data, layout, {responsive: true}); 
 1408char const* 
pyperf() noexcept {
 
 1415{{#measurement}}                        {{elapsed}}{{^-last}}, 
 1416{{/last}}{{/measurement}} 
 1423        "loops": {{sum(iterations)}}, 
 1424        "inner_loops": {{batch}}, 
 1425        "name": "{{title}}", 
 1432char const* 
json() noexcept {
 
 1436            "title": "{{title}}", 
 1440            "complexityN": {{complexityN}}, 
 1441            "epochs": {{epochs}}, 
 1442            "clockResolution": {{clockResolution}}, 
 1443            "clockResolutionMultiple": {{clockResolutionMultiple}}, 
 1444            "maxEpochTime": {{maxEpochTime}}, 
 1445            "minEpochTime": {{minEpochTime}}, 
 1446            "minEpochIterations": {{minEpochIterations}}, 
 1447            "epochIterations": {{epochIterations}}, 
 1448            "warmup": {{warmup}}, 
 1449            "relative": {{relative}}, 
 1450            "median(elapsed)": {{median(elapsed)}}, 
 1451            "medianAbsolutePercentError(elapsed)": {{medianAbsolutePercentError(elapsed)}}, 
 1452            "median(instructions)": {{median(instructions)}}, 
 1453            "medianAbsolutePercentError(instructions)": {{medianAbsolutePercentError(instructions)}}, 
 1454            "median(cpucycles)": {{median(cpucycles)}}, 
 1455            "median(contextswitches)": {{median(contextswitches)}}, 
 1456            "median(pagefaults)": {{median(pagefaults)}}, 
 1457            "median(branchinstructions)": {{median(branchinstructions)}}, 
 1458            "median(branchmisses)": {{median(branchmisses)}}, 
 1459            "totalTime": {{sumProduct(iterations, elapsed)}}, 
 1462                    "iterations": {{iterations}}, 
 1463                    "elapsed": {{elapsed}}, 
 1464                    "pagefaults": {{pagefaults}}, 
 1465                    "cpucycles": {{cpucycles}}, 
 1466                    "contextswitches": {{contextswitches}}, 
 1467                    "instructions": {{instructions}}, 
 1468                    "branchinstructions": {{branchinstructions}}, 
 1469                    "branchmisses": {{branchmisses}} 
 1470                }{{^-last}},{{/-last}} 
 1472        }{{^-last}},{{/-last}} 
 1479    enum class Type { tag, content, section, inverted_section };
 
 1483    std::vector<Node> children;
 
 1488    bool operator==(
char const (&str)[N]) 
const noexcept {
 
 1490        return static_cast<size_t>(std::distance(begin, end) + 1) == N && 0 == strncmp(str, begin, N - 1);
 
 1496static std::vector<Node> parseMustacheTemplate(
char const** tpl) {
 
 1497    std::vector<Node> nodes;
 
 1500        auto const* begin = std::strstr(*tpl, 
"{{");
 
 1501        auto const* end = begin;
 
 1502        if (begin != 
nullptr) {
 
 1505            end = std::strstr(begin, 
"}}");
 
 1508        if (begin == 
nullptr || end == 
nullptr) {
 
 1511            nodes.emplace_back(Node{*tpl, *tpl + std::strlen(*tpl), std::vector<Node>{}, Node::Type::content});
 
 1516        nodes.emplace_back(Node{*tpl, begin - 2, std::vector<Node>{}, Node::Type::content});
 
 1528            nodes.emplace_back(Node{begin + 1, end, parseMustacheTemplate(tpl), Node::Type::section});
 
 1533            nodes.emplace_back(Node{begin + 1, end, parseMustacheTemplate(tpl), Node::Type::inverted_section});
 
 1537            nodes.emplace_back(Node{begin, end, std::vector<Node>{}, Node::Type::tag});
 
 1543static bool generateFirstLast(Node 
const& n, 
size_t idx, 
size_t size, std::ostream& 
out) {
 
 1545    bool const matchFirst = n == 
"-first";
 
 1546    bool const matchLast = n == 
"-last";
 
 1547    if (!matchFirst && !matchLast) {
 
 1551    bool doWrite = 
false;
 
 1552    if (n.type == Node::Type::section) {
 
 1553        doWrite = (matchFirst && idx == 0) || (matchLast && idx == size - 1);
 
 1554    } 
else if (n.type == Node::Type::inverted_section) {
 
 1555        doWrite = (matchFirst && idx != 0) || (matchLast && idx != size - 1);
 
 1559        for (
auto const& child : n.children) {
 
 1560            if (child.type == Node::Type::content) {
 
 1561                out.write(child.begin, std::distance(child.begin, child.end));
 
 1568static bool matchCmdArgs(std::string 
const& str, std::vector<std::string>& matchResult) {
 
 1569    matchResult.clear();
 
 1570    auto idxOpen = str.find(
'(');
 
 1571    auto idxClose = str.find(
')', idxOpen);
 
 1572    if (idxClose == std::string::npos) {
 
 1576    matchResult.emplace_back(str.substr(0, idxOpen));
 
 1579    matchResult.emplace_back();
 
 1580    for (
size_t i = idxOpen + 1; i != idxClose; ++i) {
 
 1581        if (str[i] == 
' ' || str[i] == 
'\t') {
 
 1585        if (str[i] == 
',') {
 
 1587            matchResult.emplace_back();
 
 1591        matchResult.back() += str[i];
 
 1596static bool generateConfigTag(Node 
const& n, Config 
const& config, std::ostream& 
out) {
 
 1600        out << config.mBenchmarkTitle;
 
 1604        out << config.mBenchmarkName;
 
 1608        out << config.mUnit;
 
 1612        out << config.mBatch;
 
 1615    if (n == 
"complexityN") {
 
 1616        out << config.mComplexityN;
 
 1619    if (n == 
"epochs") {
 
 1620        out << config.mNumEpochs;
 
 1623    if (n == 
"clockResolution") {
 
 1624        out << d(detail::clockResolution());
 
 1627    if (n == 
"clockResolutionMultiple") {
 
 1628        out << config.mClockResolutionMultiple;
 
 1631    if (n == 
"maxEpochTime") {
 
 1632        out << d(config.mMaxEpochTime);
 
 1635    if (n == 
"minEpochTime") {
 
 1636        out << d(config.mMinEpochTime);
 
 1639    if (n == 
"minEpochIterations") {
 
 1640        out << config.mMinEpochIterations;
 
 1643    if (n == 
"epochIterations") {
 
 1644        out << config.mEpochIterations;
 
 1647    if (n == 
"warmup") {
 
 1648        out << config.mWarmup;
 
 1651    if (n == 
"relative") {
 
 1652        out << config.mIsRelative;
 
 1659static std::ostream& generateResultTag(Node 
const& n, 
Result const& r, std::ostream& 
out) {
 
 1660    if (generateConfigTag(n, r.config(), 
out)) {
 
 1668    std::vector<std::string> matchResult;
 
 1669    if (matchCmdArgs(std::string(n.begin, n.end), matchResult)) {
 
 1670        if (matchResult.size() == 2) {
 
 1671            if (matchResult[0] == 
"context") {
 
 1672                return out << r.context(matchResult[1]);
 
 1680            if (matchResult[0] == 
"median") {
 
 1681                return out << r.median(m);
 
 1683            if (matchResult[0] == 
"average") {
 
 1684                return out << r.average(m);
 
 1686            if (matchResult[0] == 
"medianAbsolutePercentError") {
 
 1687                return out << r.medianAbsolutePercentError(m);
 
 1689            if (matchResult[0] == 
"sum") {
 
 1690                return out << r.sum(m);
 
 1692            if (matchResult[0] == 
"minimum") {
 
 1693                return out << r.minimum(m);
 
 1695            if (matchResult[0] == 
"maximum") {
 
 1696                return out << r.maximum(m);
 
 1698        } 
else if (matchResult.size() == 3) {
 
 1705            if (matchResult[0] == 
"sumProduct") {
 
 1706                return out << r.sumProduct(m1, m2);
 
 1715    throw std::runtime_error(
"command '" + std::string(n.begin, n.end) + 
"' not understood");
 
 1718static void generateResultMeasurement(std::vector<Node> 
const& nodes, 
size_t idx, 
Result const& r, std::ostream& 
out) {
 
 1719    for (
auto const& n : nodes) {
 
 1720        if (!generateFirstLast(n, idx, r.size(), 
out)) {
 
 1723            case Node::Type::content:
 
 1724                out.write(n.begin, std::distance(n.begin, n.end));
 
 1727            case Node::Type::inverted_section:
 
 1728                throw std::runtime_error(
"got a inverted section inside measurement");
 
 1730            case Node::Type::section:
 
 1731                throw std::runtime_error(
"got a section inside measurement");
 
 1733            case Node::Type::tag: {
 
 1738                    out << r.get(idx, m);
 
 1747static void generateResult(std::vector<Node> 
const& nodes, 
size_t idx, std::vector<Result> 
const& results, std::ostream& 
out) {
 
 1748    auto const& r = results[idx];
 
 1749    for (
auto const& n : nodes) {
 
 1750        if (!generateFirstLast(n, idx, results.size(), 
out)) {
 
 1753            case Node::Type::content:
 
 1754                out.write(n.begin, std::distance(n.begin, n.end));
 
 1757            case Node::Type::inverted_section:
 
 1758                throw std::runtime_error(
"got a inverted section inside result");
 
 1760            case Node::Type::section:
 
 1761                if (n == 
"measurement") {
 
 1762                    for (
size_t i = 0; i < r.size(); ++i) {
 
 1763                        generateResultMeasurement(n.children, i, r, 
out);
 
 1766                    throw std::runtime_error(
"got a section inside result");
 
 1770            case Node::Type::tag:
 
 1771                generateResultTag(n, r, 
out);
 
 1783char const* getEnv(
char const* 
name);
 
 1784bool isEndlessRunning(std::string 
const& 
name);
 
 1785bool isWarningsEnabled();
 
 1787template <
typename T>
 
 1788T parseFile(std::string 
const& filename, 
bool* fail);
 
 1790void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<std::string>& recommendations);
 
 1791void printStabilityInformationOnce(std::ostream* outStream);
 
 1794uint64_t& singletonHeaderHash() noexcept;
 
 1797Clock::duration calcClockResolution(
size_t numEvaluations) noexcept;
 
 1804class NumSep : 
public std::numpunct<char> {
 
 1806    explicit NumSep(
char sep);
 
 1807    char do_thousands_sep() 
const override;
 
 1808    std::string do_grouping() 
const override;
 
 1817class StreamStateRestorer {
 
 1819    explicit StreamStateRestorer(std::ostream& 
s);
 
 1820    ~StreamStateRestorer();
 
 1826    StreamStateRestorer(StreamStateRestorer 
const&) = 
delete;
 
 1827    StreamStateRestorer& operator=(StreamStateRestorer 
const&) = 
delete;
 
 1828    StreamStateRestorer(StreamStateRestorer&&) = 
delete;
 
 1829    StreamStateRestorer& operator=(StreamStateRestorer&&) = 
delete;
 
 1832    std::ostream& mStream;
 
 1833    std::locale mLocale;
 
 1834    std::streamsize 
const mPrecision;
 
 1835    std::streamsize 
const mWidth;
 
 1836    std::ostream::char_type 
const mFill;
 
 1837    std::ostream::fmtflags 
const mFmtFlags;
 
 1844    Number(
int width, 
int precision, 
double value);
 
 1845    Number(
int width, 
int precision, int64_t value);
 
 1849    friend std::ostream& 
operator<<(std::ostream& os, Number 
const& n);
 
 1850    std::ostream& write(std::ostream& os) 
const;
 
 1858std::string to_s(uint64_t n);
 
 1860std::ostream& 
operator<<(std::ostream& os, Number 
const& n);
 
 1862class MarkDownColumn {
 
 1864    MarkDownColumn(
int w, 
int prec, std::string tit, std::string suff, 
double val) 
noexcept;
 
 1874    std::string mSuffix;
 
 1881    explicit MarkDownCode(std::string 
const& what);
 
 1884    friend std::ostream& 
operator<<(std::ostream& os, MarkDownCode 
const& mdCode);
 
 1885    std::ostream& write(std::ostream& os) 
const;
 
 1887    std::string mWhat{};
 
 1890std::ostream& 
operator<<(std::ostream& os, MarkDownCode 
const& mdCode);
 
 1900namespace nanobench {
 
 1903void render(
char const* mustacheTemplate, std::vector<Result> 
const& results, std::ostream& 
out) {
 
 1904    detail::fmt::StreamStateRestorer 
const restorer(
out);
 
 1906    out.precision(std::numeric_limits<double>::digits10);
 
 1907    auto nodes = templates::parseMustacheTemplate(&mustacheTemplate);
 
 1909    for (
auto const& n : nodes) {
 
 1912        case templates::Node::Type::content:
 
 1913            out.write(n.begin, std::distance(n.begin, n.end));
 
 1916        case templates::Node::Type::inverted_section:
 
 1917            throw std::runtime_error(
"unknown list '" + std::string(n.begin, n.end) + 
"'");
 
 1919        case templates::Node::Type::section:
 
 1920            if (n == 
"result") {
 
 1921                const size_t nbResults = results.size();
 
 1922                for (
size_t i = 0; i < nbResults; ++i) {
 
 1923                    generateResult(n.children, i, results, 
out);
 
 1925            } 
else if (n == 
"measurement") {
 
 1926                if (results.size() != 1) {
 
 1927                    throw std::runtime_error(
 
 1928                        "render: can only use section 'measurement' here if there is a single result, but there are " +
 
 1929                        detail::fmt::to_s(results.size()));
 
 1932                auto const& r = results.front();
 
 1933                for (
size_t i = 0; i < r.size(); ++i) {
 
 1934                    generateResultMeasurement(n.children, i, r, 
out);
 
 1937                throw std::runtime_error(
"render: unknown section '" + std::string(n.begin, n.end) + 
"'");
 
 1941        case templates::Node::Type::tag:
 
 1942            if (results.size() == 1) {
 
 1944                generateResultTag(n, results.front(), 
out);
 
 1947                if (!generateConfigTag(n, results.back().config(), 
out)) {
 
 1948                    throw std::runtime_error(
"unknown tag '" + std::string(n.begin, n.end) + 
"'");
 
 1956void render(std::string 
const& mustacheTemplate, std::vector<Result> 
const& results, std::ostream& 
out) {
 
 1957    render(mustacheTemplate.c_str(), results, 
out);
 
 1960void render(
char const* mustacheTemplate, 
const Bench& bench, std::ostream& 
out) {
 
 1961    render(mustacheTemplate, bench.results(), 
out);
 
 1964void render(std::string 
const& mustacheTemplate, 
const Bench& bench, std::ostream& 
out) {
 
 1965    render(mustacheTemplate.c_str(), bench.results(), 
out);
 
 1971#    if defined(__clang__) 
 1972#        pragma clang diagnostic push 
 1973#        pragma clang diagnostic ignored "-Wexit-time-destructors" 
 1975    static PerformanceCounters pc;
 
 1976#    if defined(__clang__) 
 1977#        pragma clang diagnostic pop 
 1986#    if defined(_MSC_VER) 
 1987#        pragma optimize("", off)
 
 1988void doNotOptimizeAwaySink(
void const*) {}
 
 1989#        pragma optimize("", on)
 
 1992template <
typename T>
 
 1993T parseFile(std::string 
const& filename, 
bool* fail) {
 
 1994    std::ifstream fin(filename); 
 
 1997    if (fail != 
nullptr) {
 
 2003char const* getEnv(
char const* 
name) {
 
 2004#    if defined(_MSC_VER) 
 2005#        pragma warning(push) 
 2006#        pragma warning(disable : 4996)  
 2008    return std::getenv(
name); 
 
 2009#    if defined(_MSC_VER) 
 2010#        pragma warning(pop) 
 2014bool isEndlessRunning(std::string 
const& 
name) {
 
 2015    auto const* 
const endless = getEnv(
"NANOBENCH_ENDLESS");
 
 2016    return nullptr != endless && endless == 
name;
 
 2020bool isWarningsEnabled() {
 
 2021    auto const* 
const suppression = getEnv(
"NANOBENCH_SUPPRESS_WARNINGS");
 
 2022    return nullptr == suppression || suppression == std::string(
"0");
 
 2025void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<std::string>& recommendations) {
 
 2027    recommendations.clear();
 
 2030    warnings.emplace_back(
"DEBUG defined");
 
 2031    bool const recommendCheckFlags = 
true;
 
 2033    bool const recommendCheckFlags = 
false;
 
 2036    bool recommendPyPerf = 
false;
 
 2037#    if defined(__linux__) 
 2038    auto nprocs = sysconf(_SC_NPROCESSORS_CONF);
 
 2040        warnings.emplace_back(
"couldn't figure out number of processors - no governor, turbo check possible");
 
 2043        for (
long id = 0; 
id < nprocs; ++id) {
 
 2044            auto idStr = detail::fmt::to_s(
static_cast<uint64_t
>(
id));
 
 2045            auto sysCpu = 
"/sys/devices/system/cpu/cpu" + idStr;
 
 2046            auto minFreq = parseFile<int64_t>(sysCpu + 
"/cpufreq/scaling_min_freq", 
nullptr);
 
 2047            auto maxFreq = parseFile<int64_t>(sysCpu + 
"/cpufreq/scaling_max_freq", 
nullptr);
 
 2048            if (minFreq != maxFreq) {
 
 2049                auto minMHz = d(minFreq) / 1000.0;
 
 2050                auto maxMHz = d(maxFreq) / 1000.0;
 
 2051                warnings.emplace_back(
"CPU frequency scaling enabled: CPU " + idStr + 
" between " +
 
 2052                                      detail::fmt::Number(1, 1, minMHz).to_s() + 
" and " + detail::fmt::Number(1, 1, maxMHz).to_s() +
 
 2054                recommendPyPerf = 
true;
 
 2060        auto currentGovernor = parseFile<std::string>(
"/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", &fail);
 
 2061        if (!fail && 
"performance" != currentGovernor) {
 
 2062            warnings.emplace_back(
"CPU governor is '" + currentGovernor + 
"' but should be 'performance'");
 
 2063            recommendPyPerf = 
true;
 
 2066        auto noTurbo = parseFile<int>(
"/sys/devices/system/cpu/intel_pstate/no_turbo", &fail);
 
 2067        if (!fail && noTurbo == 0) {
 
 2068            warnings.emplace_back(
"Turbo is enabled, CPU frequency will fluctuate");
 
 2069            recommendPyPerf = 
true;
 
 2074    if (recommendCheckFlags) {
 
 2075        recommendations.emplace_back(
"Make sure you compile for Release");
 
 2077    if (recommendPyPerf) {
 
 2078        recommendations.emplace_back(
"Use 'pyperf system tune' before benchmarking. See https://github.com/psf/pyperf");
 
 2082void printStabilityInformationOnce(std::ostream* outStream) {
 
 2083    static bool shouldPrint = 
true;
 
 2084    if (shouldPrint && (
nullptr != outStream) && isWarningsEnabled()) {
 
 2085        auto& os = *outStream;
 
 2086        shouldPrint = 
false;
 
 2087        std::vector<std::string> warnings;
 
 2088        std::vector<std::string> recommendations;
 
 2089        gatherStabilityInformation(warnings, recommendations);
 
 2090        if (warnings.empty()) {
 
 2094        os << 
"Warning, results might be unstable:" << std::endl;
 
 2095        for (
auto const& w : warnings) {
 
 2096            os << 
"* " << w << std::endl;
 
 2099        os << std::endl << 
"Recommendations" << std::endl;
 
 2100        for (
auto const& r : recommendations) {
 
 2101            os << 
"* " << r << std::endl;
 
 2107uint64_t& singletonHeaderHash() noexcept {
 
 2108    static uint64_t sHeaderHash{};
 
 2113inline uint64_t hash_combine(uint64_t seed, uint64_t val) {
 
 2114    return seed ^ (val + UINT64_C(0x9e3779b9) + (seed << 6U) + (seed >> 2U));
 
 2118Clock::duration calcClockResolution(
size_t numEvaluations) 
noexcept {
 
 2119    auto bestDuration = Clock::duration::max();
 
 2120    Clock::time_point tBegin;
 
 2121    Clock::time_point tEnd;
 
 2122    for (
size_t i = 0; i < numEvaluations; ++i) {
 
 2123        tBegin = Clock::now();
 
 2125            tEnd = Clock::now();
 
 2126        } 
while (tBegin == tEnd);
 
 2127        bestDuration = (std::min)(bestDuration, tEnd - tBegin);
 
 2129    return bestDuration;
 
 2133Clock::duration clockResolution() noexcept {
 
 2134    static Clock::duration 
const sResolution = calcClockResolution(20);
 
 2139struct IterationLogic::Impl {
 
 2140    enum class State { warmup, upscaling_runtime, measuring, endless };
 
 2142    explicit Impl(Bench 
const& bench)
 
 2144        , mResult(bench.config()) {
 
 2145        printStabilityInformationOnce(mBench.output());
 
 2148        mTargetRuntimePerEpoch = detail::clockResolution() * mBench.clockResolutionMultiple();
 
 2149        if (mTargetRuntimePerEpoch > mBench.maxEpochTime()) {
 
 2150            mTargetRuntimePerEpoch = mBench.maxEpochTime();
 
 2152        if (mTargetRuntimePerEpoch < mBench.minEpochTime()) {
 
 2153            mTargetRuntimePerEpoch = mBench.minEpochTime();
 
 2156        if (isEndlessRunning(mBench.name())) {
 
 2157            std::cerr << 
"NANOBENCH_ENDLESS set: running '" << mBench.name() << 
"' endlessly" << std::endl;
 
 2158            mNumIters = (std::numeric_limits<uint64_t>::max)();
 
 2159            mState = State::endless;
 
 2160        } 
else if (0 != mBench.warmup()) {
 
 2161            mNumIters = mBench.warmup();
 
 2162            mState = State::warmup;
 
 2163        } 
else if (0 != mBench.epochIterations()) {
 
 2165            mNumIters = mBench.epochIterations();
 
 2166            mState = State::measuring;
 
 2168            mNumIters = mBench.minEpochIterations();
 
 2169            mState = State::upscaling_runtime;
 
 2174    ANKERL_NANOBENCH(NODISCARD) uint64_t calcBestNumIters(std::chrono::nanoseconds elapsed, uint64_t iters) 
noexcept {
 
 2175        auto doubleElapsed = d(elapsed);
 
 2176        auto doubleTargetRuntimePerEpoch = d(mTargetRuntimePerEpoch);
 
 2177        auto doubleNewIters = doubleTargetRuntimePerEpoch / doubleElapsed * d(iters);
 
 2179        auto doubleMinEpochIters = d(mBench.minEpochIterations());
 
 2180        if (doubleNewIters < doubleMinEpochIters) {
 
 2181            doubleNewIters = doubleMinEpochIters;
 
 2183        doubleNewIters *= 1.0 + 0.2 * mRng.uniform01();
 
 2187        return static_cast<uint64_t
>(doubleNewIters + 0.5);
 
 2191        if (elapsed * 10 < mTargetRuntimePerEpoch) {
 
 2193            if (mNumIters * 10 < mNumIters) {
 
 2195                showResult(
"iterations overflow. Maybe your code got optimized away?");
 
 2201            mNumIters = calcBestNumIters(elapsed, mNumIters);
 
 2205    void add(std::chrono::nanoseconds elapsed, PerformanceCounters 
const& pc) 
noexcept {
 
 2206#    if defined(ANKERL_NANOBENCH_LOG_ENABLED) 
 2207        auto oldIters = mNumIters;
 
 2212            if (isCloseEnoughForMeasurements(elapsed)) {
 
 2215                mState = State::measuring;
 
 2216                mNumIters = calcBestNumIters(elapsed, mNumIters);
 
 2219                mState = State::upscaling_runtime;
 
 2224        case State::upscaling_runtime:
 
 2225            if (isCloseEnoughForMeasurements(elapsed)) {
 
 2227                mState = State::measuring;
 
 2228                mTotalElapsed += elapsed;
 
 2229                mTotalNumIters += mNumIters;
 
 2230                mResult.add(elapsed, mNumIters, pc);
 
 2231                mNumIters = calcBestNumIters(mTotalElapsed, mTotalNumIters);
 
 2237        case State::measuring:
 
 2240            mTotalElapsed += elapsed;
 
 2241            mTotalNumIters += mNumIters;
 
 2242            mResult.add(elapsed, mNumIters, pc);
 
 2243            if (0 != mBench.epochIterations()) {
 
 2244                mNumIters = mBench.epochIterations();
 
 2246                mNumIters = calcBestNumIters(mTotalElapsed, mTotalNumIters);
 
 2250        case State::endless:
 
 2251            mNumIters = (std::numeric_limits<uint64_t>::max)();
 
 2255        if (
static_cast<uint64_t
>(mResult.size()) == mBench.epochs()) {
 
 2261        ANKERL_NANOBENCH_LOG(mBench.name() << 
": " << detail::fmt::Number(20, 3, d(elapsed.count())) << 
" elapsed, " 
 2262                                           << detail::fmt::Number(20, 3, d(mTargetRuntimePerEpoch.count())) << 
" target. oldIters=" 
 2263                                           << oldIters << 
", mNumIters=" << mNumIters << 
", mState=" << 
static_cast<int>(mState));
 
 2267    void showResult(std::string 
const& errorMessage)
 const {
 
 2270        if (mBench.output() != 
nullptr) {
 
 2272            std::vector<fmt::MarkDownColumn> columns;
 
 2276            if (mBench.relative()) {
 
 2278                if (!mBench.results().empty()) {
 
 2281                columns.emplace_back(11, 1, 
"relative", 
"%", d);
 
 2284            if (mBench.complexityN() > 0) {
 
 2285                columns.emplace_back(14, 0, 
"complexityN", 
"", mBench.complexityN());
 
 2288            columns.emplace_back(22, 2, mBench.timeUnitName() + 
"/" + mBench.unit(), 
"",
 
 2289                                 rMedian / (mBench.timeUnit().count() * mBench.batch()));
 
 2290            columns.emplace_back(22, 2, mBench.unit() + 
"/s", 
"", rMedian <= 0.0 ? 0.0 : mBench.batch() / rMedian);
 
 2293            columns.emplace_back(10, 1, 
"err%", 
"%", rErrorMedian * 100.0);
 
 2295            double rInsMedian = -1.0;
 
 2298                columns.emplace_back(18, 2, 
"ins/" + mBench.unit(), 
"", rInsMedian / mBench.batch());
 
 2301            double rCycMedian = -1.0;
 
 2304                columns.emplace_back(18, 2, 
"cyc/" + mBench.unit(), 
"", rCycMedian / mBench.batch());
 
 2306            if (rInsMedian > 0.0 && rCycMedian > 0.0) {
 
 2307                columns.emplace_back(9, 3, 
"IPC", 
"", rCycMedian <= 0.0 ? 0.0 : rInsMedian / rCycMedian);
 
 2311                columns.emplace_back(17, 2, 
"bra/" + mBench.unit(), 
"", rBraMedian / mBench.batch());
 
 2314                    if (rBraMedian >= 1e-9) {
 
 2317                    columns.emplace_back(10, 1, 
"miss%", 
"%", p);
 
 2324            auto& os = *mBench.output();
 
 2328            hash = hash_combine(std::hash<std::string>{}(mBench.unit()), hash);
 
 2329            hash = hash_combine(std::hash<std::string>{}(mBench.title()), hash);
 
 2330            hash = hash_combine(std::hash<std::string>{}(mBench.timeUnitName()), hash);
 
 2331            hash = hash_combine(std::hash<double>{}(mBench.timeUnit().
count()), hash);
 
 2332            hash = hash_combine(std::hash<bool>{}(mBench.relative()), hash);
 
 2333            hash = hash_combine(std::hash<bool>{}(mBench.performanceCounters()), hash);
 
 2335            if (hash != singletonHeaderHash()) {
 
 2336                singletonHeaderHash() = hash;
 
 2340                for (
auto const& col : columns) {
 
 2343                os << 
"| " << mBench.title() << std::endl;
 
 2345                for (
auto const& col : columns) {
 
 2346                    os << col.separator();
 
 2348                os << 
"|:" << std::string(mBench.title().size() + 1U, 
'-') << std::endl;
 
 2351            if (!errorMessage.empty()) {
 
 2352                for (
auto const& col : columns) {
 
 2353                    os << col.invalid();
 
 2355                os << 
"| :boom: " << fmt::MarkDownCode(mBench.name()) << 
" (" << errorMessage << 
')' << std::endl;
 
 2357                for (
auto const& col : columns) {
 
 2361                auto showUnstable = isWarningsEnabled() && rErrorMedian >= 0.05;
 
 2363                    os << 
":wavy_dash: ";
 
 2365                os << fmt::MarkDownCode(mBench.name());
 
 2367                    auto avgIters = d(mTotalNumIters) / d(mBench.epochs());
 
 2369                    auto suggestedIters = 
static_cast<uint64_t
>(avgIters * 10 + 0.5);
 
 2371                    os << 
" (Unstable with ~" << detail::fmt::Number(1, 1, avgIters)
 
 2372                       << 
" iters. Increase `minEpochIterations` to e.g. " << suggestedIters << 
")";
 
 2379    ANKERL_NANOBENCH(NODISCARD) 
bool isCloseEnoughForMeasurements(std::chrono::nanoseconds elapsed) 
const noexcept {
 
 2380        return elapsed * 3 >= mTargetRuntimePerEpoch * 2;
 
 2383    uint64_t mNumIters = 1;                            
 
 2384    Bench 
const& mBench;                               
 
 2385    std::chrono::nanoseconds mTargetRuntimePerEpoch{}; 
 
 2388    std::chrono::nanoseconds mTotalElapsed{};          
 
 2389    uint64_t mTotalNumIters = 0;                       
 
 2390    State mState = State::upscaling_runtime;           
 
 2394IterationLogic::IterationLogic(Bench 
const& bench)
 
 2395    : mPimpl(new Impl(bench)) {}
 
 2397IterationLogic::~IterationLogic() {
 
 2401uint64_t IterationLogic::numIters() const noexcept {
 
 2403    return mPimpl->mNumIters;
 
 2406void IterationLogic::add(std::chrono::nanoseconds elapsed, PerformanceCounters 
const& pc) 
noexcept {
 
 2407    mPimpl->add(elapsed, pc);
 
 2410void IterationLogic::moveResultTo(std::vector<Result>& results) 
noexcept {
 
 2411    results.emplace_back(std::move(mPimpl->mResult));
 
 2414#    if ANKERL_NANOBENCH(PERF_COUNTERS) 
 2417class LinuxPerformanceCounters {
 
 2420        Target(uint64_t* targetValue_, 
bool correctMeasuringOverhead_, 
bool correctLoopOverhead_)
 
 2421            : targetValue(targetValue_)
 
 2422            , correctMeasuringOverhead(correctMeasuringOverhead_)
 
 2423            , correctLoopOverhead(correctLoopOverhead_) {}
 
 2425        uint64_t* targetValue{};         
 
 2426        bool correctMeasuringOverhead{}; 
 
 2427        bool correctLoopOverhead{};      
 
 2430    LinuxPerformanceCounters() = 
default;
 
 2431    LinuxPerformanceCounters(LinuxPerformanceCounters 
const&) = 
delete;
 
 2432    LinuxPerformanceCounters(LinuxPerformanceCounters&&) = 
delete;
 
 2433    LinuxPerformanceCounters& operator=(LinuxPerformanceCounters 
const&) = 
delete;
 
 2434    LinuxPerformanceCounters& operator=(LinuxPerformanceCounters&&) = 
delete;
 
 2435    ~LinuxPerformanceCounters();
 
 2438    inline void start() {}
 
 2440    inline void stop() {}
 
 2442    bool monitor(perf_sw_ids swId, Target target);
 
 2443    bool monitor(perf_hw_id hwId, Target target);
 
 2451    inline void beginMeasure() {
 
 2457        mHasError = -1 == ioctl(mFd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
 
 2463        mHasError = -1 == ioctl(mFd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
 
 2466    inline void endMeasure() {
 
 2472        mHasError = (-1 == ioctl(mFd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP));
 
 2477        auto const numBytes = 
sizeof(uint64_t) * mCounters.size();
 
 2478        auto ret = read(mFd, mCounters.data(), numBytes);
 
 2479        mHasError = 
ret != 
static_cast<ssize_t
>(numBytes);
 
 2482    void updateResults(uint64_t numIters);
 
 2485    template <
typename T>
 
 2486    static inline T divRounded(T a, T divisor) {
 
 2487        return (a + divisor / 2) / divisor;
 
 2491    static inline uint32_t mix(uint32_t x) noexcept {
 
 2498    template <
typename Op>
 
 2500    void calibrate(Op&& op) {
 
 2502        for (
auto& v : mCalibratedOverhead) {
 
 2507        auto newCalibration = mCalibratedOverhead;
 
 2508        for (
auto& v : newCalibration) {
 
 2509            v = (std::numeric_limits<uint64_t>::max)();
 
 2511        for (
size_t iter = 0; iter < 100; ++iter) {
 
 2519            for (
size_t i = 0; i < newCalibration.size(); ++i) {
 
 2520                auto diff = mCounters[i];
 
 2521                if (newCalibration[i] > diff) {
 
 2522                    newCalibration[i] = diff;
 
 2527        mCalibratedOverhead = std::move(newCalibration);
 
 2534            uint64_t 
const numIters = 100000U + (std::random_device{}() & 3U);
 
 2535            uint64_t n = numIters;
 
 2536            uint32_t x = 1234567;
 
 2544            auto measure1 = mCounters;
 
 2555            auto measure2 = mCounters;
 
 2557            for (
size_t i = 0; i < mCounters.size(); ++i) {
 
 2559                auto m1 = measure1[i] > mCalibratedOverhead[i] ? measure1[i] - mCalibratedOverhead[i] : 0;
 
 2560                auto m2 = measure2[i] > mCalibratedOverhead[i] ? measure2[i] - mCalibratedOverhead[i] : 0;
 
 2561                auto overhead = m1 * 2 > m2 ? m1 * 2 - m2 : 0;
 
 2563                mLoopOverhead[i] = divRounded(overhead, numIters);
 
 2569    bool monitor(uint32_t type, uint64_t eventid, Target target);
 
 2571    std::map<uint64_t, Target> mIdToTarget{};
 
 2574    std::vector<uint64_t> mCounters{3};
 
 2575    std::vector<uint64_t> mCalibratedOverhead{3};
 
 2576    std::vector<uint64_t> mLoopOverhead{3};
 
 2578    uint64_t mTimeEnabledNanos = 0;
 
 2579    uint64_t mTimeRunningNanos = 0;
 
 2581    bool mHasError = 
false;
 
 2585LinuxPerformanceCounters::~LinuxPerformanceCounters() {
 
 2591bool LinuxPerformanceCounters::monitor(perf_sw_ids swId, LinuxPerformanceCounters::Target target) {
 
 2592    return monitor(PERF_TYPE_SOFTWARE, swId, target);
 
 2595bool LinuxPerformanceCounters::monitor(perf_hw_id hwId, LinuxPerformanceCounters::Target target) {
 
 2596    return monitor(PERF_TYPE_HARDWARE, hwId, target);
 
 2601void LinuxPerformanceCounters::updateResults(uint64_t numIters) {
 
 2603    for (
auto& id_value : mIdToTarget) {
 
 2604        *id_value.second.targetValue = UINT64_C(0);
 
 2611    mTimeEnabledNanos = mCounters[1] - mCalibratedOverhead[1];
 
 2612    mTimeRunningNanos = mCounters[2] - mCalibratedOverhead[2];
 
 2614    for (uint64_t i = 0; i < mCounters[0]; ++i) {
 
 2615        auto idx = 
static_cast<size_t>(3 + i * 2 + 0);
 
 2616        auto id = mCounters[idx + 1U];
 
 2618        auto it = mIdToTarget.find(
id);
 
 2619        if (it != mIdToTarget.end()) {
 
 2621            auto& tgt = it->second;
 
 2622            *tgt.targetValue = mCounters[idx];
 
 2623            if (tgt.correctMeasuringOverhead) {
 
 2624                if (*tgt.targetValue >= mCalibratedOverhead[idx]) {
 
 2625                    *tgt.targetValue -= mCalibratedOverhead[idx];
 
 2627                    *tgt.targetValue = 0U;
 
 2630            if (tgt.correctLoopOverhead) {
 
 2631                auto correctionVal = mLoopOverhead[idx] * numIters;
 
 2632                if (*tgt.targetValue >= correctionVal) {
 
 2633                    *tgt.targetValue -= correctionVal;
 
 2635                    *tgt.targetValue = 0U;
 
 2642bool LinuxPerformanceCounters::monitor(uint32_t type, uint64_t eventid, Target target) {
 
 2643    *target.targetValue = (std::numeric_limits<uint64_t>::max)();
 
 2648    auto pea = perf_event_attr();
 
 2649    std::memset(&pea, 0, 
sizeof(perf_event_attr));
 
 2651    pea.size = 
sizeof(perf_event_attr);
 
 2652    pea.config = eventid;
 
 2654    pea.exclude_kernel = 1;
 
 2658    pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
 
 2662#        if defined(PERF_FLAG_FD_CLOEXEC)  
 2663    const unsigned long flags = PERF_FLAG_FD_CLOEXEC;
 
 2665    const unsigned long flags = 0;
 
 2669    auto fd = 
static_cast<int>(syscall(__NR_perf_event_open, &pea, pid, cpu, mFd, 
flags));
 
 2679    if (-1 == ioctl(fd, PERF_EVENT_IOC_ID, &
id)) {
 
 2685    mIdToTarget.emplace(
id, target);
 
 2688    auto size = 3 + 2 * mIdToTarget.size();
 
 2689    mCounters.resize(size);
 
 2690    mCalibratedOverhead.resize(size);
 
 2691    mLoopOverhead.resize(size);
 
 2696PerformanceCounters::PerformanceCounters()
 
 2697    : mPc(new LinuxPerformanceCounters())
 
 2702    mHas.cpuCycles = mPc->monitor(PERF_COUNT_HW_REF_CPU_CYCLES, LinuxPerformanceCounters::Target(&mVal.cpuCycles, 
true, 
false));
 
 2703    if (!mHas.cpuCycles) {
 
 2705        mHas.cpuCycles = mPc->monitor(PERF_COUNT_HW_CPU_CYCLES, LinuxPerformanceCounters::Target(&mVal.cpuCycles, 
true, 
false));
 
 2707    mHas.instructions = mPc->monitor(PERF_COUNT_HW_INSTRUCTIONS, LinuxPerformanceCounters::Target(&mVal.instructions, 
true, 
true));
 
 2708    mHas.branchInstructions =
 
 2709        mPc->monitor(PERF_COUNT_HW_BRANCH_INSTRUCTIONS, LinuxPerformanceCounters::Target(&mVal.branchInstructions, 
true, 
false));
 
 2710    mHas.branchMisses = mPc->monitor(PERF_COUNT_HW_BRANCH_MISSES, LinuxPerformanceCounters::Target(&mVal.branchMisses, 
true, 
false));
 
 2714    mHas.pageFaults = mPc->monitor(PERF_COUNT_SW_PAGE_FAULTS, LinuxPerformanceCounters::Target(&mVal.pageFaults, 
true, 
false));
 
 2715    mHas.contextSwitches =
 
 2716        mPc->monitor(PERF_COUNT_SW_CONTEXT_SWITCHES, LinuxPerformanceCounters::Target(&mVal.contextSwitches, 
true, 
false));
 
 2720        auto before = ankerl::nanobench::Clock::now();
 
 2721        auto after = ankerl::nanobench::Clock::now();
 
 2726    if (mPc->hasError()) {
 
 2728        mHas = PerfCountSet<bool>{};
 
 2732PerformanceCounters::~PerformanceCounters() {
 
 2737void PerformanceCounters::beginMeasure() {
 
 2738    mPc->beginMeasure();
 
 2741void PerformanceCounters::endMeasure() {
 
 2745void PerformanceCounters::updateResults(uint64_t numIters) {
 
 2746    mPc->updateResults(numIters);
 
 2751PerformanceCounters::PerformanceCounters() = 
default;
 
 2752PerformanceCounters::~PerformanceCounters() = 
default;
 
 2753void PerformanceCounters::beginMeasure() {}
 
 2754void PerformanceCounters::endMeasure() {}
 
 2755void PerformanceCounters::updateResults(uint64_t) {}
 
 2759ANKERL_NANOBENCH(NODISCARD) PerfCountSet<uint64_t> 
const& PerformanceCounters::val() const noexcept {
 
 2762ANKERL_NANOBENCH(NODISCARD) PerfCountSet<bool> 
const& PerformanceCounters::has() const noexcept {
 
 2770NumSep::NumSep(
char sep)
 
 2773char NumSep::do_thousands_sep()
 const {
 
 2777std::string NumSep::do_grouping()
 const {
 
 2782StreamStateRestorer::StreamStateRestorer(std::ostream& 
s)
 
 2784    , mLocale(
s.getloc())
 
 2785    , mPrecision(
s.precision())
 
 2788    , mFmtFlags(
s.
flags()) {}
 
 2790StreamStateRestorer::~StreamStateRestorer() {
 
 2795void StreamStateRestorer::restore() {
 
 2796    mStream.imbue(mLocale);
 
 2797    mStream.precision(mPrecision);
 
 2798    mStream.width(mWidth);
 
 2799    mStream.fill(mFill);
 
 2800    mStream.flags(mFmtFlags);
 
 2803Number::Number(
int width, 
int precision, int64_t value)
 
 2805    , mPrecision(precision)
 
 2806    , mValue(d(value)) {}
 
 2808Number::Number(
int width, 
int precision, 
double value)
 
 2810    , mPrecision(precision)
 
 2813std::ostream& Number::write(std::ostream& os)
 const {
 
 2814    StreamStateRestorer 
const restorer(os);
 
 2815    os.imbue(std::locale(os.getloc(), 
new NumSep(
',')));
 
 2816    os << std::setw(mWidth) << std::setprecision(mPrecision) << std::fixed << mValue;
 
 2820std::string Number::to_s()
 const {
 
 2821    std::stringstream ss;
 
 2826std::string to_s(uint64_t n) {
 
 2829        str += 
static_cast<char>(
'0' + 
static_cast<char>(n % 10));
 
 2832    std::reverse(str.begin(), str.end());
 
 2836std::ostream& 
operator<<(std::ostream& os, Number 
const& n) {
 
 2840MarkDownColumn::MarkDownColumn(
int w, 
int prec, std::string tit, std::string suff, 
double val) noexcept
 
 2843    , mTitle(std::move(tit))
 
 2844    , mSuffix(std::move(suff))
 
 2847std::string MarkDownColumn::title()
 const {
 
 2848    std::stringstream ss;
 
 2849    ss << 
'|' << std::setw(mWidth - 2) << std::right << mTitle << 
' ';
 
 2853std::string MarkDownColumn::separator()
 const {
 
 2854    std::string sep(
static_cast<size_t>(mWidth), 
'-');
 
 2860std::string MarkDownColumn::invalid()
 const {
 
 2861    std::string sep(
static_cast<size_t>(mWidth), 
' ');
 
 2863    sep[sep.size() - 2] = 
'-';
 
 2867std::string MarkDownColumn::value()
 const {
 
 2868    std::stringstream ss;
 
 2869    auto width = mWidth - 2 - 
static_cast<int>(mSuffix.size());
 
 2870    ss << 
'|' << Number(width, mPrecision, mValue) << mSuffix << 
' ';
 
 2875MarkDownCode::MarkDownCode(std::string 
const& what) {
 
 2876    mWhat.reserve(what.size() + 2);
 
 2877    mWhat.push_back(
'`');
 
 2878    for (
char const c : what) {
 
 2881            mWhat.push_back(
'`');
 
 2884    mWhat.push_back(
'`');
 
 2887std::ostream& MarkDownCode::write(std::ostream& os)
 const {
 
 2891std::ostream& 
operator<<(std::ostream& os, MarkDownCode 
const& mdCode) {
 
 2892    return mdCode.write(os);
 
 2898Config::Config() = 
default;
 
 2899Config::~Config() = 
default;
 
 2900Config& Config::operator=(Config 
const&) = 
default;
 
 2901Config& Config::operator=(Config&&) noexcept(
ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE)) = default;
 
 2902Config::Config(Config const&) = default;
 
 2903Config::Config(Config&&) noexcept = default;
 
 2913template <
typename T>
 
 2914inline constexpr typename std::underlying_type<T>::type u(T val) 
noexcept {
 
 2915    return static_cast<typename std::underlying_type<T>::type
>(val);
 
 2921    : mConfig(
std::move(benchmarkConfig))
 
 2922    , mNameToMeasurements{
detail::u(
Result::Measure::_size)} {}
 
 2924void Result::add(Clock::duration totalElapsed, uint64_t iters, detail::PerformanceCounters 
const& pc) {
 
 2928    double const dIters = d(iters);
 
 2929    mNameToMeasurements[u(Result::Measure::iterations)].push_back(dIters);
 
 2931    mNameToMeasurements[u(Result::Measure::elapsed)].push_back(d(totalElapsed) / dIters);
 
 2932    if (pc.has().pageFaults) {
 
 2933        mNameToMeasurements[u(Result::Measure::pagefaults)].push_back(d(pc.val().pageFaults) / dIters);
 
 2935    if (pc.has().cpuCycles) {
 
 2936        mNameToMeasurements[u(Result::Measure::cpucycles)].push_back(d(pc.val().cpuCycles) / dIters);
 
 2938    if (pc.has().contextSwitches) {
 
 2939        mNameToMeasurements[u(Result::Measure::contextswitches)].push_back(d(pc.val().contextSwitches) / dIters);
 
 2941    if (pc.has().instructions) {
 
 2942        mNameToMeasurements[u(Result::Measure::instructions)].push_back(d(pc.val().instructions) / dIters);
 
 2944    if (pc.has().branchInstructions) {
 
 2945        double branchInstructions = 0.0;
 
 2947        if (pc.val().branchInstructions > iters + 1U) {
 
 2948            branchInstructions = d(pc.val().branchInstructions - (iters + 1U));
 
 2950        mNameToMeasurements[u(Result::Measure::branchinstructions)].push_back(branchInstructions / dIters);
 
 2952        if (pc.has().branchMisses) {
 
 2954            double branchMisses = d(pc.val().branchMisses);
 
 2955            if (branchMisses > branchInstructions) {
 
 2957                branchMisses = branchInstructions;
 
 2961            branchMisses -= 1.0;
 
 2962            if (branchMisses < 1.0) {
 
 2965            mNameToMeasurements[u(Result::Measure::branchmisses)].push_back(branchMisses / dIters);
 
 2970Config 
const& Result::config() const noexcept {
 
 2974inline double calcMedian(std::vector<double>& 
data) {
 
 2978    std::sort(
data.begin(), 
data.end());
 
 2980    auto midIdx = 
data.size() / 2U;
 
 2981    if (1U == (
data.size() & 1U)) {
 
 2982        return data[midIdx];
 
 2984    return (
data[midIdx - 1U] + 
data[midIdx]) / 2U;
 
 2987double Result::median(Measure m)
 const {
 
 2989    auto data = mNameToMeasurements[detail::u(m)];
 
 2990    return calcMedian(
data);
 
 2993double Result::average(Measure m)
 const {
 
 2995    auto const& 
data = mNameToMeasurements[detail::u(m)];
 
 3001    return sum(m) / d(
data.size());
 
 3004double Result::medianAbsolutePercentError(Measure m)
 const {
 
 3006    auto data = mNameToMeasurements[detail::u(m)];
 
 3010    auto med = calcMedian(
data);
 
 3013    for (
auto& x : 
data) {
 
 3019    return calcMedian(
data);
 
 3023    auto const& 
data = mNameToMeasurements[detail::u(m)];
 
 3024    return std::accumulate(
data.begin(), 
data.end(), 0.0);
 
 3027double Result::sumProduct(Measure m1, Measure m2) 
const noexcept {
 
 3028    auto const& data1 = mNameToMeasurements[detail::u(m1)];
 
 3029    auto const& data2 = mNameToMeasurements[detail::u(m2)];
 
 3031    if (data1.size() != data2.size()) {
 
 3035    double result = 0.0;
 
 3036    for (
size_t i = 0, 
s = data1.size(); i != 
s; ++i) {
 
 3037        result += data1[i] * data2[i];
 
 3042bool Result::has(Measure m) 
const noexcept {
 
 3043    return !mNameToMeasurements[detail::u(m)].empty();
 
 3046double Result::get(
size_t idx, Measure m)
 const {
 
 3047    auto const& 
data = mNameToMeasurements[detail::u(m)];
 
 3048    return data.at(idx);
 
 3051bool Result::empty() const noexcept {
 
 3052    return 0U == size();
 
 3055size_t Result::size() const noexcept {
 
 3056    auto const& 
data = mNameToMeasurements[detail::u(Measure::elapsed)];
 
 3060double Result::minimum(Measure m) 
const noexcept {
 
 3061    auto const& 
data = mNameToMeasurements[detail::u(m)];
 
 3067    return *std::min_element(
data.begin(), 
data.end());
 
 3070double Result::maximum(Measure m) 
const noexcept {
 
 3071    auto const& 
data = mNameToMeasurements[detail::u(m)];
 
 3077    return *std::max_element(
data.begin(), 
data.end());
 
 3080std::string 
const& Result::context(
char const* variableName)
 const {
 
 3081    return mConfig.mContext.at(variableName);
 
 3084std::string 
const& Result::context(std::string 
const& variableName)
 const {
 
 3085    return mConfig.mContext.at(variableName);
 
 3088Result::Measure Result::fromString(std::string 
const& str) {
 
 3089    if (str == 
"elapsed") {
 
 3090        return Measure::elapsed;
 
 3092    if (str == 
"iterations") {
 
 3093        return Measure::iterations;
 
 3095    if (str == 
"pagefaults") {
 
 3096        return Measure::pagefaults;
 
 3098    if (str == 
"cpucycles") {
 
 3099        return Measure::cpucycles;
 
 3101    if (str == 
"contextswitches") {
 
 3102        return Measure::contextswitches;
 
 3104    if (str == 
"instructions") {
 
 3105        return Measure::instructions;
 
 3107    if (str == 
"branchinstructions") {
 
 3108        return Measure::branchinstructions;
 
 3110    if (str == 
"branchmisses") {
 
 3111        return Measure::branchmisses;
 
 3114    return Measure::_size;
 
 3119    mConfig.mOut = &std::cout;
 
 3122Bench::Bench(Bench&&) noexcept = default;
 
 3123Bench& Bench::operator=(Bench&&) noexcept(
ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE)) = default;
 
 3124Bench::Bench(Bench const&) = default;
 
 3125Bench& Bench::operator=(Bench const&) = default;
 
 3126Bench::~Bench() noexcept = default;
 
 3128double Bench::batch() const noexcept {
 
 3129    return mConfig.mBatch;
 
 3132double Bench::complexityN() const noexcept {
 
 3133    return mConfig.mComplexityN;
 
 3138Bench& Bench::relative(
bool isRelativeEnabled) 
noexcept {
 
 3139    mConfig.mIsRelative = isRelativeEnabled;
 
 3142bool Bench::relative() const noexcept {
 
 3143    return mConfig.mIsRelative;
 
 3147    mConfig.mShowPerformanceCounters = showPerformanceCounters;
 
 3151    return mConfig.mShowPerformanceCounters;
 
 3157Bench& Bench::unit(
char const* u) {
 
 3158    if (u != mConfig.mUnit) {
 
 3165Bench& Bench::unit(std::string 
const& u) {
 
 3166    return unit(u.c_str());
 
 3169std::string 
const& Bench::unit() const noexcept {
 
 3170    return mConfig.mUnit;
 
 3173Bench& Bench::timeUnit(std::chrono::duration<double> 
const& tu, std::string 
const& tuName) {
 
 3174    mConfig.mTimeUnit = tu;
 
 3175    mConfig.mTimeUnitName = tuName;
 
 3179std::string 
const& Bench::timeUnitName() const noexcept {
 
 3180    return mConfig.mTimeUnitName;
 
 3183std::chrono::duration<double> 
const& Bench::timeUnit() const noexcept {
 
 3184    return mConfig.mTimeUnit;
 
 3188Bench& Bench::title(
const char* benchmarkTitle) {
 
 3189    if (benchmarkTitle != mConfig.mBenchmarkTitle) {
 
 3192    mConfig.mBenchmarkTitle = benchmarkTitle;
 
 3195Bench& Bench::title(std::string 
const& benchmarkTitle) {
 
 3196    if (benchmarkTitle != mConfig.mBenchmarkTitle) {
 
 3199    mConfig.mBenchmarkTitle = benchmarkTitle;
 
 3203std::string 
const& Bench::title() const noexcept {
 
 3204    return mConfig.mBenchmarkTitle;
 
 3208    mConfig.mBenchmarkName = benchmarkName;
 
 3212Bench& 
Bench::name(std::string 
const& benchmarkName) {
 
 3213    mConfig.mBenchmarkName = benchmarkName;
 
 3218    return mConfig.mBenchmarkName;
 
 3221Bench& Bench::context(
char const* variableName, 
char const* variableValue) {
 
 3222    mConfig.mContext[variableName] = variableValue;
 
 3226Bench& Bench::context(std::string 
const& variableName, std::string 
const& variableValue) {
 
 3227    mConfig.mContext[variableName] = variableValue;
 
 3231Bench& Bench::clearContext() {
 
 3232    mConfig.mContext.clear();
 
 3237Bench& Bench::epochs(
size_t numEpochs) 
noexcept {
 
 3238    mConfig.mNumEpochs = numEpochs;
 
 3241size_t Bench::epochs() const noexcept {
 
 3242    return mConfig.mNumEpochs;
 
 3246Bench& Bench::clockResolutionMultiple(
size_t multiple) 
noexcept {
 
 3247    mConfig.mClockResolutionMultiple = multiple;
 
 3250size_t Bench::clockResolutionMultiple() const noexcept {
 
 3251    return mConfig.mClockResolutionMultiple;
 
 3255Bench& Bench::maxEpochTime(std::chrono::nanoseconds t) 
noexcept {
 
 3256    mConfig.mMaxEpochTime = 
t;
 
 3259std::chrono::nanoseconds Bench::maxEpochTime() const noexcept {
 
 3260    return mConfig.mMaxEpochTime;
 
 3264Bench& Bench::minEpochTime(std::chrono::nanoseconds t) 
noexcept {
 
 3265    mConfig.mMinEpochTime = 
t;
 
 3268std::chrono::nanoseconds Bench::minEpochTime() const noexcept {
 
 3269    return mConfig.mMinEpochTime;
 
 3272Bench& Bench::minEpochIterations(uint64_t numIters) 
noexcept {
 
 3273    mConfig.mMinEpochIterations = (numIters == 0) ? 1 : numIters;
 
 3276uint64_t Bench::minEpochIterations() const noexcept {
 
 3277    return mConfig.mMinEpochIterations;
 
 3280Bench& Bench::epochIterations(uint64_t numIters) 
noexcept {
 
 3281    mConfig.mEpochIterations = numIters;
 
 3284uint64_t Bench::epochIterations() const noexcept {
 
 3285    return mConfig.mEpochIterations;
 
 3288Bench& Bench::warmup(uint64_t numWarmupIters) 
noexcept {
 
 3289    mConfig.mWarmup = numWarmupIters;
 
 3292uint64_t Bench::warmup() const noexcept {
 
 3293    return mConfig.mWarmup;
 
 3296Bench& Bench::config(Config 
const& benchmarkConfig) {
 
 3297    mConfig = benchmarkConfig;
 
 3300Config 
const& Bench::config() const noexcept {
 
 3304Bench& Bench::output(std::ostream* outstream) 
noexcept {
 
 3305    mConfig.mOut = outstream;
 
 3310    return mConfig.mOut;
 
 3313std::vector<Result> 
const& Bench::results() const noexcept {
 
 3317Bench& 
Bench::render(
char const* templateContent, std::ostream& os) {
 
 3322Bench& 
Bench::render(std::string 
const& templateContent, std::ostream& os) {
 
 3327std::vector<BigO> Bench::complexityBigO()
 const {
 
 3328    std::vector<BigO> bigOs;
 
 3329    auto rangeMeasure = BigO::collectRangeMeasure(mResults);
 
 3330    bigOs.emplace_back(
"O(1)", rangeMeasure, [](
double) {
 
 3333    bigOs.emplace_back(
"O(n)", rangeMeasure, [](
double n) {
 
 3336    bigOs.emplace_back(
"O(log n)", rangeMeasure, [](
double n) {
 
 3337        return std::log2(n);
 
 3339    bigOs.emplace_back(
"O(n log n)", rangeMeasure, [](
double n) {
 
 3340        return n * std::log2(n);
 
 3342    bigOs.emplace_back(
"O(n^2)", rangeMeasure, [](
double n) {
 
 3345    bigOs.emplace_back(
"O(n^3)", rangeMeasure, [](
double n) {
 
 3348    std::sort(bigOs.begin(), bigOs.end());
 
 3355    std::random_device rd;
 
 3356    std::uniform_int_distribution<uint64_t> dist;
 
 3360    } 
while (mX == 0 && mY == 0);
 
 3364uint64_t splitMix64(uint64_t& state) noexcept {
 
 3365    uint64_t z = (state += UINT64_C(0x9e3779b97f4a7c15));
 
 3366    z = (z ^ (z >> 30U)) * UINT64_C(0xbf58476d1ce4e5b9);
 
 3367    z = (z ^ (z >> 27U)) * UINT64_C(0x94d049bb133111eb);
 
 3368    return z ^ (z >> 31U);
 
 3372Rng::Rng(uint64_t seed) noexcept
 
 3373    : mX(splitMix64(seed))
 
 3374    , mY(splitMix64(seed)) {
 
 3375    for (
size_t i = 0; i < 10; ++i) {
 
 3381Rng::Rng(uint64_t x, uint64_t y) noexcept
 
 3385Rng Rng::copy() const noexcept {
 
 3389Rng::Rng(std::vector<uint64_t> 
const& 
data)
 
 3392    if (
data.size() != 2) {
 
 3393        throw std::runtime_error(
"ankerl::nanobench::Rng::Rng: needed exactly 2 entries in data, but got " +
 
 3394                                 detail::fmt::to_s(
data.size()));
 
 3400std::vector<uint64_t> Rng::state()
 const {
 
 3401    std::vector<uint64_t> 
data(2);
 
 3407BigO::RangeMeasure BigO::collectRangeMeasure(std::vector<Result> 
const& results) {
 
 3408    BigO::RangeMeasure rangeMeasure;
 
 3409    for (
auto const& result : results) {
 
 3410        if (result.config().mComplexityN > 0.0) {
 
 3411            rangeMeasure.emplace_back(result.config().mComplexityN, result.median(Result::Measure::elapsed));
 
 3414    return rangeMeasure;
 
 3417BigO::BigO(std::string bigOName, RangeMeasure 
const& rangeMeasure)
 
 3418    : mName(
std::move(bigOName)) {
 
 3421    double sumRangeMeasure = 0.0;
 
 3422    double sumRangeRange = 0.0;
 
 3424    for (
const auto& rm : rangeMeasure) {
 
 3425        sumRangeMeasure += rm.first * rm.second;
 
 3426        sumRangeRange += rm.first * rm.first;
 
 3428    mConstant = sumRangeMeasure / sumRangeRange;
 
 3432    double sumMeasure = 0.0;
 
 3433    for (
const auto& rm : rangeMeasure) {
 
 3434        auto diff = mConstant * rm.first - rm.second;
 
 3437        sumMeasure += rm.second;
 
 3440    auto n = detail::d(rangeMeasure.size());
 
 3441    auto mean = sumMeasure / n;
 
 3442    mNormalizedRootMeanSquare = std::sqrt(err / n) / mean;
 
 3445BigO::BigO(
const char* bigOName, RangeMeasure 
const& rangeMeasure)
 
 3446    : BigO(
std::string(bigOName), rangeMeasure) {}
 
 3448std::string 
const& 
BigO::name() const noexcept {
 
 3452double BigO::constant() const noexcept {
 
 3456double BigO::normalizedRootMeanSquare() const noexcept {
 
 3457    return mNormalizedRootMeanSquare;
 
 3461    return std::tie(mNormalizedRootMeanSquare, mName) < std::tie(other.mNormalizedRootMeanSquare, other.mName);
 
 3464std::ostream& 
operator<<(std::ostream& os, BigO 
const& bigO) {
 
 3465    return os << bigO.constant() << 
" * " << bigO.name() << 
", rms=" << bigO.normalizedRootMeanSquare();
 
 3468std::ostream& 
operator<<(std::ostream& os, std::vector<ankerl::nanobench::BigO> 
const& bigOs) {
 
 3469    detail::fmt::StreamStateRestorer 
const restorer(os);
 
 3470    os << std::endl << 
"|   coefficient |   err% | complexity" << std::endl << 
"|--------------:|-------:|------------" << std::endl;
 
 3471    for (
auto const& bigO : bigOs) {
 
 3472        os << 
"|" << std::setw(14) << std::setprecision(7) << std::scientific << bigO.constant() << 
" ";
 
 3473        os << 
"|" << detail::fmt::Number(6, 1, bigO.normalizedRootMeanSquare() * 100.0) << 
"% ";
 
 3474        os << 
"| " << bigO.name();
 
Main entry point to nanobench's benchmarking facility.
 
Bench & operator=(Bench const &other)
 
ANKERL_NANOBENCH(NODISCARD) std Bench & doNotOptimizeAway(Arg &&arg)
Retrieves all benchmark results collected by the bench object so far.
 
Bench & run(char const *benchmarkName, Op &&op)
Repeatedly calls op() based on the configuration, and performs measurements.
 
Bench & batch(T b) noexcept
Sets the batch size.
 
std::vector< BigO > complexityBigO() const
 
Bench()
Creates a new benchmark for configuration and running of benchmarks.
 
Bench & operator=(Bench &&other) noexcept(ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE))
 
Bench(Bench &&other) noexcept
 
Bench(Bench const &other)
 
Bench & complexityN(T n) noexcept
 
static RangeMeasure mapRangeMeasure(RangeMeasure data, Op op)
 
BigO(std::string bigOName, RangeMeasure const &scaledRangeMeasure)
 
std::vector< std::pair< double, double > > RangeMeasure
 
BigO(char const *bigOName, RangeMeasure const &rangeMeasure, Op rangeToN)
 
static RangeMeasure collectRangeMeasure(std::vector< Result > const &results)
 
BigO(std::string bigOName, RangeMeasure const &rangeMeasure, Op rangeToN)
 
BigO(char const *bigOName, RangeMeasure const &scaledRangeMeasure)
 
Result(Config benchmarkConfig)
 
static Measure fromString(std::string const &str)
 
void add(Clock::duration totalElapsed, uint64_t iters, detail::PerformanceCounters const &pc)
 
Result(Result &&other) noexcept
 
ANKERL_NANOBENCH(NODISCARD) Config const &config() const noexcept
 
Result & operator=(Result const &other)
 
Result(Result const &other)
 
Result & operator=(Result &&other) noexcept(ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE))
 
An extremely fast random generator.
 
static constexpr uint64_t() min()
 
Rng(Rng const &)=delete
As a safety precaution, we don't allow copying.
 
void shuffle(Container &container) noexcept
Shuffles all entries in the given container.
 
Rng(Rng &&) noexcept=default
 
Rng & operator=(Rng const &)=delete
Same as Rng(Rng const&), we don't allow assignment.
 
static constexpr uint64_t() max()
 
double uniform01() noexcept
Provides a random uniform double value between 0 and 1.
 
uint64_t result_type
This RNG provides 64bit randomness.
 
void moveResultTo(std::vector< Result > &results) noexcept
 
void add(std::chrono::nanoseconds elapsed, PerformanceCounters const &pc) noexcept
 
IterationLogic(IterationLogic &&)=delete
 
IterationLogic & operator=(IterationLogic const &)=delete
 
ANKERL_NANOBENCH(NODISCARD) uint64_t numIters() const noexcept
 
IterationLogic(IterationLogic const &)=delete
 
IterationLogic(Bench const &bench)
 
IterationLogic & operator=(IterationLogic &&)=delete
 
#define T(expected, seed, data)
 
void doNotOptimizeAway(T &val)
 
PerformanceCounters & performanceCounters()
 
void doNotOptimizeAway(T const &val)
 
char const * json() noexcept
Template to generate JSON data.
 
char const * csv() noexcept
CSV data for the benchmark results.
 
char const * pyperf() noexcept
Output in pyperf compatible JSON format, which can be used for more analyzation.
 
char const * htmlBoxplot() noexcept
HTML output that uses plotly to generate an interactive boxplot chart. See the tutorial for an exampl...
 
void render(char const *mustacheTemplate, Bench const &bench, std::ostream &out)
Renders output from a mustache-like template and benchmark results.
 
std::conditional< std::chrono::high_resolution_clock::is_steady, std::chrono::high_resolution_clock, std::chrono::steady_clock >::type Clock
 
void render(std::string const &mustacheTemplate, std::vector< Result > const &results, std::ostream &out)
 
std::ostream & operator<<(std::ostream &os, BigO const &bigO)
 
std::ostream & operator<<(std::ostream &os, std::vector< ankerl::nanobench::BigO > const &bigOs)
 
void doNotOptimizeAway(Arg &&arg)
Makes sure none of the given arguments are optimized away by the compiler.
 
#define ANKERL_NANOBENCH_LOG(x)
 
#define ANKERL_NANOBENCH_NO_SANITIZE(...)
 
#define ANKERL_NANOBENCH(x)
 
bool operator==(const CNetAddr &a, const CNetAddr &b)
 
bool operator<(const CNetAddr &a, const CNetAddr &b)
 
Config & operator=(Config const &other)
 
Config(Config const &other)
 
Config & operator=(Config &&other) noexcept(ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE))
 
Config(Config &&other) noexcept
 
static SECP256K1_INLINE uint64_t rotl(const uint64_t x, int k)