Skip to content

Commit 9d0994d

Browse files
committed
Add benchmark runner script and regenerate all benchmark results
Add benchmark/run_benchmarks.py — a Python script that automates running all upstream tools (dupRadar, featureCounts, 7 RSeQC tools) via Docker/Wave containers and RustQC natively, with psrecord CPU/memory profiling. Regenerated all benchmark results on large (10 GB BAM) and small datasets: - RustQC (all tools, 10 threads): 16m 11s - Traditional pipeline total: ~1h 25m (dupRadar 27m, featureCounts 4m, 7 RSeQC tools 54m running sequentially) Updated all markdown files (README.md, benchmark/README.md, docs benchmark pages) with fresh timing numbers. Regenerated SVG bar charts with 10 bars (RustQC + featureCounts + dupRadar + 7 individual RSeQC scripts). New profiling output in benchmark/profiling/ with per-tool psrecord logs, CPU/memory profile plots, and a results.json summary.
1 parent 5664f89 commit 9d0994d

126 files changed

Lines changed: 129681 additions & 21871 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ All tools accept SAM/BAM/CRAM input and support processing multiple files in a s
1919
<p align="center">
2020
<picture>
2121
<source media="(prefers-color-scheme: dark)" srcset="docs/public/benchmarks/benchmark_dark.svg">
22-
<img src="docs/public/benchmarks/benchmark_light.svg" alt="Benchmark: RustQC 54s vs featureCounts 16m vs dupRadar 30m" width="600">
22+
<img src="docs/public/benchmarks/benchmark_light.svg" alt="Benchmark: RustQC 16m 11s vs traditional tools ~1h 25m (dupRadar + featureCounts + 7 RSeQC tools)" width="600">
2323
</picture>
2424
</p>
2525

@@ -36,7 +36,7 @@ Performs dupRadar-equivalent duplicate rate analysis, featureCounts-compatible r
3636
| Language | R | Rust |
3737
| Dependencies | R, Bioconductor, Rsubread | None (static binary) |
3838
| Read counting | 4 separate featureCounts calls | Single-pass alignment reading |
39-
| Speed | ~30 min for 10 GB BAM | <1 min for 10 GB BAM |
39+
| Speed | ~30 min for 10 GB BAM | ~16 min for 10 GB BAM (all tools) |
4040
| Memory | High (R overhead) | Low |
4141
| Output format | Identical | Identical |
4242

benchmark/README.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,33 @@ Benchmark data and scripts for comparing RustQC against
88
For detailed results, tables, and side-by-side plot comparisons, see the
99
documentation:
1010

11+
- [Combined benchmarks](https://ewels.github.io/RustQC/benchmarks/combined/)
1112
- [dupRadar benchmarks](https://ewels.github.io/RustQC/benchmarks/dupradar/)
1213
- [featureCounts benchmarks](https://ewels.github.io/RustQC/benchmarks/featurecounts/)
1314

15+
## Latest results (large dataset)
16+
17+
Run via `python3 benchmark/run_benchmarks.py --all` on a 10-core Apple Silicon
18+
Mac. Upstream tools run via Docker with x86 emulation; RustQC runs natively.
19+
20+
| Tool | Wall time |
21+
|------|----------:|
22+
| dupRadar (R) | 27m 21s |
23+
| featureCounts (Subread) | 3m 39s |
24+
| bam_stat (RSeQC) | 6m 07s |
25+
| infer_experiment (RSeQC) | 7s |
26+
| read_duplication (RSeQC) | 29m 43s |
27+
| read_distribution (RSeQC) | 6m 00s |
28+
| junction_annotation (RSeQC) | 4m 37s |
29+
| junction_saturation (RSeQC) | 6m 32s |
30+
| inner_distance (RSeQC) | 1m 09s |
31+
| **Traditional total** | **1h 25m** |
32+
| **RustQC (10 threads)** | **16m 11s** |
33+
34+
> **Note:** Docker x86 emulation on ARM inflates the upstream tool timings.
35+
> The key takeaway is that RustQC replaces 9 separate tool invocations
36+
> (each requiring a full BAM pass) with a single command and single BAM pass.
37+
1438
## Directory structure
1539

1640
```
@@ -86,7 +110,29 @@ pending):
86110
| `junction_saturation` | 256,466 junctions at 100% (163,710 known, 92,756 novel) |
87111
| `inner_distance` | 1,000,000 pairs sampled (mean 29.43, median 27.5, SD 32.80) |
88112

89-
## Reproducing benchmarks
113+
## Running benchmarks
114+
115+
The simplest way to run benchmarks is with the included script:
116+
117+
```bash
118+
# Run everything (requires Docker for upstream tools)
119+
python3 benchmark/run_benchmarks.py --all
120+
121+
# Run only specific tools
122+
python3 benchmark/run_benchmarks.py --rustqc --dupradar
123+
124+
# Run only the small dataset
125+
python3 benchmark/run_benchmarks.py --all --small-only
126+
```
127+
128+
The script profiles CPU/memory usage with `psrecord`, saves timing results to
129+
`benchmark/profiling/results.json`, per-tool profile logs and plots under
130+
`benchmark/profiling/<tool>/<dataset>/`, and regenerates the SVG bar charts
131+
in `docs/public/benchmarks/`.
132+
133+
Dependencies: `pip install psrecord matplotlib psutil`
134+
135+
## Manual reproduction
90136

91137
### 1. Download large benchmark input files
92138

benchmark/RSeQC/large/infer_experiment.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Reading reference gene model /data/genes.bed ... Done
1+
Reading reference gene model /data/input.bed ... Done
22
Loading SAM/BAM file ... Total 200000 usable reads were sampled
33

44

0 Bytes
Binary file not shown.

benchmark/RSeQC/large/inner_distance.inner_distance_plot.r

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
out_file = '/out/inner_distance'
2-
pdf('/out/inner_distance.inner_distance_plot.pdf')
1+
out_file = '/data/output/inner_distance'
2+
pdf('/data/output/inner_distance.inner_distance_plot.pdf')
33
fragsize=rep(c(-247.5,-242.5,-237.5,-232.5,-227.5,-222.5,-217.5,-212.5,-207.5,-202.5,-197.5,-192.5,-187.5,-182.5,-177.5,-172.5,-167.5,-162.5,-157.5,-152.5,-147.5,-142.5,-137.5,-132.5,-127.5,-122.5,-117.5,-112.5,-107.5,-102.5,-97.5,-92.5,-87.5,-82.5,-77.5,-72.5,-67.5,-62.5,-57.5,-52.5,-47.5,-42.5,-37.5,-32.5,-27.5,-22.5,-17.5,-12.5,-7.5,-2.5,2.5,7.5,12.5,17.5,22.5,27.5,32.5,37.5,42.5,47.5,52.5,57.5,62.5,67.5,72.5,77.5,82.5,87.5,92.5,97.5,102.5,107.5,112.5,117.5,122.5,127.5,132.5,137.5,142.5,147.5,152.5,157.5,162.5,167.5,172.5,177.5,182.5,187.5,192.5,197.5,202.5,207.5,212.5,217.5,222.5,227.5,232.5,237.5,242.5,247.5),times=c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,398,420,458,532,567,737,957,1235,1537,1821,2075,2516,3238,4295,6187,9181,13629,19899,27200,37423,45241,55599,64240,70990,74193,75210,73148,67875,61125,53144,44885,36500,28801,22231,15885,10801,7035,4620,2968,2132,1513,1296,1154,1089,1018,1007,921,922,874,871,813,757,702,749,621,630,582,531,579,540,521,534,453,375,325,339,308,259,287,292))
44
frag_sd = sd(fragsize)
55
frag_mean = mean(fragsize)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Get exon regions from /data/input.bed ...
2+
Load BAM file ... Total read pairs used 1000000
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
pdf("/out/junction_annotation.splice_events.pdf")
1+
pdf("/data/output/junction_annotation.splice_events.pdf")
22
events=c(1.1224763530979862,0.7011813022911578,98.012362937516)
33
pie(events,col=c(2,3,4),init.angle=30,angle=c(60,120,150),density=c(70,70,70),main="splicing events",labels=c("partial_novel 1%","complete_novel 1%","known 98%"))
44
dev.off()
5-
pdf("/out/junction_annotation.splice_junction.pdf")
5+
pdf("/data/output/junction_annotation.splice_junction.pdf")
66
junction=c(19.86072227897655,10.42360390851029,69.71567381251316)
77
pie(junction,col=c(2,3,4),init.angle=30,angle=c(60,120,150),density=c(70,70,70),main="splicing junctions",labels=c("partial_novel 20%","complete_novel 10%","known 70%"))
88
dev.off()
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Reading reference bed file: /data/input.bed ... Done
2+
Load BAM file ... Done
3+
4+
===================================================================
5+
Total splicing Events: 13065665
6+
Known Splicing Events: 12805967
7+
Partial Novel Splicing Events: 146659
8+
Novel Splicing Events: 91614
9+
Filtered Splicing Events: 21425
10+
11+
Total splicing Junctions: 256466
12+
Known Splicing Junctions: 178797
13+
Partial Novel Splicing Junctions: 50936
14+
Novel Splicing Junctions: 26733
15+
16+
===================================================================
17+
Create BED file ...
18+
Create Interact file ...

0 commit comments

Comments
 (0)