Skip to content

Commit 6d65ddd

Browse files
committed
Reduce parent execution dispatch overhead
Avoid the per-execution parent kernel cache now that ExecutionCtx already holds the session snapshot, and make patch index lookup use the primitive fast path directly. Signed-off-by: "Nicholas Gates" <nick@nickgates.com>
1 parent 5fd4370 commit 6d65ddd

3 files changed

Lines changed: 20 additions & 63 deletions

File tree

vortex-array/src/arrays/filter/execute/take/tests.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,22 @@ use crate::IntoArray;
99
use crate::RecursiveCanonical;
1010
use crate::arrays::BoolArray;
1111
use crate::arrays::DecimalArray;
12+
use crate::arrays::Dict;
1213
use crate::arrays::DictArray;
14+
use crate::arrays::Filter;
1315
use crate::arrays::FilterArray;
1416
use crate::arrays::FixedSizeListArray;
1517
use crate::arrays::ListArray;
1618
use crate::arrays::Primitive;
1719
use crate::arrays::PrimitiveArray;
1820
use crate::arrays::StructArray;
1921
use crate::arrays::VarBinViewArray;
22+
use crate::arrays::dict::TakeExecuteAdaptor;
2023
use crate::assert_arrays_eq;
2124
use crate::dtype::DecimalDType;
2225
use crate::dtype::FieldNames;
2326
use crate::executor::ExecutionCtx;
24-
use crate::optimizer::kernels::ArrayKernelsExt;
27+
use crate::kernel::ExecuteParentKernel;
2528
use crate::validity::Validity;
2629

2730
fn execute_parent(
@@ -30,19 +33,12 @@ fn execute_parent(
3033
child_idx: usize,
3134
ctx: &mut ExecutionCtx,
3235
) -> VortexResult<Option<crate::ArrayRef>> {
33-
let kernels = ctx.session().kernels().clone();
34-
let Some(plugins) = kernels.find_execute_parent(parent.encoding_id(), child.encoding_id())
35-
else {
36-
return Ok(None);
37-
};
38-
39-
for plugin in plugins.as_ref() {
40-
if let Some(result) = plugin.execute_parent(child, parent, child_idx, ctx)? {
41-
return Ok(Some(result));
42-
}
43-
}
44-
45-
Ok(None)
36+
TakeExecuteAdaptor(Filter).execute_parent(
37+
child.as_::<Filter>(),
38+
parent.as_::<Dict>(),
39+
child_idx,
40+
ctx,
41+
)
4642
}
4743

4844
#[test]

vortex-array/src/executor.rs

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use std::sync::atomic::AtomicUsize;
2222
#[cfg(debug_assertions)]
2323
use std::sync::atomic::Ordering;
2424

25-
use smallvec::SmallVec;
2625
use vortex_error::VortexExpect;
2726
use vortex_error::VortexResult;
2827
use vortex_error::vortex_bail;
@@ -43,15 +42,11 @@ use crate::memory::HostAllocatorRef;
4342
use crate::memory::MemorySessionExt;
4443
use crate::optimizer::ArrayOptimizer;
4544
use crate::optimizer::kernels::ArrayKernels;
46-
use crate::optimizer::kernels::ExecuteParentKernelRef;
4745
use crate::optimizer::kernels::ParentExecutionKernels;
4846
use crate::optimizer::kernels::execute_parent_key;
4947
use crate::stats::ArrayStats;
5048
use crate::stats::StatsSet;
5149

52-
static EMPTY_PARENT_EXECUTION_KERNELS: LazyLock<Arc<ParentExecutionKernels>> =
53-
LazyLock::new(|| Arc::new(ParentExecutionKernels::default()));
54-
5550
/// Returns the maximum number of iterations to attempt when executing an array before giving up and returning
5651
/// an error, can be by the `VORTEX_MAX_ITERATIONS` env variables, otherwise defaults to 2^22.
5752
pub(crate) fn max_iterations() -> usize {
@@ -174,7 +169,6 @@ impl ArrayRef {
174169
let mut stack: Vec<StackFrame> = Vec::new();
175170
let execute_parent_kernels = Arc::clone(&ctx.execute_parent_kernels);
176171
let kernels = execute_parent_kernels.as_ref();
177-
let mut execute_parent_cache = ExecuteParentCache::default();
178172
let max_iterations = max_iterations();
179173

180174
for _ in 0..max_iterations {
@@ -217,7 +211,6 @@ impl ArrayRef {
217211
&current_array,
218212
frame.slot_idx,
219213
kernels,
220-
&mut execute_parent_cache,
221214
ctx,
222215
)?
223216
}
@@ -234,8 +227,7 @@ impl ArrayRef {
234227

235228
// Step 2b: execute_parent against current_array's own children.
236229
if current_builder.is_none()
237-
&& let Some(rewritten) =
238-
try_execute_parent(&current_array, kernels, &mut execute_parent_cache, ctx)?
230+
&& let Some(rewritten) = try_execute_parent(&current_array, kernels, ctx)?
239231
{
240232
ctx.log(format_args!(
241233
"execute_parent rewrote {} -> {}",
@@ -340,7 +332,7 @@ impl ExecutionCtx {
340332
let execute_parent_kernels = session
341333
.get_opt::<ArrayKernels>()
342334
.map(ArrayKernels::execute_parent_snapshot)
343-
.unwrap_or_else(|| Arc::clone(&EMPTY_PARENT_EXECUTION_KERNELS));
335+
.unwrap_or_default();
344336
Self {
345337
session,
346338
execute_parent_kernels,
@@ -454,18 +446,12 @@ impl Executable for ArrayRef {
454446

455447
let execute_parent_kernels = Arc::clone(&ctx.execute_parent_kernels);
456448
let kernels = execute_parent_kernels.as_ref();
457-
let mut execute_parent_cache = ExecuteParentCache::default();
458449

459450
for (slot_idx, slot) in array.slots().iter().enumerate() {
460451
let Some(child) = slot else { continue };
461-
if let Some(executed_parent) = execute_parent_for_child(
462-
&array,
463-
child,
464-
slot_idx,
465-
kernels,
466-
&mut execute_parent_cache,
467-
ctx,
468-
)? {
452+
if let Some(executed_parent) =
453+
execute_parent_for_child(&array, child, slot_idx, kernels, ctx)?
454+
{
469455
ctx.log(format_args!(
470456
"execute_parent: slot[{}]({}) rewrote {} -> {}",
471457
slot_idx,
@@ -577,12 +563,10 @@ fn execute_parent_for_child(
577563
child: &ArrayRef,
578564
slot_idx: usize,
579565
kernels: &ParentExecutionKernels,
580-
cache: &mut ExecuteParentCache,
581566
ctx: &mut ExecutionCtx,
582567
) -> VortexResult<Option<ArrayRef>> {
583-
if let Some(plugins) =
584-
find_execute_parent(kernels, cache, parent.encoding_id(), child.encoding_id())
585-
{
568+
let key = execute_parent_key(parent.encoding_id(), child.encoding_id());
569+
if let Some(plugins) = kernels.get(&key) {
586570
for plugin in plugins.as_ref() {
587571
if let Some(result) = plugin.execute_parent(child, parent, slot_idx, ctx)? {
588572
return Ok(Some(result));
@@ -597,13 +581,12 @@ fn execute_parent_for_child(
597581
fn try_execute_parent(
598582
array: &ArrayRef,
599583
kernels: &ParentExecutionKernels,
600-
cache: &mut ExecuteParentCache,
601584
ctx: &mut ExecutionCtx,
602585
) -> VortexResult<Option<ArrayRef>> {
603586
for (slot_idx, slot) in array.slots().iter().enumerate() {
604587
let Some(child) = slot else { continue };
605588
if let Some(executed_parent) =
606-
execute_parent_for_child(array, child, slot_idx, kernels, cache, ctx)?
589+
execute_parent_for_child(array, child, slot_idx, kernels, ctx)?
607590
{
608591
ctx.log(format_args!(
609592
"execute_parent: slot[{}]({}) rewrote {} -> {}",
@@ -621,25 +604,6 @@ fn try_execute_parent(
621604
Ok(None)
622605
}
623606

624-
type ExecuteParentCache = SmallVec<[(u64, Option<Arc<[ExecuteParentKernelRef]>>); 8]>;
625-
626-
fn find_execute_parent(
627-
kernels: &ParentExecutionKernels,
628-
cache: &mut ExecuteParentCache,
629-
parent: ArrayId,
630-
child: ArrayId,
631-
) -> Option<Arc<[ExecuteParentKernelRef]>> {
632-
let key = execute_parent_key(parent, child);
633-
634-
if let Some((_, cached)) = cache.iter().find(|(cached_key, _)| *cached_key == key) {
635-
return cached.clone();
636-
}
637-
638-
let found = kernels.get(&key).cloned();
639-
cache.push((key, found.clone()));
640-
found
641-
}
642-
643607
/// A predicate that determines when an array has reached a desired form during execution.
644608
pub type DonePredicate = fn(&ArrayRef) -> bool;
645609

vortex-array/src/patches.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ use crate::ArraySlots;
2424
use crate::ExecutionCtx;
2525
use crate::IntoArray;
2626
use crate::LEGACY_SESSION;
27-
#[expect(deprecated)]
28-
use crate::ToCanonical as _;
2927
use crate::VortexSessionExecute;
28+
use crate::arrays::Primitive;
3029
use crate::arrays::PrimitiveArray;
3130
use crate::arrays::primitive::PrimitiveArrayExt;
3231
use crate::builtins::ArrayBuiltins;
@@ -497,9 +496,7 @@ impl Patches {
497496
/// [`SearchResult::Found`] with the position if needle exists, or [`SearchResult::NotFound`]
498497
/// with the insertion point if not found.
499498
fn search_index_binary_search(indices: &ArrayRef, needle: usize) -> VortexResult<SearchResult> {
500-
if indices.is_canonical() {
501-
#[expect(deprecated)]
502-
let primitive = indices.to_primitive();
499+
if let Some(primitive) = indices.as_opt::<Primitive>() {
503500
match_each_integer_ptype!(primitive.ptype(), |T| {
504501
let Ok(needle) = T::try_from(needle) else {
505502
// If the needle is not of type T, then it cannot possibly be in this array.

0 commit comments

Comments
 (0)