-
Notifications
You must be signed in to change notification settings - Fork 205
feat: Implement custom RecordBatch serde for shuffle for improved performance #1190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
andygrove
merged 14 commits into
apache:main
from
andygrove:experimental-fast-batch-serde
Jan 13, 2025
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
eda771a
Implement faster encoder for shuffle blocks
andygrove b9b3d9d
make code more concise
andygrove d0fe67a
enable fast encoding for columnar shuffle
andygrove 629598a
update benches
andygrove 498bf70
Merge remote-tracking branch 'apache/main' into experimental-fast-bat…
andygrove 98846c9
test all int types
andygrove a373aaf
test float
andygrove d03c957
remaining types
andygrove 5397ae7
add Snappy and Zstd(6) back to benchmark
andygrove 09448e5
fix regression
andygrove 7c93806
Update native/core/src/execution/shuffle/codec.rs
andygrove 48030b9
address feedback
andygrove 78cc24f
support nullable flag
andygrove 7666fd9
Merge branch 'experimental-fast-batch-serde' of github.com:andygrove/…
andygrove File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,6 +79,7 @@ fn benchmark(c: &mut Criterion) { | |
0, | ||
None, | ||
&CompressionCodec::Zstd(1), | ||
true, | ||
) | ||
.unwrap(); | ||
}); | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,10 +15,10 @@ | |
// specific language governing permissions and limitations | ||
// under the License. | ||
|
||
use arrow_array::builder::Int32Builder; | ||
use arrow_array::builder::{Date32Builder, Decimal128Builder, Int32Builder}; | ||
use arrow_array::{builder::StringBuilder, RecordBatch}; | ||
use arrow_schema::{DataType, Field, Schema}; | ||
use comet::execution::shuffle::{write_ipc_compressed, CompressionCodec, ShuffleWriterExec}; | ||
use comet::execution::shuffle::{CompressionCodec, ShuffleBlockWriter, ShuffleWriterExec}; | ||
use criterion::{criterion_group, criterion_main, Criterion}; | ||
use datafusion::physical_plan::metrics::Time; | ||
use datafusion::{ | ||
|
@@ -31,67 +31,56 @@ use std::sync::Arc; | |
use tokio::runtime::Runtime; | ||
|
||
fn criterion_benchmark(c: &mut Criterion) { | ||
let batch = create_batch(8192, true); | ||
let mut group = c.benchmark_group("shuffle_writer"); | ||
group.bench_function("shuffle_writer: encode (no compression))", |b| { | ||
let batch = create_batch(8192, true); | ||
let mut buffer = vec![]; | ||
let ipc_time = Time::default(); | ||
b.iter(|| { | ||
buffer.clear(); | ||
let mut cursor = Cursor::new(&mut buffer); | ||
write_ipc_compressed(&batch, &mut cursor, &CompressionCodec::None, &ipc_time) | ||
}); | ||
}); | ||
group.bench_function("shuffle_writer: encode and compress (snappy)", |b| { | ||
let batch = create_batch(8192, true); | ||
let mut buffer = vec![]; | ||
let ipc_time = Time::default(); | ||
b.iter(|| { | ||
buffer.clear(); | ||
let mut cursor = Cursor::new(&mut buffer); | ||
write_ipc_compressed(&batch, &mut cursor, &CompressionCodec::Snappy, &ipc_time) | ||
}); | ||
}); | ||
group.bench_function("shuffle_writer: encode and compress (lz4)", |b| { | ||
let batch = create_batch(8192, true); | ||
let mut buffer = vec![]; | ||
let ipc_time = Time::default(); | ||
b.iter(|| { | ||
buffer.clear(); | ||
let mut cursor = Cursor::new(&mut buffer); | ||
write_ipc_compressed(&batch, &mut cursor, &CompressionCodec::Lz4Frame, &ipc_time) | ||
}); | ||
}); | ||
group.bench_function("shuffle_writer: encode and compress (zstd level 1)", |b| { | ||
let batch = create_batch(8192, true); | ||
let mut buffer = vec![]; | ||
let ipc_time = Time::default(); | ||
b.iter(|| { | ||
buffer.clear(); | ||
let mut cursor = Cursor::new(&mut buffer); | ||
write_ipc_compressed(&batch, &mut cursor, &CompressionCodec::Zstd(1), &ipc_time) | ||
}); | ||
}); | ||
group.bench_function("shuffle_writer: encode and compress (zstd level 6)", |b| { | ||
let batch = create_batch(8192, true); | ||
let mut buffer = vec![]; | ||
let ipc_time = Time::default(); | ||
b.iter(|| { | ||
buffer.clear(); | ||
let mut cursor = Cursor::new(&mut buffer); | ||
write_ipc_compressed(&batch, &mut cursor, &CompressionCodec::Zstd(6), &ipc_time) | ||
}); | ||
}); | ||
group.bench_function("shuffle_writer: end to end", |b| { | ||
let ctx = SessionContext::new(); | ||
let exec = create_shuffle_writer_exec(CompressionCodec::Zstd(1)); | ||
b.iter(|| { | ||
let task_ctx = ctx.task_ctx(); | ||
let stream = exec.execute(0, task_ctx).unwrap(); | ||
let rt = Runtime::new().unwrap(); | ||
criterion::black_box(rt.block_on(collect(stream)).unwrap()); | ||
}); | ||
}); | ||
for compression_codec in &[ | ||
CompressionCodec::None, | ||
CompressionCodec::Lz4Frame, | ||
CompressionCodec::Snappy, | ||
CompressionCodec::Zstd(1), | ||
CompressionCodec::Zstd(6), | ||
] { | ||
for enable_fast_encoding in [true, false] { | ||
let name = format!("shuffle_writer: write encoded (enable_fast_encoding={enable_fast_encoding}, compression={compression_codec:?})"); | ||
group.bench_function(name, |b| { | ||
let mut buffer = vec![]; | ||
let ipc_time = Time::default(); | ||
let w = ShuffleBlockWriter::try_new( | ||
&batch.schema(), | ||
enable_fast_encoding, | ||
compression_codec.clone(), | ||
) | ||
.unwrap(); | ||
b.iter(|| { | ||
buffer.clear(); | ||
let mut cursor = Cursor::new(&mut buffer); | ||
w.write_batch(&batch, &mut cursor, &ipc_time).unwrap(); | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
for compression_codec in [ | ||
CompressionCodec::None, | ||
CompressionCodec::Lz4Frame, | ||
CompressionCodec::Snappy, | ||
CompressionCodec::Zstd(1), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit/optional: snappy and zstd(6) here as well? |
||
CompressionCodec::Zstd(6), | ||
] { | ||
group.bench_function( | ||
format!("shuffle_writer: end to end (compression = {compression_codec:?}"), | ||
|b| { | ||
let ctx = SessionContext::new(); | ||
let exec = create_shuffle_writer_exec(compression_codec.clone()); | ||
b.iter(|| { | ||
let task_ctx = ctx.task_ctx(); | ||
let stream = exec.execute(0, task_ctx).unwrap(); | ||
let rt = Runtime::new().unwrap(); | ||
rt.block_on(collect(stream)).unwrap(); | ||
}); | ||
}, | ||
); | ||
} | ||
} | ||
|
||
fn create_shuffle_writer_exec(compression_codec: CompressionCodec) -> ShuffleWriterExec { | ||
|
@@ -104,6 +93,7 @@ fn create_shuffle_writer_exec(compression_codec: CompressionCodec) -> ShuffleWri | |
compression_codec, | ||
"/tmp/data.out".to_string(), | ||
"/tmp/index.out".to_string(), | ||
true, | ||
) | ||
.unwrap() | ||
} | ||
|
@@ -121,11 +111,19 @@ fn create_batch(num_rows: usize, allow_nulls: bool) -> RecordBatch { | |
let schema = Arc::new(Schema::new(vec![ | ||
Field::new("c0", DataType::Int32, true), | ||
Field::new("c1", DataType::Utf8, true), | ||
Field::new("c2", DataType::Date32, true), | ||
Field::new("c3", DataType::Decimal128(11, 2), true), | ||
])); | ||
let mut a = Int32Builder::new(); | ||
let mut b = StringBuilder::new(); | ||
let mut c = Date32Builder::new(); | ||
let mut d = Decimal128Builder::new() | ||
.with_precision_and_scale(11, 2) | ||
.unwrap(); | ||
for i in 0..num_rows { | ||
a.append_value(i as i32); | ||
c.append_value(i as i32); | ||
d.append_value((i * 1000000) as i128); | ||
if allow_nulls && i % 10 == 0 { | ||
b.append_null(); | ||
} else { | ||
|
@@ -134,7 +132,13 @@ fn create_batch(num_rows: usize, allow_nulls: bool) -> RecordBatch { | |
} | ||
let a = a.finish(); | ||
let b = b.finish(); | ||
RecordBatch::try_new(schema.clone(), vec![Arc::new(a), Arc::new(b)]).unwrap() | ||
let c = c.finish(); | ||
let d = d.finish(); | ||
RecordBatch::try_new( | ||
schema.clone(), | ||
vec![Arc::new(a), Arc::new(b), Arc::new(c), Arc::new(d)], | ||
) | ||
.unwrap() | ||
} | ||
|
||
fn config() -> Criterion { | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.