Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
9fed182
Phase 14: STARsolo single-cell support (MVP + CellRanger matching)
Jun 13, 2026
5bbdeeb
solo: buffered matrix output + per-cell build_matrix + 3-way benchmark
Jun 15, 2026
2088e16
solo: stream count matrix to temp file (Step 2; bounded output memory)
Jun 15, 2026
7ba3a9d
Merge branch 'main' into phase14-starsolo
iandriver Jun 15, 2026
4480806
index: mmap the SA + SAindex on load (reclaimable, no OOM)
Jun 15, 2026
9ec634e
index: mmap the genome too, compute reverse-complement on access (Pha…
Jun 16, 2026
6757905
solo: GeneFull feature (intron-inclusive) + multi-feature output
Jun 16, 2026
d2da941
solo: EmptyDrops_CR cell caller (standalone Rust binary)
Jun 16, 2026
63dacb3
test: GeneFull + EmptyDrops comparison scripts
Jun 16, 2026
20d839a
test: rustar-vs-CellRanger GeneFull + EmptyDrops h5 comparison
Jun 16, 2026
b9ebc4b
test: strip 10x '-1' suffix in solo_genefull_compare barcode matching
Jun 16, 2026
0c74045
perf: implement --outSAMtype None + reuse gene-assignment scratch buf…
Jun 16, 2026
e7fb2df
fix(windows): gate mmap MADV_RANDOM behind cfg(unix)
Jun 16, 2026
0e16f59
solo: CellRanger-style Summary.csv per feature + cross-tool compare
Jun 17, 2026
d334cae
solo: CellRanger-style region funnel (exonic/intronic/intergenic/anti…
Jun 17, 2026
ca8f579
solo: filtered/ cell-called matrix output + --soloOutGzip
Jun 17, 2026
f16c1dd
solo: SJ (splice-junction) feature matrix
Jun 17, 2026
441d4a3
solo: --soloMultiMappers (Uniform/PropUnique/Rescue/EM)
Jun 17, 2026
5bb7df5
test: rustar-vs-STARsolo SJ + multiMapper diff harness
Jun 18, 2026
19a8355
solo: --soloType SmartSeq (plate-based, manifest, no UMI)
Jun 18, 2026
76fb51a
solo: --soloType CB_UMI_Complex (multi-segment barcodes)
Jun 18, 2026
1cfc5dd
solo: EmptyDrops_CR Monte-Carlo rescue in the filtered/ writer
Jun 18, 2026
2257e29
solo: paired-end SmartSeq (fragment counts)
Jun 18, 2026
b66b377
solo: Velocyto feature (spliced/unspliced/ambiguous) per Sullivan 2025
Jun 19, 2026
82a5d3f
perf: libdeflate for solo matrix gzip + BGZF/BAM
Jun 20, 2026
72ef40e
perf: pipeline solo FASTQ decode + parallelize matrix build & EmptyDr…
iandriver Jun 24, 2026
dfadf81
solo: --soloVelocytoAmbiguous mode + fix solo reader early-exit deadlock
iandriver Jun 24, 2026
b364650
solo: keep Summary.csv STARsolo-faithful; split CellRanger funnel to …
iandriver Jun 25, 2026
56a426d
perf: FxHash for cluster_seeds window/diagonal maps (top align hotspot)
iandriver Jun 26, 2026
15927f6
perf: disable mimalloc page purging (kill ~12% page-zeroing churn)
iandriver Jun 26, 2026
ab7e65b
perf: FxHashSet for find_seeds dedup + pre-size cluster_seeds windows
iandriver Jun 26, 2026
388fce0
perf: make mimalloc purge delay tunable via RUSTAR_PURGE_DELAY_MS
iandriver Jun 29, 2026
473ccc4
perf: disable mimalloc eager arena commit (RssAnon 17 GB -> 2 GB)
iandriver Jun 29, 2026
7bcce05
perf(solo): O(log n + k) segment-tree gene-overlap query
iandriver Jul 8, 2026
caf8c6f
perf(index): sparse suffix array (--genomeSAsparseD) + SA/array prefetch
iandriver Jul 8, 2026
6b234f5
perf(align): SIMD stop-scan, seed prefetch, stitch allocation hoisting
iandriver Jul 8, 2026
0f6acff
perf(io): pipelined align (bg decode + writer threads), zlib-rs, buff…
iandriver Jul 8, 2026
132b3e8
build(ci): profile-guided optimization for Linux release binaries
iandriver Jul 8, 2026
dde3d8c
test(bench): AWS EC2 benchmark + profiling harness and results
iandriver Jul 8, 2026
770c922
fix(ci): clippy ptr_as_ptr + bump anyhow/memmap2/crossbeam-epoch for …
iandriver Jul 8, 2026
866dc25
docs: benchmarks + STARsolo (Phase 14) completion in README and ROADMAP
iandriver Jul 8, 2026
5570f81
docs: add human (GRCh38, memory-bound) benchmark alongside mouse
iandriver Jul 10, 2026
f7b33d1
fix(ci): clippy 1.97 byte_char_slices/question_mark/manual_assert_eq
iandriver Jul 10, 2026
5c020ff
reconcile: cross-batch pipeline + 5' soloBarcodeMate onto phase14-sta…
iandriver Jul 11, 2026
f79cd4a
Merge remote-tracking branch 'origin/main' into pr90-testland
Psy-Fer Jul 25, 2026
649a877
features.tsv gene-name fix (was gene_id in the name column)
Psy-Fer Jul 25, 2026
9a256c7
GX/GN gene SAM tags (--outSAMattributes GX GN)
Psy-Fer Jul 25, 2026
d3511b5
Gene concordance fix
Psy-Fer Jul 25, 2026
b90ead8
Update CHANGELOG.md
Psy-Fer Jul 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,33 +90,49 @@ jobs:
fail-fast: false
matrix:
include:
# Linux targets are built with profile-guided optimization (`pgo:
# true`): a fresh synthetic genome+reads fixture (scripts/../
# src/bin/gen_pgo_fixture.rs) trains an instrumented build, which is
# then rebuilt using that profile. ~10-20% faster alignment in
# practice (see docs-old perf notes), output-identical to a plain
# build. Restricted to Linux because these are the only matrix
# entries that run NATIVELY on their own build runner — PGO needs to
# execute the instrumented binary to collect a profile, which is not
# possible for the cross-compiled targets below (e.g. macOS x86_64
# built on an Apple Silicon runner).

# Linux x86_64 (baseline)
- name: linux-x86_64
os: ubuntu-latest
target: x86_64-unknown-linux-gnu
pgo: true

# Linux x86_64 with AVX2 (x86-64-v3)
- name: linux-x86_64-v3
os: ubuntu-latest
target: x86_64-unknown-linux-gnu
target_cpu: x86-64-v3
pgo: true

# Linux x86_64 with AVX-512 (x86-64-v4)
- name: linux-x86_64-v4
os: ubuntu-latest
target: x86_64-unknown-linux-gnu
target_cpu: x86-64-v4
pgo: true

# Linux aarch64 (native arm64 runner, baseline)
- name: linux-aarch64
os: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
pgo: true

# Linux aarch64 with SVE (Graviton 3+, Axion, Grace)
- name: linux-aarch64-neoverse-v1
os: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
target_cpu: neoverse-v1
pgo: true

# macOS x86_64 (cross-compiled on Apple Silicon runner)
- name: macos-x86_64
Expand Down Expand Up @@ -147,8 +163,31 @@ jobs:
uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # ratchet:dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
components: ${{ matrix.pgo && 'llvm-tools' || '' }}

- name: Build (PGO)
if: matrix.pgo
shell: bash
run: |
# Build a plain (non-instrumented, host-default-target) binary just to
# generate the tiny synthetic training fixture and its genome index —
# scripts/pgo-build.sh does the actual instrumented + profile-use
# builds of the SHIPPED binary below.
cargo build --release --bin gen_pgo_fixture --bin rustar-aligner
FIXTURE_DIR="$(mktemp -d)"
./target/release/gen_pgo_fixture --out-dir "$FIXTURE_DIR" --n-reads 50000
IDX_DIR="$(mktemp -d)"
./target/release/rustar-aligner --runMode genomeGenerate \
--genomeDir "$IDX_DIR" --genomeFastaFiles "$FIXTURE_DIR/genome.fa" \
--genomeSAindexNbases 8 --runThreadN 2
PGO_TARGET="${{ matrix.target }}" \
PGO_EXTRA_RUSTFLAGS="${TARGET_CPU:+-Ctarget-cpu=$TARGET_CPU}" \
bash scripts/pgo-build.sh "$IDX_DIR" "$FIXTURE_DIR/reads.fastq" 50000
env:
TARGET_CPU: ${{ matrix.target_cpu || '' }}

- name: Build
if: ${{ !matrix.pgo }}
shell: bash
run: >
cargo build --release --target ${{ matrix.target }}
Expand Down
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,13 @@ target
*.out
*.log
*.tab
*.sam
*.sam

# Linux build dir used by the solo Docker benchmark/diff (CARGO_TARGET_DIR)
/target-linux/

# amd64 Linux build dir for the benchmark container
/target-amd64/

# macOS Finder metadata
.DS_Store
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,27 @@ Sections commonly used: Features, Bug fixes, Other changes.

### Features

- **STARsolo single-cell quantification (`--soloType`)** — the 10x
Chromium / plate-based count-matrix pipeline, ported from STAR and
verified against real STARsolo (#90).

- Chemistries: `CB_UMI_Simple` (10x 3'/5'), `CB_UMI_Complex`
(multi-segment CB), and `SmartSeq` (manifest-driven, SE read counts
/ PE fragment counts).
- Features: `Gene`, `GeneFull` (pre-mRNA), `SJ` (splice-junction
counts), and `Velocyto` (spliced/unspliced/ambiguous matrices for
RNA velocity).
- Barcode correction: all `--soloCBmatchWLtype` modes
(`Exact`/`1MM`/`1MM_multi`/`1MM_multi_pseudocounts`/
`1MM_multi_Nbase_pseudocounts`); all `--soloUMIdedup` and
`--soloUMIfiltering` modes; real-valued `--soloMultiMappers`
(`Uniform`/`PropUnique`/`Rescue`/`EM`).
- Output: `raw/` + `filtered/` matrices, `EmptyDrops_CR` cell calling,
CellRanger-style `Summary.csv`, and `--soloOutGzip`.

- **`--outSAMattributes GX GN`** — per-read gene-id / gene-name SAM tags
for the solo `Gene` assignment.

- **`genomeGenerate` peak RSS cut from ~113 GB → ~11 GB** on the human
genome (GRCh38, 32 threads). The construction pipeline no longer
materialises three large intermediates that were dominating the peak:
Expand Down Expand Up @@ -76,6 +97,20 @@ Sections commonly used: Features, Bug fixes, Other changes.
glibc's malloc and per-thread heaps that return whole segments to
the OS when abandoned, so allocator cache size stays bounded.

### Bug fixes

- **STARsolo `Gene` assignment now requires exon concordance**, matching
STARsolo: a read counts toward a gene only when every aligned block
lies within the gene's exons, rather than merely overlapping one. This
removes over-assignment of reads that extend past an exon boundary into
an intron. On the mouse-chr19 differential test the `Gene` count matrix
now matches STAR 2.7.11b (raw matrix identical apart from the
multimapper tie-break tail that even a byte-faithful reimplementation
cannot reproduce).
- **STARsolo `features.tsv` column 2 now emits the GTF `gene_name`**
(symbol), with the STAR gene_id fallback, instead of duplicating the
gene_id.

### Bumps

- `caps-sa` → `0.5` (adds `build_ext_mem_for_filter*`; see the caps-sa
Expand Down
55 changes: 41 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,12 @@ memmap2 = "0.9"
byteorder = "1"
noodles = { version = "0.111", features = ["fastq", "sam", "bam", "bgzf"] }
bstr = "1"
flate2 = "1"
# Use the pure-Rust `zlib-rs` backend instead of flate2's default `miniz_oxide`:
# ~2-3x faster inflate/deflate on the FASTQ decode + BGZF (BAM) paths, with no C
# toolchain dependency. Backend is chosen at build time; API is unchanged.
flate2 = { version = "1", default-features = false, features = ["zlib-rs"] }
rayon = "1"
rustc-hash = "2"
dashmap = "6"
chrono = "0.4"
rand = "0.10"
Expand All @@ -59,6 +63,9 @@ caps-sa = "0.6"
# extra cost in release, but the default features add a few hundred
# kB of fast-path stubs we don't need).
mimalloc = { version = "0.1", default-features = false }
libmimalloc-sys = { version = "0.1.49", features = ["extended"] } # mi_option_set (purge_delay); see main.rs
libdeflater = "1.25.2"
noodles-bgzf = { version = "0.47", features = ["libdeflate"] }

[dev-dependencies]
assert_cmd = "2"
Expand Down
Loading
Loading