Skip to content

Commit c1382ba

Browse files
committed
Execute tensor product functions with RowFn
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
1 parent f220999 commit c1382ba

10 files changed

Lines changed: 1263 additions & 1113 deletions

File tree

‎vortex-tensor/benches/cosine_similarity.rs‎

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use vortex_array::VortexSessionExecute;
2121
use vortex_array::arrays::ConstantArray;
2222
use vortex_array::arrays::ExtensionArray;
2323
use vortex_array::arrays::FixedSizeListArray;
24+
use vortex_array::arrays::MaskedArray;
2425
use vortex_array::arrays::PrimitiveArray;
2526
use vortex_array::dtype::DType;
2627
use vortex_array::dtype::Nullability;
@@ -41,15 +42,11 @@ fn main() {
4142
}
4243

4344
/// Total `f64` elements per operand, held constant across widths: the row count is
44-
/// `ELEMENTS / width`. This budget is well below the one the other tensor benches use, because
45-
/// the constant arms recompute the broadcast vector's norm per row and cost roughly ten times the
46-
/// column arms per element. It is what keeps every arm inside the 1 ms per-iteration limit from
47-
/// `docs/developer-guide/benchmarking.md`, measured against CodSpeed's CPU simulation.
45+
/// `ELEMENTS / width`. The smaller budget keeps the wider cosine kernels inside the 1 ms
46+
/// per-iteration limit from `docs/developer-guide/benchmarking.md` under CodSpeed simulation.
4847
const ELEMENTS: usize = 1_024;
4948

50-
/// Widths chosen to separate the two costs, as in `l2_norm.rs`: the redundant norm pass is
51-
/// `O(rows * width)`, one third of the closure's arithmetic, so wide tensors show the hoist
52-
/// while a narrow one is dominated by per-row framework costs.
49+
/// Widths that expose both fixed row-framework costs and the `O(width)` kernel work.
5350
const WIDTHS: &[usize] = &[2, 32, 256];
5451

5552
/// `ELEMENTS / width` vectors of `width` `f64` elements, non-nullable. `seed` offsets the values so
@@ -106,6 +103,22 @@ fn column_x_constant(bencher: Bencher, width: usize) {
106103
bench_cosine(bencher, vectors(width, 0), constant_vector(width));
107104
}
108105

106+
/// The lhs is a broadcast query vector, whose norm is the same in every row.
107+
#[divan::bench(args = WIDTHS)]
108+
fn constant_x_column(bencher: Bencher, width: usize) {
109+
bench_cosine(bencher, constant_vector(width), vectors(width, 31));
110+
}
111+
112+
/// A nullable broadcast rhs exercises constant preparation and output validity together.
113+
#[divan::bench(args = WIDTHS)]
114+
fn column_x_nullable_constant(bencher: Bencher, width: usize) {
115+
let validity = Validity::from_iter((0..ELEMENTS / width).map(|i| i % 8 != 0));
116+
let rhs = MaskedArray::try_new(constant_vector(width), validity)
117+
.unwrap()
118+
.into_array();
119+
bench_cosine(bencher, vectors(width, 0), rhs);
120+
}
121+
109122
/// One query vector represented as an extension array over constant storage.
110123
fn extension_constant_vector(width: usize) -> ArrayRef {
111124
let ext_dtype = vectors(width, 0).dtype().as_extension().clone();

‎vortex-tensor/benches/inner_product.rs‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@ use divan::Bencher;
1515
use divan::counter::ItemsCount;
1616
use mimalloc::MiMalloc;
1717
use vortex_array::ArrayRef;
18+
use vortex_array::EmptyMetadata;
1819
use vortex_array::IntoArray;
1920
use vortex_array::VortexSessionExecute;
21+
use vortex_array::arrays::ConstantArray;
2022
use vortex_array::arrays::FixedSizeListArray;
2123
use vortex_array::arrays::MaskedArray;
2224
use vortex_array::arrays::PrimitiveArray;
25+
use vortex_array::dtype::DType;
26+
use vortex_array::dtype::Nullability;
27+
use vortex_array::dtype::PType;
28+
use vortex_array::scalar::Scalar;
2329
use vortex_array::validity::Validity;
2430
use vortex_buffer::Buffer;
2531
use vortex_tensor::scalar_fns::inner_product::InnerProduct;
@@ -56,6 +62,16 @@ fn vectors(width: usize, seed: usize) -> ArrayRef {
5662
Vector::try_new_vector_array(storage).unwrap()
5763
}
5864

65+
fn constant_vector(width: usize) -> ArrayRef {
66+
let element_dtype = DType::Primitive(PType::F64, Nullability::NonNullable);
67+
let children = (0..width)
68+
.map(|i| Scalar::primitive(((i % 97) as f64) - 48.0, Nullability::NonNullable))
69+
.collect();
70+
let storage = Scalar::fixed_size_list(element_dtype, children, Nullability::NonNullable);
71+
let vector = Scalar::extension::<Vector>(EmptyMetadata, storage);
72+
ConstantArray::new(vector, ELEMENTS / width).into_array()
73+
}
74+
5975
fn bench_inner_product(bencher: Bencher, lhs: ArrayRef, rhs: ArrayRef) {
6076
let session = vortex_array::array_session();
6177
bencher
@@ -84,3 +100,22 @@ fn nullable(bencher: Bencher, width: usize) {
84100
.into_array();
85101
bench_inner_product(bencher, lhs, vectors(width, 31));
86102
}
103+
104+
#[divan::bench(args = WIDTHS)]
105+
fn column_x_constant(bencher: Bencher, width: usize) {
106+
bench_inner_product(bencher, vectors(width, 0), constant_vector(width));
107+
}
108+
109+
#[divan::bench(args = WIDTHS)]
110+
fn constant_x_column(bencher: Bencher, width: usize) {
111+
bench_inner_product(bencher, constant_vector(width), vectors(width, 31));
112+
}
113+
114+
#[divan::bench(args = WIDTHS)]
115+
fn column_x_nullable_constant(bencher: Bencher, width: usize) {
116+
let validity = Validity::from_iter((0..ELEMENTS / width).map(|i| i % 8 != 0));
117+
let rhs = MaskedArray::try_new(constant_vector(width), validity)
118+
.unwrap()
119+
.into_array();
120+
bench_inner_product(bencher, vectors(width, 0), rhs);
121+
}

‎vortex-tensor/src/encodings/normalized/mod.rs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ pub use array::NormalizedSlots;
2121
mod compress;
2222
pub use compress::NormalizedScheme;
2323
pub use compress::normalize;
24-
pub(crate) use compress::try_build_constant_normalized;
2524

2625
mod execute;
2726

0 commit comments

Comments
 (0)