From 0c458fab9d411b8b63ed9ab6d3244c0617113672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Thu, 7 Mar 2024 23:07:05 +0100 Subject: [PATCH 1/3] Add benchmarking library --- .gitmodules | 3 +++ CMakeLists.txt | 5 +++++ nano/benchmarks/CMakeLists.txt | 5 +++++ nano/benchmarks/entry.cpp | 0 submodules/benchmark | 1 + 5 files changed, 14 insertions(+) create mode 100644 nano/benchmarks/CMakeLists.txt create mode 100644 nano/benchmarks/entry.cpp create mode 160000 submodules/benchmark diff --git a/.gitmodules b/.gitmodules index c1d9a0bf26..6417e2174e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,3 +37,6 @@ [submodule "submodules/fmt"] path = submodules/fmt url = https://github.com/fmtlib/fmt.git +[submodule "submodules/benchmark"] + path = submodules/benchmark + url = https://github.com/google/benchmark.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 10d92541ca..436e1cffc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -737,10 +737,15 @@ if(NANO_TEST OR RAIBLOCKS_TEST) gtest PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/submodules/gtest/googletest/include") + set(BENCHMARK_ENABLE_TESTING OFF) + add_subdirectory(submodules/benchmark) + add_subdirectory(nano/test_common) add_subdirectory(nano/core_test) add_subdirectory(nano/rpc_test) add_subdirectory(nano/slow_test) + add_subdirectory(nano/benchmarks) + add_custom_target( all_tests COMMAND echo "BATCH BUILDING TESTS" diff --git a/nano/benchmarks/CMakeLists.txt b/nano/benchmarks/CMakeLists.txt new file mode 100644 index 0000000000..97aa9665bb --- /dev/null +++ b/nano/benchmarks/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(benchmarks entry.cpp) + +target_link_libraries(benchmarks test_common benchmark::benchmark) + +include_directories(${CMAKE_SOURCE_DIR}/submodules) diff --git a/nano/benchmarks/entry.cpp b/nano/benchmarks/entry.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/submodules/benchmark b/submodules/benchmark new file mode 160000 index 0000000000..eaafe694d2 --- /dev/null +++ b/submodules/benchmark @@ -0,0 +1 @@ +Subproject commit eaafe694d27f31fe05dd9d055da1e57c8d37a004 From 134eca17868b02c2f3e7cd46aae7477f9a8bcf7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Thu, 7 Mar 2024 23:18:34 +0100 Subject: [PATCH 2/3] Stats benchmarks --- nano/benchmarks/CMakeLists.txt | 2 +- nano/benchmarks/entry.cpp | 20 ++++++++++++++ nano/benchmarks/stats.cpp | 49 ++++++++++++++++++++++++++++++++++ nano/lib/logging.cpp | 14 +++++++++- nano/lib/logging.hpp | 1 + 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 nano/benchmarks/stats.cpp diff --git a/nano/benchmarks/CMakeLists.txt b/nano/benchmarks/CMakeLists.txt index 97aa9665bb..dc3829303d 100644 --- a/nano/benchmarks/CMakeLists.txt +++ b/nano/benchmarks/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(benchmarks entry.cpp) +add_executable(benchmarks entry.cpp stats.cpp) target_link_libraries(benchmarks test_common benchmark::benchmark) diff --git a/nano/benchmarks/entry.cpp b/nano/benchmarks/entry.cpp index e69de29bb2..ed325334e8 100644 --- a/nano/benchmarks/entry.cpp +++ b/nano/benchmarks/entry.cpp @@ -0,0 +1,20 @@ +#include + +static void BM_StringCreation (benchmark::State & state) +{ + for (auto _ : state) + std::string empty_string; +} +// Register the function as a benchmark +BENCHMARK (BM_StringCreation); + +// Define another benchmark +static void BM_StringCopy (benchmark::State & state) +{ + std::string x = "hello"; + for (auto _ : state) + std::string copy (x); +} +BENCHMARK (BM_StringCopy); + +BENCHMARK_MAIN (); \ No newline at end of file diff --git a/nano/benchmarks/stats.cpp b/nano/benchmarks/stats.cpp new file mode 100644 index 0000000000..05725cb60f --- /dev/null +++ b/nano/benchmarks/stats.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +#include + +#include + +static void BM_stats_inc_single (benchmark::State & state) +{ + nano::logger::initialize_dummy (); + nano::stats stats{ nano::default_logger () }; + + for (auto _ : state) + { + stats.inc (nano::stat::type::ledger, nano::stat::detail::open); + } +} + +BENCHMARK (BM_stats_inc_single); +BENCHMARK (BM_stats_inc_single)->Threads (10); + +static void BM_stats_inc_random (benchmark::State & state) +{ + nano::logger::initialize_dummy (); + nano::stats stats{ nano::default_logger () }; + + auto random_subset = [] (auto elements, size_t count) -> std::vector { + std::shuffle (elements.begin (), elements.end (), std::mt19937 (std::random_device () ())); + return { elements.begin (), elements.begin () + std::min (count, elements.size ()) }; + }; + + auto stat_types = random_subset (nano::enum_util::values (), state.range (0)); + auto stat_details = random_subset (nano::enum_util::values (), state.range (1)); + + size_t type_index = 0; + size_t detail_index = 0; + + for (auto _ : state) + { + stats.inc (stat_types[type_index], stat_details[detail_index]); + + type_index = (type_index + 1) % stat_types.size (); + detail_index = (detail_index + 1) % stat_details.size (); + } +} + +BENCHMARK (BM_stats_inc_random)->Args ({ 32, 32 }); +BENCHMARK (BM_stats_inc_random)->Args ({ 32, 32 })->Threads (10); \ No newline at end of file diff --git a/nano/lib/logging.cpp b/nano/lib/logging.cpp index 0953007fa0..c6d1a67738 100644 --- a/nano/lib/logging.cpp +++ b/nano/lib/logging.cpp @@ -117,6 +117,18 @@ void nano::logger::initialize_for_tests (nano::log_config fallback) global_initialized = true; } +void nano::logger::initialize_dummy () +{ + nano::log_config config{ + .default_level = nano::log::level::off, + .flush_level = nano::log::level::off, + .console.enable = false, + .file.enable = false, + }; + initialize_common (config, std::nullopt); + global_initialized = true; +} + // Using std::cerr here, since logging may not be initialized yet void nano::logger::initialize_common (nano::log_config const & config, std::optional data_path) { @@ -307,7 +319,7 @@ nano::log_config nano::log_config::cli_default () { log_config config{}; config.default_level = nano::log::level::critical; - config.console.colors = false; // to avoid printing warning about cerr and colors + config.console.colors = false; config.console.to_cerr = true; // Use cerr to avoid interference with CLI output that goes to stdout config.file.enable = false; return config; diff --git a/nano/lib/logging.hpp b/nano/lib/logging.hpp index ae9563300a..3d059ee9e9 100644 --- a/nano/lib/logging.hpp +++ b/nano/lib/logging.hpp @@ -157,6 +157,7 @@ class logger final public: static void initialize (nano::log_config fallback, std::optional data_path = std::nullopt, std::vector const & config_overrides = {}); static void initialize_for_tests (nano::log_config fallback); + static void initialize_dummy (); // TODO: This is less than ideal, provide `nano::dummy_logger ()` instead static void flush (); private: From 6a0d882b07e18d63ff483f6bf344022fc7c8fe51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:33:25 +0200 Subject: [PATCH 3/3] Store & ledger benchmarks --- nano/benchmarks/CMakeLists.txt | 2 +- nano/benchmarks/ledger.cpp | 105 +++++++++++++++++++++++++++ nano/secure/generate_cache_flags.hpp | 12 +++ nano/store/lmdb/lmdb.hpp | 1 + 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 nano/benchmarks/ledger.cpp diff --git a/nano/benchmarks/CMakeLists.txt b/nano/benchmarks/CMakeLists.txt index dc3829303d..94a3e64f21 100644 --- a/nano/benchmarks/CMakeLists.txt +++ b/nano/benchmarks/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(benchmarks entry.cpp stats.cpp) +add_executable(benchmarks entry.cpp ledger.cpp stats.cpp) target_link_libraries(benchmarks test_common benchmark::benchmark) diff --git a/nano/benchmarks/ledger.cpp b/nano/benchmarks/ledger.cpp new file mode 100644 index 0000000000..53660e0300 --- /dev/null +++ b/nano/benchmarks/ledger.cpp @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +// Expects live ledger in default location +// PLEASE NOTE: Make sure to purge disk cache between runs (`purge` command on macOS) +static void BM_ledger_iterate_accounts (benchmark::State & state) +{ + nano::logger::initialize_dummy (); + nano::logger logger; + nano::stats stats{ logger }; + + // Use live ledger + nano::networks network = nano::networks::nano_live_network; + nano::network_params network_params{ network }; + nano::node_config config{ network_params }; + config.rocksdb_config.enable = state.range (0); + auto application_path = nano::working_path (network); + + auto store_impl{ nano::make_store (logger, application_path, network_params.ledger, false, true, config.rocksdb_config, config.diagnostics_config.txn_tracking, config.block_processor_batch_max_time, config.lmdb_config, config.backup_before_upgrade) }; + auto & store{ *store_impl }; + + if (store.init_error ()) + { + state.SkipWithError ("Store initialization failed. Make sure ledger files are present in the default location."); + } + + auto ledger_impl{ std::make_unique (store, stats, network_params.ledger, nano::generate_cache_flags::all_disabled (), config.representative_vote_weight_minimum.number ()) }; + auto & ledger{ *ledger_impl }; + + auto transaction = ledger.tx_begin_read (); + nano::account current{ 0 }; + nano::account_info current_info; + auto it = ledger.any.account_begin (transaction); + for (auto _ : state) + { + if (it != ledger.any.account_end ()) + { + current = it->first; + current_info = it->second; + benchmark::DoNotOptimize (current); + benchmark::DoNotOptimize (current_info); + + ++it; + } + else + { + break; + } + } +} +BENCHMARK (BM_ledger_iterate_accounts)->ArgName ("use_rocksdb")->Arg (0)->Arg (1); + +// Expects live ledger in default location +// PLEASE NOTE: Make sure to purge disk cache between runs (`purge` command on macOS) +static void BM_store_iterate_accounts (benchmark::State & state) +{ + nano::logger::initialize_dummy (); + nano::logger logger; + nano::stats stats{ logger }; + + // Use live ledger + nano::networks network = nano::networks::nano_live_network; + nano::network_params network_params{ network }; + nano::node_config config{ network_params }; + config.rocksdb_config.enable = state.range (0); + nano::node_flags flags; + auto application_path = nano::working_path (network); + + auto store_impl{ nano::make_store (logger, application_path, network_params.ledger, false, true, config.rocksdb_config, config.diagnostics_config.txn_tracking, config.block_processor_batch_max_time, config.lmdb_config, config.backup_before_upgrade, flags.force_use_write_queue) }; + auto & store{ *store_impl }; + + if (store.init_error ()) + { + state.SkipWithError ("Store initialization failed. Make sure ledger files are present in the default location."); + } + + auto transaction = store.tx_begin_read (); + nano::account current{ 0 }; + nano::account_info current_info; + auto it = store.account.begin (transaction); + for (auto _ : state) + { + if (it != store.account.end ()) + { + current = it->first; + current_info = it->second; + benchmark::DoNotOptimize (current); + benchmark::DoNotOptimize (current_info); + + ++it; + } + else + { + break; + } + } +} +BENCHMARK (BM_store_iterate_accounts)->ArgName ("use_rocksdb")->Arg (0)->Arg (1); \ No newline at end of file diff --git a/nano/secure/generate_cache_flags.hpp b/nano/secure/generate_cache_flags.hpp index 29445e53d8..f3d832d70d 100644 --- a/nano/secure/generate_cache_flags.hpp +++ b/nano/secure/generate_cache_flags.hpp @@ -14,5 +14,17 @@ class generate_cache_flags bool block_count = true; void enable_all (); + +public: + static generate_cache_flags all_disabled () + { + generate_cache_flags flags; + flags.reps = false; + flags.cemented_count = false; + flags.unchecked_count = false; + flags.account_count = false; + flags.block_count = false; + return flags; + } }; } diff --git a/nano/store/lmdb/lmdb.hpp b/nano/store/lmdb/lmdb.hpp index 8cf9d94bc3..3a87154695 100644 --- a/nano/store/lmdb/lmdb.hpp +++ b/nano/store/lmdb/lmdb.hpp @@ -64,6 +64,7 @@ class component : public nano::store::component public: component (nano::logger &, std::filesystem::path const &, nano::ledger_constants & constants, nano::txn_tracking_config const & txn_tracking_config_a = nano::txn_tracking_config{}, std::chrono::milliseconds block_processor_batch_max_time_a = std::chrono::milliseconds (5000), nano::lmdb_config const & lmdb_config_a = nano::lmdb_config{}, bool backup_before_upgrade = false); + store::write_transaction tx_begin_write (std::vector const & tables_requiring_lock = {}, std::vector const & tables_no_lock = {}) override; store::read_transaction tx_begin_read () const override;