From abe4fed4527e07ad7ae4464e574fa582150e306e Mon Sep 17 00:00:00 2001 From: boris Date: Sat, 5 Sep 2026 02:17:24 +0800 Subject: [PATCH] perf: transpose rolling boundary index by date --- crates/fidc-core/src/data.rs | 68 +++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/crates/fidc-core/src/data.rs b/crates/fidc-core/src/data.rs index e9c433a..0753b4b 100644 --- a/crates/fidc-core/src/data.rs +++ b/crates/fidc-core/src/data.rs @@ -572,13 +572,11 @@ const MISSING_ROW_POSITION: u32 = u32::MAX; const MAX_DENSE_ROW_INDEX_BYTES: usize = 256 * 1024 * 1024; #[derive(Debug, Clone)] -struct SymbolSeriesEndPositions { - decision: Vec, - current: Vec, +struct CalendarSeriesEndPositions { + decision: Vec>, + current: Vec>, } -type SymbolSeriesEndPositionIndex = Vec>; - const MAX_SERIES_END_POSITION_INDEX_BYTES: usize = 256 * 1024 * 1024; #[derive(Debug, Clone)] @@ -1324,7 +1322,7 @@ pub struct DataSet { adjusted_close_series_by_symbol: Arc>>, market_series_by_symbol_id: Arc>>>, adjusted_close_series_by_symbol_id: Arc>>>, - market_series_end_positions_by_symbol_id: Arc>, + market_series_end_positions_by_calendar_index: Arc>, benchmark_series_cache: Arc, symbol_id_by_code: Arc>, symbol_by_id: Arc>>, @@ -1399,8 +1397,8 @@ impl DataSet { let mut calendar_dates = self.calendar.days().to_vec(); calendar_dates.extend(dates); let calendar = Arc::new(TradingCalendar::new(calendar_dates)); - self.market_series_end_positions_by_symbol_id = Arc::new( - build_symbol_series_end_positions(&self.market_series_by_symbol_id, &calendar), + self.market_series_end_positions_by_calendar_index = Arc::new( + build_calendar_series_end_positions(&self.market_series_by_symbol_id, &calendar), ); self.calendar = calendar; self @@ -1823,8 +1821,8 @@ impl DataSet { adjusted_close_series_by_symbol_id[symbol_id as usize] = Some(Arc::clone(series)); } } - let market_series_end_positions_by_symbol_id = - build_symbol_series_end_positions(&market_series_by_symbol_id, &calendar); + let market_series_end_positions_by_calendar_index = + build_calendar_series_end_positions(&market_series_by_symbol_id, &calendar); let execution_quotes_by_date = build_execution_quote_index(execution_quotes); let mut execution_quote_dates = execution_quotes_by_date.keys().copied().collect::>(); @@ -1859,8 +1857,8 @@ impl DataSet { adjusted_close_series_by_symbol: Arc::new(adjusted_close_series_by_symbol), market_series_by_symbol_id: Arc::new(market_series_by_symbol_id), adjusted_close_series_by_symbol_id: Arc::new(adjusted_close_series_by_symbol_id), - market_series_end_positions_by_symbol_id: Arc::new( - market_series_end_positions_by_symbol_id, + market_series_end_positions_by_calendar_index: Arc::new( + market_series_end_positions_by_calendar_index, ), benchmark_series_cache: Arc::new(benchmark_series_cache), symbol_id_by_code: Arc::new(symbol_id_by_code), @@ -2041,17 +2039,21 @@ impl DataSet { include_now: bool, ) -> Option { let positions = self - .market_series_end_positions_by_symbol_id + .market_series_end_positions_by_calendar_index .as_ref() - .as_ref()? - .get(symbol_id as usize)? .as_ref()?; let end = if include_now { - positions.current.get(calendar_index) + positions + .current + .get(calendar_index)? + .get(symbol_id as usize) } else { - positions.decision.get(calendar_index) + positions + .decision + .get(calendar_index)? + .get(symbol_id as usize) }?; - Some(*end as usize) + (*end != MISSING_ROW_POSITION).then_some(*end as usize) } pub(crate) fn market_current_series_end_index_by_symbol_id( @@ -4299,10 +4301,10 @@ fn build_dense_row_positions( Some(positions_by_date) } -fn build_symbol_series_end_positions( +fn build_calendar_series_end_positions( series_by_symbol_id: &[Option>], calendar: &TradingCalendar, -) -> Option { +) -> Option { let entries = series_by_symbol_id.len().checked_mul(calendar.len())?; let bytes = entries .checked_mul(2)? @@ -4316,7 +4318,7 @@ fn build_symbol_series_end_positions( } let calendar_days = calendar.days(); - let positions = series_by_symbol_id + let positions_by_symbol = series_by_symbol_id .par_iter() .map(|series| { let series = series.as_deref()?; @@ -4339,10 +4341,28 @@ fn build_symbol_series_end_positions( }; current.push(current_index as u32); } - Some(SymbolSeriesEndPositions { decision, current }) + Some((decision, current)) }) .collect::>(); - Some(positions) + let positions_by_calendar = (0..calendar_days.len()) + .into_par_iter() + .map(|calendar_index| { + let mut decision = Vec::with_capacity(series_by_symbol_id.len()); + let mut current = Vec::with_capacity(series_by_symbol_id.len()); + for positions in &positions_by_symbol { + if let Some((symbol_decision, symbol_current)) = positions { + decision.push(symbol_decision[calendar_index]); + current.push(symbol_current[calendar_index]); + } else { + decision.push(MISSING_ROW_POSITION); + current.push(MISSING_ROW_POSITION); + } + } + (decision, current) + }) + .collect::>(); + let (decision, current) = positions_by_calendar.into_iter().unzip(); + Some(CalendarSeriesEndPositions { decision, current }) } fn dense_row_position( @@ -6000,7 +6020,7 @@ mod tests { let dates = data.calendar().days(); assert!( - data.market_series_end_positions_by_symbol_id + data.market_series_end_positions_by_calendar_index .as_ref() .is_some() );