aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--depends/packages/qt.mk11
-rw-r--r--depends/patches/qt/fix_android_jni_static.patch2
-rw-r--r--depends/patches/qt/fix_bigsur_drawing.patch31
-rw-r--r--doc/dependencies.md2
-rw-r--r--src/bench/nanobench.h239
-rw-r--r--src/net_processing.cpp21
-rw-r--r--src/validation.cpp12
-rw-r--r--src/validation.h15
-rw-r--r--test/sanitizer_suppressions/ubsan1
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/