Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
2251} else {2252mNumIters = mBench.minEpochIterations();2253mState = State::upscaling_runtime;2254}2255}2257// directly calculates new iters based on elapsed&iters, and adds a 10% noise. Makes sure we don't underflow.2258ANKERL_NANOBENCH(NODISCARD) uint64_t calcBestNumIters(std::chrono::nanoseconds elapsed, uint64_t iters) noexcept {2259auto doubleElapsed = d(elapsed);2260auto doubleTargetRuntimePerEpoch = d(mTargetRuntimePerEpoch);2261auto doubleNewIters = doubleTargetRuntimePerEpoch / doubleElapsed * d(iters);2263auto doubleMinEpochIters = d(mBench.minEpochIterations());2264if (doubleNewIters < doubleMinEpochIters) {2265doubleNewIters = doubleMinEpochIters;2266}2267doubleNewIters *= 1.0 + 0.2 * mRng.uniform01();2269// +0.5 for correct rounding when casting2270// NOLINTNEXTLINE(bugprone-incorrect-roundings)2271return static_cast<uint64_t>(doubleNewIters + 0.5);2272}2274ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") void upscale(std::chrono::nanoseconds elapsed) {2275if (elapsed * 10 < mTargetRuntimePerEpoch) {2276// we are far below the target runtime. Multiply iterations by 10 (with overflow check)2277if (mNumIters * 10 < mNumIters) {2278// overflow :-(2279showResult("iterations overflow. Maybe your code got optimized away?");2280mNumIters = 0;2281return;2282}2283mNumIters *= 10;2284} else {2285mNumIters = calcBestNumIters(elapsed, mNumIters);2286}2287}2289void add(std::chrono::nanoseconds elapsed, PerformanceCounters const& pc) noexcept {2290# if defined(ANKERL_NANOBENCH_LOG_ENABLED)2291auto oldIters = mNumIters;2292# endif2294switch (mState) {2295case State::warmup:2296if (isCloseEnoughForMeasurements(elapsed)) {2297// if elapsed is close enough, we can skip upscaling and go right to measurements2298// still, we don't add the result to the measurements.2299mState = State::measuring;2300mNumIters = calcBestNumIters(elapsed, mNumIters);2301} else {2302// not close enough: switch to upscaling2303mState = State::upscaling_runtime;2304upscale(elapsed);2305}2306break;2308case State::upscaling_runtime:2309if (isCloseEnoughForMeasurements(elapsed)) {2310// if we are close enough, add measurement and switch to always measuring2311mState = State::measuring;2312mTotalElapsed += elapsed;2313mTotalNumIters += mNumIters;2314mResult.add(elapsed, mNumIters, pc);2315mNumIters = calcBestNumIters(mTotalElapsed, mTotalNumIters);2316} else {2317upscale(elapsed);2318}2319break;2321case State::measuring:2322// just add measurements - no questions asked. Even when runtime is low. But we can't ignore2323// that fluctuation, or else we would bias the result2324mTotalElapsed += elapsed;2325mTotalNumIters += mNumIters;2326mResult.add(elapsed, mNumIters, pc);2327if (0 != mBench.epochIterations()) {2328mNumIters = mBench.epochIterations();2329} else {2330mNumIters = calcBestNumIters(mTotalElapsed, mTotalNumIters);2331}2332break;2334case State::endless:2335mNumIters = (std::numeric_limits<uint64_t>::max)();2336break;2337}2339if (static_cast<uint64_t>(mResult.size()) == mBench.epochs()) {2340// we got all the results that we need, finish it2341showResult("");2342mNumIters = 0;2343}2345ANKERL_NANOBENCH_LOG(mBench.name() << ": " << detail::fmt::Number(20, 3, d(elapsed.count())) << " elapsed, "2346<< detail::fmt::Number(20, 3, d(mTargetRuntimePerEpoch.count())) << " target. oldIters="2347<< oldIters << ", mNumIters=" << mNumIters << ", mState=" << static_cast<int>(mState));2348}2350// NOLINTNEXTLINE(readability-function-cognitive-complexity)2351void showResult(std::string const& errorMessage) const {2352ANKERL_NANOBENCH_LOG(errorMessage);2354if (mBench.output() != nullptr) {2355// prepare column data ///////2356std::vector<fmt::MarkDownColumn> columns;2358auto rMedian = mResult.median(Result::Measure::elapsed);2360if (mBench.relative()) {2361double d = 100.0;2362if (!mBench.results().empty()) {2363d = rMedian <= 0.0 ? 0.0 : mBench.results().front().median(Result::Measure::elapsed) / rMedian * 100.0;2364}2365columns.emplace_back(11, 1, "relative", "%", d);2366}2368if (mBench.complexityN() > 0) {2369columns.emplace_back(14, 0, "complexityN", "", mBench.complexityN());2370}2372columns.emplace_back(22, 2, mBench.timeUnitName() + "/" + mBench.unit(), "",2373rMedian / (mBench.timeUnit().count() * mBench.batch()));2374columns.emplace_back(22, 2, mBench.unit() + "/s", "", rMedian <= 0.0 ? 0.0 : mBench.batch() / rMedian);2376double const rErrorMedian = mResult.medianAbsolutePercentError(Result::Measure::elapsed);2377columns.emplace_back(10, 1, "err%", "%", rErrorMedian * 100.0);2379double rInsMedian = -1.0;2380if (mBench.performanceCounters() && mResult.has(Result::Measure::instructions)) {2381rInsMedian = mResult.median(Result::Measure::instructions);2382columns.emplace_back(18, 2, "ins/" + mBench.unit(), "", rInsMedian / mBench.batch());2383}2385double rCycMedian = -1.0;2386if (mBench.performanceCounters() && mResult.has(Result::Measure::cpucycles)) {2387rCycMedian = mResult.median(Result::Measure::cpucycles);2388columns.emplace_back(18, 2, "cyc/" + mBench.unit(), "", rCycMedian / mBench.batch());2389}2390if (rInsMedian > 0.0 && rCycMedian > 0.0) {2391columns.emplace_back(9, 3, "IPC", "", rCycMedian <= 0.0 ? 0.0 : rInsMedian / rCycMedian);2392}2393if (mBench.performanceCounters() && mResult.has(Result::Measure::branchinstructions)) {2394double const rBraMedian = mResult.median(Result::Measure::branchinstructions);2395columns.emplace_back(17, 2, "bra/" + mBench.unit(), "", rBraMedian / mBench.batch());2396if (mResult.has(Result::Measure::branchmisses)) {2397double p = 0.0;2398if (rBraMedian >= 1e-9) {2399p = 100.0 * mResult.median(Result::Measure::branchmisses) / rBraMedian;2400}2401columns.emplace_back(10, 1, "miss%", "%", p);2402}2403}2405columns.emplace_back(12, 2, "total", "", mResult.sumProduct(Result::Measure::iterations, Result::Measure::elapsed));2407// write everything2408auto& os = *mBench.output();2410// combine all elements that are relevant for printing the header2411uint64_t hash = 0;2412hash = hash_combine(std::hash<std::string>{}(mBench.unit()), hash);2413hash = hash_combine(std::hash<std::string>{}(mBench.title()), hash);2414hash = hash_combine(std::hash<std::string>{}(mBench.timeUnitName()), hash);2415hash = hash_combine(std::hash<double>{}(mBench.timeUnit().count()), hash);2416hash = hash_combine(std::hash<bool>{}(mBench.relative()), hash);2417hash = hash_combine(std::hash<bool>{}(mBench.performanceCounters()), hash);2419if (hash != singletonHeaderHash()) {2420singletonHeaderHash() = hash;2422// no result yet, print header2423os << std::endl;2424for (auto const& col : columns) {2425os << col.title();2426}2427os << "| " << mBench.title() << std::endl;2429for (auto const& col : columns) {2430os << col.separator();2431}2432os << "|:" << std::string(mBench.title().size() + 1U, '-') << std::endl;2433}2435if (!errorMessage.empty()) {2436for (auto const& col : columns) {2437os << col.invalid();2438}2439os << "| :boom: " << fmt::MarkDownCode(mBench.name()) << " (" << errorMessage << ')' << std::endl;2440} else {2441for (auto const& col : columns) {2442os << col.value();2443}2444os << "| ";2445auto showUnstable = isWarningsEnabled() && rErrorMedian >= 0.05;2446if (showUnstable) {2447os << ":wavy_dash: ";2448}2449os << fmt::MarkDownCode(mBench.name());2450if (showUnstable) {2451auto avgIters = d(mTotalNumIters) / d(mBench.epochs());2452// NOLINTNEXTLINE(bugprone-incorrect-roundings)2453auto suggestedIters = static_cast<uint64_t>(avgIters * 10 + 0.5);2455os << " (Unstable with ~" << detail::fmt::Number(1, 1, avgIters)2456<< " iters. Increase `minEpochIterations` to e.g. " << suggestedIters << ")";2457}2458os << std::endl;2459}2460}2461}2463ANKERL_NANOBENCH(NODISCARD) bool isCloseEnoughForMeasurements(std::chrono::nanoseconds elapsed) const noexcept {2464return elapsed * 3 >= mTargetRuntimePerEpoch * 2;2465}2467uint64_t mNumIters = 1; // NOLINT(misc-non-private-member-variables-in-classes)2468Bench const& mBench; // NOLINT(misc-non-private-member-variables-in-classes)2469std::chrono::nanoseconds mTargetRuntimePerEpoch{}; // NOLINT(misc-non-private-member-variables-in-classes)2470Result mResult; // NOLINT(misc-non-private-member-variables-in-classes)2471Rng mRng{123}; // NOLINT(misc-non-private-member-variables-in-classes)2472std::chrono::nanoseconds mTotalElapsed{}; // NOLINT(misc-non-private-member-variables-in-classes)2473uint64_t mTotalNumIters = 0; // NOLINT(misc-non-private-member-variables-in-classes)2474State mState = State::upscaling_runtime; // NOLINT(misc-non-private-member-variables-in-classes)2475};2476ANKERL_NANOBENCH(IGNORE_PADDED_POP)2478IterationLogic::IterationLogic(Bench const& bench)2479: mPimpl(new Impl(bench)) {}2481IterationLogic::~IterationLogic() {2482delete mPimpl;2483}2485uint64_t IterationLogic::numIters() const noexcept {2486ANKERL_NANOBENCH_LOG(mPimpl->mBench.name() << ": mNumIters=" << mPimpl->mNumIters);2487return mPimpl->mNumIters;2488}2490void IterationLogic::add(std::chrono::nanoseconds elapsed, PerformanceCounters const& pc) noexcept {2491mPimpl->add(elapsed, pc);2492}2494void IterationLogic::moveResultTo(std::vector<Result>& results) noexcept {2495results.emplace_back(std::move(mPimpl->mResult));2496}2498# if ANKERL_NANOBENCH(PERF_COUNTERS)2500ANKERL_NANOBENCH(IGNORE_PADDED_PUSH)
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.