Files
foxhunt/crates/ml-features/Cargo.toml
jgrusewski e7ce4395e8 perf(precompute): parallel trades load + predecoded sidecar cache
Flamegraph of precompute_features on 1Q ES showed 62% of CPU time in
zstd decompression, 6% in DBN FSM parsing, and only 2% in the actual
feature math — single-threaded zstd was the bottleneck, not compute.

Two fixes:

1. Per-quarter parallelism on the volume-bar trades loop (was sequential
   `for file in &trade_files`); brings it in line with the OFI path that
   already used par_iter.

2. Predecoded sidecar cache in `crates/ml-features/src/predecoded.rs`:
   first call to a `.dbn.zst` writes a bincode'd Vec<Mbp10Snapshot> or
   Vec<DbnTrade> under `<output_dir>/predecoded/`. Subsequent calls
   deserialize the sidecar and skip zstd entirely. An mtime+size header
   self-invalidates the sidecar when the source changes — no manual
   flush needed when a quarter is re-downloaded.

   Local 1Q ES results:
   - cold (writes sidecar): 40.7s (was 39.3s; +1.4s for write)
   - warm (HIT):             4.7s  (8.7× faster)
   - zstd in flat perf:      62% → 0% of CPU samples
   - sidecar disk per Q:     ~150MB

The sidecar layer also auto-dedupes within a single run: the OFI section
re-loads trades, but the second call hits the sidecar that the
volume-bar section wrote moments earlier.

CLI: `--rebuild-predecoded` purges sidecars for cold-path testing or
after a wire-format change to Mbp10Snapshot / DbnTrade. Sidecars also
self-invalidate on format-version mismatch so old caches are skipped
silently rather than mis-deserializing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 14:11:26 +02:00

56 lines
1.3 KiB
TOML

[package]
name = "ml-features"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
publish.workspace = true
keywords.workspace = true
categories.workspace = true
description = "Feature engineering for Foxhunt ML models"
[features]
default = []
[dependencies]
# Internal workspace crates
ml-core.workspace = true
common.workspace = true
data = { path = "../data" }
# Alpha Block M (fractional differentiation): reuse `FractionalCoeffs` from
# ml-labeling instead of duplicating the binomial-coefficient math.
# ml-labeling only depends on ml-core, so this adds no new transitive weight.
ml-labeling.workspace = true
# Serialization and error handling
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
bincode.workspace = true
anyhow.workspace = true
chrono.workspace = true
chrono-tz = "0.10"
tracing.workspace = true
once_cell = "1.19"
# Async and parallelism
tokio.workspace = true
rayon.workspace = true
# Data loading (DBN/Databento)
dbn = "0.42"
zstd.workspace = true
rand.workspace = true
[dev-dependencies]
tokio = { workspace = true, features = ["test-util", "macros"] }
approx.workspace = true
toml.workspace = true
tempfile = "3"
[lints]
workspace = true