From 8347ac8c8639b20c592098aa0bcc4e518d9123f1 Mon Sep 17 00:00:00 2001 From: notV4l <122404722+notV4l@users.noreply.github.com> Date: Tue, 18 Jun 2024 05:33:09 +0200 Subject: [PATCH] [dojo-core]: update gas logs (#1877) dojo-core: update gas logs Co-authored-by: glihm --- crates/dojo-core/src/benchmarks.cairo | 209 ++++++++---------- .../dojo-core/src/database/introspect.cairo | 3 - crates/dojo-core/src/test_utils.cairo | 60 ++--- crates/dojo-core/src/world_test.cairo | 25 +-- 4 files changed, 139 insertions(+), 158 deletions(-) diff --git a/crates/dojo-core/src/benchmarks.cairo b/crates/dojo-core/src/benchmarks.cairo index 2aa7482f53..b0e827ed25 100644 --- a/crates/dojo-core/src/benchmarks.cairo +++ b/crates/dojo-core/src/benchmarks.cairo @@ -10,15 +10,14 @@ use dojo::database; use dojo::database::storage; use dojo::model::Model; use dojo::world_test::Foo; -use dojo::test_utils::end; - +use dojo::test_utils::GasCounterImpl; +use dojo::database::introspect::{Introspect, Layout}; #[test] #[available_gas(1000000000)] fn bench_reference_offset() { - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); - end(gas, 'bench empty'); + let gas = GasCounterImpl::start(); + gas.end("bench empty"); } #[test] @@ -26,15 +25,13 @@ fn bench_reference_offset() { fn bench_storage_single() { let keys = array!['database_test', '42'].span(); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); storage::set(0, keys, 420); - end(gas, 'storage set'); + gas.end("storage set"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let res = storage::get(0, keys); - end(gas, 'storage get'); + gas.end("storage get"); assert(res == 420, 'values differ'); } @@ -46,15 +43,13 @@ fn bench_storage_many() { let values = array![1, 2].span(); let layout = array![251, 251].span(); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); storage::set_many(0, keys, values, 0, layout).unwrap(); - end(gas, 'storage set mny'); + gas.end("storage set_many"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let res = storage::get_many(0, keys, layout).unwrap(); - end(gas, 'storage get mny'); + gas.end("storage get_many"); assert(res.len() == 2, 'wrong number of values'); assert(*res.at(0) == *values.at(0), 'value not set'); @@ -64,22 +59,19 @@ fn bench_storage_many() { #[test] #[available_gas(1000000000)] fn bench_native_storage() { - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let keys = array![0x1337].span(); let base = starknet::storage_base_address_from_felt252(poseidon_hash_span(keys)); let address = starknet::storage_address_from_base(base); - end(gas, 'native prep'); + gas.end("native prep"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); starknet::storage_write_syscall(0, address, 42).unwrap_syscall(); - end(gas, 'native write'); + gas.end("native write"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let value = starknet::storage_read_syscall(0, address).unwrap_syscall(); - end(gas, 'native read'); + gas.end("native read"); assert(value == 42, 'read invalid'); } @@ -87,22 +79,19 @@ fn bench_native_storage() { #[test] #[available_gas(1000000000)] fn bench_native_storage_offset() { - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let keys = array![0x1337].span(); let base = starknet::storage_base_address_from_felt252(poseidon_hash_span(keys)); let address = starknet::storage_address_from_base_and_offset(base, 42); - end(gas, 'native prep of'); + gas.end("native prep of"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); starknet::storage_write_syscall(0, address, 42).unwrap_syscall(); - end(gas, 'native writ of'); + gas.end("native writ of"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let value = starknet::storage_read_syscall(0, address).unwrap_syscall(); - end(gas, 'native read of'); + gas.end("native read of"); assert(value == 42, 'read invalid'); } @@ -129,15 +118,13 @@ fn bench_database_array() { i += 1; }; - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); database::set('table', 'key', values.span(), 0, layout.span()); - end(gas, 'db set arr'); + gas.end("db set arr"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let res = database::get('table', 'key', layout.span()); - end(gas, 'db get arr'); + gas.end("db get arr"); let mut i = 0; loop { @@ -155,23 +142,20 @@ fn bench_database_array() { fn bench_simple_struct() { let caller = starknet::contract_address_const::<0x42>(); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let mut foo = Foo { caller, a: 0x123456789abcdef, b: 0x123456789abcdef, }; - end(gas, 'foo init'); + gas.end("foo init"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let mut serialized = ArrayTrait::new(); serde::Serde::serialize(@foo.a, ref serialized); serde::Serde::serialize(@foo.b, ref serialized); let serialized = array::ArrayTrait::span(@serialized); - end(gas, 'foo serialize'); + gas.end("foo serialize"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let values: Span = foo.values(); - end(gas, 'foo values'); + gas.end("foo values"); assert(serialized.len() == 2, 'serialized wrong length'); assert(values.len() == 2, 'value wrong length'); @@ -179,7 +163,7 @@ fn bench_simple_struct() { assert(serialized.at(1) == values.at(1), 'serialized differ at 1'); } -#[derive(Introspect, Copy, Drop, Serde)] +#[derive(Copy, Drop, Serde, IntrospectPacked)] #[dojo::model] struct PositionWithQuaterions { #[key] @@ -195,11 +179,9 @@ struct PositionWithQuaterions { // TODO: this test should be adapted to benchmark the new layout system #[test] -#[ignore] #[available_gas(1000000000)] -fn test_struct_with_many_fields() { - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); +fn test_struct_with_many_fields_fixed() { + let gas = GasCounterImpl::start(); let mut pos = PositionWithQuaterions { id: 0x123456789abcdef, @@ -211,10 +193,9 @@ fn test_struct_with_many_fields() { c: 0x123456789abcdef, d: 0x123456789abcdef, }; - end(gas, 'pos init'); + gas.end("pos init"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let mut serialized = ArrayTrait::new(); serde::Serde::serialize(@pos.x, ref serialized); serde::Serde::serialize(@pos.y, ref serialized); @@ -224,12 +205,11 @@ fn test_struct_with_many_fields() { serde::Serde::serialize(@pos.c, ref serialized); serde::Serde::serialize(@pos.d, ref serialized); let serialized = array::ArrayTrait::span(@serialized); - end(gas, 'pos serialize'); + gas.end("pos serialize"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let values: Span = pos.values(); - end(gas, 'pos values'); + gas.end("pos values"); assert(serialized.len() == values.len(), 'serialized not equal'); let mut idx = 0; @@ -241,26 +221,27 @@ fn test_struct_with_many_fields() { idx += 1; }; - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let layout = match dojo::model::Model::::layout() { + Layout::Fixed(layout) => layout, + _ => panic!("expected fixed layout"), + }; - //database::set('positions', '42', pos.values(), 0, pos.instance_layout()); - end(gas, 'pos db set'); + let gas = GasCounterImpl::start(); + database::set('positions', '42', pos.values(), 0, layout); + gas.end("pos db set"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); - //database::get('positions', '42', pos.instance_layout()); - end(gas, 'pos db get'); + let gas = GasCounterImpl::start(); + database::get('positions', '42', layout); + gas.end("pos db get"); } - -#[derive(Introspect, Copy, Drop, Serde)] +#[derive(IntrospectPacked, Copy, Drop, Serde)] struct Sword { swordsmith: ContractAddress, damage: u32, } -#[derive(Introspect, Copy, Drop, Serde)] +#[derive(IntrospectPacked, Copy, Drop, Serde)] #[dojo::model] struct Case { #[key] @@ -269,35 +250,33 @@ struct Case { material: felt252, } - // TODO: this test should be adapted to benchmark the new layout system #[test] #[ignore] #[available_gas(1000000000)] -fn bench_nested_struct() { +fn bench_nested_struct_packed() { let caller = starknet::contract_address_const::<0x42>(); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let mut case = Case { owner: caller, sword: Sword { swordsmith: caller, damage: 0x12345678, }, material: 'wooden', }; - end(gas, 'case init'); + gas.end("case init"); + + // ???? let _gas = testing::get_available_gas(); gas::withdraw_gas().unwrap(); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let mut serialized = ArrayTrait::new(); serde::Serde::serialize(@case.sword, ref serialized); serde::Serde::serialize(@case.material, ref serialized); let serialized = array::ArrayTrait::span(@serialized); - end(gas, 'case serialize'); + gas.end("case serialize"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let values: Span = case.values(); - end(gas, 'case values'); + gas.end("case values"); assert(serialized.len() == values.len(), 'serialized not equal'); let mut idx = 0; @@ -309,19 +288,21 @@ fn bench_nested_struct() { idx += 1; }; - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let layout = match dojo::model::Model::::layout() { + Layout::Fixed(layout) => layout, + _ => panic!("expected fixed layout"), + }; - //database::set('cases', '42', values, case.instance_layout()); - end(gas, 'case db set'); + let gas = GasCounterImpl::start(); + database::set('cases', '42', values, 0, layout); + gas.end("case db set"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); - //database::get('cases', '42', case.instance_layout()); - end(gas, 'case db get'); + let gas = GasCounterImpl::start(); + database::get('cases', '42', layout); + gas.end("case db get"); } -#[derive(Introspect, Copy, Drop, Serde)] +#[derive(IntrospectPacked, Copy, Drop, Serde)] #[dojo::model] struct Character { #[key] @@ -333,7 +314,7 @@ struct Character { gold: u32, } -#[derive(Introspect, Copy, Drop, Serde)] +#[derive(IntrospectPacked, Copy, Drop, Serde)] struct Abilities { strength: u8, dexterity: u8, @@ -343,7 +324,7 @@ struct Abilities { charisma: u8, } -#[derive(Introspect, Copy, Drop, Serde)] +#[derive(IntrospectPacked, Copy, Drop, Serde)] struct Stats { kills: u128, deaths: u16, @@ -356,7 +337,7 @@ struct Stats { romances: u16, } -#[derive(Introspect, Copy, Drop, Serde)] +#[derive(IntrospectPacked, Copy, Drop, Serde)] enum Weapon { DualWield: (Sword, Sword), Fists: (Sword, Sword), // Introspect requires same arms @@ -366,9 +347,8 @@ enum Weapon { #[test] #[ignore] #[available_gas(1000000000)] -fn bench_complex_struct() { - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); +fn bench_complex_struct_packed() { + let gas = GasCounterImpl::start(); let char = Character { caller: starknet::contract_address_const::<0x42>(), @@ -404,10 +384,9 @@ fn bench_complex_struct() { ), gold: 0x12345678, }; - end(gas, 'chars init'); + gas.end("chars init"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let mut serialized = ArrayTrait::new(); serde::Serde::serialize(@char.heigth, ref serialized); serde::Serde::serialize(@char.abilities, ref serialized); @@ -415,12 +394,11 @@ fn bench_complex_struct() { serde::Serde::serialize(@char.weapon, ref serialized); serde::Serde::serialize(@char.gold, ref serialized); let serialized = array::ArrayTrait::span(@serialized); - end(gas, 'chars serialize'); + gas.end("chars serialize"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let values: Span = char.values(); - end(gas, 'chars values'); + gas.end("chars values"); assert(serialized.len() == values.len(), 'serialized not equal'); @@ -433,13 +411,16 @@ fn bench_complex_struct() { idx += 1; }; - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); - //database::set('chars', '42', char.values(), char.instance_layout()); - end(gas, 'chars db set'); + let layout = match dojo::model::Model::::layout() { + Layout::Fixed(layout) => layout, + _ => panic!("expected fixed layout"), + }; - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); - //database::get('chars', '42', char.instance_layout()); - end(gas, 'chars db get'); + let gas = GasCounterImpl::start(); + database::set('chars', '42', char.values(), 0, layout); + gas.end("chars db set"); + + let gas = GasCounterImpl::start(); + database::get('chars', '42', layout); + gas.end("chars db get"); } diff --git a/crates/dojo-core/src/database/introspect.cairo b/crates/dojo-core/src/database/introspect.cairo index d3ad4e6962..1eb1e2a1ad 100644 --- a/crates/dojo-core/src/database/introspect.cairo +++ b/crates/dojo-core/src/database/introspect.cairo @@ -60,7 +60,6 @@ trait Introspect { fn ty() -> Ty; } - impl Introspect_felt252 of Introspect { fn size() -> Option { Option::Some(1) @@ -73,7 +72,6 @@ impl Introspect_felt252 of Introspect { } } - impl Introspect_bool of Introspect { fn size() -> Option { Option::Some(1) @@ -182,7 +180,6 @@ impl Introspect_classhash of Introspect { } } - impl Introspect_bytearray of Introspect { fn size() -> Option { Option::None diff --git a/crates/dojo-core/src/test_utils.cairo b/crates/dojo-core/src/test_utils.cairo index 0079e18429..1bb6c91286 100644 --- a/crates/dojo-core/src/test_utils.cairo +++ b/crates/dojo-core/src/test_utils.cairo @@ -68,36 +68,40 @@ fn spawn_test_world(models: Array) -> IWorldDispatcher { } -const GAS_OFFSET: felt252 = 0x1_000000_000000_000000_000000_000000; // 15 bajtów +#[derive(Drop)] +struct GasCounter { + start: u128, +} -/// Measures gas used after previous measurement and prints it -/// -/// # Arguments -/// -/// * `start` - gas before measurement -/// * `name` - name of test, at most 15 bytes, will be padded with spaces -fn end(start: u128, name: felt252) { - let gas_after = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); - let mut name: u256 = name.into(); - - // overwriting zeros with spaces - let mut char = 0; - loop { - if char == 15 { - break; - } - // if given byte is zero - if shl(0xff, 8 * char) & name == 0 { - name = name | shl(0x20, 8 * char); // set space - } - char += 1; - }; +#[generate_trait] +impl GasCounterImpl of GasCounterTrait { + fn start() -> GasCounter { + let start = testing::get_available_gas(); + gas::withdraw_gas().unwrap(); + GasCounter { start } + } + + fn end(self: GasCounter, name: ByteArray) { + let end = testing::get_available_gas(); + let gas_used = self.start - end; - let name: felt252 = (name % GAS_OFFSET.into()).try_into().unwrap(); - // Q?: What's this 1070 value that needed to be adjusted? - let used_gas = (start - gas_after - 1070).into() * GAS_OFFSET; - (used_gas + name).print(); + println!("# GAS # {}: {}", Self::pad_start(name, 18), gas_used); + gas::withdraw_gas().unwrap(); + } + + fn pad_start(str: ByteArray, len: u32) -> ByteArray { + let mut missing: ByteArray = ""; + let missing_len = if str.len() >= len { + 0 + } else { + len - str.len() + }; + + while missing.len() < missing_len { + missing.append(@"."); + }; + missing + str + } } // assert that `value` and `expected` have the same size and the same content diff --git a/crates/dojo-core/src/world_test.cairo b/crates/dojo-core/src/world_test.cairo index 4d8829410e..634309cd61 100644 --- a/crates/dojo-core/src/world_test.cairo +++ b/crates/dojo-core/src/world_test.cairo @@ -16,11 +16,11 @@ use dojo::world::{ use dojo::database::introspect::{Introspect, Layout, FieldLayout}; use dojo::database::MAX_ARRAY_LENGTH; use dojo::test_utils::{spawn_test_world, deploy_with_world_address, assert_array}; -use dojo::benchmarks::{Character, end}; use dojo::config::component::Config::{ DifferProgramHashUpdate, MergerProgramHashUpdate, FactsRegistryUpdate }; use dojo::model::Model; +use dojo::benchmarks::{Character, GasCounterImpl}; #[derive(Introspect, Copy, Drop, Serde)] enum OneEnum { @@ -690,15 +690,14 @@ fn bench_execute() { let alice = starknet::contract_address_const::<0x1337>(); starknet::testing::set_contract_address(alice); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); + bar_contract.set_foo(1337, 1337); - end(gas, 'foo set call'); + gas.end("foo set call"); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); let data = get!(world, alice, Foo); - end(gas, 'foo get macro'); + gas.end("foo get macro"); assert(data.a == 1337, 'data not stored'); } @@ -713,15 +712,15 @@ fn bench_execute_complex() { let alice = starknet::contract_address_const::<0x1337>(); starknet::testing::set_contract_address(alice); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); + let gas = GasCounterImpl::start(); + bar_contract.set_char(1337, 1337); - end(gas, 'char set call'); + gas.end("char set call"); + + let gas = GasCounterImpl::start(); - let gas = testing::get_available_gas(); - gas::withdraw_gas().unwrap(); let data = get!(world, alice, Character); - end(gas, 'char get macro'); + gas.end("char get macro"); assert(data.heigth == 1337, 'data not stored'); }