Skip to content

Commit

Permalink
Merge bitcoin#28877: bench: Update nanobench to 4.3.11
Browse files Browse the repository at this point in the history
fe434a4 bench: Update nanobench to 4.3.11 (TheCharlatan)

Pull request description:

  The newest version fixes the false positive `* Turbo is enabled, CPU frequency will fluctuate` warning on AMD CPUs. The file was directly taken from the release page: https://github.com/martinus/nanobench/releases/tag/v4.3.11.

  Other changes from the release notes:

  * Check for failures in parseFile(), perf events tweaks by tommi-cujo in martinus/nanobench#84
  * Workaround missing noexcept for std::string move assignment by tommi-cujo in martinus/nanobench#87
  * removed the link by martinus in martinus/nanobench#89
  * Lots of minor cleanups by martinus in martinus/nanobench#85
  * Add linter for version & clang-format. Updated version by martinus in martinus/nanobench#90

ACKs for top commit:
  fanquake:
    ACK fe434a4 - have not tested.

Tree-SHA512: a8f15e1db1d993673e4b295a3bab22e67ee3c9f3c0bcbef28974fe9ff37dbb741967a526088d5b148c8d25c9d57cd3b844238100c17b23038638787461805678
  • Loading branch information
fanquake authored and PastaPastaPasta committed Oct 24, 2024
1 parent db526f7 commit c934ad5
Showing 1 changed file with 56 additions and 42 deletions.
98 changes: 56 additions & 42 deletions src/bench/nanobench.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
// see https://semver.org/
#define ANKERL_NANOBENCH_VERSION_MAJOR 4 // incompatible API changes
#define ANKERL_NANOBENCH_VERSION_MINOR 3 // backwards-compatible changes
#define ANKERL_NANOBENCH_VERSION_PATCH 10 // backwards-compatible bug fixes
#define ANKERL_NANOBENCH_VERSION_PATCH 11 // backwards-compatible bug fixes

///////////////////////////////////////////////////////////////////////////////////////////////////
// public facing api - as minimal as possible
Expand Down Expand Up @@ -120,6 +120,10 @@
# define ANKERL_NANOBENCH_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value
#endif

// noexcept may be missing for std::string.
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58265
#define ANKERL_NANOBENCH_PRIVATE_NOEXCEPT_STRING_MOVE() std::is_nothrow_move_assignable<std::string>::value

// declarations ///////////////////////////////////////////////////////////////////////////////////

namespace ankerl {
Expand Down Expand Up @@ -404,7 +408,7 @@ struct Config {
Config();
~Config();
Config& operator=(Config const& other);
Config& operator=(Config&& other) noexcept;
Config& operator=(Config&& other) noexcept(ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE));
Config(Config const& other);
Config(Config&& other) noexcept;
};
Expand All @@ -430,7 +434,7 @@ class Result {

~Result();
Result& operator=(Result const& other);
Result& operator=(Result&& other) noexcept;
Result& operator=(Result&& other) noexcept(ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE));
Result(Result const& other);
Result(Result&& other) noexcept;

Expand Down Expand Up @@ -596,7 +600,7 @@ class Rng final {
*
* @return Vector containing the full state:
*/
std::vector<uint64_t> state() const;
ANKERL_NANOBENCH(NODISCARD) std::vector<uint64_t> state() const;

private:
static constexpr uint64_t rotl(uint64_t x, unsigned k) noexcept;
Expand Down Expand Up @@ -628,7 +632,7 @@ class Bench {
Bench();

Bench(Bench&& other) noexcept;
Bench& operator=(Bench&& other) noexcept;
Bench& operator=(Bench&& other) noexcept(ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE));
Bench(Bench const& other);
Bench& operator=(Bench const& other);
~Bench() noexcept;
Expand Down Expand Up @@ -818,7 +822,7 @@ class Bench {
* Default is zero, so we are fully relying on clockResolutionMultiple(). In most cases this is exactly what you want. If you see
* that the evaluation is unreliable with a high `err%`, you can increase either minEpochTime() or minEpochIterations().
*
* @see maxEpochTim), minEpochIterations
* @see maxEpochTime, minEpochIterations
*
* @param t Minimum time each epoch should take.
*/
Expand Down Expand Up @@ -1030,7 +1034,7 @@ void doNotOptimizeAway(T const& val);

// These assembly magic is directly from what Google Benchmark is doing. I have previously used what facebook's folly was doing, but
// this seemed to have compilation problems in some cases. Google Benchmark seemed to be the most well tested anyways.
// see https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307
// see https://github.com/google/benchmark/blob/v1.7.1/include/benchmark/benchmark.h#L443-L446
template <typename T>
void doNotOptimizeAway(T const& val) {
// NOLINTNEXTLINE(hicpp-no-assembler)
Expand Down Expand Up @@ -1781,7 +1785,7 @@ bool isEndlessRunning(std::string const& name);
bool isWarningsEnabled();

template <typename T>
T parseFile(std::string const& filename);
T parseFile(std::string const& filename, bool* fail);

void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<std::string>& recommendations);
void printStabilityInformationOnce(std::ostream* outStream);
Expand Down Expand Up @@ -1839,7 +1843,7 @@ class Number {
public:
Number(int width, int precision, double value);
Number(int width, int precision, int64_t value);
std::string to_s() const;
ANKERL_NANOBENCH(NODISCARD) std::string to_s() const;

private:
friend std::ostream& operator<<(std::ostream& os, Number const& n);
Expand All @@ -1857,11 +1861,11 @@ std::ostream& operator<<(std::ostream& os, Number const& n);

class MarkDownColumn {
public:
MarkDownColumn(int w, int prec, std::string tit, std::string suff, double val);
std::string title() const;
std::string separator() const;
std::string invalid() const;
std::string value() const;
MarkDownColumn(int w, int prec, std::string tit, std::string suff, double val) noexcept;
ANKERL_NANOBENCH(NODISCARD) std::string title() const;
ANKERL_NANOBENCH(NODISCARD) std::string separator() const;
ANKERL_NANOBENCH(NODISCARD) std::string invalid() const;
ANKERL_NANOBENCH(NODISCARD) std::string value() const;

private:
int mWidth;
Expand Down Expand Up @@ -1976,20 +1980,23 @@ PerformanceCounters& performanceCounters() {
}

// Windows version of doNotOptimizeAway
// see https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307
// see https://github.com/facebook/folly/blob/master/folly/Benchmark.h#L280
// see https://docs.microsoft.com/en-us/cpp/preprocessor/optimize
// see https://github.com/google/benchmark/blob/v1.7.1/include/benchmark/benchmark.h#L514
// see https://github.com/facebook/folly/blob/v2023.01.30.00/folly/lang/Hint-inl.h#L54-L58
// see https://learn.microsoft.com/en-us/cpp/preprocessor/optimize
# if defined(_MSC_VER)
# pragma optimize("", off)
void doNotOptimizeAwaySink(void const*) {}
# pragma optimize("", on)
# endif

template <typename T>
T parseFile(std::string const& filename) {
T parseFile(std::string const& filename, bool* fail) {
std::ifstream fin(filename); // NOLINT(misc-const-correctness)
T num{};
fin >> num;
if (fail != nullptr) {
*fail = fin.fail();
}
return num;
}

Expand Down Expand Up @@ -2032,16 +2039,15 @@ void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<
if (nprocs <= 0) {
warnings.emplace_back("couldn't figure out number of processors - no governor, turbo check possible");
} else {

// check frequency scaling
for (long id = 0; id < nprocs; ++id) {
auto idStr = detail::fmt::to_s(static_cast<uint64_t>(id));
auto sysCpu = "/sys/devices/system/cpu/cpu" + idStr;
auto minFreq = parseFile<int64_t>(sysCpu + "/cpufreq/scaling_min_freq");
auto maxFreq = parseFile<int64_t>(sysCpu + "/cpufreq/scaling_max_freq");
auto minFreq = parseFile<int64_t>(sysCpu + "/cpufreq/scaling_min_freq", nullptr);
auto maxFreq = parseFile<int64_t>(sysCpu + "/cpufreq/scaling_max_freq", nullptr);
if (minFreq != maxFreq) {
auto minMHz = static_cast<double>(minFreq) / 1000.0;
auto maxMHz = static_cast<double>(maxFreq) / 1000.0;
auto minMHz = d(minFreq) / 1000.0;
auto maxMHz = d(maxFreq) / 1000.0;
warnings.emplace_back("CPU frequency scaling enabled: CPU " + idStr + " between " +
detail::fmt::Number(1, 1, minMHz).to_s() + " and " + detail::fmt::Number(1, 1, maxMHz).to_s() +
" MHz");
Expand All @@ -2050,13 +2056,15 @@ void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<
}
}

auto currentGovernor = parseFile<std::string>("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
if ("performance" != currentGovernor) {
auto fail = false;
auto currentGovernor = parseFile<std::string>("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", &fail);
if (!fail && "performance" != currentGovernor) {
warnings.emplace_back("CPU governor is '" + currentGovernor + "' but should be 'performance'");
recommendPyPerf = true;
}

if (0 == parseFile<int>("/sys/devices/system/cpu/intel_pstate/no_turbo")) {
auto noTurbo = parseFile<int>("/sys/devices/system/cpu/intel_pstate/no_turbo", &fail);
if (!fail && noTurbo == 0) {
warnings.emplace_back("Turbo is enabled, CPU frequency will fluctuate");
recommendPyPerf = true;
}
Expand Down Expand Up @@ -2250,10 +2258,9 @@ struct IterationLogic::Impl {
mNumIters = 0;
}

ANKERL_NANOBENCH_LOG(mBench.name() << ": " << detail::fmt::Number(20, 3, static_cast<double>(elapsed.count())) << " elapsed, "
<< detail::fmt::Number(20, 3, static_cast<double>(mTargetRuntimePerEpoch.count()))
<< " target. oldIters=" << oldIters << ", mNumIters=" << mNumIters
<< ", mState=" << static_cast<int>(mState));
ANKERL_NANOBENCH_LOG(mBench.name() << ": " << detail::fmt::Number(20, 3, d(elapsed.count())) << " elapsed, "
<< detail::fmt::Number(20, 3, d(mTargetRuntimePerEpoch.count())) << " target. oldIters="
<< oldIters << ", mNumIters=" << mNumIters << ", mState=" << static_cast<int>(mState));
}

// NOLINTNEXTLINE(readability-function-cognitive-complexity)
Expand Down Expand Up @@ -2357,7 +2364,7 @@ struct IterationLogic::Impl {
}
os << fmt::MarkDownCode(mBench.name());
if (showUnstable) {
auto avgIters = static_cast<double>(mTotalNumIters) / static_cast<double>(mBench.epochs());
auto avgIters = d(mTotalNumIters) / d(mBench.epochs());
// NOLINTNEXTLINE(bugprone-incorrect-roundings)
auto suggestedIters = static_cast<uint64_t>(avgIters * 10 + 0.5);

Expand Down Expand Up @@ -2435,7 +2442,7 @@ class LinuxPerformanceCounters {
bool monitor(perf_sw_ids swId, Target target);
bool monitor(perf_hw_id hwId, Target target);

bool hasError() const noexcept {
ANKERL_NANOBENCH(NODISCARD) bool hasError() const noexcept {
return mHasError;
}

Expand Down Expand Up @@ -2691,16 +2698,23 @@ PerformanceCounters::PerformanceCounters()
, mVal()
, mHas() {

mHas.pageFaults = mPc->monitor(PERF_COUNT_SW_PAGE_FAULTS, LinuxPerformanceCounters::Target(&mVal.pageFaults, true, false));
// HW events
mHas.cpuCycles = mPc->monitor(PERF_COUNT_HW_REF_CPU_CYCLES, LinuxPerformanceCounters::Target(&mVal.cpuCycles, true, false));
mHas.contextSwitches =
mPc->monitor(PERF_COUNT_SW_CONTEXT_SWITCHES, LinuxPerformanceCounters::Target(&mVal.contextSwitches, true, false));
if (!mHas.cpuCycles) {
// Fallback to cycles counter, reference cycles not available in many systems.
mHas.cpuCycles = mPc->monitor(PERF_COUNT_HW_CPU_CYCLES, LinuxPerformanceCounters::Target(&mVal.cpuCycles, true, false));
}
mHas.instructions = mPc->monitor(PERF_COUNT_HW_INSTRUCTIONS, LinuxPerformanceCounters::Target(&mVal.instructions, true, true));
mHas.branchInstructions =
mPc->monitor(PERF_COUNT_HW_BRANCH_INSTRUCTIONS, LinuxPerformanceCounters::Target(&mVal.branchInstructions, true, false));
mHas.branchMisses = mPc->monitor(PERF_COUNT_HW_BRANCH_MISSES, LinuxPerformanceCounters::Target(&mVal.branchMisses, true, false));
// mHas.branchMisses = false;

// SW events
mHas.pageFaults = mPc->monitor(PERF_COUNT_SW_PAGE_FAULTS, LinuxPerformanceCounters::Target(&mVal.pageFaults, true, false));
mHas.contextSwitches =
mPc->monitor(PERF_COUNT_SW_CONTEXT_SWITCHES, LinuxPerformanceCounters::Target(&mVal.contextSwitches, true, false));

mPc->start();
mPc->calibrate([] {
auto before = ankerl::nanobench::Clock::now();
Expand Down Expand Up @@ -2789,7 +2803,7 @@ void StreamStateRestorer::restore() {
Number::Number(int width, int precision, int64_t value)
: mWidth(width)
, mPrecision(precision)
, mValue(static_cast<double>(value)) {}
, mValue(d(value)) {}

Number::Number(int width, int precision, double value)
: mWidth(width)
Expand Down Expand Up @@ -2823,7 +2837,7 @@ std::ostream& operator<<(std::ostream& os, Number const& n) {
return n.write(os);
}

MarkDownColumn::MarkDownColumn(int w, int prec, std::string tit, std::string suff, double val)
MarkDownColumn::MarkDownColumn(int w, int prec, std::string tit, std::string suff, double val) noexcept
: mWidth(w)
, mPrecision(prec)
, mTitle(std::move(tit))
Expand Down Expand Up @@ -2884,14 +2898,14 @@ std::ostream& operator<<(std::ostream& os, MarkDownCode const& mdCode) {
Config::Config() = default;
Config::~Config() = default;
Config& Config::operator=(Config const&) = default;
Config& Config::operator=(Config&&) noexcept = default;
Config& Config::operator=(Config&&) noexcept(ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE)) = default;
Config::Config(Config const&) = default;
Config::Config(Config&&) noexcept = default;

// provide implementation here so it's only generated once
Result::~Result() = default;
Result& Result::operator=(Result const&) = default;
Result& Result::operator=(Result&&) noexcept = default;
Result& Result::operator=(Result&&) noexcept(ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE)) = default;
Result::Result(Result const&) = default;
Result::Result(Result&&) noexcept = default;

Expand Down Expand Up @@ -2992,7 +3006,7 @@ double Result::medianAbsolutePercentError(Measure m) const {
auto data = mNameToMeasurements[detail::u(m)];

// calculates MdAPE which is the median of percentage error
// see https://www.spiderfinancial.com/support/documentation/numxl/reference-manual/forecasting-performance/mdape
// see https://support.numxl.com/hc/en-us/articles/115001223503-MdAPE-Median-Absolute-Percentage-Error
auto med = calcMedian(data);

// transform the data to absolute error
Expand Down Expand Up @@ -3106,7 +3120,7 @@ Bench::Bench() {
}

Bench::Bench(Bench&&) noexcept = default;
Bench& Bench::operator=(Bench&&) noexcept = default;
Bench& Bench::operator=(Bench&&) noexcept(ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE)) = default;
Bench::Bench(Bench const&) = default;
Bench& Bench::operator=(Bench const&) = default;
Bench::~Bench() noexcept = default;
Expand Down Expand Up @@ -3423,7 +3437,7 @@ BigO::BigO(std::string bigOName, RangeMeasure const& rangeMeasure)
sumMeasure += rm.second;
}

auto n = static_cast<double>(rangeMeasure.size());
auto n = detail::d(rangeMeasure.size());
auto mean = sumMeasure / n;
mNormalizedRootMeanSquare = std::sqrt(err / n) / mean;
}
Expand Down

0 comments on commit c934ad5

Please sign in to comment.