Skip to content

Add arrow-avro Decoder Benchmarks - #8025

Merged
alamb merged 2 commits into
apache:mainfrom
elastiflow:avro-decoder-benchmarks
Aug 7, 2025
Merged

Add arrow-avro Decoder Benchmarks #8025
alamb merged 2 commits into
apache:mainfrom
elastiflow:avro-decoder-benchmarks

Conversation

@jecsand838

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

This change introduces a comprehensive benchmark suite for the arrow-avro decoder. Having robust benchmarks is crucial for several reasons:

  • It allows for the measurement and tracking of decoding performance over time.
  • It helps identify performance regressions or improvements as the codebase evolves.
  • It provides a standardized way to evaluate the impact of optimizations and new features.

What changes are included in this PR?

This PR adds a new benchmark file: arrow-avro/benches/decoder.rs.

The key components of this new file are:

  • Comprehensive Type Coverage: Adds benchmark scenarios for a wide range of data types, including:
    • Primitive types (Int32, Int64, Float32, Float64, Boolean)
    • Binary and String types (Binary(Bytes), String, StringView)
    • Logical types (Date32, TimeMillis, TimeMicros, TimestampMillis, TimestampMicros, Decimal128, UUID, Interval, Enum)
    • Complex types (Map, Array, Nested(Struct))
    • FixedSizeBinary
    • A Mixed schema with multiple fields
  • Update to criterion 7.0.0
  • Made mod schema public

Are these changes tested?

These changes are covered by the benchmark tests themselves.

Are there any user-facing changes?

N/A

@github-actions github-actions Bot added the arrow Changes to the arrow crate label Jul 30, 2025
@jecsand838
jecsand838 force-pushed the avro-decoder-benchmarks branch 3 times, most recently from 6bbd823 to 112ffb7 Compare July 30, 2025 05:45
Introduce benchmarks for the `arrow-avro` decoder to evaluate performance under various scenarios, such as different data types and schemas. Additionally, update the `criterion` and other dependencies, and make the `schema` module public to enable broader usage.
@jecsand838
jecsand838 force-pushed the avro-decoder-benchmarks branch from 112ffb7 to 3b39d66 Compare July 30, 2025 05:55

@klion26 klion26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution, I executed the benchmark with the command cargo bench --features=arrow,async,test_common,experimental --bench decoder, it can output the time and throughput like below

..... Only part of the result data is retained ....

Nested(Struct)/100      time:   [6.6012 µs 6.6925 µs 6.7970 µs]
                        thrpt:  [145.36 MiB/s 147.63 MiB/s 149.67 MiB/s]
Found 4 outliers among 100 measurements (4.00%)
  2 (2.00%) high mild
  2 (2.00%) high severe
Nested(Struct)/10000    time:   [467.44 µs 470.22 µs 473.82 µs]
                        thrpt:  [224.91 MiB/s 226.63 MiB/s 227.98 MiB/s]
Nested(Struct)/1000000  time:   [3.2511 ms 3.3813 ms 3.5785 ms]
                        thrpt:  [3.1209 GiB/s 3.3030 GiB/s 3.4352 GiB/s]

Comment thread arrow-avro/Cargo.toml
"thread_rng",
] }
criterion = { version = "0.6.0", default-features = false }
criterion = { version = "0.7.0", default-features = false }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any features we need in 0.7.0?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just figured it was a good idea to bump it up. I noticed dependabot was also trying to update it.

};
}

dataset!(INT_DATA, INT_SCHEMA, gen_int);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice generation logic

Comment thread arrow-avro/benches/decoder.rs Outdated
b.iter_batched_ref(
|| new_decoder(schema_json, DEFAULT_BATCH, utf8view),
|decoder| {
decoder.decode(black_box(datum)).unwrap();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the black_box here? From the doc, black_box is used to It prevents the compiler from making optimizations, seems that datum is an array precomputed above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true, I included black_box because I was having difficultly getting consistent benchmarks. I can experiment with removing it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up putting the black_box around the entire decoder.decode method call. This was a good catch!

Comment thread arrow-avro/benches/decoder.rs Outdated
|decoder| {
decoder.decode(black_box(datum)).unwrap();
let batch = decoder.flush().unwrap().unwrap();
black_box(batch.get_array_memory_size());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the black_box here to make sure that the batch.get_array_memory_size() was executed every time? Is there any reason we want to include get_array_memory_size in the benchmark?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good call out, I'll remove it. We don't need that there.

@jecsand838 jecsand838 Aug 6, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and removed the get_array_memory_size in my latest push.

Comment thread arrow-avro/benches/decoder.rs Outdated
}
group.bench_function(BenchmarkId::from_parameter(rows), |b| {
b.iter_batched_ref(
|| new_decoder(schema_json, DEFAULT_BATCH, utf8view),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we need to benchmark some other batch size or not

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea! I can add different batch sizes to this benchmark.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added benchmarking on different batch sizes in my latest push as well.

.with_schema(schema)
.with_batch_size(batch_size)
.with_utf8_view(utf8view)
.build_decoder(io::empty())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that we use io::empty() here because we always set schema above?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's about to be removed as .build_decoder doesn't need a Reader once #8006 is finalized and merged in.

@alamb

alamb commented Aug 6, 2025

Copy link
Copy Markdown
Contributor

Thanks for the review @klion26 -- @jecsand838 maybe you can address the comments and then I'll take a final review over this PR

@jecsand838

Copy link
Copy Markdown
Contributor Author

@klion26 Thank you for the solid review! I just pushed up changes which should address all of your comments. I can bump criterion back down if needed as well. @alamb

@alamb

alamb commented Aug 6, 2025

Copy link
Copy Markdown
Contributor

@klion26 Thank you for the solid review! I just pushed up changes which should address all of your comments. I can bump criterion back down if needed as well. @alamb

I think updating criterion sounds good to me

@jecsand838
jecsand838 requested a review from klion26 August 7, 2025 02:21

@klion26 klion26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jecsand838 thanks for the update, LGTM, cc @alamb

}
_ => {}
}
group.bench_function(BenchmarkId::from_parameter(rows), |b| {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to add the batch size here?

@alamb
alamb merged commit a4bcd6d into apache:main Aug 7, 2025
24 checks passed
@alamb

alamb commented Aug 7, 2025

Copy link
Copy Markdown
Contributor

Thanks again @jecsand838 and @klion26 for the review. I merged the PR figuring we should continue to move things forward -- let's do any additional things in a follow on PR

@jecsand838
jecsand838 deleted the avro-decoder-benchmarks branch August 7, 2025 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arrow Changes to the arrow crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants