0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-24 12:41:41 -05:00
bitcoin-bitcoin-core/src/bench/bench_bitcoin.cpp
MarcoFalke b9028b2e26
Merge bitcoin/bitcoin#26481: bench: Suppress output when running with -sanity-check option
f1e89597c8 test: Drop no longer required bench output redirection (Hennadii Stepanov)
4dbcdf26a3 bench: Suppress output when running with `-sanity-check` option (Hennadii Stepanov)

Pull request description:

  This change allows to simplify CI tests, and makes it easier to integrate the `bench_bitcoin` binary into CMake custom [targets](https://cmake.org/cmake/help/latest/command/add_custom_target.html) or [commands](https://cmake.org/cmake/help/latest/command/add_custom_command.html), as `COMMAND` does not support output redirection.

ACKs for top commit:
  aureleoules:
    tACK f1e89597c8. Ran as expected and is more practical than using an output redirection.

Tree-SHA512: 29086d428cccedcfd031c0b4514213cbc1670e35f955e8fd35cee212bc6f9616cf9f20d0cb984495390c4ae2c50788ace616aea907d44e0d6a905b9dda1685d8
2022-12-29 11:42:03 +01:00

139 lines
6.5 KiB
C++

// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
#include <clientversion.h>
#include <crypto/sha256.h>
#include <fs.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <chrono>
#include <cstdint>
#include <iostream>
#include <sstream>
#include <vector>
static const char* DEFAULT_BENCH_FILTER = ".*";
static constexpr int64_t DEFAULT_MIN_TIME_MS{10};
/** Priority level default value, run "all" priority levels */
static const std::string DEFAULT_PRIORITY{"all"};
static void SetupBenchArgs(ArgsManager& argsman)
{
SetupHelpOptions(argsman);
argsman.AddArg("-asymptote=<n1,n2,n3,...>", "Test asymptotic growth of the runtime of an algorithm, if supported by the benchmark", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-filter=<regex>", strprintf("Regular expression filter to select benchmark by name (default: %s)", DEFAULT_BENCH_FILTER), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-list", "List benchmarks without executing them", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-min-time=<milliseconds>", strprintf("Minimum runtime per benchmark, in milliseconds (default: %d)", DEFAULT_MIN_TIME_MS), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
argsman.AddArg("-output-csv=<output.csv>", "Generate CSV file with the most important benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-output-json=<output.json>", "Generate JSON file with all benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-sanity-check", "Run benchmarks for only one iteration with no output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-priority-level=<l1,l2,l3>", strprintf("Run benchmarks of one or multiple priority level(s) (%s), default: '%s'",
benchmark::ListPriorities(), DEFAULT_PRIORITY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
}
// parses a comma separated list like "10,20,30,50"
static std::vector<double> parseAsymptote(const std::string& str) {
std::stringstream ss(str);
std::vector<double> numbers;
double d;
char c;
while (ss >> d) {
numbers.push_back(d);
ss >> c;
}
return numbers;
}
static uint8_t parsePriorityLevel(const std::string& str) {
uint8_t levels{0};
for (const auto& level: SplitString(str, ',')) {
levels |= benchmark::StringToPriority(level);
}
return levels;
}
int main(int argc, char** argv)
{
ArgsManager argsman;
SetupBenchArgs(argsman);
SHA256AutoDetect();
std::string error;
if (!argsman.ParseParameters(argc, argv, error)) {
tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
return EXIT_FAILURE;
}
if (HelpRequested(argsman)) {
std::cout << "Usage: bench_bitcoin [options]\n"
"\n"
<< argsman.GetHelpMessage()
<< "Description:\n"
"\n"
" bench_bitcoin executes microbenchmarks. The quality of the benchmark results\n"
" highly depend on the stability of the machine. It can sometimes be difficult\n"
" to get stable, repeatable results, so here are a few tips:\n"
"\n"
" * Use pyperf [1] to disable frequency scaling, turbo boost etc. For best\n"
" results, use CPU pinning and CPU isolation (see [2]).\n"
"\n"
" * Each call of run() should do exactly the same work. E.g. inserting into\n"
" a std::vector doesn't do that as it will reallocate on certain calls. Make\n"
" sure each run has exactly the same preconditions.\n"
"\n"
" * If results are still not reliable, increase runtime with e.g.\n"
" -min-time=5000 to let a benchmark run for at least 5 seconds.\n"
"\n"
" * bench_bitcoin uses nanobench [3] for which there is extensive\n"
" documentation available online.\n"
"\n"
"Environment Variables:\n"
"\n"
" To attach a profiler you can run a benchmark in endless mode. This can be\n"
" done with the environment variable NANOBENCH_ENDLESS. E.g. like so:\n"
"\n"
" NANOBENCH_ENDLESS=MuHash ./bench_bitcoin -filter=MuHash\n"
"\n"
" In rare cases it can be useful to suppress stability warnings. This can be\n"
" done with the environment variable NANOBENCH_SUPPRESS_WARNINGS, e.g:\n"
"\n"
" NANOBENCH_SUPPRESS_WARNINGS=1 ./bench_bitcoin\n"
"\n"
"Notes:\n"
"\n"
" 1. pyperf\n"
" https://github.com/psf/pyperf\n"
"\n"
" 2. CPU pinning & isolation\n"
" https://pyperf.readthedocs.io/en/latest/system.html\n"
"\n"
" 3. nanobench\n"
" https://github.com/martinus/nanobench\n"
"\n";
return EXIT_SUCCESS;
}
try {
benchmark::Args args;
args.asymptote = parseAsymptote(argsman.GetArg("-asymptote", ""));
args.is_list_only = argsman.GetBoolArg("-list", false);
args.min_time = std::chrono::milliseconds(argsman.GetIntArg("-min-time", DEFAULT_MIN_TIME_MS));
args.output_csv = argsman.GetPathArg("-output-csv");
args.output_json = argsman.GetPathArg("-output-json");
args.regex_filter = argsman.GetArg("-filter", DEFAULT_BENCH_FILTER);
args.sanity_check = argsman.GetBoolArg("-sanity-check", false);
args.priority = parsePriorityLevel(argsman.GetArg("-priority-level", DEFAULT_PRIORITY));
benchmark::BenchRunner::RunAll(args);
return EXIT_SUCCESS;
} catch (const std::exception& e) {
tfm::format(std::cerr, "Error: %s\n", e.what());
return EXIT_FAILURE;
}
}