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.
3001} // namespace detail3003// Result returned after a benchmark has finished. Can be used as a baseline for relative().3004Result::Result(Config benchmarkConfig)3005: mConfig(std::move(benchmarkConfig))3006, mNameToMeasurements{detail::u(Result::Measure::_size)} {}3008void Result::add(Clock::duration totalElapsed, uint64_t iters, detail::PerformanceCounters const& pc) {3009using detail::d;3010using detail::u;3012double const dIters = d(iters);3013mNameToMeasurements[u(Result::Measure::iterations)].push_back(dIters);3015mNameToMeasurements[u(Result::Measure::elapsed)].push_back(d(totalElapsed) / dIters);3016if (pc.has().pageFaults) {3017mNameToMeasurements[u(Result::Measure::pagefaults)].push_back(d(pc.val().pageFaults) / dIters);3018}3019if (pc.has().cpuCycles) {3020mNameToMeasurements[u(Result::Measure::cpucycles)].push_back(d(pc.val().cpuCycles) / dIters);3021}3022if (pc.has().contextSwitches) {3023mNameToMeasurements[u(Result::Measure::contextswitches)].push_back(d(pc.val().contextSwitches) / dIters);3024}3025if (pc.has().instructions) {3026mNameToMeasurements[u(Result::Measure::instructions)].push_back(d(pc.val().instructions) / dIters);3027}3028if (pc.has().branchInstructions) {3029double branchInstructions = 0.0;3030// correcting branches: remove branch introduced by the while (...) loop for each iteration.3031if (pc.val().branchInstructions > iters + 1U) {3032branchInstructions = d(pc.val().branchInstructions - (iters + 1U));3033}3034mNameToMeasurements[u(Result::Measure::branchinstructions)].push_back(branchInstructions / dIters);3036if (pc.has().branchMisses) {3037// correcting branch misses3038double branchMisses = d(pc.val().branchMisses);3039if (branchMisses > branchInstructions) {3040// can't have branch misses when there were branches...3041branchMisses = branchInstructions;3042}3044// assuming at least one missed branch for the loop3045branchMisses -= 1.0;3046if (branchMisses < 1.0) {3047branchMisses = 1.0;3048}3049mNameToMeasurements[u(Result::Measure::branchmisses)].push_back(branchMisses / dIters);3050}3051}3052}3054Config const& Result::config() const noexcept {3055return mConfig;3056}3058inline double calcMedian(std::vector<double>& data) {3059if (data.empty()) {3060return 0.0;3061}3062std::sort(data.begin(), data.end());3064auto midIdx = data.size() / 2U;3065if (1U == (data.size() & 1U)) {3066return data[midIdx];3067}3068return (data[midIdx - 1U] + data[midIdx]) / 2U;3069}3071double Result::median(Measure m) const {3072// create a copy so we can sort3073auto data = mNameToMeasurements[detail::u(m)];3074return calcMedian(data);3075}3077double Result::average(Measure m) const {3078using detail::d;3079auto const& data = mNameToMeasurements[detail::u(m)];3080if (data.empty()) {3081return 0.0;3082}3084// create a copy so we can sort3085return sum(m) / d(data.size());3086}3088double Result::medianAbsolutePercentError(Measure m) const {3089// create copy3090auto data = mNameToMeasurements[detail::u(m)];3092// calculates MdAPE which is the median of percentage error3093// see https://support.numxl.com/hc/en-us/articles/115001223503-MdAPE-Median-Absolute-Percentage-Error3094auto med = calcMedian(data);3096// transform the data to absolute error3097for (auto& x : data) {3098x = (x - med) / x;3099if (x < 0) {3100x = -x;3101}3102}3103return calcMedian(data);3104}3106double Result::sum(Measure m) const noexcept {3107auto const& data = mNameToMeasurements[detail::u(m)];3108return std::accumulate(data.begin(), data.end(), 0.0);3109}3111double Result::sumProduct(Measure m1, Measure m2) const noexcept {3112auto const& data1 = mNameToMeasurements[detail::u(m1)];3113auto const& data2 = mNameToMeasurements[detail::u(m2)];3115if (data1.size() != data2.size()) {3116return 0.0;3117}3119double result = 0.0;3120for (size_t i = 0, s = data1.size(); i != s; ++i) {3121result += data1[i] * data2[i];3122}3123return result;3124}3126bool Result::has(Measure m) const noexcept {3127return !mNameToMeasurements[detail::u(m)].empty();3128}3130double Result::get(size_t idx, Measure m) const {3131auto const& data = mNameToMeasurements[detail::u(m)];3132return data.at(idx);3133}3135bool Result::empty() const noexcept {3136return 0U == size();3137}3139size_t Result::size() const noexcept {3140auto const& data = mNameToMeasurements[detail::u(Measure::elapsed)];3141return data.size();3142}3144double Result::minimum(Measure m) const noexcept {3145auto const& data = mNameToMeasurements[detail::u(m)];3146if (data.empty()) {3147return 0.0;3148}3150// here its save to assume that at least one element is there3151return *std::min_element(data.begin(), data.end());3152}3154double Result::maximum(Measure m) const noexcept {3155auto const& data = mNameToMeasurements[detail::u(m)];3156if (data.empty()) {3157return 0.0;3158}3160// here its save to assume that at least one element is there3161return *std::max_element(data.begin(), data.end());3162}3164std::string const& Result::context(char const* variableName) const {3165return mConfig.mContext.at(variableName);3166}3168std::string const& Result::context(std::string const& variableName) const {3169return mConfig.mContext.at(variableName);3170}3172Result::Measure Result::fromString(std::string const& str) {3173if (str == "elapsed") {3174return Measure::elapsed;3175}3176if (str == "iterations") {3177return Measure::iterations;3178}3179if (str == "pagefaults") {3180return Measure::pagefaults;3181}3182if (str == "cpucycles") {3183return Measure::cpucycles;3184}3185if (str == "contextswitches") {3186return Measure::contextswitches;3187}3188if (str == "instructions") {3189return Measure::instructions;3190}3191if (str == "branchinstructions") {3192return Measure::branchinstructions;3193}3194if (str == "branchmisses") {3195return Measure::branchmisses;3196}3197// not found, return _size3198return Measure::_size;3199}3201// Configuration of a microbenchmark.3202Bench::Bench() {3203mConfig.mOut = &std::cout;3204}3206Bench::Bench(Bench&&) noexcept = default;3207Bench& Bench::operator=(Bench&&) noexcept(ANKERL_NANOBENCH(NOEXCEPT_STRING_MOVE)) = default;3208Bench::Bench(Bench const&) = default;3209Bench& Bench::operator=(Bench const&) = default;3210Bench::~Bench() noexcept = default;3212double Bench::batch() const noexcept {3213return mConfig.mBatch;3214}3216double Bench::complexityN() const noexcept {3217return mConfig.mComplexityN;3218}3220// Set a baseline to compare it to. 100% it is exactly as fast as the baseline, >100% means it is faster than the baseline, <100%3221// means it is slower than the baseline.3222Bench& Bench::relative(bool isRelativeEnabled) noexcept {3223mConfig.mIsRelative = isRelativeEnabled;3224return *this;3225}3226bool Bench::relative() const noexcept {3227return mConfig.mIsRelative;3228}3230Bench& Bench::performanceCounters(bool showPerformanceCounters) noexcept {3231mConfig.mShowPerformanceCounters = showPerformanceCounters;3232return *this;3233}3234bool Bench::performanceCounters() const noexcept {3235return mConfig.mShowPerformanceCounters;3236}3238// Operation unit. Defaults to "op", could be e.g. "byte" for string processing.3239// If u differs from currently set unit, the stored results will be cleared.3240// Use singular (byte, not bytes).3241Bench& Bench::unit(char const* u) {3242if (u != mConfig.mUnit) {3243mResults.clear();3244}3245mConfig.mUnit = u;3246return *this;3247}3249Bench& Bench::unit(std::string const& u) {3250return unit(u.c_str());
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.