Skip to content

[Rust] Inline generated header methods#1110

Merged
vyazelenko merged 1 commit into
aeron-io:masterfrom
sunlei:sunlei/rust-inline-generated-header-methods
Jun 12, 2026
Merged

[Rust] Inline generated header methods#1110
vyazelenko merged 1 commit into
aeron-io:masterfrom
sunlei:sunlei/rust-inline-generated-header-methods

Conversation

@sunlei

@sunlei sunlei commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Add #[inline] to the Rust generator output for message-level header methods on both encoders and decoders.

The generated API and behavior are unchanged. This only adds an inline hint to the small hot-path methods that bridge generated message encoders/decoders and the generated message header codec.

Benchmark Results

Environment:

  • macOS aarch64
  • Gradle 9.5.1
  • Temurin JDK 25.0.3
  • rustc 1.96.0
  • cargo 1.96.0

Commands:

gradle generateRustCodecs
cd rust
cargo bench --bench header_benchmark -- --warm-up-time 1 --measurement-time 10 --save-baseline no-inline-header
cargo bench --bench header_benchmark -- --warm-up-time 1 --measurement-time 10 --baseline no-inline-header
cargo bench --bench car_benchmark -- --warm-up-time 1 --measurement-time 10
cargo bench --bench md_benchmark -- --warm-up-time 1 --measurement-time 10

Focused header benchmark:

Benchmark no inline inline change speedup
rust/message_header/car_encode_header 4.2770 ns 1.6354 ns -61.665% 2.62x
rust/message_header/car_decode_header 6.3381 ns 1.3190 ns -79.001% 4.81x
rust/message_header/md_encode_header 4.3086 ns 1.5345 ns -64.527% 2.81x
rust/message_header/md_decode_header 6.2009 ns 1.3220 ns -78.752% 4.69x

Existing Rust example benchmarks:

Benchmark no inline inline change speedup
encode car 33.289 ns 26.777 ns -19.587% 1.24x
decode car 27.919 ns 24.469 ns -12.447% 1.14x
encode md 8.2370 ns 5.4894 ns -33.454% 1.50x
decode md 9.4024 ns 4.4269 ns -53.127% 2.12x

Validation

gradle generateRustCodecs
gradle runRustTests
gradle :sbe-tool:test --tests '*rust*'
rustfmt --check rust/benches/header_benchmark.rs

Benchmark Code

Local benchmark helper used for the focused header benchmark
use criterion::{criterion_group, criterion_main, Criterion};
use examples_uk_co_real_logic_sbe_benchmarks as car_schema;
use examples_uk_co_real_logic_sbe_benchmarks::{
    car_codec::{CarDecoder, CarEncoder},
    message_header_codec::MessageHeaderDecoder as CarMessageHeaderDecoder,
};
use examples_uk_co_real_logic_sbe_benchmarks_fix as md_schema;
use examples_uk_co_real_logic_sbe_benchmarks_fix::{
    market_data_incremental_refresh_trades_codec::{
        MarketDataIncrementalRefreshTradesDecoder, MarketDataIncrementalRefreshTradesEncoder,
    },
    message_header_codec::MessageHeaderDecoder as MdMessageHeaderDecoder,
};
use std::hint::black_box;

const BUFFER_LEN: usize = 1024;

struct State {
    buffer: Vec<u8>,
}

fn car_state() -> State {
    State {
        buffer: vec![0u8; BUFFER_LEN],
    }
}

fn car_state_with_header() -> State {
    let mut state = car_state();
    car_header_encode(&mut state).unwrap();
    state
}

fn md_state() -> State {
    State {
        buffer: vec![0u8; BUFFER_LEN],
    }
}

fn md_state_with_header() -> State {
    let mut state = md_state();
    md_header_encode(&mut state).unwrap();
    state
}

fn car_header_encode(state: &mut State) -> car_schema::SbeResult<usize> {
    let mut car = CarEncoder::default();
    let buffer = black_box(state.buffer.as_mut_slice());
    car = car.wrap(
        car_schema::WriteBuf::new(buffer),
        car_schema::message_header_codec::ENCODED_LENGTH,
    );
    car = car.header(0).parent()?;
    Ok(car.encoded_length())
}

fn car_header_decode(state: &State) -> usize {
    let buffer = black_box(state.buffer.as_slice());
    let buf = car_schema::ReadBuf::new(buffer);
    let header = CarMessageHeaderDecoder::default().wrap(buf, 0);
    let car = CarDecoder::default().header(header, 0);
    car.encoded_length()
}

fn md_header_encode(state: &mut State) -> md_schema::SbeResult<usize> {
    let mut market_data = MarketDataIncrementalRefreshTradesEncoder::default();
    let buffer = black_box(state.buffer.as_mut_slice());
    market_data = market_data.wrap(
        md_schema::WriteBuf::new(buffer),
        md_schema::message_header_codec::ENCODED_LENGTH,
    );
    market_data = market_data.header(0).parent()?;
    Ok(market_data.encoded_length())
}

fn md_header_decode(state: &State) -> usize {
    let buffer = black_box(state.buffer.as_slice());
    let buf = md_schema::ReadBuf::new(buffer);
    let header = MdMessageHeaderDecoder::default().wrap(buf, 0);
    let market_data = MarketDataIncrementalRefreshTradesDecoder::default().header(header, 0);
    market_data.encoded_length()
}

fn bench_message_header(c: &mut Criterion) {
    let mut group = c.benchmark_group("rust/message_header");

    group.bench_function("car_encode_header", |b| {
        let mut state = car_state();
        b.iter(|| {
            let len = car_header_encode(black_box(&mut state)).unwrap();
            black_box(len);
        });
    });

    group.bench_function("car_decode_header", |b| {
        let state = car_state_with_header();
        b.iter(|| {
            let len = car_header_decode(black_box(&state));
            black_box(len);
        });
    });

    group.bench_function("md_encode_header", |b| {
        let mut state = md_state();
        b.iter(|| {
            let len = md_header_encode(black_box(&mut state)).unwrap();
            black_box(len);
        });
    });

    group.bench_function("md_decode_header", |b| {
        let state = md_state_with_header();
        b.iter(|| {
            let len = md_header_decode(black_box(&state));
            black_box(len);
        });
    });

    group.finish();
}

criterion_group!(benches, bench_message_header);
criterion_main!(benches);

@vyazelenko

Copy link
Copy Markdown
Contributor

@mward Can you please have a look? Thanks.

@sunlei

sunlei commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

@vyazelenko Friendly ping on this PR. @mward added a +1 reaction to your review request, but there is no formal approval recorded. Could you please confirm whether anything else is needed before this can move forward?

@mward

mward commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Sorry, not had chance to look yet. I'll do my best to review it tonight or early tomorrow.

@mward

mward commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

this looks good! Thanks!

@vyazelenko vyazelenko merged commit b9cf706 into aeron-io:master Jun 12, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants