Skip to content

Optimise samtools depth histogram incrementing code.#2078

Merged
whitwham merged 1 commit into
samtools:developfrom
jkbonfield:bam2depth_opt
Jul 16, 2024
Merged

Optimise samtools depth histogram incrementing code.#2078
whitwham merged 1 commit into
samtools:developfrom
jkbonfield:bam2depth_opt

Conversation

@jkbonfield

Copy link
Copy Markdown
Contributor

NB: both of these are benchmarked with samtools/htslib#1805 in situ. Without that the numbers are considerably higher again. Samtools depth now takes about 40% longer than the pure-decode test_view -B in.bam loop, so it's diminishing returns.

The incr with and without -q qual filter are now in their own functions. These functions use HTS_OPT3 to force -O3 as gcc -O2 refuses to vectorise much at all before gcc 12.0. With O3 enforced, we no longer need manual loop unrolling too, so the code is simpler.

Also removed the wrap-around vs non-wrap-around case as given the external function we can handle both together quite easily with one extra conditional.

Speed ups vary by compiler, but are particularly significant with clang. Benchmarks of add_depth + incr_qual* with and without qual filtering on 10 million novaseq reads.

depth -q10

        gcc7    gcc13   clang16
dev -O2 12620   10219   8536
dev -O3 10933   10847   8321

PR  -O2 10498    8020   5802
PR  -O3 11087    9397   6312

depth (no -q)

        gcc     gcc13   clang16
dev -O2 10677   7097    4997
dev -O3  9564   8448    5340

PR  -O2  8605   6528    4414
PR  -O3  9231   7620    4369

NB: oddly -O3 is poorer than -O2 with HTS_OPT3 on key functions.

It's clear there is still a significant speed difference between gcc and clang, but it's elsewhere in the add_depth function..

The incr with and without -q qual filter are now in their own
functions.  These functions use HTS_OPT3 to force -O3 as gcc -O2
refuses to vectorise much at all before gcc 12.0.  With O3 enforced,
we no longer need manual loop unrolling too, so the code is simpler.

Also removed the wrap-around vs non-wrap-around case as given the
external function we can handle both together quite easily with one
extra conditional.

Speed ups vary by compiler, but are particularly significant with clang.
Benchmarks of add_depth + incr_qual* with and without qual filtering
on 10 million novaseq reads.

depth -q10

            gcc7    gcc13   clang16
    dev -O2 12620   10219   8536
    dev -O3 10933   10847   8321

    PR  -O2 10498    8020   5802
    PR  -O3 11087    9397   6312

depth (no -q)

            gcc     gcc13   clang16
    dev -O2 10677   7097    4997
    dev -O3  9564   8448    5340

    PR  -O2  8605   6528    4414
    PR  -O3  9231   7620    4369

NB: oddly -O3 is poorer than -O2 with HTS_OPT3 on key functions.

It's clear there is still a significant speed difference between gcc
and clang, but it's elsewhere in the add_depth function..
@jkbonfield

jkbonfield commented Jul 11, 2024

Copy link
Copy Markdown
Contributor Author

The speed tests using develop htslib branch (built with system gcc) and develop samtools (built using gcc7, gcc13 and clang16) are 14159, 10545, 11302 respectively.

Those are perf record counters for the add_depth function, so it's 1.6x to 2.6x faster with the combined changes, so maybe ~15% overall speed gain for the entire program. It probably didn't warrant speeding up to be honest as it's fast anyway, but I noticed the inefficiency while looking to see what else heavily depended on kputll so I could evaluate the impact of that code change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants