use std::sync::atomic::{AtomicU64, Ordering};
use rudb_common::{Cause, slow};
use rudb_vector::Form;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Kernel {
Compare,
Scalar,
Logic,
Cast,
Aggregate,
Select,
}
impl Kernel {
const ALL: [Self; 6] =
[Self::Compare, Self::Scalar, Self::Logic, Self::Cast, Self::Aggregate, Self::Select];
#[must_use]
pub fn name(self) -> &'static str {
match self {
Self::Compare => "compare",
Self::Scalar => "scalar",
Self::Logic => "logic",
Self::Cast => "cast",
Self::Aggregate => "aggregate",
Self::Select => "select",
}
}
fn index(self) -> usize {
match self {
Self::Compare => 0,
Self::Scalar => 1,
Self::Logic => 2,
Self::Cast => 3,
Self::Aggregate => 4,
Self::Select => 5,
}
}
const fn cause(self) -> Cause {
match self {
Self::Compare => Cause::Compare,
Self::Scalar => Cause::Scalar,
Self::Logic => Cause::Logic,
Self::Cast => Cause::Cast,
Self::Aggregate => Cause::Aggregate,
Self::Select => Cause::Select,
}
}
}
const FORMS: [Form; 4] = [Form::Flat, Form::Constant, Form::Sequence, Form::Dictionary];
fn form_name(form: Form) -> &'static str {
match form {
Form::Flat => "flat",
Form::Constant => "constant",
Form::Sequence => "sequence",
Form::Dictionary => "dictionary",
_ => "other",
}
}
fn form_index(form: Form) -> usize {
FORMS.iter().position(|&known| known == form).unwrap_or(FORMS.len())
}
const WIDTH: usize = FORMS.len() + 1;
const CELLS: usize = Kernel::ALL.len() * WIDTH * WIDTH;
#[cfg(not(test))]
static COUNTS: [AtomicU64; CELLS] = [const { AtomicU64::new(0) }; CELLS];
#[cfg(test)]
thread_local! {
static COUNTS: [AtomicU64; CELLS] = const { [const { AtomicU64::new(0) }; CELLS] };
}
#[cfg(not(test))]
fn with_counts<T>(read: impl FnOnce(&[AtomicU64; CELLS]) -> T) -> T {
read(&COUNTS)
}
#[cfg(test)]
fn with_counts<T>(read: impl FnOnce(&[AtomicU64; CELLS]) -> T) -> T {
COUNTS.with(read)
}
fn cell(kernel: Kernel, left: Form, right: Form) -> usize {
kernel.index() * WIDTH * WIDTH + form_index(left) * WIDTH + form_index(right)
}
pub fn record(kernel: Kernel, left: Form, right: Form) {
with_counts(|counts| counts[cell(kernel, left, right)].fetch_add(1, Ordering::Relaxed));
slow::took(kernel.cause());
}
#[must_use]
pub fn count(kernel: Kernel, left: Form, right: Form) -> u64 {
with_counts(|counts| counts[cell(kernel, left, right)].load(Ordering::Relaxed))
}
#[must_use]
pub fn hot() -> Vec<(Kernel, Form, Form, u64)> {
let mut out = Vec::new();
for kernel in Kernel::ALL {
for left in FORMS {
for right in FORMS {
let seen = count(kernel, left, right);
if seen > 0 {
out.push((kernel, left, right, seen));
}
}
}
}
out.sort_by_key(|entry| std::cmp::Reverse(entry.3));
out
}
pub fn reset() {
with_counts(|counts| {
for counter in counts {
counter.store(0, Ordering::Relaxed);
}
});
}
#[must_use]
pub fn report() -> String {
let hot = hot();
if hot.is_empty() {
return "every kernel call took a specialized path".to_owned();
}
let mut out = String::from("kernel calls that fell through to the row at a time path\n");
for (kernel, left, right, seen) in hot {
out.push_str(&format!(
" {:<10} {:<10} against {:<10} {seen}\n",
kernel.name(),
form_name(left),
form_name(right)
));
}
out
}
#[cfg(test)]
mod tests {
use rudb_common::slow;
use super::{Cause, Form, Kernel, count, hot, record, report, reset};
#[test]
fn a_fall_through_is_counted_by_form_pair_here_and_by_kernel_where_the_document_reads_it() {
reset();
slow::reset();
record(Kernel::Select, Form::Dictionary, Form::Flat);
record(Kernel::Select, Form::Constant, Form::Flat);
assert_eq!(count(Kernel::Select, Form::Dictionary, Form::Flat), 1);
assert_eq!(count(Kernel::Select, Form::Constant, Form::Flat), 1);
assert_eq!(slow::here().get(Cause::Select), 2);
assert_eq!(slow::here().total(), 2);
reset();
slow::reset();
}
#[test]
fn every_kernel_names_a_cause_of_its_own() {
let mut named: Vec<&str> = Kernel::ALL.iter().map(|kernel| kernel.cause().name()).collect();
named.sort_unstable();
named.dedup();
assert_eq!(named.len(), Kernel::ALL.len());
for kernel in Kernel::ALL {
assert_eq!(kernel.name(), kernel.cause().name(), "one kernel, one name");
}
}
#[test]
fn a_fall_through_lands_in_the_cell_for_its_own_form_pair() {
reset();
record(Kernel::Compare, Form::Sequence, Form::Constant);
record(Kernel::Compare, Form::Sequence, Form::Constant);
record(Kernel::Cast, Form::Dictionary, Form::Flat);
assert_eq!(count(Kernel::Compare, Form::Sequence, Form::Constant), 2);
assert_eq!(count(Kernel::Cast, Form::Dictionary, Form::Flat), 1);
assert_eq!(count(Kernel::Compare, Form::Constant, Form::Sequence), 0);
assert_eq!(count(Kernel::Compare, Form::Flat, Form::Flat), 0);
reset();
}
#[test]
fn the_report_names_the_combination_rather_than_a_number_on_its_own() {
reset();
assert!(report().contains("every kernel call took a specialized path"));
for _ in 0..7 {
record(Kernel::Compare, Form::Sequence, Form::Constant);
}
record(Kernel::Logic, Form::Flat, Form::Dictionary);
let text = report();
assert!(text.contains("compare"), "{text}");
assert!(text.contains("sequence"), "{text}");
assert!(text.contains('7'), "{text}");
assert_eq!(hot().first().map(|entry| entry.3), Some(7));
reset();
}
}