Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion parquet-variant-compute/benches/variant_kernels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use arrow::array::{Array, ArrayRef, BinaryViewArray, BinaryViewBuilder, StringArray, StructArray};
use arrow::buffer::Buffer;
use arrow_schema::{DataType, Field, FieldRef, Fields};
use criterion::{Criterion, criterion_group, criterion_main};
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
use parquet_variant::{EMPTY_VARIANT_METADATA_BYTES, Variant, VariantBuilder, VariantPath};
use parquet_variant_compute::{
GetOptions, VariantArray, VariantArrayBuilder, json_to_variant, variant_get,
Expand All @@ -33,6 +33,23 @@ use std::fmt::Write;
use std::sync::Arc;

const VARIANT_GET_UNSHREDDED_OBJECT_ROWS: usize = 262_144;
const VARIANT_ARRAY_BUILD_ROWS: usize = 262_144;

fn variant_array_builder_build_bench(c: &mut Criterion) {
c.bench_function("variant_array_builder_build_262k_small_values", |b| {
b.iter_batched(
|| {
let mut builder = VariantArrayBuilder::new(VARIANT_ARRAY_BUILD_ROWS);
for value in 0..VARIANT_ARRAY_BUILD_ROWS {
builder.append_variant(Variant::Int8((value % 128) as i8));
}
builder
},
|builder| std::hint::black_box(builder.build()),
BatchSize::LargeInput,
)
});
}

fn benchmark_batch_json_string_to_variant(c: &mut Criterion) {
let input_array = StringArray::from_iter_values(json_repeated_struct(8000));
Expand Down Expand Up @@ -189,6 +206,7 @@ criterion_group!(
variant_get_bench,
variant_get_shredded_utf8_bench,
variant_get_unshredded_object_path_bench,
variant_array_builder_build_bench,
benchmark_batch_json_string_to_variant
);
criterion_main!(benches);
Expand Down
29 changes: 15 additions & 14 deletions parquet-variant-compute/src/variant_array_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
//! [`VariantArrayBuilder`] implementation

use crate::VariantArray;
use arrow::array::{ArrayRef, BinaryViewArray, BinaryViewBuilder, NullBufferBuilder, StructArray};
use arrow::array::builder::make_view;
use arrow::array::{ArrayRef, BinaryViewArray, NullBufferBuilder, StructArray};
use arrow::buffer::Buffer;
use arrow_schema::{ArrowError, DataType, Field, Fields};
use parquet_variant::{
BuilderSpecificState, ListBuilder, MetadataBuilder, ObjectBuilder, Variant, VariantBuilderExt,
Expand Down Expand Up @@ -458,22 +460,21 @@ impl VariantBuilderExt for VariantValueArrayBuilderExt<'_> {
}

fn binary_view_array_from_buffers(buffer: Vec<u8>, offsets: Vec<usize>) -> BinaryViewArray {
// All offsets are less than or equal to the buffer length, so we can safely cast all offsets
// inside the loop below, as long as the buffer length fits in u32.
u32::try_from(buffer.len()).expect("buffer length should fit in u32");

let mut builder = BinaryViewBuilder::with_capacity(offsets.len());
let block = builder.append_block(buffer.into());
// TODO this can be much faster if it creates the views directly during append
let mut start = 0;
// Each builder records the current buffer length after appending a row, so offsets are
// monotonically increasing and bounded by the final buffer length.
assert!(buffer.len() < u32::MAX as usize);

let buffer = Buffer::from(buffer);
let mut views = Vec::with_capacity(offsets.len());
let mut start = 0_usize;
for end in offsets {
let end = end as u32; // Safe cast: validated max offset fits in u32 above
builder
.try_append_view(block, start, end - start)
.expect("Failed to append view");
views.push(make_view(&buffer[start..end], 0, start as u32));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

buffer & offsets here is guaranteed to come from trusted/correct data?

start = end;
}
builder.finish()

// SAFETY: `make_view` constructs every view from an in-bounds slice of buffer 0, and there
// are no nulls. The buffer length check above guarantees every offset fits in a `u32`.
unsafe { BinaryViewArray::new_unchecked(views.into(), vec![buffer], None) }
}

#[cfg(test)]
Expand Down
Loading