diff --git a/barretenberg/cpp/src/barretenberg/vm2/common/ankerl_map.hpp b/barretenberg/cpp/src/barretenberg/vm2/common/ankerl_dense.hpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/vm2/common/ankerl_map.hpp rename to barretenberg/cpp/src/barretenberg/vm2/common/ankerl_dense.hpp diff --git a/barretenberg/cpp/src/barretenberg/vm2/common/map.hpp b/barretenberg/cpp/src/barretenberg/vm2/common/map.hpp index 0f0d12514ec8..964bdd179baf 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/common/map.hpp +++ b/barretenberg/cpp/src/barretenberg/vm2/common/map.hpp @@ -1,6 +1,6 @@ #pragma once -#include "barretenberg/vm2/common/ankerl_map.hpp" +#include "barretenberg/vm2/common/ankerl_dense.hpp" namespace bb::avm2 { @@ -16,4 +16,4 @@ template using unordered_flat_map = ::ankerl::unordered_den // Note: if we eventually want to have lower memory usage at the cost of some speed, // we can use ::ankerl::unordered_dense::segmented_map instead. -} // namespace bb::avm2 \ No newline at end of file +} // namespace bb::avm2 diff --git a/barretenberg/cpp/src/barretenberg/vm2/common/set.hpp b/barretenberg/cpp/src/barretenberg/vm2/common/set.hpp new file mode 100644 index 000000000000..5a6c2c9dc274 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm2/common/set.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "barretenberg/vm2/common/ankerl_dense.hpp" + +namespace bb::avm2 { + +// We use an alternative single-header implementation that is faster and more memory efficient. +// https://github.com/martinus/unordered_dense +// https://martin.ankerl.com/2019/04/01/hashmap-benchmarks-01-overview/ +// https://github.com/martinus/robin-hood-hashing is archived and recommends ankerl::unordered_dense. +template using unordered_flat_set = ::ankerl::unordered_dense::set; + +} // namespace bb::avm2 diff --git a/barretenberg/cpp/src/barretenberg/vm2/simulation/bytecode_manager.cpp b/barretenberg/cpp/src/barretenberg/vm2/simulation/bytecode_manager.cpp index 6c03f2c61276..1fa299c8e7a9 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/simulation/bytecode_manager.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/simulation/bytecode_manager.cpp @@ -55,10 +55,11 @@ Instruction TxBytecodeManager::read_instruction(BytecodeId bytecode_id, uint32_t // TODO: catch errors etc. Instruction instruction = decode_instruction(bytecode, pc); + // The event will be deduplicated internally. fetching_events.emit( { .bytecode_id = bytecode_id, .pc = pc, .instruction = instruction, .bytecode = bytecode_ptr }); return instruction; } -} // namespace bb::avm2::simulation \ No newline at end of file +} // namespace bb::avm2::simulation diff --git a/barretenberg/cpp/src/barretenberg/vm2/simulation/events/bytecode_events.hpp b/barretenberg/cpp/src/barretenberg/vm2/simulation/events/bytecode_events.hpp index cf086d2e88b6..9f247cb5d7a5 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/simulation/events/bytecode_events.hpp +++ b/barretenberg/cpp/src/barretenberg/vm2/simulation/events/bytecode_events.hpp @@ -44,6 +44,10 @@ struct InstructionFetchingEvent { // TODO: Do we want to have a dep on Instruction here or do we redefine what we need? Instruction instruction; std::shared_ptr> bytecode; + + // To be used with deduplicating event emitters. + using Key = std::tuple; + Key get_key() const { return { bytecode_id, pc }; } }; -} // namespace bb::avm2::simulation \ No newline at end of file +} // namespace bb::avm2::simulation diff --git a/barretenberg/cpp/src/barretenberg/vm2/simulation/events/event_emitter.hpp b/barretenberg/cpp/src/barretenberg/vm2/simulation/events/event_emitter.hpp index ea1082b796a7..34aeaef0f8e1 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/simulation/events/event_emitter.hpp +++ b/barretenberg/cpp/src/barretenberg/vm2/simulation/events/event_emitter.hpp @@ -3,6 +3,8 @@ #include #include +#include "barretenberg/vm2/common/set.hpp" + namespace bb::avm2::simulation { template class EventEmitterInterface { @@ -30,6 +32,29 @@ template class EventEmitter : public EventEmitterInterface class DeduplicatingEventEmitter : public EventEmitter { + public: + virtual ~DeduplicatingEventEmitter() = default; + + void emit(Event&& event) override + { + typename Event::Key key = event.get_key(); + if (!elements_seen.contains(key)) { + elements_seen.insert(key); + EventEmitter::emit(std::move(event)); + } + }; + EventEmitter::Container dump_events() override + { + elements_seen.clear(); + return EventEmitter::dump_events(); + } + + private: + unordered_flat_set elements_seen; +}; + // This is an event emmiter that offers stable references to the events. // It lets you access the last event that was emitted. // Note: this is currently unused but it might be needed for the execution trace (calls). @@ -64,4 +89,4 @@ template class NoopEventEmitter : public EventEmitterInterface< Container dump_events() override { return {}; } }; -} // namespace bb::avm2::simulation \ No newline at end of file +} // namespace bb::avm2::simulation diff --git a/barretenberg/cpp/src/barretenberg/vm2/simulation_helper.cpp b/barretenberg/cpp/src/barretenberg/vm2/simulation_helper.cpp index 8eac6544a444..e3a1fb6e105d 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/simulation_helper.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/simulation_helper.cpp @@ -39,11 +39,13 @@ namespace { // Configuration for full simulation (for proving). struct ProvingSettings { template using DefaultEventEmitter = EventEmitter; + template using DefaultDeduplicatingEventEmitter = DeduplicatingEventEmitter; }; // Configuration for fast simulation. struct FastSettings { template using DefaultEventEmitter = NoopEventEmitter; + template using DefaultDeduplicatingEventEmitter = NoopEventEmitter; }; } // namespace @@ -58,7 +60,7 @@ template EventsContainer AvmSimulationHelper::simulate_with_setting typename S::template DefaultEventEmitter bytecode_retrieval_emitter; typename S::template DefaultEventEmitter bytecode_hashing_emitter; typename S::template DefaultEventEmitter bytecode_decomposition_emitter; - typename S::template DefaultEventEmitter instruction_fetching_emitter; + typename S::template DefaultDeduplicatingEventEmitter instruction_fetching_emitter; typename S::template DefaultEventEmitter address_derivation_emitter; typename S::template DefaultEventEmitter class_id_derivation_emitter; typename S::template DefaultEventEmitter siloing_emitter;