Skip to content

Commit e599e32

Browse files
committed
test[gpu]: cover binary export edge cases
Signed-off-by: Alexander Droste <alexander.droste@protonmail.com>
1 parent 156b86f commit e599e32

2 files changed

Lines changed: 100 additions & 3 deletions

File tree

vortex-cuda/benches/arrow_binary_cuda.rs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use vortex::array::validity::Validity;
2626
use vortex::buffer::Buffer;
2727
use vortex::buffer::ByteBuffer;
2828
use vortex::dtype::DType;
29-
use vortex::dtype::Nullability;
3029
use vortex::error::VortexExpect;
3130
use vortex::error::VortexResult;
3231
use vortex::session::VortexSession;
@@ -45,6 +44,15 @@ async fn binary_on_device(
4544
views: Buffer<BinaryView>,
4645
buffers: Arc<[ByteBuffer]>,
4746
ctx: &mut CudaExecutionCtx,
47+
) -> VortexResult<ArrayRef> {
48+
binary_on_device_with_validity(views, buffers, Validity::NonNullable, ctx).await
49+
}
50+
51+
async fn binary_on_device_with_validity(
52+
views: Buffer<BinaryView>,
53+
buffers: Arc<[ByteBuffer]>,
54+
validity: Validity,
55+
ctx: &mut CudaExecutionCtx,
4856
) -> VortexResult<ArrayRef> {
4957
let views = ctx
5058
.ensure_on_device(BufferHandle::new_host(views.into_byte_buffer()))
@@ -60,8 +68,8 @@ async fn binary_on_device(
6068
Ok(VarBinViewArray::new_handle(
6169
views,
6270
device_buffers.into(),
63-
DType::Binary(Nullability::NonNullable),
64-
Validity::NonNullable,
71+
DType::Binary(validity.nullability()),
72+
validity,
6573
)
6674
.into_array())
6775
}
@@ -85,6 +93,14 @@ async fn out_of_line_binary(len: usize, ctx: &mut CudaExecutionCtx) -> VortexRes
8593
binary_on_device(views, Arc::from([values]), ctx).await
8694
}
8795

96+
async fn sliced_validity_binary(len: usize, ctx: &mut CudaExecutionCtx) -> VortexResult<ArrayRef> {
97+
let views =
98+
Buffer::from_iter((0..len).map(|idx| BinaryView::make_view(&idx.to_le_bytes(), 0, 0)));
99+
let validity = Validity::from_iter((0..=len).map(|idx| idx % 3 != 0)).slice(1..len + 1)?;
100+
101+
binary_on_device_with_validity(views, Arc::from([]), validity, ctx).await
102+
}
103+
88104
unsafe fn release_arrow_device_array(array: &mut ArrowDeviceArray) {
89105
unsafe {
90106
if let Some(release) = array.array.release {
@@ -154,6 +170,35 @@ fn benchmark_arrow_binary_export(c: &mut Criterion) {
154170
});
155171
},
156172
);
173+
174+
group.throughput(Throughput::Bytes(
175+
(len * (size_of::<BinaryView>() + 8) + len.div_ceil(8)) as u64,
176+
));
177+
group.bench_with_input(
178+
BenchmarkId::new("cuda/arrow_binary/sliced_validity", len_label),
179+
&len,
180+
|b, &len| {
181+
b.iter_custom(|iters| {
182+
let timed = TimedLaunchStrategy::default();
183+
let timer = timed.timer();
184+
185+
let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty())
186+
.vortex_expect("failed to create execution context")
187+
.with_launch_strategy(Arc::new(timed));
188+
let array = block_on(sliced_validity_binary(len, &mut cuda_ctx))
189+
.vortex_expect("failed to create binary fixture");
190+
191+
for _ in 0..iters {
192+
let mut exported =
193+
block_on(array.clone().export_device_array(&mut cuda_ctx))
194+
.vortex_expect("failed to export device array");
195+
unsafe { release_arrow_device_array(&mut exported) };
196+
}
197+
198+
Duration::from_nanos(timer.load(Ordering::Relaxed))
199+
});
200+
},
201+
);
157202
}
158203

159204
group.finish();

vortex-cuda/src/arrow/canonical.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,58 @@ mod tests {
19651965
Ok(())
19661966
}
19671967

1968+
#[crate::test]
1969+
async fn test_export_binary_empty_and_all_null() -> VortexResult<()> {
1970+
let mut ctx = CudaSession::create_execution_ctx(&VortexSession::empty())
1971+
.vortex_expect("failed to create execution context");
1972+
1973+
let empty = VarBinViewArray::from_iter_nullable_bin(std::iter::empty::<Option<&[u8]>>())
1974+
.into_array();
1975+
let mut exported = empty.export_device_array_with_schema(&mut ctx).await?;
1976+
let field = Field::try_from(&exported.schema)?;
1977+
assert_eq!(field, Field::new("", DataType::Binary, true));
1978+
assert_binary_layout(&exported.array.array, 0, 0, &[0], b"")?;
1979+
assert_eq!(exported.array.device_type, ARROW_DEVICE_CUDA);
1980+
unsafe { release_exported_array(&raw mut exported.array.array) };
1981+
1982+
let all_null =
1983+
VarBinViewArray::from_iter_nullable_bin([None::<&[u8]>, None::<&[u8]>]).into_array();
1984+
let mut exported = all_null.export_device_array_with_schema(&mut ctx).await?;
1985+
let field = Field::try_from(&exported.schema)?;
1986+
assert_eq!(field, Field::new("", DataType::Binary, true));
1987+
assert_binary_layout(&exported.array.array, 2, 2, &[0, 0, 0], b"")?;
1988+
assert_eq!(exported.array.device_type, ARROW_DEVICE_CUDA);
1989+
unsafe { release_exported_array(&raw mut exported.array.array) };
1990+
1991+
Ok(())
1992+
}
1993+
1994+
#[crate::test]
1995+
async fn test_export_binary_invalid_data_buffer_ref_errors() -> VortexResult<()> {
1996+
let mut ctx = CudaSession::create_execution_ctx(&VortexSession::empty())
1997+
.vortex_expect("failed to create execution context");
1998+
1999+
let view = BinaryView::make_view(b"this references a missing data buffer", 0, 0);
2000+
let array = VarBinViewArray::new_handle(
2001+
BufferHandle::new_host(Buffer::from_iter([view]).into_byte_buffer()),
2002+
Arc::from([]),
2003+
DType::Binary(Nullability::NonNullable),
2004+
Validity::NonNullable,
2005+
)
2006+
.into_array();
2007+
2008+
let err = array
2009+
.export_device_array_with_schema(&mut ctx)
2010+
.await
2011+
.expect_err("missing binary data buffer should fail");
2012+
assert!(
2013+
err.to_string()
2014+
.contains("a view references an invalid data buffer")
2015+
);
2016+
2017+
Ok(())
2018+
}
2019+
19682020
#[crate::test]
19692021
async fn test_export_list() -> VortexResult<()> {
19702022
let mut ctx = CudaSession::create_execution_ctx(&VortexSession::empty())

0 commit comments

Comments
 (0)