summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2019-04-16 14:32:40 -0400
committerBen Gamari <ben@smart-cactus.org>2019-10-22 12:18:39 -0400
commit039d29068f0c0ae6ab133f5dac61948584335677 (patch)
tree189c14478df76ebcc27b3cc8438cfde6a97550b3
parent8fffe12bf61347aa9e7fc52d172c989d8d4ca31f (diff)
downloadhaskell-039d29068f0c0ae6ab133f5dac61948584335677.tar.gz
NonMoving: Eliminate integer division in nonmovingBlockCount
Perf showed that the this single div was capturing up to 10% of samples in nonmovingMark. However, the overwhelming majority of cases is looking at small block sizes. These cases we can easily compute explicitly, allowing the compiler to turn the division into a significantly more efficient division-by-constant. While the increase in source code looks scary, this all optimises down to very nice looking assembler. At this point the only remaining hotspots in nonmovingBlockCount are due to memory access.
-rw-r--r--rts/sm/NonMoving.h24
1 files changed, 20 insertions, 4 deletions
diff --git a/rts/sm/NonMoving.h b/rts/sm/NonMoving.h
index 0f9cfa0e48..fdeee19d96 100644
--- a/rts/sm/NonMoving.h
+++ b/rts/sm/NonMoving.h
@@ -161,13 +161,29 @@ INLINE_HEADER unsigned int nonmovingSegmentBlockSize(struct NonmovingSegment *se
return 1 << seg->block_size;
}
-// How many blocks does the given segment contain? Also the size of the bitmap.
-INLINE_HEADER unsigned int nonmovingSegmentBlockCount(struct NonmovingSegment *seg)
+// How many blocks does a segment with the given block size have?
+INLINE_HEADER unsigned int nonmovingBlockCount(uint8_t log_block_size)
{
- unsigned int sz = nonmovingSegmentBlockSize(seg);
unsigned int segment_data_size = NONMOVING_SEGMENT_SIZE - sizeof(struct NonmovingSegment);
segment_data_size -= segment_data_size % SIZEOF_VOID_P;
- return segment_data_size / (sz + 1);
+ unsigned int blk_size = 1 << log_block_size;
+ // N.B. +1 accounts for the byte in the mark bitmap.
+ return segment_data_size / (blk_size + 1);
+}
+
+// How many blocks does the given segment contain? Also the size of the bitmap.
+INLINE_HEADER unsigned int nonmovingSegmentBlockCount(struct NonmovingSegment *seg)
+{
+ // We compute the overwhelmingly common size cases directly to avoid a very
+ // expensive integer division.
+ switch (seg->block_size) {
+ case 3: return nonmovingBlockCount(3);
+ case 4: return nonmovingBlockCount(4);
+ case 5: return nonmovingBlockCount(5);
+ case 6: return nonmovingBlockCount(6);
+ case 7: return nonmovingBlockCount(7);
+ default: return nonmovingBlockCount(seg->block_size);
+ }
}
// Get a pointer to the given block index