Skip to content

Use galloping search in IndexEntry::get_count - #643

Open
ksahlin wants to merge 1 commit into
mainfrom
gallop-get-count
Open

ksahlin wants to merge 1 commit into
mainfrom
gallop-get-count

Conversation

@ksahlin

@ksahlin ksahlin commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

When at least 8 entries remained in the bucket, get_count binary-searched
the entire rest of the bucket. Callers usually need only small counts
(is_too_frequent calls it only when the count is at most the filter
cutoff), but for repetitive seeds the rest of the bucket can contain
hundreds of thousands of entries, so most binary search probes were
cache misses far away from the entry.

get_count now gallops from the entry: it probes offsets 1, 2, 4, ...
until an entry no longer matches and then binary-searches between the
last two probes. This needs O(log count) steps and only touches entries
close to this one. The result is identical; a new test compares
get_count with the previous implementation.

Speedup on top of index prefetching (#642) on an Apple M4 Max, -x,
1 thread, median of 5 runs, measured with a prototype of this change:

  • CHM13, 150 nt reads: finding hits -7%, total mapping time -4%
  • CHM13, 10 kb reads: finding hits -3%, total mapping time -1%
  • maize, 150 nt reads: finding hits -7%, total mapping time -4%
  • maize, 10 kb reads: finding hits -3%, total mapping time -1%
  • chrY, 150 nt reads: finding hits -4%, total mapping time -1%
  • chrY, 10 kb reads: finding hits -3%, total mapping time -0.4%

When at least 8 entries remained in the bucket, get_count binary-searched
the entire rest of the bucket. Callers usually need only small counts
(is_too_frequent calls it only when the count is at most the filter
cutoff), but for repetitive seeds the rest of the bucket can contain
hundreds of thousands of entries, so most binary search probes were
cache misses far away from the entry.

get_count now gallops from the entry: it probes offsets 1, 2, 4, ...
until an entry no longer matches and then binary-searches between the
last two probes. This needs O(log count) steps and only touches entries
close to this one. The result is identical; a new test compares
get_count with the previous implementation.

Speedup on top of index prefetching (#XXX) on an Apple M4 Max, -x,
1 thread, median of 5 runs, measured with a prototype of this change:

- CHM13, 150 nt reads: finding hits -7%, total mapping time -4%
- CHM13, 10 kb reads: finding hits -3%, total mapping time -1%
- maize, 150 nt reads: finding hits -7%, total mapping time -4%
- maize, 10 kb reads: finding hits -3%, total mapping time -1%
- chrY, 150 nt reads: finding hits -4%, total mapping time -1%
- chrY, 10 kb reads: finding hits -3%, total mapping time -0.4%
@marcelm

marcelm commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator

The benefits from this PR are unclear. I’m not posting the plots because the runtime difference is not really visible in them, but here is the table:

Comparing this PR, rebased on main, to commit c841de3:

mode library accuracy (%) ∆accuracy speedup
map se-sim6-blueflax-50 32.631 0.0000 1.07×
map se-sim6-blueflax-100 48.671 0.0000 1.05×
map se-sim6-blueflax-150 58.386 0.0000 1.02×
map se-sim6-blueflax-200 63.085 0.0000 1.01×
map se-sim6-blueflax-300 70.959 0.0000 1.00×
map se-sim6-blueflax-500 77.210 0.0000 1.00×
map se-sim6-blueflax-1000 85.662 0.0000 0.99×
map se-sim6-blueflax-5000 94.683 0.0000 1.00×
map se-sim6-blueflax-10000 96.238 0.0000 1.01×
map se-sim6-fruitfly-50 63.039 0.0000 0.91×
map se-sim6-fruitfly-100 80.016 0.0000 0.99×
map se-sim6-fruitfly-150 87.089 0.0000 0.99×
map se-sim6-fruitfly-200 88.970 0.0000 0.98×
map se-sim6-fruitfly-300 91.578 0.0000 1.01×
map se-sim6-fruitfly-500 93.104 0.0000 0.99×
map se-sim6-fruitfly-1000 95.330 0.0000 1.01×
map se-sim6-fruitfly-5000 98.833 0.0000 1.03×
map se-sim6-fruitfly-10000 99.234 0.0000 1.00×
map se-sim6-maize-50 23.817 0.0000 0.99×
map se-sim6-maize-100 39.301 0.0000 1.05×
map se-sim6-maize-150 49.943 0.0000 1.04×
map se-sim6-maize-200 56.146 0.0000 1.04×
map se-sim6-maize-300 66.574 0.0000 1.07×
map se-sim6-maize-500 75.730 0.0000 1.07×
map se-sim6-maize-1000 87.941 0.0000 1.05×
map se-sim6-maize-5000 98.445 0.0000 1.03×
map se-sim6-maize-10000 98.954 0.0000 1.06×
map se-sim6-CHM13-50 50.436 0.0000 1.01×
map se-sim6-CHM13-100 72.352 0.0000 0.93×
map se-sim6-CHM13-150 81.383 0.0000 1.04×
map se-sim6-CHM13-200 84.877 0.0000 0.93×
map se-sim6-CHM13-300 89.255 0.0000 1.02×
map se-sim6-CHM13-500 91.621 0.0000 0.98×
map se-sim6-CHM13-1000 93.580 0.0000 1.03×
map se-sim6-CHM13-5000 96.808 0.0000 1.00×
map se-sim6-CHM13-10000 97.610 0.0000 0.99×
map se-sim6-rye-50 20.049 0.0000 1.00×
map se-sim6-rye-100 35.002 0.0000 1.01×
map se-sim6-rye-150 45.551 0.0000 0.96×
map se-sim6-rye-200 52.049 0.0000 1.02×
map se-sim6-rye-300 62.926 0.0000 1.01×
map se-sim6-rye-500 72.674 0.0000 0.97×
map se-sim6-rye-1000 85.768 0.0000 1.01×
map se-sim6-rye-5000 97.758 0.0000 0.95×
map se-sim6-rye-10000 98.646 0.0000 0.92×
map se-sim6-chrY-50 23.076 0.0000 0.99×
map se-sim6-chrY-100 31.009 0.0000 1.00×
map se-sim6-chrY-150 35.004 0.0000 1.00×
map se-sim6-chrY-200 36.486 0.0000 0.99×
map se-sim6-chrY-300 38.877 0.0000 0.99×
map se-sim6-chrY-500 41.189 0.0000 0.99×
map se-sim6-chrY-1000 46.178 0.0000 0.99×
map se-sim6-chrY-5000 72.636 0.0000 1.00×
map se-sim6-chrY-10000 85.708 0.0000 1.00×
map se-sim0-blueflax-50 56.828 0.0000 1.00×
map se-sim0-blueflax-100 71.130 0.0000 1.01×
map se-sim0-blueflax-150 77.983 0.0000 1.02×
map se-sim0-blueflax-200 81.882 0.0000 0.99×
map se-sim0-blueflax-300 86.019 0.0000 1.00×
map se-sim0-blueflax-500 89.849 0.0000 1.00×
map se-sim0-blueflax-1000 93.529 0.0000 1.00×
map se-sim0-blueflax-5000 98.468 0.0000 1.00×
map se-sim0-blueflax-10000 99.432 0.0000 1.00×
map se-sim0-fruitfly-50 88.745 0.0000 0.99×
map se-sim0-fruitfly-100 90.941 0.0000 0.98×
map se-sim0-fruitfly-150 92.098 0.0000 1.00×
map se-sim0-fruitfly-200 92.879 0.0000 1.00×
map se-sim0-fruitfly-300 93.987 0.0000 0.99×
map se-sim0-fruitfly-500 95.284 0.0000 1.00×
map se-sim0-fruitfly-1000 96.818 0.0000 0.99×
map se-sim0-fruitfly-5000 99.345 0.0000 0.97×
map se-sim0-fruitfly-10000 99.858 0.0000 1.00×
map se-sim0-maize-50 47.726 0.0000 0.99×
map se-sim0-maize-100 69.292 0.0000 0.99×
map se-sim0-maize-150 80.156 0.0000 1.00×
map se-sim0-maize-200 85.956 0.0000 1.00×
map se-sim0-maize-300 91.413 0.0000 1.00×
map se-sim0-maize-500 95.541 0.0000 1.00×
map se-sim0-maize-1000 98.115 0.0000 0.99×
map se-sim0-maize-5000 99.569 0.0000 1.01×
map se-sim0-maize-10000 99.706 0.0000 1.02×
map se-sim0-CHM13-50 85.470 0.0000 0.99×
map se-sim0-CHM13-100 91.072 0.0000 0.99×
map se-sim0-CHM13-150 92.573 0.0000 1.00×
map se-sim0-CHM13-200 93.383 0.0000 1.01×
map se-sim0-CHM13-300 94.281 0.0000 1.02×
map se-sim0-CHM13-500 95.302 0.0000 1.04×
map se-sim0-CHM13-1000 96.507 0.0000 1.02×
map se-sim0-CHM13-5000 98.753 0.0000 1.05×
map se-sim0-CHM13-10000 99.252 0.0000 1.05×
map se-sim0-rye-50 45.304 0.0000 1.00×
map se-sim0-rye-100 68.997 0.0000 0.99×
map se-sim0-rye-150 80.465 0.0000 0.98×
map se-sim0-rye-200 86.276 0.0000 1.00×
map se-sim0-rye-300 91.390 0.0000 1.00×
map se-sim0-rye-500 94.713 0.0000 1.02×
map se-sim0-rye-1000 96.790 0.0000 0.99×
map se-sim0-rye-5000 99.203 0.0000 1.00×
map se-sim0-rye-10000 99.688 0.0000 1.00×
map se-sim0-chrY-50 35.651 0.0000 0.99×
map se-sim0-chrY-100 39.158 0.0000 0.96×
map se-sim0-chrY-150 41.754 0.0000 0.99×
map se-sim0-chrY-200 43.862 0.0000 0.99×
map se-sim0-chrY-300 46.476 0.0000 1.00×
map se-sim0-chrY-500 51.765 0.0000 0.99×
map se-sim0-chrY-1000 59.587 0.0000 0.98×
map se-sim0-chrY-5000 82.777 0.0000 0.99×
map se-sim0-chrY-10000 92.676 0.0000 1.00×
map se-sim4-blueflax-50 53.363 0.0000 0.97×
map se-sim4-blueflax-100 68.098 0.0000 0.99×
map se-sim4-blueflax-150 75.333 0.0000 0.99×
map se-sim4-blueflax-200 79.400 0.0000 1.00×
map se-sim4-blueflax-300 84.180 0.0000 1.02×
map se-sim4-blueflax-500 88.264 0.0000 0.99×
map se-sim4-blueflax-1000 92.257 0.0000 0.99×
map se-sim4-blueflax-5000 97.153 0.0000 0.99×
map se-sim4-blueflax-10000 98.114 0.0000 0.99×
map se-sim4-fruitfly-50 87.122 0.0000 1.00×
map se-sim4-fruitfly-100 90.363 0.0000 0.99×
map se-sim4-fruitfly-150 91.646 0.0000 1.00×
map se-sim4-fruitfly-200 92.428 0.0000 1.01×
map se-sim4-fruitfly-300 93.553 0.0000 0.99×
map se-sim4-fruitfly-500 94.881 0.0000 0.99×
map se-sim4-fruitfly-1000 96.529 0.0000 1.00×
map se-sim4-fruitfly-5000 99.119 0.0000 0.98×
map se-sim4-fruitfly-10000 99.484 0.0000 0.99×
map se-sim4-maize-50 43.509 0.0000 0.98×
map se-sim4-maize-100 64.287 0.0000 0.98×
map se-sim4-maize-150 75.432 0.0000 0.99×
map se-sim4-maize-200 81.850 0.0000 1.00×
map se-sim4-maize-300 88.471 0.0000 1.01×
map se-sim4-maize-500 93.629 0.0000 0.99×
map se-sim4-maize-1000 97.311 0.0000 0.98×
map se-sim4-maize-5000 99.200 0.0000 1.00×
map se-sim4-maize-10000 99.230 0.0000 1.01×
map se-sim4-CHM13-50 81.766 0.0000 1.00×
map se-sim4-CHM13-100 89.670 0.0000 0.97×
map se-sim4-CHM13-150 91.771 0.0000 0.98×
map se-sim4-CHM13-200 92.717 0.0000 0.99×
map se-sim4-CHM13-300 93.697 0.0000 0.99×
map se-sim4-CHM13-500 94.746 0.0000 1.02×
map se-sim4-CHM13-1000 95.975 0.0000 1.00×
map se-sim4-CHM13-5000 98.248 0.0000 0.98×
map se-sim4-CHM13-10000 98.598 0.0000 0.99×
map se-sim4-rye-50 40.406 0.0000 0.99×
map se-sim4-rye-100 62.739 0.0000 0.99×
map se-sim4-rye-150 74.667 0.0000 0.98×
map se-sim4-rye-200 81.374 0.0000 0.99×
map se-sim4-rye-300 88.059 0.0000 1.00×
map se-sim4-rye-500 92.832 0.0000 0.99×
map se-sim4-rye-1000 96.155 0.0000 0.99×
map se-sim4-rye-5000 98.793 0.0000 0.99×
map se-sim4-rye-10000 99.052 0.0000 0.98×
map se-sim4-chrY-50 34.340 0.0000 0.97×
map se-sim4-chrY-100 38.405 0.0000 0.96×
map se-sim4-chrY-150 40.733 0.0000 0.97×
map se-sim4-chrY-200 42.513 0.0000 1.02×
map se-sim4-chrY-300 45.014 0.0000 0.98×
map se-sim4-chrY-500 49.535 0.0000 0.97×
map se-sim4-chrY-1000 56.300 0.0000 0.97×
map se-sim4-chrY-5000 76.537 0.0000 0.97×
map se-sim4-chrY-10000 86.726 0.0000 0.99×
map se-sim6-blueflax-50 32.631 0.0000 1.07×
map se-sim6-blueflax-100 48.671 0.0000 1.05×
map se-sim6-blueflax-150 58.386 0.0000 1.02×
map se-sim6-blueflax-200 63.085 0.0000 1.01×
map se-sim6-blueflax-300 70.959 0.0000 1.00×
map se-sim6-blueflax-500 77.210 0.0000 1.00×
map se-sim6-blueflax-1000 85.662 0.0000 0.99×
map se-sim6-blueflax-5000 94.683 0.0000 1.00×
map se-sim6-blueflax-10000 96.238 0.0000 1.01×
map se-sim6-fruitfly-50 63.039 0.0000 0.91×
map se-sim6-fruitfly-100 80.016 0.0000 0.99×
map se-sim6-fruitfly-150 87.089 0.0000 0.99×
map se-sim6-fruitfly-200 88.970 0.0000 0.98×
map se-sim6-fruitfly-300 91.578 0.0000 1.01×
map se-sim6-fruitfly-500 93.104 0.0000 0.99×
map se-sim6-fruitfly-1000 95.330 0.0000 1.01×
map se-sim6-fruitfly-5000 98.833 0.0000 1.03×
map se-sim6-fruitfly-10000 99.234 0.0000 1.00×
map se-sim6-maize-50 23.817 0.0000 0.99×
map se-sim6-maize-100 39.301 0.0000 1.05×
map se-sim6-maize-150 49.943 0.0000 1.04×
map se-sim6-maize-200 56.146 0.0000 1.04×
map se-sim6-maize-300 66.574 0.0000 1.07×
map se-sim6-maize-500 75.730 0.0000 1.07×
map se-sim6-maize-1000 87.941 0.0000 1.05×
map se-sim6-maize-5000 98.445 0.0000 1.03×
map se-sim6-maize-10000 98.954 0.0000 1.06×
map se-sim6-CHM13-50 50.436 0.0000 1.01×
map se-sim6-CHM13-100 72.352 0.0000 0.93×
map se-sim6-CHM13-150 81.383 0.0000 1.04×
map se-sim6-CHM13-200 84.877 0.0000 0.93×
map se-sim6-CHM13-300 89.255 0.0000 1.02×
map se-sim6-CHM13-500 91.621 0.0000 0.98×
map se-sim6-CHM13-1000 93.580 0.0000 1.03×
map se-sim6-CHM13-5000 96.808 0.0000 1.00×
map se-sim6-CHM13-10000 97.610 0.0000 0.99×
map se-sim6-rye-50 20.049 0.0000 1.00×
map se-sim6-rye-100 35.002 0.0000 1.01×
map se-sim6-rye-150 45.551 0.0000 0.96×
map se-sim6-rye-200 52.049 0.0000 1.02×
map se-sim6-rye-300 62.926 0.0000 1.01×
map se-sim6-rye-500 72.674 0.0000 0.97×
map se-sim6-rye-1000 85.768 0.0000 1.01×
map se-sim6-rye-5000 97.758 0.0000 0.95×
map se-sim6-rye-10000 98.646 0.0000 0.92×
map se-sim6-chrY-50 23.076 0.0000 0.99×
map se-sim6-chrY-100 31.009 0.0000 1.00×
map se-sim6-chrY-150 35.004 0.0000 1.00×
map se-sim6-chrY-200 36.486 0.0000 0.99×
map se-sim6-chrY-300 38.877 0.0000 0.99×
map se-sim6-chrY-500 41.189 0.0000 0.99×
map se-sim6-chrY-1000 46.178 0.0000 0.99×
map se-sim6-chrY-5000 72.636 0.0000 1.00×
map se-sim6-chrY-10000 85.708 0.0000 1.00×

Average accuracy change: +0.000000
Average speedup: 0.999

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