sbitmap: add helpers for dumping to a seq_file
authorOmar Sandoval <osandov@fb.com>
Wed, 25 Jan 2017 22:32:13 +0000 (14:32 -0800)
committerJens Axboe <axboe@fb.com>
Fri, 27 Jan 2017 15:17:44 +0000 (08:17 -0700)
This is useful debugging information that will be used in the blk-mq
debugfs directory.

Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Changed 'weight' to 'busy'.

Signed-off-by: Jens Axboe <axboe@fb.com>
include/linux/sbitmap.h
lib/sbitmap.c

index f017fd6e69c4f64cdd3612fee5329a40fa82e75f..d4e0a204c118c7244e7e5d167cc3d0429832de01 100644 (file)
@@ -258,6 +258,26 @@ static inline int sbitmap_test_bit(struct sbitmap *sb, unsigned int bitnr)
 
 unsigned int sbitmap_weight(const struct sbitmap *sb);
 
+/**
+ * sbitmap_show() - Dump &struct sbitmap information to a &struct seq_file.
+ * @sb: Bitmap to show.
+ * @m: struct seq_file to write to.
+ *
+ * This is intended for debugging. The format may change at any time.
+ */
+void sbitmap_show(struct sbitmap *sb, struct seq_file *m);
+
+/**
+ * sbitmap_bitmap_show() - Write a hex dump of a &struct sbitmap to a &struct
+ * seq_file.
+ * @sb: Bitmap to show.
+ * @m: struct seq_file to write to.
+ *
+ * This is intended for debugging. The output isn't guaranteed to be internally
+ * consistent.
+ */
+void sbitmap_bitmap_show(struct sbitmap *sb, struct seq_file *m);
+
 /**
  * sbitmap_queue_init_node() - Initialize a &struct sbitmap_queue on a specific
  * memory node.
@@ -370,4 +390,14 @@ static inline struct sbq_wait_state *sbq_wait_ptr(struct sbitmap_queue *sbq,
  */
 void sbitmap_queue_wake_all(struct sbitmap_queue *sbq);
 
+/**
+ * sbitmap_queue_show() - Dump &struct sbitmap_queue information to a &struct
+ * seq_file.
+ * @sbq: Bitmap queue to show.
+ * @m: struct seq_file to write to.
+ *
+ * This is intended for debugging. The format may change at any time.
+ */
+void sbitmap_queue_show(struct sbitmap_queue *sbq, struct seq_file *m);
+
 #endif /* __LINUX_SCALE_BITMAP_H */
index 8f5c3b268c773559ca85f26e30aa8150a4c5d2fe..55e11c4b2f3b8e65ca118fe107ae931b877f187f 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/random.h>
 #include <linux/sbitmap.h>
+#include <linux/seq_file.h>
 
 int sbitmap_init_node(struct sbitmap *sb, unsigned int depth, int shift,
                      gfp_t flags, int node)
@@ -180,6 +181,62 @@ unsigned int sbitmap_weight(const struct sbitmap *sb)
 }
 EXPORT_SYMBOL_GPL(sbitmap_weight);
 
+void sbitmap_show(struct sbitmap *sb, struct seq_file *m)
+{
+       seq_printf(m, "depth=%u\n", sb->depth);
+       seq_printf(m, "busy=%u\n", sbitmap_weight(sb));
+       seq_printf(m, "bits_per_word=%u\n", 1U << sb->shift);
+       seq_printf(m, "map_nr=%u\n", sb->map_nr);
+}
+EXPORT_SYMBOL_GPL(sbitmap_show);
+
+static inline void emit_byte(struct seq_file *m, unsigned int offset, u8 byte)
+{
+       if ((offset & 0xf) == 0) {
+               if (offset != 0)
+                       seq_putc(m, '\n');
+               seq_printf(m, "%08x:", offset);
+       }
+       if ((offset & 0x1) == 0)
+               seq_putc(m, ' ');
+       seq_printf(m, "%02x", byte);
+}
+
+void sbitmap_bitmap_show(struct sbitmap *sb, struct seq_file *m)
+{
+       u8 byte = 0;
+       unsigned int byte_bits = 0;
+       unsigned int offset = 0;
+       int i;
+
+       for (i = 0; i < sb->map_nr; i++) {
+               unsigned long word = READ_ONCE(sb->map[i].word);
+               unsigned int word_bits = READ_ONCE(sb->map[i].depth);
+
+               while (word_bits > 0) {
+                       unsigned int bits = min(8 - byte_bits, word_bits);
+
+                       byte |= (word & (BIT(bits) - 1)) << byte_bits;
+                       byte_bits += bits;
+                       if (byte_bits == 8) {
+                               emit_byte(m, offset, byte);
+                               byte = 0;
+                               byte_bits = 0;
+                               offset++;
+                       }
+                       word >>= bits;
+                       word_bits -= bits;
+               }
+       }
+       if (byte_bits) {
+               emit_byte(m, offset, byte);
+               offset++;
+       }
+       if (offset)
+               seq_putc(m, '\n');
+}
+EXPORT_SYMBOL_GPL(sbitmap_bitmap_show);
+
 static unsigned int sbq_calc_wake_batch(unsigned int depth)
 {
        unsigned int wake_batch;
@@ -377,3 +434,37 @@ void sbitmap_queue_wake_all(struct sbitmap_queue *sbq)
        }
 }
 EXPORT_SYMBOL_GPL(sbitmap_queue_wake_all);
+
+void sbitmap_queue_show(struct sbitmap_queue *sbq, struct seq_file *m)
+{
+       bool first;
+       int i;
+
+       sbitmap_show(&sbq->sb, m);
+
+       seq_puts(m, "alloc_hint={");
+       first = true;
+       for_each_possible_cpu(i) {
+               if (!first)
+                       seq_puts(m, ", ");
+               first = false;
+               seq_printf(m, "%u", *per_cpu_ptr(sbq->alloc_hint, i));
+       }
+       seq_puts(m, "}\n");
+
+       seq_printf(m, "wake_batch=%u\n", sbq->wake_batch);
+       seq_printf(m, "wake_index=%d\n", atomic_read(&sbq->wake_index));
+
+       seq_puts(m, "ws={\n");
+       for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
+               struct sbq_wait_state *ws = &sbq->ws[i];
+
+               seq_printf(m, "\t{.wait_cnt=%d, .wait=%s},\n",
+                          atomic_read(&ws->wait_cnt),
+                          waitqueue_active(&ws->wait) ? "active" : "inactive");
+       }
+       seq_puts(m, "}\n");
+
+       seq_printf(m, "round_robin=%d\n", sbq->round_robin);
+}
+EXPORT_SYMBOL_GPL(sbitmap_queue_show);