From 049ff88614d23965ec7adbf18e021be328cea3c3 Mon Sep 17 00:00:00 2001 From: rob-p Date: Wed, 12 Aug 2026 20:11:37 -0400 Subject: [PATCH 1/4] perf: enable geometric LCP memoization for genome indexing --- src/index/sa_build.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/index/sa_build.rs b/src/index/sa_build.rs index a23a53d..57f70bd 100644 --- a/src/index/sa_build.rs +++ b/src/index/sa_build.rs @@ -633,7 +633,17 @@ fn dispatch_caps_sa_segmented( ); if use_ext_mem(n) { - let opts = caps_sa_ext_mem_opts(temp_dir); + // The production segmented genome-plus-junction layout contains many + // long shared contexts across phase-4 partition merges. Enable caps-sa's + // bounded, partition-local geometric LCP memoization with its measured + // defaults. The policy remains explicit here: caps-sa itself defaults + // to the direct kernel for generic inputs. + let opts = + caps_sa_ext_mem_opts(temp_dir).lcp_memoization( + caps_sa::LcpMemoizationPolicy::Geometric( + caps_sa::GeometricMemoizationConfig::default(), + ), + ); // Predicate accepts ACGT only (rejects N at 4, spacer at 5). // Borrows `original` via `&[u8]` — `Send + Sync` is satisfied. let original_ref: &[u8] = original; From 859ac800c9b30987f4ea99ba46ec7f9a24a81b4a Mon Sep 17 00:00:00 2001 From: rob-p Date: Wed, 12 Aug 2026 23:14:15 -0400 Subject: [PATCH 2/4] chore: require caps-sa 0.7 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8a4638f..831e694 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ chrono = "0.4" tempfile = "3" bitflags = { version = "2.12.1", features = ["std"] } shlex = "2.0.1" -caps-sa = "0.6" +caps-sa = "0.7" # mimalloc as the global allocator. Two reasons: # 1. **Memory return**: glibc malloc creates one arena per worker # thread (rayon spawns ~num_cpus workers + sub-threads) and From 5fbc0c1faafdcd209d788a5c58047e936b78c2e0 Mon Sep 17 00:00:00 2001 From: rob-p Date: Thu, 13 Aug 2026 08:43:29 -0400 Subject: [PATCH 3/4] ci: pin caps-sa 0.7 to its release commit --- Cargo.lock | 5 ++--- Cargo.toml | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f77c86..2bd87fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,9 +174,8 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "caps-sa" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be62f8675f16876a7f29cfd8b26cc18dcc52eca05a8428d530cc7036b2269f30" +version = "0.7.0" +source = "git+https://github.com/COMBINE-lab/caps-sa.git?rev=967a7b9a1ac505e6c3882b56604514cd59b7b22d#967a7b9a1ac505e6c3882b56604514cd59b7b22d" dependencies = [ "rayon", "tempfile", diff --git a/Cargo.toml b/Cargo.toml index 831e694..9ee1ca6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,8 @@ chrono = "0.4" tempfile = "3" bitflags = { version = "2.12.1", features = ["std"] } shlex = "2.0.1" -caps-sa = "0.7" +# Temporary Git pin until caps-sa 0.7.0 is published to crates.io. +caps-sa = { version = "0.7", git = "https://github.com/COMBINE-lab/caps-sa.git", rev = "967a7b9a1ac505e6c3882b56604514cd59b7b22d" } # mimalloc as the global allocator. Two reasons: # 1. **Memory return**: glibc malloc creates one arena per worker # thread (rayon spawns ~num_cpus workers + sub-threads) and From a739e1f86b08dab49b3b6faffde084cbf63b30ed Mon Sep 17 00:00:00 2001 From: rob-p Date: Thu, 13 Aug 2026 10:33:48 -0400 Subject: [PATCH 4/4] Use published caps-sa 0.7 API --- CHANGELOG.md | 8 ++++++++ Cargo.lock | 3 ++- Cargo.toml | 3 +-- src/index/sa_build.rs | 8 ++------ 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b4346..7c20e6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,14 @@ Sections commonly used: Features, Bug fixes, Other changes. ### Other changes +- Production genome indexing now enables caps-sa 0.7's bounded geometric LCP + memoization through its stable policy API. On the complete ruSTAR-shaped + GRCh38 plus GENCODE v50 fixture (6.56 billion symbols, 6.18 billion retained + suffixes, 1.40 million segments, 32 physical cores), the final caps-sa 0.7 + implementation built the SA in 172.953 s versus 267.592 s for its original + 0.7 baseline: 35.4% faster, with peak RSS reduced from 10,512,408 to + 9,169,892 KiB. The complete output hash was unchanged. + - `cluster_seeds` reuses its window-bin map across reads on a thread instead of rebuilding it per read. Merging two windows re-keys every bin in the merged span, so the per-read pre-sizing was only a floor and the map diff --git a/Cargo.lock b/Cargo.lock index 2bd87fd..c98c649 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,7 +175,8 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "caps-sa" version = "0.7.0" -source = "git+https://github.com/COMBINE-lab/caps-sa.git?rev=967a7b9a1ac505e6c3882b56604514cd59b7b22d#967a7b9a1ac505e6c3882b56604514cd59b7b22d" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46cbd8870dc17f488813e4c5499ff1bdc2feedb9a650ca2b597933943101394" dependencies = [ "rayon", "tempfile", diff --git a/Cargo.toml b/Cargo.toml index 9ee1ca6..831e694 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,8 +46,7 @@ chrono = "0.4" tempfile = "3" bitflags = { version = "2.12.1", features = ["std"] } shlex = "2.0.1" -# Temporary Git pin until caps-sa 0.7.0 is published to crates.io. -caps-sa = { version = "0.7", git = "https://github.com/COMBINE-lab/caps-sa.git", rev = "967a7b9a1ac505e6c3882b56604514cd59b7b22d" } +caps-sa = "0.7" # mimalloc as the global allocator. Two reasons: # 1. **Memory return**: glibc malloc creates one arena per worker # thread (rayon spawns ~num_cpus workers + sub-threads) and diff --git a/src/index/sa_build.rs b/src/index/sa_build.rs index 57f70bd..113e72c 100644 --- a/src/index/sa_build.rs +++ b/src/index/sa_build.rs @@ -638,12 +638,8 @@ fn dispatch_caps_sa_segmented( // bounded, partition-local geometric LCP memoization with its measured // defaults. The policy remains explicit here: caps-sa itself defaults // to the direct kernel for generic inputs. - let opts = - caps_sa_ext_mem_opts(temp_dir).lcp_memoization( - caps_sa::LcpMemoizationPolicy::Geometric( - caps_sa::GeometricMemoizationConfig::default(), - ), - ); + let opts = caps_sa_ext_mem_opts(temp_dir) + .lcp_memoization(caps_sa::LcpMemoizationPolicy::geometric()); // Predicate accepts ACGT only (rejects N at 4, spacer at 5). // Borrows `original` via `&[u8]` — `Send + Sync` is satisfied. let original_ref: &[u8] = original;