Viewing: ext4-add-mballoc-stats-proc-file.patch

commit a6c75eaf11032f4a3d2b3ce2265a194ac6e4a7f0
Author:     Harshad Shirwadkar <harshadshirwadkar@gmail.com>
AuthorDate: Thu Apr 1 10:21:25 2021 -0700
ext4: add mballoc stats proc file

Add new stats for measuring the performance of mballoc. This patch is
forked from Artem Blagodarenko's work that can be found here:

https://github.com/lustre/lustre-release/blob/master/ldiskfs/kernel_patches/patches/rhel8/ext4-simple-blockalloc.patch

This patch reorganizes the stats by cr level. This is how the output
looks like:

    mballoc:
        reqs: 0
        success: 0
        groups_scanned: 0
        cr0_stats:
                hits: 0
                groups_considered: 0
                useless_loops: 0
                bad_suggestions: 0
        cr1_stats:
                hits: 0
                groups_considered: 0
                useless_loops: 0
                bad_suggestions: 0
        cr2_stats:
                hits: 0
                groups_considered: 0
                useless_loops: 0
        cr3_stats:
                hits: 0
                groups_considered: 0
                useless_loops: 0
        extents_scanned: 0
                goal_hits: 0
                2^n_hits: 0
                breaks: 0
                lost: 0
        buddies_generated: 0/40
        buddies_time_used: 0
        preallocated: 0
        discarded: 0

Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Reviewed-by: Ritesh Harjani <ritesh.list@gmail.com>
Link: https://lore.kernel.org/r/20210401172129.189766-4-harshadshirwadkar@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
Index: linux-stage/fs/ext4/ext4.h
===================================================================
--- linux-stage.orig/fs/ext4/ext4.h
+++ linux-stage/fs/ext4/ext4.h
@@ -1516,11 +1516,13 @@ struct ext4_sb_info {
 	atomic_t s_bal_success;	/* we found long enough chunks */
 	atomic_t s_bal_allocated;	/* in blocks */
 	atomic_t s_bal_ex_scanned;	/* total extents scanned */
+	atomic_t s_bal_groups_scanned;  /* number of groups scanned */
 	atomic_t s_bal_goals;	/* goal hits */
 	atomic_t s_bal_breaks;	/* too long searches */
 	atomic_t s_bal_2orders;	/* 2^order hits */
-	/* cX loop didn't find blocks */
-	atomic64_t s_bal_cX_failed[4];
+	atomic64_t s_bal_cX_groups_considered[4];
+	atomic64_t s_bal_cX_hits[4];
+	atomic64_t s_bal_cX_failed[4];          /* cX loop didn't find blocks */
 	atomic64_t s_bal_cX_skipped[3];
 	atomic_t s_mb_buddies_generated;	/* number of buddies generated */
 	atomic64_t s_mb_generation_time;
@@ -2702,6 +2704,7 @@ extern const struct file_operations ext4
 extern int ext4_mb_seq_last_start_seq_show(struct seq_file *m, void *v);
 extern long ext4_mb_stats;
 extern long ext4_mb_max_to_scan;
+extern int ext4_seq_mb_stats_show(struct seq_file *seq, void *offset);
 extern int ext4_mb_init(struct super_block *);
 extern int ext4_mb_release(struct super_block *);
 extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
Index: linux-stage/fs/ext4/mballoc.c
===================================================================
--- linux-stage.orig/fs/ext4/mballoc.c
+++ linux-stage/fs/ext4/mballoc.c
@@ -2191,10 +2191,13 @@ static int ext4_mb_good_group_nolock(str
 {
 	struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group);
 	struct super_block *sb = ac->ac_sb;
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	bool should_lock = ac->ac_flags & EXT4_MB_STRICT_CHECK;
 	ext4_grpblk_t free;
 	int ret = 0;
 
+	if (sbi->s_mb_stats)
+		atomic64_inc(&sbi->s_bal_cX_groups_considered[ac->ac_criteria]);
 	if (should_lock)
 		ext4_lock_group(sb, group);
 	free = grp->bb_free;
@@ -2488,7 +2491,7 @@ repeat:
 				break;
 		}
 		/* Processed all groups and haven't found blocks */
-		if (i == ngroups)
+		if (sbi->s_mb_stats && i == ngroups)
 			atomic64_inc(&sbi->s_bal_cX_failed[cr]);
 	}
 
@@ -2517,6 +2520,9 @@ repeat:
 			goto repeat;
 		}
 	}
+
+	if (sbi->s_mb_stats && ac->ac_status == AC_STATUS_FOUND)
+		atomic64_inc(&sbi->s_bal_cX_hits[ac->ac_criteria]);
 out:
 	if (!err && ac->ac_status != AC_STATUS_FOUND && first_err)
 		err = first_err;
@@ -2623,6 +2629,67 @@ const struct seq_operations ext4_mb_seq_
 	.show   = ext4_mb_seq_groups_show,
 };
 
+int ext4_seq_mb_stats_show(struct seq_file *seq, void *offset)
+{
+	struct super_block *sb = (struct super_block *)seq->private;
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+	seq_puts(seq, "mballoc:\n");
+	if (!sbi->s_mb_stats) {
+		seq_puts(seq, "\tmb stats collection turned off.\n");
+		seq_puts(seq, "\tTo enable, please write \"1\" to sysfs file mb_stats.\n");
+		return 0;
+	}
+	seq_printf(seq, "\treqs: %u\n", atomic_read(&sbi->s_bal_reqs));
+	seq_printf(seq, "\tsuccess: %u\n", atomic_read(&sbi->s_bal_success));
+
+	seq_printf(seq, "\tgroups_scanned: %u\n",  atomic_read(&sbi->s_bal_groups_scanned));
+
+	seq_puts(seq, "\tcr0_stats:\n");
+	seq_printf(seq, "\t\thits: %llu\n", (unsigned long long)atomic64_read(&sbi->s_bal_cX_hits[0]));
+	seq_printf(seq, "\t\tgroups_considered: %llu\n",
+		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_groups_considered[0]));
+	seq_printf(seq, "\t\tuseless_loops: %llu\n",
+		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_failed[0]));
+
+	seq_puts(seq, "\tcr1_stats:\n");
+	seq_printf(seq, "\t\thits: %llu\n", (unsigned long long)atomic64_read(&sbi->s_bal_cX_hits[1]));
+	seq_printf(seq, "\t\tgroups_considered: %llu\n",
+		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_groups_considered[1]));
+	seq_printf(seq, "\t\tuseless_loops: %llu\n",
+		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_failed[1]));
+
+	seq_puts(seq, "\tcr2_stats:\n");
+	seq_printf(seq, "\t\thits: %llu\n", (unsigned long long)atomic64_read(&sbi->s_bal_cX_hits[2]));
+	seq_printf(seq, "\t\tgroups_considered: %llu\n",
+		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_groups_considered[2]));
+	seq_printf(seq, "\t\tuseless_loops: %llu\n",
+		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_failed[2]));
+
+	seq_puts(seq, "\tcr3_stats:\n");
+	seq_printf(seq, "\t\thits: %llu\n", (unsigned long long)atomic64_read(&sbi->s_bal_cX_hits[3]));
+	seq_printf(seq, "\t\tgroups_considered: %llu\n",
+		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_groups_considered[3]));
+	seq_printf(seq, "\t\tuseless_loops: %llu\n",
+		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_failed[3]));
+	seq_printf(seq, "\textents_scanned: %u\n", atomic_read(&sbi->s_bal_ex_scanned));
+	seq_printf(seq, "\t\tgoal_hits: %u\n", atomic_read(&sbi->s_bal_goals));
+	seq_printf(seq, "\t\t2^n_hits: %u\n", atomic_read(&sbi->s_bal_2orders));
+	seq_printf(seq, "\t\tbreaks: %u\n", atomic_read(&sbi->s_bal_breaks));
+	seq_printf(seq, "\t\tlost: %u\n", atomic_read(&sbi->s_mb_lost_chunks));
+
+	seq_printf(seq, "\tbuddies_generated: %u/%u\n",
+		   atomic_read(&sbi->s_mb_buddies_generated),
+		   ext4_get_groups_count(sb));
+	seq_printf(seq, "\tbuddies_time_used: %llu\n",
+		   (unsigned long long)atomic64_read(&sbi->s_mb_generation_time));
+	seq_printf(seq, "\tpreallocated: %u\n",
+		   atomic_read(&sbi->s_mb_preallocated));
+	seq_printf(seq, "\tdiscarded: %u\n",
+		   atomic_read(&sbi->s_mb_discarded));
+	return 0;
+}
+
 static int ext4_mb_check_and_update_prealloc(struct ext4_sb_info *sbi,
 						 char *str, size_t cnt,
 						 int update)
@@ -2777,97 +2844,6 @@ const struct file_operations ext4_seq_mb
 	.write         = ext4_mb_last_group_write,
 };
 
-static int mb_seq_alloc_show(struct seq_file *seq, void *v)
-{
-	struct super_block *sb = seq->private;
-	struct ext4_sb_info *sbi = EXT4_SB(sb);
-
-	seq_printf(seq, "mballoc:\n");
-	seq_printf(seq, "\tblocks: %u\n", atomic_read(&sbi->s_bal_allocated));
-	seq_printf(seq, "\treqs: %u\n", atomic_read(&sbi->s_bal_reqs));
-	seq_printf(seq, "\tsuccess: %u\n", atomic_read(&sbi->s_bal_success));
-
-	seq_printf(seq, "\textents_scanned: %u\n",
-		   atomic_read(&sbi->s_bal_ex_scanned));
-	seq_printf(seq, "\t\tgoal_hits: %u\n", atomic_read(&sbi->s_bal_goals));
-	seq_printf(seq, "\t\t2^n_hits: %u\n", atomic_read(&sbi->s_bal_2orders));
-	seq_printf(seq, "\t\tbreaks: %u\n", atomic_read(&sbi->s_bal_breaks));
-	seq_printf(seq, "\t\tlost: %u\n", atomic_read(&sbi->s_mb_lost_chunks));
-
-	seq_printf(seq, "\tuseless_c0_loops: %llu\n",
-		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_failed[0]));
-	seq_printf(seq, "\tuseless_c1_loops: %llu\n",
-		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_failed[1]));
-	seq_printf(seq, "\tuseless_c2_loops: %llu\n",
-		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_failed[2]));
-	seq_printf(seq, "\tuseless_c3_loops: %llu\n",
-		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_failed[3]));
-	seq_printf(seq, "\tskipped_c0_loops: %llu\n",
-		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_skipped[0]));
-	seq_printf(seq, "\tskipped_c1_loops: %llu\n",
-		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_skipped[1]));
-	seq_printf(seq, "\tskipped_c2_loops: %llu\n",
-		   (unsigned long long)atomic64_read(&sbi->s_bal_cX_skipped[2]));
-	seq_printf(seq, "\tbuddies_generated: %u\n",
-		   atomic_read(&sbi->s_mb_buddies_generated));
-	seq_printf(seq, "\tbuddies_time_used: %llu\n",
-		   (unsigned long long)atomic64_read(&sbi->s_mb_generation_time));
-	seq_printf(seq, "\tpreallocated: %u\n",
-		   atomic_read(&sbi->s_mb_preallocated));
-	seq_printf(seq, "\tdiscarded: %u\n",
-		   atomic_read(&sbi->s_mb_discarded));
-	return 0;
-}
-
-static ssize_t mb_seq_alloc_write(struct file *file,
-			      const char __user *buf,
-			      size_t cnt, loff_t *pos)
-{
-	struct ext4_sb_info *sbi = EXT4_SB(PDE_DATA(file_inode(file)));
-
-	atomic_set(&sbi->s_bal_allocated, 0),
-	atomic_set(&sbi->s_bal_reqs, 0),
-	atomic_set(&sbi->s_bal_success, 0);
-
-	atomic_set(&sbi->s_bal_ex_scanned, 0),
-	atomic_set(&sbi->s_bal_goals, 0),
-	atomic_set(&sbi->s_bal_2orders, 0),
-	atomic_set(&sbi->s_bal_breaks, 0),
-	atomic_set(&sbi->s_mb_lost_chunks, 0);
-
-	atomic64_set(&sbi->s_bal_cX_failed[0], 0),
-	atomic64_set(&sbi->s_bal_cX_failed[1], 0),
-	atomic64_set(&sbi->s_bal_cX_failed[2], 0);
-	atomic64_set(&sbi->s_bal_cX_failed[3], 0);
-
-	atomic64_set(&sbi->s_bal_cX_skipped[0], 0),
-	atomic64_set(&sbi->s_bal_cX_skipped[1], 0),
-	atomic64_set(&sbi->s_bal_cX_skipped[2], 0);
-
-
-	atomic_set(&sbi->s_mb_buddies_generated, 0);
-	atomic64_set(&sbi->s_mb_generation_time, 0);
-
-	atomic_set(&sbi->s_mb_preallocated, 0),
-	atomic_set(&sbi->s_mb_discarded, 0);
-
-	return cnt;
-}
-
-static int mb_seq_alloc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, mb_seq_alloc_show, PDE_DATA(inode));
-}
-
-const struct file_operations ext4_mb_seq_alloc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= mb_seq_alloc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= mb_seq_alloc_write,
-};
-
 int ext4_mb_seq_last_start_seq_show(struct seq_file *m, void *v)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(m->private);
@@ -3350,9 +3326,10 @@ int ext4_mb_release(struct super_block *
 				(unsigned long long)atomic64_read(&sbi->s_bal_cX_skipped[1]),
 				(unsigned long long)atomic64_read(&sbi->s_bal_cX_skipped[2]));
 		ext4_msg(sb, KERN_INFO,
-		      "mballoc: %u extents scanned, %u goal hits, "
+		      "mballoc: %u extents scanned, %u groups scanned, %u goal hits, "
 				"%u 2^N hits, %u breaks, %u lost",
 				atomic_read(&sbi->s_bal_ex_scanned),
+				atomic_read(&sbi->s_bal_groups_scanned),
 				atomic_read(&sbi->s_bal_goals),
 				atomic_read(&sbi->s_bal_2orders),
 				atomic_read(&sbi->s_bal_breaks),
@@ -3871,12 +3848,13 @@ static void ext4_mb_collect_stats(struct
 {
 	struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
 
-	if (sbi->s_mb_stats && ac->ac_g_ex.fe_len > 1) {
+	if (sbi->s_mb_stats && ac->ac_g_ex.fe_len >= 1) {
 		atomic_inc(&sbi->s_bal_reqs);
 		atomic_add(ac->ac_b_ex.fe_len, &sbi->s_bal_allocated);
 		if (ac->ac_b_ex.fe_len >= ac->ac_o_ex.fe_len)
 			atomic_inc(&sbi->s_bal_success);
 		atomic_add(ac->ac_found, &sbi->s_bal_ex_scanned);
+		atomic_add(ac->ac_groups_scanned, &sbi->s_bal_groups_scanned);
 		if (ac->ac_g_ex.fe_start == ac->ac_b_ex.fe_start &&
 				ac->ac_g_ex.fe_group == ac->ac_b_ex.fe_group)
 			atomic_inc(&sbi->s_bal_goals);
Index: linux-stage/fs/ext4/sysfs.c
===================================================================
--- linux-stage.orig/fs/ext4/sysfs.c
+++ linux-stage/fs/ext4/sysfs.c
@@ -477,14 +477,14 @@ int ext4_register_sysfs(struct super_blo
 				sb);
 		proc_create_seq_data("mb_groups", S_IRUGO, sbi->s_proc,
 				&ext4_mb_seq_groups_ops, sb);
+		proc_create_single_data("mb_stats", 0444, sbi->s_proc,
+				ext4_seq_mb_stats_show, sb);
 		proc_create_data("prealloc_table", S_IRUGO, sbi->s_proc,
 				&ext4_seq_prealloc_table_fops, sb);
 		proc_create_data("mb_last_group", S_IRUGO, sbi->s_proc,
 				&ext4_seq_mb_last_group_fops, sb);
 		proc_create_single_data("mb_last_start", S_IRUGO, sbi->s_proc,
 				ext4_mb_seq_last_start_seq_show, sb);
-		proc_create_data("mb_alloc_stats", S_IFREG | S_IRUGO | S_IWUSR,
-				 sbi->s_proc, &ext4_mb_seq_alloc_fops, sb);
 	}
 	return 0;
 }