-
Notifications
You must be signed in to change notification settings - Fork 225
perf(array): reuse probe state in RLE, RunEnd and PCO #9844
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
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
f1008f3
perf(array): reuse probe state in RLE, RunEnd and PCO
joseph-isaacs a49e20c
Merge remote-tracking branch 'origin/develop' into ji/array-probe-enc…
joseph-isaacs d4ad102
bench(pco): read the scalar bench through a repeated probe
joseph-isaacs 0d5143b
perf(pco): retain every decoded page in the probe state
joseph-isaacs a0f1a8d
refactor(pco): drop the probe example and test-only probe state
joseph-isaacs 07dbdae
test(pco): probe tests use only PCO arrays
joseph-isaacs 41fe853
refactor(pco): make the probe's last page an Option
joseph-isaacs 96bb450
perf(pco): decode probe pages into an uninitialized buffer
joseph-isaacs 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ pub use array::RLESlots; | |
|
|
||
| mod compute; | ||
| mod kernel; | ||
| mod probe; | ||
|
|
||
| mod vtable; | ||
| pub use vtable::RLE; | ||
|
|
||
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 |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // SPDX-FileCopyrightText: Copyright the Vortex contributors | ||
|
|
||
| //! RLE scalar access through the indices, offsets, and values slots. | ||
|
|
||
| use vortex_array::ExecutionCtx; | ||
| use vortex_array::ProbeState; | ||
| use vortex_array::scalar::Scalar; | ||
| use vortex_error::VortexResult; | ||
| use vortex_error::vortex_err; | ||
|
|
||
| use crate::FL_CHUNK_SIZE; | ||
| use crate::RLE; | ||
| use crate::rle::RLEArrayExt; | ||
| use crate::rle::RLESlots; | ||
|
|
||
| /// The slice's base value offset, retained across repeated lookups. | ||
| #[derive(Default)] | ||
| pub struct RleProbeState { | ||
| base: Option<usize>, | ||
| } | ||
|
|
||
| pub(crate) fn scalar_at( | ||
| state: &mut ProbeState<'_, RLE>, | ||
| index: usize, | ||
| ctx: &mut ExecutionCtx, | ||
| ) -> VortexResult<Scalar> { | ||
| let array = state.array(); | ||
| let logical_index = array.offset() + index; | ||
| // Hold the retained state while reading children: the base offset is cached across rows. | ||
| let (mut retained, mut children) = state.split(); | ||
| let code = children | ||
| .slot(RLESlots::INDICES)? | ||
| .ok_or_else(|| vortex_err!("RLE indices slot is missing"))? | ||
|
myrrc marked this conversation as resolved.
|
||
| .execute_scalar(logical_index, ctx)?; | ||
|
myrrc marked this conversation as resolved.
|
||
| let Some(code) = code.as_primitive().as_::<usize>() else { | ||
| return Ok(Scalar::null(array.dtype().clone())); | ||
| }; | ||
|
|
||
| let chunk = logical_index / FL_CHUNK_SIZE; | ||
| let offset = if chunk == 0 { | ||
| 0 | ||
| } else { | ||
| let base = match retained.as_deref().and_then(|state| state.base) { | ||
| Some(base) => base, | ||
| None => { | ||
| let value = read_offset( | ||
| children | ||
| .slot(RLESlots::VALUES_IDX_OFFSETS)? | ||
| .ok_or_else(|| vortex_err!("RLE offsets slot is missing"))? | ||
| .execute_scalar(0, ctx)?, | ||
| )?; | ||
| if let Some(state) = retained.as_mut() { | ||
| state.base = Some(value); | ||
| } | ||
| value | ||
| } | ||
| }; | ||
| read_offset( | ||
| children | ||
| .slot(RLESlots::VALUES_IDX_OFFSETS)? | ||
| .ok_or_else(|| vortex_err!("RLE offsets slot is missing"))? | ||
| .execute_scalar(chunk, ctx)?, | ||
| )? | ||
| .checked_sub(base) | ||
| .ok_or_else(|| vortex_err!("RLE offsets precede the slice base"))? | ||
| }; | ||
| let value_index = offset | ||
| .checked_add(code) | ||
| .ok_or_else(|| vortex_err!("RLE value index overflow"))?; | ||
| let scalar = children | ||
| .slot(RLESlots::VALUES)? | ||
| .ok_or_else(|| vortex_err!("RLE values slot is missing"))? | ||
| .execute_scalar(value_index, ctx)?; | ||
| Scalar::try_new(array.dtype().clone(), scalar.into_value()) | ||
| } | ||
|
|
||
| fn read_offset(scalar: Scalar) -> VortexResult<usize> { | ||
| scalar | ||
| .as_primitive() | ||
| .as_::<usize>() | ||
| .ok_or_else(|| vortex_err!("RLE offset must be a non-null usize")) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests; | ||
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 |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // SPDX-FileCopyrightText: Copyright the Vortex contributors | ||
|
|
||
| use rstest::rstest; | ||
| use vortex_array::ArrayProbe; | ||
| use vortex_array::ArrayRef; | ||
| use vortex_array::IntoArray; | ||
| use vortex_array::RepeatedArrayProbe; | ||
| use vortex_array::VortexSessionExecute; | ||
| use vortex_array::arrays::PrimitiveArray; | ||
| use vortex_array::assert_arrays_eq; | ||
| use vortex_array::builders::builder_with_capacity_in; | ||
| use vortex_array::builtins::ArrayBuiltins; | ||
| use vortex_array::scalar_fn::fns::operators::Operator; | ||
| use vortex_array::validity::Validity; | ||
| use vortex_error::VortexResult; | ||
|
|
||
| use crate::RLE; | ||
| use crate::RLEData; | ||
|
|
||
| /// A one-off or retained probe over `array`, the retained one living in `retained`. | ||
| fn probe_for<'a>( | ||
| array: &'a ArrayRef, | ||
| retained: &'a mut Option<RepeatedArrayProbe>, | ||
| repeated: bool, | ||
| ) -> ArrayProbe<'a> { | ||
| if repeated { | ||
| retained.insert(array.repeated_probe()).as_probe() | ||
| } else { | ||
| array.probe() | ||
| } | ||
| } | ||
|
|
||
| #[rstest] | ||
| fn random_access_across_chunks_and_nulls( | ||
| #[values(false, true)] repeated: bool, | ||
| #[values(false, true)] sliced: bool, | ||
| ) -> VortexResult<()> { | ||
| let mut ctx = crate::test::SESSION.create_execution_ctx(); | ||
| let input = | ||
| PrimitiveArray::from_option_iter((0..8192u32).map(|i| (i % 11 != 0).then_some(i / 16))); | ||
| let encoded = RLEData::encode(input.as_view(), &mut ctx)?.into_array(); | ||
| let range = if sliced { 1777..7333 } else { 0..8192 }; | ||
| let source = if sliced { | ||
| encoded | ||
| .slice(range.clone())? | ||
| .execute::<ArrayRef>(&mut ctx)? | ||
| } else { | ||
| encoded | ||
| }; | ||
| assert!(source.is::<RLE>()); | ||
| let input = input.slice(range)?; | ||
| let indices = [0u32, 1, 1023, 1024, 2048, 2047, 4097, 11, 33, 17, 0]; | ||
| let mut actual = builder_with_capacity_in(source.dtype(), indices.len(), ctx.allocator()); | ||
| let mut retained = None; | ||
| let mut probe = probe_for(&source, &mut retained, repeated); | ||
| for index in indices { | ||
| actual.append_scalar(&probe.execute_scalar(index as usize, &mut ctx)?)?; | ||
| } | ||
| assert_arrays_eq!( | ||
| actual.finish(), | ||
| input.take(PrimitiveArray::from_iter(indices).into_array())?, | ||
| &mut ctx | ||
| ); | ||
| assert!(probe.execute_scalar(source.len(), &mut ctx).is_err()); | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[rstest] | ||
| fn lazy_validity_does_not_evaluate_unrequested_rows( | ||
| #[values(false, true)] repeated: bool, | ||
| ) -> VortexResult<()> { | ||
| let mut ctx = crate::test::SESSION.create_execution_ctx(); | ||
| let numerators = PrimitiveArray::from_iter(vec![1u32; 1024]).into_array(); | ||
| let denominators = | ||
| PrimitiveArray::from_iter((0..1024).map(|i| u32::from(i != 1023))).into_array(); | ||
| let validity = numerators | ||
| .binary(denominators, Operator::Div)? | ||
| .binary(numerators, Operator::Eq)?; | ||
| let array = RLE::try_new( | ||
| PrimitiveArray::from_iter([42u32]).into_array(), | ||
| PrimitiveArray::new(vec![0u16; 1024], Validity::Array(validity)).into_array(), | ||
| PrimitiveArray::from_iter([0u64]).into_array(), | ||
| 0, | ||
| 1024, | ||
| )? | ||
| .into_array(); | ||
| let expected = array.execute_scalar(0, &mut ctx)?; | ||
| let mut retained = None; | ||
| let mut probe = probe_for(&array, &mut retained, repeated); | ||
| assert_eq!(probe.execute_scalar(0, &mut ctx)?, expected); | ||
| assert!(probe.execute_scalar(1023, &mut ctx).is_err()); | ||
| Ok(()) | ||
| } |
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
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 |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
|
|
||
| mod array; | ||
| mod compute; | ||
| mod probe; | ||
| mod rules; | ||
| mod slice; | ||
|
|
||
|
|
||
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.