diff options
-rw-r--r-- | depends/packages/qt.mk | 11 | ||||
-rw-r--r-- | depends/patches/qt/fix_android_jni_static.patch | 2 | ||||
-rw-r--r-- | depends/patches/qt/fix_bigsur_drawing.patch | 31 | ||||
-rw-r--r-- | doc/dependencies.md | 2 | ||||
-rw-r--r-- | src/bench/nanobench.h | 239 | ||||
-rw-r--r-- | src/net_processing.cpp | 21 | ||||
-rw-r--r-- | src/validation.cpp | 12 | ||||
-rw-r--r-- | src/validation.h | 15 | ||||
-rw-r--r-- | test/sanitizer_suppressions/ubsan | 1 |
9 files changed, 218 insertions, 116 deletions
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index d23a64923b..5f9958e0ed 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -1,22 +1,22 @@ PACKAGE=qt -$(package)_version=5.12.10 +$(package)_version=5.12.11 $(package)_download_path=https://download.qt.io/official_releases/qt/5.12/$($(package)_version)/submodules $(package)_suffix=everywhere-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) -$(package)_sha256_hash=8088f174e6d28e779516c083b6087b6a9e3c8322b4bc161fd1b54195e3c86940 +$(package)_sha256_hash=1c1b4e33137ca77881074c140d54c3c9747e845a31338cfe8680f171f0bc3a39 $(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon $(package)_qt_libs=corelib network widgets gui plugins testlib $(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_no_printer.patch no-xlib.patch $(package)_patches+= fix_android_qmake_conf.patch fix_android_jni_static.patch dont_hardcode_pwd.patch $(package)_patches+= drop_lrelease_dependency.patch no_sdk_version_check.patch $(package)_patches+= fix_lib_paths.patch fix_android_pch.patch -$(package)_patches+= fix_bigsur_drawing.patch qtbase-moc-ignore-gcc-macro.patch +$(package)_patches+= qtbase-moc-ignore-gcc-macro.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) -$(package)_qttranslations_sha256_hash=e1de58ed108b7e0a138815ea60fd46a2c4e1fc31396a707e5630e92de79c53de +$(package)_qttranslations_sha256_hash=577b0668a777eb2b451c61e8d026d79285371597ce9df06b6dee6c814164b7c3 $(package)_qttools_file_name=qttools-$($(package)_suffix) -$(package)_qttools_sha256_hash=b0cfa6e7aac41b7c61fc59acc04843d7a98f9e1840370611751bcfc1834a636c +$(package)_qttools_sha256_hash=98b2aaca230458f65996f3534fd471d2ffd038dd58ac997c0589c06dc2385b4f $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) @@ -232,7 +232,6 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \ patch -p1 -i $($(package)_patch_dir)/no_sdk_version_check.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_lib_paths.patch && \ - patch -p1 -i $($(package)_patch_dir)/fix_bigsur_drawing.patch && \ patch -p1 -i $($(package)_patch_dir)/qtbase-moc-ignore-gcc-macro.patch && \ sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ diff --git a/depends/patches/qt/fix_android_jni_static.patch b/depends/patches/qt/fix_android_jni_static.patch index f891da6ddf..a186aeb8f6 100644 --- a/depends/patches/qt/fix_android_jni_static.patch +++ b/depends/patches/qt/fix_android_jni_static.patch @@ -1,6 +1,6 @@ --- old/qtbase/src/plugins/platforms/android/androidjnimain.cpp +++ new/qtbase/src/plugins/platforms/android/androidjnimain.cpp -@@ -897,6 +897,14 @@ +@@ -898,6 +898,14 @@ __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed"); return -1; } diff --git a/depends/patches/qt/fix_bigsur_drawing.patch b/depends/patches/qt/fix_bigsur_drawing.patch deleted file mode 100644 index 98c0c6be30..0000000000 --- a/depends/patches/qt/fix_bigsur_drawing.patch +++ /dev/null @@ -1,31 +0,0 @@ -Fix GUI stuck on Big Sur - -See: - - https://github.com/bitcoin-core/gui/issues/249 - - https://github.com/bitcoin/bitcoin/pull/21495 - - https://bugreports.qt.io/browse/QTBUG-87014 - -We should be able to drop this once we are using one of the following versions: - - Qt 5.12.11 or later, see upstream commit: c5d904639dbd690a36306e2b455610029704d821 - - Qt 5.15.3 or later, see upstream commit: 2cae34354bd41ae286258c7a6b3653b746e786ae - ---- a/qtbase/src/plugins/platforms/cocoa/qnsview_drawing.mm -+++ b/qtbase/src/plugins/platforms/cocoa/qnsview_drawing.mm -@@ -95,8 +95,15 @@ - // by AppKit at a point where we've already set up other parts of the platform plugin - // based on the presence of layers or not. Once we've rewritten these parts to support - // dynamically picking up layer enablement we can let AppKit do its thing. -- return QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave -- && QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave; -+ -+ if (QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSBigSur) -+ return true; // Big Sur always enables layer-backing, regardless of SDK -+ -+ if (QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave -+ && QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave) -+ return true; // Mojave and Catalina enable layers based on the app's SDK -+ -+ return false; // Prior versions needed explicitly enabled layer backing - } - - - (BOOL)layerExplicitlyRequested diff --git a/doc/dependencies.md b/doc/dependencies.md index 854ff7f52d..9754952221 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -21,7 +21,7 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct | PCRE | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) | | Python (tests) | | [3.6](https://www.python.org/downloads) | | | | | qrencode | [3.4.4](https://fukuchi.org/works/qrencode) | | No | | | -| Qt | [5.12.10](https://download.qt.io/official_releases/qt/) | [5.9.5](https://github.com/bitcoin/bitcoin/issues/20104) | No | | | +| Qt | [5.12.11](https://download.qt.io/official_releases/qt/) | [5.9.5](https://github.com/bitcoin/bitcoin/issues/20104) | No | | | | SQLite | [3.32.1](https://sqlite.org/download.html) | [3.7.17](https://github.com/bitcoin/bitcoin/pull/19077) | | | | | XCB | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) (Linux only) | | xkbcommon | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) (Linux only) | diff --git a/src/bench/nanobench.h b/src/bench/nanobench.h index c5379e7fd4..030d6ebf6a 100644 --- a/src/bench/nanobench.h +++ b/src/bench/nanobench.h @@ -7,7 +7,7 @@ // // Licensed under the MIT License <http://opensource.org/licenses/MIT>. // SPDX-License-Identifier: MIT -// Copyright (c) 2019-2020 Martin Ankerl <martin.ankerl@gmail.com> +// Copyright (c) 2019-2021 Martin Ankerl <martin.ankerl@gmail.com> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,8 +32,8 @@ // see https://semver.org/ #define ANKERL_NANOBENCH_VERSION_MAJOR 4 // incompatible API changes -#define ANKERL_NANOBENCH_VERSION_MINOR 0 // backwards-compatible changes -#define ANKERL_NANOBENCH_VERSION_PATCH 0 // backwards-compatible bug fixes +#define ANKERL_NANOBENCH_VERSION_MINOR 3 // backwards-compatible changes +#define ANKERL_NANOBENCH_VERSION_PATCH 4 // backwards-compatible bug fixes /////////////////////////////////////////////////////////////////////////////////////////////////// // public facing api - as minimal as possible @@ -78,12 +78,20 @@ #if defined(ANKERL_NANOBENCH_LOG_ENABLED) # include <iostream> -# define ANKERL_NANOBENCH_LOG(x) std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << x << std::endl +# define ANKERL_NANOBENCH_LOG(x) \ + do { \ + std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << x << std::endl; \ + } while (0) #else -# define ANKERL_NANOBENCH_LOG(x) +# define ANKERL_NANOBENCH_LOG(x) \ + do { \ + } while (0) #endif -#if defined(__linux__) && !defined(ANKERL_NANOBENCH_DISABLE_PERF_COUNTERS) +#if defined(__linux__) && defined(PERF_EVENT_IOC_ID) && defined(PERF_COUNT_HW_REF_CPU_CYCLES) && defined(PERF_FLAG_FD_CLOEXEC) && \ + !defined(ANKERL_NANOBENCH_DISABLE_PERF_COUNTERS) +// only enable perf counters on kernel 3.14 which seems to have all the necessary defines. The three PERF_... defines are not in +// kernel 2.6.32 (all others are). # define ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS() 1 #else # define ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS() 0 @@ -173,7 +181,7 @@ class BigO; * `contextswitches`, `instructions`, `branchinstructions`, and `branchmisses`. All the measuers (except `iterations`) are * provided for a single iteration (so `elapsed` is the time a single iteration took). The following tags are available: * - * * `{{median(<name>>)}}` Calculate median of a measurement data set, e.g. `{{median(elapsed)}}`. + * * `{{median(<name>)}}` Calculate median of a measurement data set, e.g. `{{median(elapsed)}}`. * * * `{{average(<name>)}}` Average (mean) calculation. * @@ -181,10 +189,11 @@ class BigO; * metric for the variation of measurements. It is more robust to outliers than the * [Mean absolute percentage error (M-APE)](https://en.wikipedia.org/wiki/Mean_absolute_percentage_error). * @f[ - * \mathrm{medianAbsolutePercentError}(e) = \mathrm{median}\{| \frac{e_i - \mathrm{median}\{e\}}{e_i}| \} + * \mathrm{MdAPE}(e) = \mathrm{med}\{| \frac{e_i - \mathrm{med}\{e\}}{e_i}| \} * @f] - * E.g. for *elapsed*: First, @f$ \mathrm{median}\{elapsed\} @f$ is calculated. This is used to calculate the absolute percentage - * error to this median for each measurement, as in @f$ | \frac{e_i - \mathrm{median}\{e\}}{e_i}| @f$. All these results + * E.g. for *elapsed*: First, @f$ \mathrm{med}\{e\} @f$ calculates the median by sorting and then taking the middle element + * of all *elapsed* measurements. This is used to calculate the absolute percentage + * error to this median for each measurement, as in @f$ | \frac{e_i - \mathrm{med}\{e\}}{e_i}| @f$. All these results * are sorted, and the middle value is chosen as the median absolute percent error. * * This measurement is a bit hard to interpret, but it is very robust against outliers. E.g. a value of 5% means that half of the @@ -207,7 +216,7 @@ class BigO; * * * `{{#measurement}}` To access individual measurement results, open the begin tag for measurements. * - * * `{{elapsed}}` Average elapsed time per iteration, in seconds. + * * `{{elapsed}}` Average elapsed wall clock time per iteration, in seconds. * * * `{{iterations}}` Number of iterations in the measurement. The number of iterations will fluctuate due * to some applied randomness, to enhance accuracy. @@ -261,6 +270,7 @@ class BigO; * :cpp:func:`templates::csv() <ankerl::nanobench::templates::csv()>` * :cpp:func:`templates::json() <ankerl::nanobench::templates::json()>` * :cpp:func:`templates::htmlBoxplot() <ankerl::nanobench::templates::htmlBoxplot()>` + * :cpp:func:`templates::pyperf() <ankerl::nanobench::templates::pyperf()>` @endverbatim * @@ -269,6 +279,7 @@ class BigO; * @param out Output for the generated output. */ void render(char const* mustacheTemplate, Bench const& bench, std::ostream& out); +void render(std::string const& mustacheTemplate, Bench const& bench, std::ostream& out); /** * Same as render(char const* mustacheTemplate, Bench const& bench, std::ostream& out), but for when @@ -279,6 +290,7 @@ void render(char const* mustacheTemplate, Bench const& bench, std::ostream& out) * @param out Output for the generated output. */ void render(char const* mustacheTemplate, std::vector<Result> const& results, std::ostream& out); +void render(std::string const& mustacheTemplate, std::vector<Result> const& results, std::ostream& out); // Contains mustache-like templates namespace templates { @@ -297,7 +309,7 @@ char const* csv() noexcept; /*! @brief HTML output that uses plotly to generate an interactive boxplot chart. See the tutorial for an example output. - The output uses only the elapsed time, and displays each epoch as a single dot. + The output uses only the elapsed wall clock time, and displays each epoch as a single dot. @verbatim embed:rst See the tutorial at :ref:`tutorial-template-html` for an example. @endverbatim @@ -307,6 +319,14 @@ char const* csv() noexcept; char const* htmlBoxplot() noexcept; /*! + @brief Output in pyperf compatible JSON format, which can be used for more analyzations. + @verbatim embed:rst + See the tutorial at :ref:`tutorial-template-pyperf` for an example how to further analyze the output. + @endverbatim + */ +char const* pyperf() noexcept; + +/*! @brief Template to generate JSON data. The generated JSON data contains *all* data that has been generated. All times are as double values, in seconds. The output can get @@ -369,6 +389,8 @@ struct Config { uint64_t mEpochIterations{0}; // If not 0, run *exactly* these number of iterations per epoch. uint64_t mWarmup = 0; std::ostream* mOut = nullptr; + std::chrono::duration<double> mTimeUnit = std::chrono::nanoseconds{1}; + std::string mTimeUnitName = "ns"; bool mShowPerformanceCounters = true; bool mIsRelative = false; @@ -504,6 +526,7 @@ public: */ explicit Rng(uint64_t seed) noexcept; Rng(uint64_t x, uint64_t y) noexcept; + Rng(std::vector<uint64_t> const& data); /** * Creates a copy of the Rng, thus the copy provides exactly the same random sequence as the original. @@ -558,6 +581,14 @@ public: template <typename Container> void shuffle(Container& container) noexcept; + /** + * Extracts the full state of the generator, e.g. for serialization. For this RNG this is just 2 values, but to stay API compatible + * with future implementations that potentially use more state, we use a vector. + * + * @return Vector containing the full state: + */ + std::vector<uint64_t> state() const; + private: static constexpr uint64_t rotl(uint64_t x, unsigned k) noexcept; @@ -667,6 +698,19 @@ public: ANKERL_NANOBENCH(NODISCARD) std::string const& unit() const noexcept; /** + * @brief Sets the time unit to be used for the default output. + * + * Nanobench defaults to using ns (nanoseconds) as output in the markdown. For some benchmarks this is too coarse, so it is + * possible to configure this. E.g. use `timeUnit(1ms, "ms")` to show `ms/op` instead of `ns/op`. + * + * @param tu Time unit to display the results in, default is 1ns. + * @param tuName Name for the time unit, default is "ns" + */ + Bench& timeUnit(std::chrono::duration<double> const& tu, std::string const& tuName); + ANKERL_NANOBENCH(NODISCARD) std::string const& timeUnitName() const noexcept; + ANKERL_NANOBENCH(NODISCARD) std::chrono::duration<double> const& timeUnit() const noexcept; + + /** * @brief Set the output stream where the resulting markdown table will be printed to. * * The default is `&std::cout`. You can disable all output by setting `nullptr`. @@ -916,6 +960,7 @@ public: @endverbatim */ Bench& render(char const* templateContent, std::ostream& os); + Bench& render(std::string const& templateContent, std::ostream& os); Bench& config(Config const& benchmarkConfig); ANKERL_NANOBENCH(NODISCARD) Config const& config() const noexcept; @@ -945,23 +990,24 @@ void doNotOptimizeAway(T const& val); #else -// see folly's Benchmark.h -template <typename T> -constexpr bool doNotOptimizeNeedsIndirect() { - using Decayed = typename std::decay<T>::type; - return !ANKERL_NANOBENCH_IS_TRIVIALLY_COPYABLE(Decayed) || sizeof(Decayed) > sizeof(long) || std::is_pointer<Decayed>::value; -} - +// These assembly magic is directly from what Google Benchmark is doing. I have previously used what facebook's folly was doing, but +// this seemd 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 template <typename T> -typename std::enable_if<!doNotOptimizeNeedsIndirect<T>()>::type doNotOptimizeAway(T const& val) { +void doNotOptimizeAway(T const& val) { // NOLINTNEXTLINE(hicpp-no-assembler) - asm volatile("" ::"r"(val)); + asm volatile("" : : "r,m"(val) : "memory"); } template <typename T> -typename std::enable_if<doNotOptimizeNeedsIndirect<T>()>::type doNotOptimizeAway(T const& val) { +void doNotOptimizeAway(T& val) { +# if defined(__clang__) + // NOLINTNEXTLINE(hicpp-no-assembler) + asm volatile("" : "+r,m"(val) : : "memory"); +# else // NOLINTNEXTLINE(hicpp-no-assembler) - asm volatile("" ::"m"(val) : "memory"); + asm volatile("" : "+m,r"(val) : : "memory"); +# endif } #endif @@ -1067,7 +1113,7 @@ constexpr uint64_t(Rng::max)() { return (std::numeric_limits<uint64_t>::max)(); } -ANKERL_NANOBENCH_NO_SANITIZE("integer") +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") uint64_t Rng::operator()() noexcept { auto x = mX; @@ -1077,7 +1123,7 @@ uint64_t Rng::operator()() noexcept { return x; } -ANKERL_NANOBENCH_NO_SANITIZE("integer") +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") uint32_t Rng::bounded(uint32_t range) noexcept { uint64_t r32 = static_cast<uint32_t>(operator()()); auto multiresult = r32 * range; @@ -1103,6 +1149,7 @@ void Rng::shuffle(Container& container) noexcept { } } +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") constexpr uint64_t Rng::rotl(uint64_t x, unsigned k) noexcept { return (x << k) | (x >> (64U - k)); } @@ -1306,6 +1353,30 @@ char const* htmlBoxplot() noexcept { </html>)DELIM"; } +char const* pyperf() noexcept { + return R"DELIM({ + "benchmarks": [ + { + "runs": [ + { + "values": [ +{{#measurement}} {{elapsed}}{{^-last}}, +{{/last}}{{/measurement}} + ] + } + ] + } + ], + "metadata": { + "loops": {{sum(iterations)}}, + "inner_loops": {{batch}}, + "name": "{{title}}", + "unit": "second" + }, + "version": "1.0" +})DELIM"; +} + char const* json() noexcept { return R"DELIM({ "results": [ @@ -1410,6 +1481,7 @@ static std::vector<Node> parseMustacheTemplate(char const** tpl) { } static bool generateFirstLast(Node const& n, size_t idx, size_t size, std::ostream& out) { + ANKERL_NANOBENCH_LOG("n.type=" << static_cast<int>(n.type)); bool matchFirst = n == "-first"; bool matchLast = n == "-last"; if (!matchFirst && !matchLast) { @@ -1632,6 +1704,7 @@ namespace detail { char const* getEnv(char const* name); bool isEndlessRunning(std::string const& name); +bool isWarningsEnabled(); template <typename T> T parseFile(std::string const& filename); @@ -1770,25 +1843,49 @@ void render(char const* mustacheTemplate, std::vector<Result> const& results, st for (size_t i = 0; i < nbResults; ++i) { generateResult(n.children, i, results, out); } + } else if (n == "measurement") { + if (results.size() != 1) { + throw std::runtime_error( + "render: can only use section 'measurement' here if there is a single result, but there are " + + detail::fmt::to_s(results.size())); + } + // when we only have a single result, we can immediately go into its measurement. + auto const& r = results.front(); + for (size_t i = 0; i < r.size(); ++i) { + generateResultMeasurement(n.children, i, r, out); + } } else { - throw std::runtime_error("unknown section '" + std::string(n.begin, n.end) + "'"); + throw std::runtime_error("render: unknown section '" + std::string(n.begin, n.end) + "'"); } break; case templates::Node::Type::tag: - // This just uses the last result's config. - if (!generateConfigTag(n, results.back().config(), out)) { - throw std::runtime_error("unknown tag '" + std::string(n.begin, n.end) + "'"); + if (results.size() == 1) { + // result & config are both supported there + generateResultTag(n, results.front(), out); + } else { + // This just uses the last result's config. + if (!generateConfigTag(n, results.back().config(), out)) { + throw std::runtime_error("unknown tag '" + std::string(n.begin, n.end) + "'"); + } } break; } } } +void render(std::string const& mustacheTemplate, std::vector<Result> const& results, std::ostream& out) { + render(mustacheTemplate.c_str(), results, out); +} + void render(char const* mustacheTemplate, const Bench& bench, std::ostream& out) { render(mustacheTemplate, bench.results(), out); } +void render(std::string const& mustacheTemplate, const Bench& bench, std::ostream& out) { + render(mustacheTemplate.c_str(), bench.results(), out); +} + namespace detail { PerformanceCounters& performanceCounters() { @@ -1837,6 +1934,12 @@ bool isEndlessRunning(std::string const& name) { return nullptr != endless && endless == name; } +// True when environment variable NANOBENCH_SUPPRESS_WARNINGS is either not set at all, or set to "0" +bool isWarningsEnabled() { + auto suppression = getEnv("NANOBENCH_SUPPRESS_WARNINGS"); + return nullptr == suppression || suppression == std::string("0"); +} + void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<std::string>& recommendations) { warnings.clear(); recommendations.clear(); @@ -1889,13 +1992,13 @@ void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector< recommendations.emplace_back("Make sure you compile for Release"); } if (recommendPyPerf) { - recommendations.emplace_back("Use 'pyperf system tune' before benchmarking. See https://github.com/vstinner/pyperf"); + recommendations.emplace_back("Use 'pyperf system tune' before benchmarking. See https://github.com/psf/pyperf"); } } void printStabilityInformationOnce(std::ostream* outStream) { static bool shouldPrint = true; - if (shouldPrint && outStream) { + if (shouldPrint && outStream && isWarningsEnabled()) { auto& os = *outStream; shouldPrint = false; std::vector<std::string> warnings; @@ -1923,16 +2026,7 @@ uint64_t& singletonHeaderHash() noexcept { return sHeaderHash; } -ANKERL_NANOBENCH_NO_SANITIZE("integer") -inline uint64_t fnv1a(std::string const& str) noexcept { - auto val = UINT64_C(14695981039346656037); - for (auto c : str) { - val = (val ^ static_cast<uint8_t>(c)) * UINT64_C(1099511628211); - } - return val; -} - -ANKERL_NANOBENCH_NO_SANITIZE("integer") +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") inline uint64_t hash_combine(uint64_t seed, uint64_t val) { return seed ^ (val + UINT64_C(0x9e3779b9) + (seed << 6U) + (seed >> 2U)); } @@ -2010,7 +2104,7 @@ struct IterationLogic::Impl { return static_cast<uint64_t>(doubleNewIters + 0.5); } - ANKERL_NANOBENCH_NO_SANITIZE("integer") void upscale(std::chrono::nanoseconds elapsed) { + ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") void upscale(std::chrono::nanoseconds elapsed) { if (elapsed * 10 < mTargetRuntimePerEpoch) { // we are far below the target runtime. Multiply iterations by 10 (with overflow check) if (mNumIters * 10 < mNumIters) { @@ -2108,7 +2202,8 @@ struct IterationLogic::Impl { columns.emplace_back(14, 0, "complexityN", "", mBench.complexityN()); } - columns.emplace_back(22, 2, "ns/" + mBench.unit(), "", 1e9 * rMedian / mBench.batch()); + columns.emplace_back(22, 2, mBench.timeUnitName() + "/" + mBench.unit(), "", + rMedian / (mBench.timeUnit().count() * mBench.batch())); columns.emplace_back(22, 2, mBench.unit() + "/s", "", rMedian <= 0.0 ? 0.0 : mBench.batch() / rMedian); double rErrorMedian = mResult.medianAbsolutePercentError(Result::Measure::elapsed); @@ -2140,16 +2235,19 @@ struct IterationLogic::Impl { } } - columns.emplace_back(12, 2, "total", "", mResult.sum(Result::Measure::elapsed)); + columns.emplace_back(12, 2, "total", "", mResult.sumProduct(Result::Measure::iterations, Result::Measure::elapsed)); // write everything auto& os = *mBench.output(); + // combine all elements that are relevant for printing the header uint64_t hash = 0; - hash = hash_combine(fnv1a(mBench.unit()), hash); - hash = hash_combine(fnv1a(mBench.title()), hash); - hash = hash_combine(mBench.relative(), hash); - hash = hash_combine(mBench.performanceCounters(), hash); + hash = hash_combine(std::hash<std::string>{}(mBench.unit()), hash); + hash = hash_combine(std::hash<std::string>{}(mBench.title()), hash); + hash = hash_combine(std::hash<std::string>{}(mBench.timeUnitName()), hash); + hash = hash_combine(std::hash<double>{}(mBench.timeUnit().count()), hash); + hash = hash_combine(std::hash<bool>{}(mBench.relative()), hash); + hash = hash_combine(std::hash<bool>{}(mBench.performanceCounters()), hash); if (hash != singletonHeaderHash()) { singletonHeaderHash() = hash; @@ -2177,7 +2275,7 @@ struct IterationLogic::Impl { os << col.value(); } os << "| "; - auto showUnstable = rErrorMedian >= 0.05; + auto showUnstable = isWarningsEnabled() && rErrorMedian >= 0.05; if (showUnstable) { os << ":wavy_dash: "; } @@ -2305,7 +2403,7 @@ public: } template <typename Op> - ANKERL_NANOBENCH_NO_SANITIZE("integer") + ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") void calibrate(Op&& op) { // clear current calibration data, for (auto& v : mCalibratedOverhead) { @@ -2411,7 +2509,7 @@ bool LinuxPerformanceCounters::monitor(perf_hw_id hwId, LinuxPerformanceCounters } // overflow is ok, it's checked -ANKERL_NANOBENCH_NO_SANITIZE("integer") +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") void LinuxPerformanceCounters::updateResults(uint64_t numIters) { // clear old data for (auto& id_value : mIdToTarget) { @@ -2963,6 +3061,20 @@ std::string const& Bench::unit() const noexcept { return mConfig.mUnit; } +Bench& Bench::timeUnit(std::chrono::duration<double> const& tu, std::string const& tuName) { + mConfig.mTimeUnit = tu; + mConfig.mTimeUnitName = tuName; + return *this; +} + +std::string const& Bench::timeUnitName() const noexcept { + return mConfig.mTimeUnitName; +} + +std::chrono::duration<double> const& Bench::timeUnit() const noexcept { + return mConfig.mTimeUnit; +} + // If benchmarkTitle differs from currently set title, the stored results will be cleared. Bench& Bench::title(const char* benchmarkTitle) { if (benchmarkTitle != mConfig.mBenchmarkTitle) { @@ -3083,6 +3195,11 @@ Bench& Bench::render(char const* templateContent, std::ostream& os) { return *this; } +Bench& Bench::render(std::string const& templateContent, std::ostream& os) { + ::ankerl::nanobench::render(templateContent, *this, os); + return *this; +} + std::vector<BigO> Bench::complexityBigO() const { std::vector<BigO> bigOs; auto rangeMeasure = BigO::collectRangeMeasure(mResults); @@ -3119,7 +3236,7 @@ Rng::Rng() } while (mX == 0 && mY == 0); } -ANKERL_NANOBENCH_NO_SANITIZE("integer") +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") uint64_t splitMix64(uint64_t& state) noexcept { uint64_t z = (state += UINT64_C(0x9e3779b97f4a7c15)); z = (z ^ (z >> 30U)) * UINT64_C(0xbf58476d1ce4e5b9); @@ -3145,6 +3262,24 @@ Rng Rng::copy() const noexcept { return Rng{mX, mY}; } +Rng::Rng(std::vector<uint64_t> const& data) + : mX(0) + , mY(0) { + if (data.size() != 2) { + throw std::runtime_error("ankerl::nanobench::Rng::Rng: needed exactly 2 entries in data, but got " + + detail::fmt::to_s(data.size())); + } + mX = data[0]; + mY = data[1]; +} + +std::vector<uint64_t> Rng::state() const { + std::vector<uint64_t> data(2); + data[0] = mX; + data[1] = mY; + return data; +} + BigO::RangeMeasure BigO::collectRangeMeasure(std::vector<Result> const& results) { BigO::RangeMeasure rangeMeasure; for (auto const& result : results) { diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 0b83f756b3..65224b4259 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -491,7 +491,8 @@ private: void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(peer.m_getdata_requests_mutex) LOCKS_EXCLUDED(::cs_main); - void ProcessBlock(CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing); + /** Process a new block. Perform any post-processing housekeeping */ + void ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing); /** Relay map (txid or wtxid -> CTransactionRef) */ typedef std::map<uint256, CTransactionRef> MapRelay; @@ -2384,15 +2385,15 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv) m_connman.PushMessage(&peer, std::move(msg)); } -void PeerManagerImpl::ProcessBlock(CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing) +void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing) { - bool fNewBlock = false; - m_chainman.ProcessNewBlock(m_chainparams, pblock, fForceProcessing, &fNewBlock); - if (fNewBlock) { - pfrom.nLastBlockTime = GetTime(); + bool new_block{false}; + m_chainman.ProcessNewBlock(m_chainparams, block, force_processing, &new_block); + if (new_block) { + node.nLastBlockTime = GetTime(); } else { LOCK(cs_main); - mapBlockSource.erase(pblock->GetHash()); + mapBlockSource.erase(block->GetHash()); } } @@ -3475,7 +3476,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, LOCK(cs_main); mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom.GetId(), false)); } - // Setting fForceProcessing to true means that we bypass some of + // Setting force_processing to true means that we bypass some of // our anti-DoS protections in AcceptBlock, which filters // unrequested blocks that might be trying to waste our resources // (eg disk space). Because we only try to reconstruct blocks when @@ -3484,7 +3485,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // we have a chain with at least nMinimumChainWork), and we ignore // compact blocks with less work than our tip, it is safe to treat // reconstructed compact blocks as having been requested. - ProcessBlock(pfrom, pblock, /*fForceProcessing=*/true); + ProcessBlock(pfrom, pblock, /*force_processing=*/true); LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid() if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) { // Clear download state for this block, which is in @@ -3567,7 +3568,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // disk-space attacks), but this should be safe due to the // protections in the compact block handler -- see related comment // in compact block optimistic reconstruction handling. - ProcessBlock(pfrom, pblock, /*fForceProcessing=*/true); + ProcessBlock(pfrom, pblock, /*force_processing=*/true); } return; } diff --git a/src/validation.cpp b/src/validation.cpp index 86539ab01f..4c861599fd 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3591,14 +3591,14 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block return true; } -bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool* fNewBlock) +bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) { AssertLockNotHeld(cs_main); assert(std::addressof(::ChainstateActive()) == std::addressof(ActiveChainstate())); { CBlockIndex *pindex = nullptr; - if (fNewBlock) *fNewBlock = false; + if (new_block) *new_block = false; BlockValidationState state; // CheckBlock() does not support multi-threaded block validation because CBlock::fChecked can cause data race. @@ -3607,13 +3607,13 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s // Ensure that CheckBlock() passes before calling AcceptBlock, as // belt-and-suspenders. - bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus()); + bool ret = CheckBlock(*block, state, chainparams.GetConsensus()); if (ret) { // Store to disk - ret = ActiveChainstate().AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock); + ret = ActiveChainstate().AcceptBlock(block, state, chainparams, &pindex, force_processing, nullptr, new_block); } if (!ret) { - GetMainSignals().BlockChecked(*pblock, state); + GetMainSignals().BlockChecked(*block, state); return error("%s: AcceptBlock FAILED (%s)", __func__, state.ToString()); } } @@ -3621,7 +3621,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s NotifyHeaderTip(ActiveChainstate()); BlockValidationState state; // Only used to report errors, not invalidity - ignore it - if (!ActiveChainstate().ActivateBestChain(state, chainparams, pblock)) + if (!ActiveChainstate().ActivateBestChain(state, chainparams, block)) return error("%s: ActivateBestChain failed (%s)", __func__, state.ToString()); return true; diff --git a/src/validation.h b/src/validation.h index 43e1c5c22e..9c718b3d63 100644 --- a/src/validation.h +++ b/src/validation.h @@ -970,22 +970,21 @@ public: * block is made active. Note that it does not, however, guarantee that the * specific block passed to it has been checked for validity! * - * If you want to *possibly* get feedback on whether pblock is valid, you must + * If you want to *possibly* get feedback on whether block is valid, you must * install a CValidationInterface (see validationinterface.h) - this will have * its BlockChecked method called whenever *any* block completes validation. * - * Note that we guarantee that either the proof-of-work is valid on pblock, or + * Note that we guarantee that either the proof-of-work is valid on block, or * (and possibly also) BlockChecked will have been called. * - * May not be called in a - * validationinterface callback. + * May not be called in a validationinterface callback. * - * @param[in] pblock The block we want to process. - * @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources. - * @param[out] fNewBlock A boolean which is set to indicate if the block was first received via this call + * @param[in] block The block we want to process. + * @param[in] force_processing Process this block even if unrequested; used for non-network block sources. + * @param[out] new_block A boolean which is set to indicate if the block was first received via this call * @returns If the block was processed, independently of block validity */ - bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool* fNewBlock) LOCKS_EXCLUDED(cs_main); + bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) LOCKS_EXCLUDED(cs_main); /** * Process incoming block headers. diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan index 4f6f92bd3c..2850cfcea5 100644 --- a/test/sanitizer_suppressions/ubsan +++ b/test/sanitizer_suppressions/ubsan @@ -98,7 +98,6 @@ implicit-unsigned-integer-truncation:crypto/ implicit-unsigned-integer-truncation:leveldb/ # std::variant warning fixed in https://github.com/gcc-mirror/gcc/commit/074436cf8cdd2a9ce75cadd36deb8301f00e55b9 implicit-unsigned-integer-truncation:std::__detail::__variant::_Variant_storage -shift-base:nanobench.h shift-base:*/include/c++/ shift-base:arith_uint256.cpp shift-base:crypto/ |