diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index d878fb210d3f..2e8ded03c602 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -35,6 +35,7 @@ option(ENABLE_STACKTRACES "Enable stack traces on assertion" OFF) option(ENABLE_TRACY "Enable low-medium overhead profiling for memory and performance with tracy" OFF) option(ENABLE_PIC "Builds with position independent code" OFF) option(SYNTAX_ONLY "only check syntax (-fsyntax-only)" OFF) +option(ENABLE_WASM_BENCH "Enable BB_BENCH benchmarking support in WASM builds (dev only, not for releases)" OFF) option(AVM "enable building of vm2 module and bb-avm" ON) if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64") @@ -97,6 +98,10 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "wasm32") set(OMP_MULTITHREADING OFF) set(ENABLE_PAR_ALGOS 0) add_compile_definitions(_WASI_EMULATED_PROCESS_CLOCKS=1) + if(ENABLE_WASM_BENCH) + message(STATUS "Enabling WASM benchmarking support (ENABLE_WASM_BENCH)") + add_compile_definitions(ENABLE_WASM_BENCH) + endif() endif() set(CMAKE_C_STANDARD 11) diff --git a/barretenberg/cpp/bootstrap.sh b/barretenberg/cpp/bootstrap.sh index ef88c2ff45fc..538dca033bc4 100755 --- a/barretenberg/cpp/bootstrap.sh +++ b/barretenberg/cpp/bootstrap.sh @@ -61,11 +61,15 @@ function inject_version { function build_preset() { local preset=$1 shift - local avm_transpiler_flag="" + local cmake_args=() if [ "${AVM_TRANSPILER:-1}" -eq 0 ]; then - avm_transpiler_flag="-DAVM_TRANSPILER_LIB=" + cmake_args+=(-DAVM_TRANSPILER_LIB=) fi - cmake --fresh --preset "$preset" $avm_transpiler_flag + # Auto-enable ENABLE_WASM_BENCH for wasm-threads preset on non-semver builds + if [[ "$preset" == "wasm-threads" ]] && ! semver check "$REF_NAME"; then + cmake_args+=(-DENABLE_WASM_BENCH=ON) + fi + cmake --fresh --preset "$preset" "${cmake_args[@]}" cmake --build --preset "$preset" "$@" } diff --git a/barretenberg/cpp/scripts/wasmtime.sh b/barretenberg/cpp/scripts/wasmtime.sh index 439cb5a43649..3ad657d5798d 100755 --- a/barretenberg/cpp/scripts/wasmtime.sh +++ b/barretenberg/cpp/scripts/wasmtime.sh @@ -9,6 +9,7 @@ exec wasmtime run \ ${HARDWARE_CONCURRENCY:+--env HARDWARE_CONCURRENCY} \ --env HOME \ ${MAIN_ARGS:+--env MAIN_ARGS} \ + ${BB_BENCH:+--env BB_BENCH} \ --dir=$HOME/.bb-crs \ --dir=. \ "$@" diff --git a/barretenberg/cpp/src/barretenberg/bb/cli.cpp b/barretenberg/cpp/src/barretenberg/bb/cli.cpp index d0d72dea4e86..d9933a1f913e 100644 --- a/barretenberg/cpp/src/barretenberg/bb/cli.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/cli.cpp @@ -553,12 +553,13 @@ int parse_and_run_cli_command(int argc, char* argv[]) debug_logging = flags.debug; verbose_logging = debug_logging || flags.verbose; slow_low_memory = flags.slow_low_memory; -#ifndef __wasm__ +#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH) if (!flags.storage_budget.empty()) { storage_budget = parse_size_string(flags.storage_budget); } if (print_bench || !bench_out.empty() || !bench_out_hierarchical.empty()) { bb::detail::use_bb_bench = true; + vinfo("BB_BENCH enabled via --print_bench or --bench_out"); } #endif @@ -649,9 +650,11 @@ int parse_and_run_cli_command(int argc, char* argv[]) " (default ./ivc-inputs.msgpack)"); } api.prove(flags, ivc_inputs_path, output_path); -#ifndef __wasm__ +#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH) if (print_bench) { + vinfo("Printing BB_BENCH results..."); bb::detail::GLOBAL_BENCH_STATS.print_aggregate_counts_hierarchical(std::cout); + std::cout << std::flush; } if (!bench_out.empty()) { std::ofstream file(bench_out); @@ -677,7 +680,7 @@ int parse_and_run_cli_command(int argc, char* argv[]) UltraHonkAPI api; if (prove->parsed()) { api.prove(flags, bytecode_path, witness_path, vk_path, output_path); -#ifndef __wasm__ +#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH) if (print_bench) { bb::detail::GLOBAL_BENCH_STATS.print_aggregate_counts_hierarchical(std::cout); } diff --git a/barretenberg/cpp/src/barretenberg/common/bb_bench.cpp b/barretenberg/cpp/src/barretenberg/common/bb_bench.cpp index eb60779094b0..2d7794c7c30f 100644 --- a/barretenberg/cpp/src/barretenberg/common/bb_bench.cpp +++ b/barretenberg/cpp/src/barretenberg/common/bb_bench.cpp @@ -1,7 +1,7 @@ #include "barretenberg/common/assert.hpp" #include #include -#ifndef __wasm__ +#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH) #include "barretenberg/serialize/msgpack_impl.hpp" #include "bb_bench.hpp" #include @@ -182,7 +182,7 @@ void AggregateEntry::add_thread_time_sample(const TimeAndCount& stats) // Account for aggregate time and count time += stats.time; count += stats.count; - time_max = std::max(static_cast(stats.time), time_max); + time_max = std::max(stats.time, time_max); // Use Welford's method to be able to track the variance num_threads++; double delta = static_cast(stats.time) - time_mean; @@ -300,12 +300,12 @@ void GlobalBenchStatsContainer::print_aggregate_counts(std::ostream& os, size_t // Serializable structure for a single benchmark entry (msgpack-compatible) struct SerializableEntry { std::string parent; - std::size_t time; - std::size_t time_max; + uint64_t time; + uint64_t time_max; double time_mean; double time_stddev; - std::size_t count; - std::size_t num_threads; + uint64_t count; + uint64_t num_threads; MSGPACK_FIELDS(parent, time, time_max, time_mean, time_stddev, count, num_threads); }; @@ -578,7 +578,7 @@ void GlobalBenchStatsContainer::print_aggregate_counts_hierarchical(std::ostream uint64_t total_time = 0; for (const auto& [_, parent_map] : aggregated) { if (auto it = parent_map.find(""); it != parent_map.end()) { - total_time = std::max(static_cast(total_time), it->second.time_max); + total_time = std::max(total_time, it->second.time_max); } } diff --git a/barretenberg/cpp/src/barretenberg/common/bb_bench.hpp b/barretenberg/cpp/src/barretenberg/common/bb_bench.hpp index f01f5de0513f..ea858c2198ff 100644 --- a/barretenberg/cpp/src/barretenberg/common/bb_bench.hpp +++ b/barretenberg/cpp/src/barretenberg/common/bb_bench.hpp @@ -58,11 +58,11 @@ struct AggregateEntry { // For convenience, even though redundant with map store OperationKey key; OperationKey parent; - std::size_t time = 0; - std::size_t count = 0; + uint64_t time = 0; + uint64_t count = 0; size_t num_threads = 0; double time_mean = 0; - std::size_t time_max = 0; + uint64_t time_max = 0; double time_stddev = 0; // Welford's algorithm state @@ -106,19 +106,19 @@ extern GlobalBenchStatsContainer GLOBAL_BENCH_STATS; // but doesn't provide recursive parent-child relationships through the entire call stack. struct TimeStats { TimeStatsEntry* parent = nullptr; - std::size_t count = 0; - std::size_t time = 0; + uint64_t count = 0; + uint64_t time = 0; // Used if the parent changes from last call - chains to handle multiple parent contexts std::unique_ptr next; TimeStats() = default; - TimeStats(TimeStatsEntry* parent_ptr, std::size_t count_val, std::size_t time_val) + TimeStats(TimeStatsEntry* parent_ptr, uint64_t count_val, uint64_t time_val) : parent(parent_ptr) , count(count_val) , time(time_val) {} - void track(TimeStatsEntry* current_parent, std::size_t time_val) + void track(TimeStatsEntry* current_parent, uint64_t time_val) { // Try to track with current stats if parent matches // Check if 'next' already handles this parent to avoid creating duplicates @@ -138,7 +138,7 @@ struct TimeStats { private: // Returns true if successfully tracked (parent matches), false otherwise - bool raw_track(TimeStatsEntry* expected_parent, std::size_t time_val) + bool raw_track(TimeStatsEntry* expected_parent, uint64_t time_val) { if (parent != expected_parent) { return false; @@ -181,7 +181,7 @@ template struct ThreadBenchStats { struct BenchReporter { TimeStatsEntry* parent; TimeStatsEntry* stats; - std::size_t time; + uint64_t time; BenchReporter(TimeStatsEntry* entry); ~BenchReporter(); }; @@ -196,7 +196,7 @@ struct BenchReporter { #define BB_BENCH_ONLY_NAME(name) (void)0 #define BB_BENCH_ENABLE_NESTING() (void)0 #define BB_BENCH_ONLY() (void)0 -#elif defined __wasm__ +#elif defined __wasm__ && !defined ENABLE_WASM_BENCH #define BB_TRACY() (void)0 #define BB_TRACY_NAME(name) (void)0 #define BB_BENCH_TRACY() (void)0 diff --git a/barretenberg/cpp/src/barretenberg/polynomials/backing_memory.cpp b/barretenberg/cpp/src/barretenberg/polynomials/backing_memory.cpp index 13c9ecd1c4b8..2336c95521d7 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/backing_memory.cpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/backing_memory.cpp @@ -10,9 +10,19 @@ bool slow_low_memory = std::getenv("BB_SLOW_LOW_MEMORY") == nullptr ? false : std::string(std::getenv("BB_SLOW_LOW_MEMORY")) == "1"; -// Storage budget is disabled for WASM builds -#ifndef __wasm__ +// Storage budget is disabled for WASM builds unless ENABLE_WASM_BENCH is defined +#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH) +#if defined(__wasm__) && defined(BB_NO_EXCEPTIONS) +// Simplified version for WASM builds without exception support +// For WASM benchmarking, we don't enforce storage budgets +size_t parse_size_string(const std::string& /* size_str */) +{ + // Return unlimited budget for WASM builds + return std::numeric_limits::max(); +} +#else +// Full version with exception handling for native builds // Parse storage size string (e.g., "500m", "2g", "1024k") size_t parse_size_string(const std::string& size_str) { @@ -55,6 +65,7 @@ size_t parse_size_string(const std::string& size_str) throw_or_abort("Invalid storage size format: '" + size_str + "'. Value out of range"); } } +#endif namespace { // Parse storage budget from environment variable (supports k/m/g suffixes like Docker) @@ -75,4 +86,4 @@ size_t storage_budget = parse_storage_budget(); // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) std::atomic current_storage_usage{ 0 }; -#endif // __wasm__ +#endif // !defined(__wasm__) || defined(ENABLE_WASM_BENCH)