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-07-10 01:41:01 -0400
commitf0d0e6ebc6f5ebc935e3879e1bbe2e827118f5ec (patch)
tree43fe782c221a9baae6ee84c1d214d10ad26a3e96
parent7c783ffcc5ab309d90025093e50a241537139dfd (diff)
downloadhaskell-f0d0e6ebc6f5ebc935e3879e1bbe2e827118f5ec.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 58860a5712..d1624a494d 100644
--- a/rts/sm/NonMoving.h
+++ b/rts/sm/NonMoving.h
@@ -160,13 +160,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