summaryrefslogtreecommitdiffstats
path: root/include/linux/sbitmap.h
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2018-11-30 15:18:06 -0500
committerJens Axboe <axboe@kernel.dk>2018-11-30 16:47:45 -0500
commitea86ea2cdced20057da4d2c32965c1219c238197 (patch)
tree08926009b00df1229668f131d41d2b467a78cc87 /include/linux/sbitmap.h
parent531724abc3bfb556c1dd68086cf9cb51f76464e3 (diff)
sbitmap: ammortize cost of clearing bits
sbitmap maintains a set of words that we use to set and clear bits, with each bit representing a tag for blk-mq. Even though we spread the bits out and maintain a hint cache, one particular bit allocated will end up being cleared in the exact same spot. This introduces batched clearing of bits. Instead of clearing a given bit, the same bit is set in a cleared/free mask instead. If we fail allocating a bit from a given word, then we check the free mask, and batch move those cleared bits at that time. This trades 64 atomic bitops for 2 cmpxchg(). In a threaded poll test case, half the overhead of getting and clearing tags is removed with this change. On another poll test case with a single thread, performance is unchanged. Reviewed-by: Omar Sandoval <osandov@fb.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'include/linux/sbitmap.h')
-rw-r--r--include/linux/sbitmap.h33
1 files changed, 27 insertions, 6 deletions
diff --git a/include/linux/sbitmap.h b/include/linux/sbitmap.h
index 804a50983ec5..81359d45751e 100644
--- a/include/linux/sbitmap.h
+++ b/include/linux/sbitmap.h
@@ -30,14 +30,24 @@ struct seq_file;
30 */ 30 */
31struct sbitmap_word { 31struct sbitmap_word {
32 /** 32 /**
33 * @word: The bitmap word itself. 33 * @depth: Number of bits being used in @word/@cleared
34 */ 34 */
35 unsigned long word; 35 unsigned long depth;
36 36
37 /** 37 /**
38 * @depth: Number of bits being used in @word. 38 * @word: word holding free bits
39 */ 39 */
40 unsigned long depth; 40 unsigned long word ____cacheline_aligned_in_smp;
41
42 /**
43 * @cleared: word holding cleared bits
44 */
45 unsigned long cleared ____cacheline_aligned_in_smp;
46
47 /**
48 * @swap_lock: Held while swapping word <-> cleared
49 */
50 spinlock_t swap_lock;
41} ____cacheline_aligned_in_smp; 51} ____cacheline_aligned_in_smp;
42 52
43/** 53/**
@@ -310,6 +320,19 @@ static inline void sbitmap_clear_bit(struct sbitmap *sb, unsigned int bitnr)
310 clear_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr)); 320 clear_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr));
311} 321}
312 322
323/*
324 * This one is special, since it doesn't actually clear the bit, rather it
325 * sets the corresponding bit in the ->cleared mask instead. Paired with
326 * the caller doing sbitmap_batch_clear() if a given index is full, which
327 * will clear the previously freed entries in the corresponding ->word.
328 */
329static inline void sbitmap_deferred_clear_bit(struct sbitmap *sb, unsigned int bitnr)
330{
331 unsigned long *addr = &sb->map[SB_NR_TO_INDEX(sb, bitnr)].cleared;
332
333 set_bit(SB_NR_TO_BIT(sb, bitnr), addr);
334}
335
313static inline void sbitmap_clear_bit_unlock(struct sbitmap *sb, 336static inline void sbitmap_clear_bit_unlock(struct sbitmap *sb,
314 unsigned int bitnr) 337 unsigned int bitnr)
315{ 338{
@@ -321,8 +344,6 @@ static inline int sbitmap_test_bit(struct sbitmap *sb, unsigned int bitnr)
321 return test_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr)); 344 return test_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr));
322} 345}
323 346
324unsigned int sbitmap_weight(const struct sbitmap *sb);
325
326/** 347/**
327 * sbitmap_show() - Dump &struct sbitmap information to a &struct seq_file. 348 * sbitmap_show() - Dump &struct sbitmap information to a &struct seq_file.
328 * @sb: Bitmap to show. 349 * @sb: Bitmap to show.