Going to be adding more things to this in the next patch.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
 #undef BCH_DEBUG_PARAM
 #endif
 
-#define BCH_LOCK_TIME_NR 128
-
 #define BCH_TIME_STATS()                       \
        x(btree_node_mem_alloc)                 \
        x(btree_node_split)                     \
        unsigned                id;
 };
 
-struct lock_held_stats {
-       struct bch2_time_stats  times[BCH_LOCK_TIME_NR];
-       const char              *names[BCH_LOCK_TIME_NR];
+#define BCH_TRANSACTIONS_NR 128
+
+struct btree_transaction_stats {
+       struct bch2_time_stats  lock_hold_times;
 };
 
 struct bch_fs_pcpu {
 
        struct bch2_time_stats  times[BCH_TIME_STAT_NR];
 
-       struct lock_held_stats  lock_held_stats;
+       const char              *btree_transaction_fns[BCH_TRANSACTIONS_NR];
+       struct btree_transaction_stats btree_transaction_stats[BCH_TRANSACTIONS_NR];
 };
 
 static inline void bch2_set_ra_pages(struct bch_fs *c, unsigned ra_pages)
 
        trans->updates          = p; p += updates_bytes;
 }
 
+static inline unsigned bch2_trans_get_fn_idx(struct btree_trans *trans, struct bch_fs *c,
+                                       const char *fn)
+{
+       unsigned i;
+
+       for (i = 0; i < ARRAY_SIZE(c->btree_transaction_fns); i++)
+               if (!c->btree_transaction_fns[i] ||
+                   c->btree_transaction_fns[i] == fn) {
+                       c->btree_transaction_fns[i] = fn;
+                       return i;
+               }
+
+       pr_warn_once("BCH_TRANSACTIONS_NR not big enough!");
+       return i;
+}
+
 void __bch2_trans_init(struct btree_trans *trans, struct bch_fs *c,
                       unsigned expected_nr_iters,
                       size_t expected_mem_bytes,
        trans->c                = c;
        trans->fn               = fn;
        trans->last_begin_time  = ktime_get_ns();
+       trans->fn_idx           = bch2_trans_get_fn_idx(trans, c, fn);
        trans->task             = current;
        trans->journal_replay_not_finished =
                !test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags);
 
-       while (c->lock_held_stats.names[trans->lock_name_idx] != fn
-              && c->lock_held_stats.names[trans->lock_name_idx] != 0)
-               trans->lock_name_idx++;
-
-       if (trans->lock_name_idx >= BCH_LOCK_TIME_NR)
-               pr_warn_once("lock_times array not big enough!");
-       else
-               c->lock_held_stats.names[trans->lock_name_idx] = fn;
-
        bch2_trans_alloc_paths(trans, c);
 
        if (expected_mem_bytes) {
 
 void bch2_fs_btree_iter_exit(struct bch_fs *c)
 {
+       struct btree_transaction_stats *s;
+
+       for (s = c->btree_transaction_stats;
+            s < c->btree_transaction_stats + ARRAY_SIZE(c->btree_transaction_stats);
+            s++)
+               bch2_time_stats_exit(&s->lock_hold_times);
+
        if (c->btree_trans_barrier_initialized)
                cleanup_srcu_struct(&c->btree_trans_barrier);
        mempool_exit(&c->btree_trans_mem_pool);
 
 int bch2_fs_btree_iter_init(struct bch_fs *c)
 {
+       struct btree_transaction_stats *s;
        unsigned nr = BTREE_ITER_MAX;
        int ret;
 
+       for (s = c->btree_transaction_stats;
+            s < c->btree_transaction_stats + ARRAY_SIZE(c->btree_transaction_stats);
+            s++)
+               bch2_time_stats_init(&s->lock_hold_times);
+
        INIT_LIST_HEAD(&c->btree_trans_list);
        mutex_init(&c->btree_trans_lock);
 
 
        return BTREE_NODE_UNLOCKED;
 }
 
+static inline struct btree_transaction_stats *btree_trans_stats(struct btree_trans *trans)
+{
+       return trans->fn_idx < ARRAY_SIZE(trans->c->btree_transaction_stats)
+               ? &trans->c->btree_transaction_stats[trans->fn_idx]
+               : NULL;
+}
+
+static void btree_trans_lock_hold_time_update(struct btree_trans *trans,
+                                             struct btree_path *path, unsigned level)
+{
+#ifdef CONFIG_BCACHEFS_LOCK_TIME_STATS
+       struct btree_transaction_stats *s = btree_trans_stats(trans);
+
+       if (s)
+               __bch2_time_stats_update(&s->lock_hold_times,
+                                        path->l[level].lock_taken_time,
+                                        ktime_get_ns());
+#endif
+}
+
 static inline void btree_node_unlock(struct btree_trans *trans,
                                     struct btree_path *path, unsigned level)
 {
 
        if (lock_type != BTREE_NODE_UNLOCKED) {
                six_unlock_type(&path->l[level].b->c.lock, lock_type);
-#ifdef CONFIG_BCACHEFS_LOCK_TIME_STATS
-               if (trans->lock_name_idx < BCH_LOCK_TIME_NR) {
-                       struct bch_fs *c = trans->c;
-
-                       __bch2_time_stats_update(&c->lock_held_stats.times[trans->lock_name_idx],
-                                              path->l[level].lock_taken_time,
-                                                ktime_get_ns());
-               }
-#endif
+               btree_trans_lock_hold_time_update(trans, path, level);
        }
        mark_btree_node_unlocked(path, level);
 }
 
        struct task_struct      *task;
        int                     srcu_idx;
 
+       u8                      fn_idx;
        u8                      nr_sorted;
        u8                      nr_updates;
        bool                    used_mempool:1;
        unsigned                journal_u64s;
        unsigned                journal_preres_u64s;
        struct replicas_delta_list *fs_usage_deltas;
-       int                      lock_name_idx;
 };
 
 #define BTREE_FLAGS()                                                  \
 
                                      size_t size, loff_t *ppos)
 {
        struct dump_iter        *i = file->private_data;
-       struct lock_held_stats *lhs = &i->c->lock_held_stats;
+       struct bch_fs *c = i->c;
        int err;
 
        i->ubuf = buf;
        i->size = size;
        i->ret  = 0;
 
-       while (lhs->names[i->iter] != 0 && i->iter < BCH_LOCK_TIME_NR) {
+       while (i->iter < ARRAY_SIZE(c->btree_transaction_fns) &&
+              c->btree_transaction_fns[i->iter]) {
+               struct btree_transaction_stats *s = &c->btree_transaction_stats[i->iter];
+
                err = flush_buf(i);
                if (err)
                        return err;
                if (!i->size)
                        break;
 
-               prt_printf(&i->buf, "%s:", lhs->names[i->iter]);
+               prt_printf(&i->buf, "%s: ", c->btree_transaction_fns[i->iter]);
                prt_newline(&i->buf);
-               printbuf_indent_add(&i->buf, 8);
-               bch2_time_stats_to_text(&i->buf, &lhs->times[i->iter]);
-               printbuf_indent_sub(&i->buf, 8);
+               printbuf_indent_add(&i->buf, 2);
+               bch2_time_stats_to_text(&i->buf, &s->lock_hold_times);
+               printbuf_indent_sub(&i->buf, 2);
                prt_newline(&i->buf);
                i->iter++;
        }
                            c->btree_debug, &journal_pins_ops);
 
        if (IS_ENABLED(CONFIG_BCACHEFS_LOCK_TIME_STATS)) {
-               debugfs_create_file("lock_held_stats", 0400, c->fs_debug_dir,
+               debugfs_create_file("btree_transaction_stats", 0400, c->fs_debug_dir,
                                c, &lock_held_stats_op);
        }