perf: reuse stock-state calendar index

This commit is contained in:
boris
2026-09-04 23:49:33 +08:00
parent f7708331d3
commit 6d458dbbc6
2 changed files with 158 additions and 16 deletions
+135 -5
View File
@@ -1997,7 +1997,24 @@ impl DataSet {
symbol_id: u32,
include_now: bool,
) -> Option<usize> {
let calendar_index = self.calendar.index_of(date)?;
let calendar_index = self.calendar_index(date)?;
self.market_series_end_index_by_symbol_id_at_calendar_index(
calendar_index,
symbol_id,
include_now,
)
}
pub(crate) fn calendar_index(&self, date: NaiveDate) -> Option<usize> {
self.calendar.index_of(date)
}
fn market_series_end_index_by_symbol_id_at_calendar_index(
&self,
calendar_index: usize,
symbol_id: u32,
include_now: bool,
) -> Option<usize> {
let positions = self
.market_series_end_positions_by_symbol_id
.as_ref()
@@ -2020,6 +2037,14 @@ impl DataSet {
self.market_series_end_index_by_symbol_id(date, symbol_id, true)
}
pub(crate) fn market_current_series_end_index_by_symbol_id_at_calendar_index(
&self,
calendar_index: usize,
symbol_id: u32,
) -> Option<usize> {
self.market_series_end_index_by_symbol_id_at_calendar_index(calendar_index, symbol_id, true)
}
pub fn factor(&self, date: NaiveDate, symbol: &str) -> Option<&DailyFactorSnapshot> {
let symbol_id = self.symbol_id(symbol)?;
self.factor_by_symbol_id(date, symbol_id)
@@ -2061,9 +2086,10 @@ impl DataSet {
)
}
pub(crate) fn market_standard_rolling_means_by_symbol_id(
pub(crate) fn market_standard_rolling_means_by_symbol_id_with_calendar_index(
&self,
date: NaiveDate,
calendar_index: Option<usize>,
symbol_id: u32,
close_lookbacks: &[usize; 7],
volume_lookbacks: &[usize; 5],
@@ -2079,7 +2105,13 @@ impl DataSet {
}
// Both series are built from the same market-date sequence. Reuse the
// indexed boundary lookup instead of repeating it for close and volume.
let series_end = self.market_series_end_index_by_symbol_id(date, symbol_id, include_now);
let series_end = calendar_index.and_then(|calendar_index| {
self.market_series_end_index_by_symbol_id_at_calendar_index(
calendar_index,
symbol_id,
include_now,
)
});
let close = if close_required {
self.adjusted_close_series_by_symbol_id(symbol_id)
.map(|series| {
@@ -5227,6 +5259,85 @@ mod tests {
);
}
#[test]
#[ignore = "manual release-mode calendar index reuse benchmark"]
fn benchmark_series_boundary_reuses_calendar_index() {
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 date = *data.calendar().days().last().expect("calendar date");
let calendar_index = data.calendar_index(date).expect("calendar index");
let iterations = 5_000_000usize;
let mut date_lookup_nanos = 0u128;
let mut reused_nanos = 0u128;
let mut date_lookup_checksum = 0usize;
let mut reused_checksum = 0usize;
for sample in 0..6 {
let measure_date_lookup = || {
let started = Instant::now();
let mut checksum = 0usize;
for _ in 0..iterations {
checksum += black_box(
data.market_series_end_index_by_symbol_id(
black_box(date),
black_box(symbol_id),
true,
)
.unwrap(),
);
}
(started.elapsed().as_nanos(), checksum)
};
let measure_reused = || {
let started = Instant::now();
let mut checksum = 0usize;
for _ in 0..iterations {
checksum += black_box(
data.market_series_end_index_by_symbol_id_at_calendar_index(
black_box(calendar_index),
black_box(symbol_id),
true,
)
.unwrap(),
);
}
(started.elapsed().as_nanos(), checksum)
};
let (first_nanos, first_checksum, second_nanos, second_checksum) = if sample % 2 == 0 {
let (date_nanos, date_checksum) = measure_date_lookup();
let (reused_nanos, reused_checksum) = measure_reused();
(date_nanos, date_checksum, reused_nanos, reused_checksum)
} else {
let (reused_nanos, reused_checksum) = measure_reused();
let (date_nanos, date_checksum) = measure_date_lookup();
(date_nanos, date_checksum, reused_nanos, reused_checksum)
};
date_lookup_nanos += first_nanos;
date_lookup_checksum += first_checksum;
reused_nanos += second_nanos;
reused_checksum += second_checksum;
}
assert_eq!(date_lookup_checksum, reused_checksum);
let date_lookup_seconds = date_lookup_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-series-boundary-calendar-index-benchmark/v1",
"samples": 6,
"iterationsPerSample": iterations,
"dateLookupSeconds": date_lookup_seconds,
"reusedCalendarIndexSeconds": reused_seconds,
"speedup": date_lookup_seconds / reused_seconds,
"checksum": date_lookup_checksum,
})
);
}
#[test]
#[ignore = "manual component benchmark"]
fn benchmark_daily_snapshot_view_lookup() {
@@ -5743,8 +5854,10 @@ mod tests {
let symbol_id = data.symbol_id("000001.SZ").unwrap();
let close_lookbacks = [1, 2, 3, 1, 2, 3, 0];
let volume_lookbacks = [1, 2, 3, 0, 2];
let batched = data.market_standard_rolling_means_by_symbol_id(
let calendar_index = data.calendar_index(date);
let batched = data.market_standard_rolling_means_by_symbol_id_with_calendar_index(
date,
calendar_index,
symbol_id,
&close_lookbacks,
&volume_lookbacks,
@@ -5774,8 +5887,9 @@ mod tests {
)
);
}
let current = data.market_standard_rolling_means_by_symbol_id(
let current = data.market_standard_rolling_means_by_symbol_id_with_calendar_index(
date,
calendar_index,
symbol_id,
&close_lookbacks,
&volume_lookbacks,
@@ -5830,6 +5944,22 @@ mod tests {
data.market_series_end_index_by_symbol_id(dates[2], symbol_id, true),
Some(3)
);
let calendar_index = data.calendar_index(dates[2]).expect("calendar index");
assert_eq!(
data.market_series_end_index_by_symbol_id_at_calendar_index(
calendar_index,
symbol_id,
false,
),
Some(2)
);
assert_eq!(
data.market_current_series_end_index_by_symbol_id_at_calendar_index(
calendar_index,
symbol_id,
),
Some(3)
);
let extended = data
.clone()