perf: reuse duplicate rolling lookbacks
This commit is contained in:
@@ -688,7 +688,17 @@ impl AdjustedCloseSeries {
|
||||
end: usize,
|
||||
lookbacks: &[usize; N],
|
||||
) -> [Option<f64>; N] {
|
||||
std::array::from_fn(|index| self.moving_average_at_end(end, lookbacks[index]))
|
||||
let mut values = [None; N];
|
||||
for index in 0..N {
|
||||
if let Some(previous) =
|
||||
(0..index).find(|previous| lookbacks[*previous] == lookbacks[index])
|
||||
{
|
||||
values[index] = values[previous];
|
||||
} else {
|
||||
values[index] = self.moving_average_at_end(end, lookbacks[index]);
|
||||
}
|
||||
}
|
||||
values
|
||||
}
|
||||
|
||||
fn moving_average_at_end(&self, end: usize, lookback: usize) -> Option<f64> {
|
||||
@@ -5399,6 +5409,81 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "manual release-mode duplicate rolling lookback benchmark"]
|
||||
fn benchmark_adjusted_close_reuses_duplicate_lookbacks() {
|
||||
use std::hint::black_box;
|
||||
use std::time::Instant;
|
||||
|
||||
let data = volume_contract_data(Some([1.0, 1.0, 1.0]));
|
||||
let symbol_id = data.symbol_id("000001.SZ").expect("symbol id");
|
||||
let series = data
|
||||
.adjusted_close_series_by_symbol_id(symbol_id)
|
||||
.expect("adjusted close series");
|
||||
let lookbacks = [1usize, 2, 3, 1, 2, 3, 1];
|
||||
let end = 3usize;
|
||||
let iterations = 3_000_000usize;
|
||||
let mut repeated_nanos = 0u128;
|
||||
let mut reused_nanos = 0u128;
|
||||
let mut repeated_checksum = 0.0;
|
||||
let mut reused_checksum = 0.0;
|
||||
|
||||
for sample in 0..6 {
|
||||
let measure_repeated = || {
|
||||
let started = Instant::now();
|
||||
let mut checksum = 0.0;
|
||||
for _ in 0..iterations {
|
||||
let values = std::array::from_fn::<_, 7, _>(|index| {
|
||||
series.moving_average_at_end(black_box(end), black_box(lookbacks[index]))
|
||||
});
|
||||
checksum += black_box(values).into_iter().flatten().sum::<f64>();
|
||||
}
|
||||
(started.elapsed().as_nanos(), checksum)
|
||||
};
|
||||
let measure_reused = || {
|
||||
let started = Instant::now();
|
||||
let mut checksum = 0.0;
|
||||
for _ in 0..iterations {
|
||||
checksum += black_box(
|
||||
series.moving_averages_at_end(black_box(end), black_box(&lookbacks)),
|
||||
)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.sum::<f64>();
|
||||
}
|
||||
(started.elapsed().as_nanos(), checksum)
|
||||
};
|
||||
let (baseline, candidate) = if sample % 2 == 0 {
|
||||
(measure_repeated(), measure_reused())
|
||||
} else {
|
||||
let candidate = measure_reused();
|
||||
let baseline = measure_repeated();
|
||||
(baseline, candidate)
|
||||
};
|
||||
repeated_nanos += baseline.0;
|
||||
repeated_checksum += baseline.1;
|
||||
reused_nanos += candidate.0;
|
||||
reused_checksum += candidate.1;
|
||||
}
|
||||
|
||||
assert_eq!(repeated_checksum, reused_checksum);
|
||||
let repeated_seconds = repeated_nanos as f64 / 1_000_000_000.0;
|
||||
let reused_seconds = reused_nanos as f64 / 1_000_000_000.0;
|
||||
eprintln!(
|
||||
"{}",
|
||||
serde_json::json!({
|
||||
"schemaVersion": "fidc-adjusted-close-duplicate-lookback-benchmark/v1",
|
||||
"samples": 6,
|
||||
"iterationsPerSample": iterations,
|
||||
"lookbacks": lookbacks,
|
||||
"repeatedSeconds": repeated_seconds,
|
||||
"reusedSeconds": reused_seconds,
|
||||
"speedup": repeated_seconds / reused_seconds,
|
||||
"checksum": repeated_checksum,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "manual component benchmark"]
|
||||
fn benchmark_daily_snapshot_view_lookup() {
|
||||
|
||||
Reference in New Issue
Block a user