Commit ac9e84a
### What
Changed the implementation of `BytesIter` to match the more efficient
implementation of `VecTryIter`.
### Why
This reduces the need to allocate memory and increases performance. This
is benchmarked on [dkcumming/rs-soroban-sdk branch
dc/bytes-from-zc-bench](main...dkcumming:rs-soroban-sdk:dc/bytes-iter-bench).
For completeness the key end-to-end results are communicated in this
table:
| Bench | Before CPU | After CPU | Δ % | Before Mem | After Mem | Δ % |
|-------------------|-----------:|----------:|-------:|-----------:|----------:|------:|
| `baseline_*` | 245,345 | 232,140 | -5.4% | 1,146,818 | 1,144,946 |
-0.2% |
| `iter_32` | 386,297 | 258,596 | -33.1% | 1,151,154 | 1,144,946 | -0.5%
|
| `iter_rev_32` | 364,213 | 259,068 | -28.9% | 1,151,154 | 1,144,946 |
-0.5% |
| `iter_48` | 456,057 | 271,268 | -40.5% | 1,153,706 | 1,144,946 | -0.8%
|
| `iter_rev_48` | 422,837 | 271,740 | -35.7% | 1,153,706 | 1,144,946 |
-0.8% |
| `iter_96` | 665,721 | 309,284 | -53.5% | 1,162,898 | 1,144,946 | -1.5%
|
| `iter_rev_96` | 599,093 | 309,756 | -48.3% | 1,162,898 | 1,144,946 |
-1.5% |
| `iter_192` | 1,086,777 | 385,316 | -64.5% | 1,188,194 | 1,144,946 |
-3.6% |
| `iter_rev_192` | 953,333 | 385,788 | -59.5% | 1,188,194 | 1,144,946 |
-3.6% |
The tests to run these benchmarks were:
<details>
The contract:
```rust
#![no_std]
use soroban_sdk::{contract, contractimpl, Bytes, Env};
#[contract]
pub struct Contract;
// Each function derives its result from every byte so the iteration cannot be
// optimized out of the guest Wasm.
//
// `baseline` has the same signature as the iterating functions, so subtracting
// it isolates the iteration cost from dispatch and operand-passing overhead.
#[contractimpl]
impl Contract {
pub fn baseline(_env: Env, _b: Bytes) -> u32 {
0
}
pub fn sum_iter(_env: Env, b: Bytes) -> u32 {
let mut acc: u32 = 0;
for x in b.iter() {
acc = acc.wrapping_add(x as u32);
}
acc
}
pub fn sum_iter_rev(_env: Env, b: Bytes) -> u32 {
let mut acc: u32 = 0;
for x in b.iter().rev() {
acc = acc.wrapping_add(x as u32);
}
acc
}
}
```
The benchmark harnesses:
```rust
//! Compute-budget microbenches for iterating a `Bytes` (host-function metering
//! only).
//!
//! These benches are disabled by default (`#[ignore]`) because:
//! 1. they should be run under `--release` rather than the default test profile.
//! 2. their output is only meaningful with `--nocapture`.
//!
//! Run with the following command:
//! cargo test --release --package soroban-sdk --lib --features testutils \
//! -- tests::bytes_iter_bench --ignored --nocapture
use crate::{Bytes, Env};
fn report(label: &str, env: &Env) {
let cpu = env.cost_estimate().budget().cpu_instruction_cost();
let mem = env.cost_estimate().budget().memory_bytes_cost();
println!("BENCH {label} cpu={cpu} mem={mem}");
}
macro_rules! bench_iter {
($fwd:ident, $rev:ident, $n:literal) => {
#[test]
#[ignore]
fn $fwd() {
let env = Env::default();
let b = Bytes::from_slice(&env, &[7u8; $n]);
env.cost_estimate().budget().reset_unlimited();
let mut acc: u32 = 0;
for x in b.iter() {
acc = acc.wrapping_add(x as u32);
}
core::hint::black_box(acc);
report(stringify!($fwd), &env);
}
#[test]
#[ignore]
fn $rev() {
let env = Env::default();
let b = Bytes::from_slice(&env, &[7u8; $n]);
env.cost_estimate().budget().reset_unlimited();
let mut acc: u32 = 0;
for x in b.iter().rev() {
acc = acc.wrapping_add(x as u32);
}
core::hint::black_box(acc);
report(stringify!($rev), &env);
}
};
}
bench_iter!(bench_iter_32, bench_iter_rev_32, 32);
bench_iter!(bench_iter_48, bench_iter_rev_48, 48);
bench_iter!(bench_iter_96, bench_iter_rev_96, 96);
bench_iter!(bench_iter_192, bench_iter_rev_192, 192);
```
</details>
### Known limitations
No known limitations with this approach. This was a targeted
investigation and is not comprehensive in scope, there may be other
places where similar improvements can be made.
Co-authored-by: Leigh <351529+leighmcculloch@users.noreply.github.com>
1 parent 28142cd commit ac9e84a
1 file changed
Lines changed: 98 additions & 28 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
839 | 839 | | |
840 | 840 | | |
841 | 841 | | |
842 | | - | |
| 842 | + | |
843 | 843 | | |
844 | 844 | | |
845 | 845 | | |
846 | 846 | | |
847 | | - | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
848 | 852 | | |
849 | 853 | | |
850 | | - | |
851 | | - | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
852 | 860 | | |
853 | 861 | | |
854 | 862 | | |
855 | 863 | | |
856 | 864 | | |
857 | 865 | | |
858 | 866 | | |
859 | | - | |
860 | | - | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
861 | 871 | | |
862 | | - | |
863 | | - | |
864 | | - | |
865 | | - | |
866 | | - | |
867 | | - | |
868 | | - | |
869 | | - | |
| 872 | + | |
870 | 873 | | |
871 | 874 | | |
872 | 875 | | |
873 | 876 | | |
874 | | - | |
| 877 | + | |
875 | 878 | | |
876 | 879 | | |
877 | 880 | | |
878 | 881 | | |
879 | 882 | | |
880 | 883 | | |
881 | | - | |
882 | | - | |
883 | | - | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
884 | 887 | | |
885 | | - | |
886 | | - | |
887 | | - | |
888 | | - | |
889 | | - | |
890 | | - | |
891 | | - | |
892 | | - | |
| 888 | + | |
893 | 889 | | |
894 | 890 | | |
895 | 891 | | |
| |||
898 | 894 | | |
899 | 895 | | |
900 | 896 | | |
901 | | - | |
| 897 | + | |
902 | 898 | | |
903 | 899 | | |
904 | 900 | | |
| |||
1304 | 1300 | | |
1305 | 1301 | | |
1306 | 1302 | | |
1307 | | - | |
| 1303 | + | |
1308 | 1304 | | |
1309 | 1305 | | |
1310 | 1306 | | |
| |||
1532 | 1528 | | |
1533 | 1529 | | |
1534 | 1530 | | |
| 1531 | + | |
| 1532 | + | |
| 1533 | + | |
| 1534 | + | |
| 1535 | + | |
| 1536 | + | |
| 1537 | + | |
| 1538 | + | |
| 1539 | + | |
| 1540 | + | |
| 1541 | + | |
| 1542 | + | |
| 1543 | + | |
| 1544 | + | |
| 1545 | + | |
| 1546 | + | |
| 1547 | + | |
| 1548 | + | |
| 1549 | + | |
| 1550 | + | |
| 1551 | + | |
| 1552 | + | |
| 1553 | + | |
| 1554 | + | |
| 1555 | + | |
| 1556 | + | |
| 1557 | + | |
| 1558 | + | |
| 1559 | + | |
| 1560 | + | |
| 1561 | + | |
| 1562 | + | |
| 1563 | + | |
| 1564 | + | |
| 1565 | + | |
| 1566 | + | |
| 1567 | + | |
| 1568 | + | |
| 1569 | + | |
| 1570 | + | |
| 1571 | + | |
| 1572 | + | |
| 1573 | + | |
| 1574 | + | |
| 1575 | + | |
| 1576 | + | |
| 1577 | + | |
| 1578 | + | |
| 1579 | + | |
| 1580 | + | |
| 1581 | + | |
| 1582 | + | |
| 1583 | + | |
| 1584 | + | |
| 1585 | + | |
| 1586 | + | |
| 1587 | + | |
| 1588 | + | |
| 1589 | + | |
| 1590 | + | |
| 1591 | + | |
| 1592 | + | |
| 1593 | + | |
| 1594 | + | |
| 1595 | + | |
| 1596 | + | |
| 1597 | + | |
| 1598 | + | |
| 1599 | + | |
| 1600 | + | |
| 1601 | + | |
| 1602 | + | |
| 1603 | + | |
| 1604 | + | |
1535 | 1605 | | |
1536 | 1606 | | |
1537 | 1607 | | |
| |||
0 commit comments