diff mbox series

[v2,5/5] ext4: add proc files to monitor new structures

Message ID 20210209202857.4185846-6-harshadshirwadkar@gmail.com
State New
Headers show
Series [v2,1/5] ext4: drop s_mb_bal_lock and convert protected fields to atomic | expand

Commit Message

harshad shirwadkar Feb. 9, 2021, 8:28 p.m. UTC
This patch adds a new file "mb_structs_summary" which allows us to see the
summary of the new allocator structures added in this series.

Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
---
 fs/ext4/ext4.h    |  1 +
 fs/ext4/mballoc.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/ext4/sysfs.c   |  2 ++
 3 files changed, 87 insertions(+)

Comments

Andreas Dilger Feb. 12, 2021, 10:36 p.m. UTC | #1
On Feb 9, 2021, at 1:28 PM, Harshad Shirwadkar <harshadshirwadkar@gmail.com> wrote:
> 
> This patch adds a new file "mb_structs_summary" which allows us to see the
> summary of the new allocator structures added in this series.

Hmm, it is hard to visualize what these files will look like, could you
please include an example output in the commit message?  It looks like
they will no longer have one line per group, which is good, but maybe
one line per order?

If at all possible, it makes sense to have well-formatted output that
follows YAML formatting (https://yaml-online-parser.appspot.com/ can
verify this) so that it can be easily parsed (both as YAML and via
awk or other text processing tools).  That doesn't mean you need to
embed a YAML parser, just a few well-placed ':' and spaces...

Unfortunately, files like "mb_groups" were created before that wisdom
was learned, and are a bit of a nightmare to parse today.

A few comments inline...

> Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
> 
> +static int ext4_mb_seq_structs_summary_show(struct seq_file *seq, void *v)
> +{
> +

Extra blank line here can be removed

> +	if (position >= MB_NUM_ORDERS(sb)) {
> +		seq_puts(seq, "Tree\n");

Prefer not to use capitalized words.

This should have a ':' like "tree:", but this still leaves the question
"what is the tree for?" so using "fragment_size_tree:" or similar would
be better.

> +		n = rb_first(&sbi->s_mb_avg_fragment_size_root);
> +		if (!n) {
> +			seq_puts(seq, "<Empty>\n");

I'm guessing this won't happen very often, but it might be easier if it
kept the same output format, so "min: 0, max: 0, num_nodes: 0", or just
initialize those values and then skip the intermediate processing below
before printing out the summary line (better because there is only one
place that is formatting the output, so it will be consistent)?

> +			return 0;
> +		}
> +		grp = rb_entry(n, struct ext4_group_info, bb_avg_fragment_size_rb);
> +		min = grp->bb_fragments ? grp->bb_free / grp->bb_fragments : 0;
> +		count = 1;
> +		while (rb_next(n)) {
> +			count++;
> +			n = rb_next(n);
> +		}
> +		grp = rb_entry(n, struct ext4_group_info, bb_avg_fragment_size_rb);
> +		max = grp->bb_fragments ? grp->bb_free / grp->bb_fragments : 0;
> +
> +		seq_printf(seq, "Min: %d, Max: %d, Num Nodes: %d\n",

These should be "%u" and not "%d"?  I'd assume none will ever be negative.

Prefer not to have spaces within keys, so that it is possible to use
e.g. 'awk /field:/ { print $2 }' to extract a value.  "num_nodes:" or
"tree_nodes: is better. To be a subset of "tree:" they should be
indented with 4 spaces or a tab:

    fragment_size_tree:
        tree_min: nnn
        tree_max: mmm
        tree_nodes: ooo


> +	if (position == 0)
> +		seq_puts(seq, "Largest Free Order Lists:\n");

Similarly, avoiding spaces in the key makes this easier to parse,
like "max_free_order_lists:" or similar.

> +	seq_printf(seq, "Order %ld list: ", position);

Here, "    list_order_%u: %u groups\n" would be more clear, and
can be printed in a single call instead of being split up.


Cheers, Andreas
harshad shirwadkar Feb. 16, 2021, 4:55 p.m. UTC | #2
On Fri, Feb 12, 2021 at 2:37 PM Andreas Dilger <adilger@dilger.ca> wrote:
>
> On Feb 9, 2021, at 1:28 PM, Harshad Shirwadkar <harshadshirwadkar@gmail.com> wrote:
> >
> > This patch adds a new file "mb_structs_summary" which allows us to see the
> > summary of the new allocator structures added in this series.
>
> Hmm, it is hard to visualize what these files will look like, could you
> please include an example output in the commit message?  It looks like
> they will no longer have one line per group, which is good, but maybe
> one line per order?
Sure, will do that in the next version.
>
> If at all possible, it makes sense to have well-formatted output that
> follows YAML formatting (https://yaml-online-parser.appspot.com/ can
> verify this) so that it can be easily parsed (both as YAML and via
> awk or other text processing tools).  That doesn't mean you need to
> embed a YAML parser, just a few well-placed ':' and spaces...
Yeah I like the idea. YAML sounds good to me!
>
> Unfortunately, files like "mb_groups" were created before that wisdom
> was learned, and are a bit of a nightmare to parse today.
>
> A few comments inline...
>
> > Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
> >
> > +static int ext4_mb_seq_structs_summary_show(struct seq_file *seq, void *v)
> > +{
> > +
>
> Extra blank line here can be removed
Ack
>
> > +     if (position >= MB_NUM_ORDERS(sb)) {
> > +             seq_puts(seq, "Tree\n");
>
> Prefer not to use capitalized words.
>
> This should have a ':' like "tree:", but this still leaves the question
> "what is the tree for?" so using "fragment_size_tree:" or similar would
> be better.
Ack
>
> > +             n = rb_first(&sbi->s_mb_avg_fragment_size_root);
> > +             if (!n) {
> > +                     seq_puts(seq, "<Empty>\n");
>
> I'm guessing this won't happen very often, but it might be easier if it
> kept the same output format, so "min: 0, max: 0, num_nodes: 0", or just
> initialize those values and then skip the intermediate processing below
> before printing out the summary line (better because there is only one
> place that is formatting the output, so it will be consistent)?
Sounds good!
>
> > +                     return 0;
> > +             }
> > +             grp = rb_entry(n, struct ext4_group_info, bb_avg_fragment_size_rb);
> > +             min = grp->bb_fragments ? grp->bb_free / grp->bb_fragments : 0;
> > +             count = 1;
> > +             while (rb_next(n)) {
> > +                     count++;
> > +                     n = rb_next(n);
> > +             }
> > +             grp = rb_entry(n, struct ext4_group_info, bb_avg_fragment_size_rb);
> > +             max = grp->bb_fragments ? grp->bb_free / grp->bb_fragments : 0;
> > +
> > +             seq_printf(seq, "Min: %d, Max: %d, Num Nodes: %d\n",
>
> These should be "%u" and not "%d"?  I'd assume none will ever be negative.
Ack
>
> Prefer not to have spaces within keys, so that it is possible to use
> e.g. 'awk /field:/ { print $2 }' to extract a value.  "num_nodes:" or
> "tree_nodes: is better. To be a subset of "tree:" they should be
> indented with 4 spaces or a tab:
>
>     fragment_size_tree:
>         tree_min: nnn
>         tree_max: mmm
>         tree_nodes: ooo
Ack
>
>
> > +     if (position == 0)
> > +             seq_puts(seq, "Largest Free Order Lists:\n");
>
> Similarly, avoiding spaces in the key makes this easier to parse,
> like "max_free_order_lists:" or similar.
>
> > +     seq_printf(seq, "Order %ld list: ", position);
>
> Here, "    list_order_%u: %u groups\n" would be more clear, and
> can be printed in a single call instead of being split up.
Ack

Sounds good, thanks for the feedback. I'll incorporate these changes
in the next version.

Thanks,
Harshad
>
>
> Cheers, Andreas
>
>
>
>
>
diff mbox series

Patch

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 0601c997c87f..39830c07c27e 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2817,6 +2817,7 @@  int __init ext4_fc_init_dentry_cache(void);
 
 /* mballoc.c */
 extern const struct seq_operations ext4_mb_seq_groups_ops;
+extern const struct seq_operations ext4_mb_seq_structs_summary_ops;
 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);
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 63562f5f42f1..d9cb74787a47 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2864,6 +2864,90 @@  int ext4_seq_mb_stats_show(struct seq_file *seq, void *offset)
 	return 0;
 }
 
+static void *ext4_mb_seq_structs_summary_start(struct seq_file *seq, loff_t *pos)
+{
+	struct super_block *sb = PDE_DATA(file_inode(seq->file));
+	unsigned long position;
+
+	read_lock(&EXT4_SB(sb)->s_mb_rb_lock);
+
+	if (*pos < 0 || *pos >= MB_NUM_ORDERS(sb) + 1)
+		return NULL;
+	position = *pos + 1;
+	return (void *) ((unsigned long) position);
+}
+
+static void *ext4_mb_seq_structs_summary_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct super_block *sb = PDE_DATA(file_inode(seq->file));
+	unsigned long position;
+
+	++*pos;
+	if (*pos < 0 || *pos >= MB_NUM_ORDERS(sb) + 1)
+		return NULL;
+	position = *pos + 1;
+	return (void *) ((unsigned long) position);
+}
+
+static int ext4_mb_seq_structs_summary_show(struct seq_file *seq, void *v)
+{
+	struct super_block *sb = PDE_DATA(file_inode(seq->file));
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	unsigned long position = ((unsigned long) v);
+	struct ext4_group_info *grp;
+	struct rb_node *n;
+	int count, min, max;
+
+	position--;
+
+	if (position >= MB_NUM_ORDERS(sb)) {
+		seq_puts(seq, "Tree\n");
+		n = rb_first(&sbi->s_mb_avg_fragment_size_root);
+		if (!n) {
+			seq_puts(seq, "<Empty>\n");
+			return 0;
+		}
+		grp = rb_entry(n, struct ext4_group_info, bb_avg_fragment_size_rb);
+		min = grp->bb_fragments ? grp->bb_free / grp->bb_fragments : 0;
+		count = 1;
+		while (rb_next(n)) {
+			count++;
+			n = rb_next(n);
+		}
+		grp = rb_entry(n, struct ext4_group_info, bb_avg_fragment_size_rb);
+		max = grp->bb_fragments ? grp->bb_free / grp->bb_fragments : 0;
+
+		seq_printf(seq, "Min: %d, Max: %d, Num Nodes: %d\n",
+			   min, max, count);
+		return 0;
+	}
+
+	if (position == 0)
+		seq_puts(seq, "Largest Free Order Lists:\n");
+
+	seq_printf(seq, "Order %ld list: ", position);
+	count = 0;
+	list_for_each_entry(grp, &sbi->s_mb_largest_free_orders[position],
+			    bb_largest_free_order_node)
+		count++;
+	seq_printf(seq, "%d Groups\n", count);
+	return 0;
+}
+
+static void ext4_mb_seq_structs_summary_stop(struct seq_file *seq, void *v)
+{
+	struct super_block *sb = PDE_DATA(file_inode(seq->file));
+
+	read_unlock(&EXT4_SB(sb)->s_mb_rb_lock);
+}
+
+const struct seq_operations ext4_mb_seq_structs_summary_ops = {
+	.start  = ext4_mb_seq_structs_summary_start,
+	.next   = ext4_mb_seq_structs_summary_next,
+	.stop   = ext4_mb_seq_structs_summary_stop,
+	.show   = ext4_mb_seq_structs_summary_show,
+};
+
 static struct kmem_cache *get_groupinfo_cache(int blocksize_bits)
 {
 	int cache_index = blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE;
diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
index 752d1c261e2a..b78bc6b57bce 100644
--- a/fs/ext4/sysfs.c
+++ b/fs/ext4/sysfs.c
@@ -529,6 +529,8 @@  int ext4_register_sysfs(struct super_block *sb)
 				&ext4_mb_seq_groups_ops, sb);
 		proc_create_single_data("mb_stats", 0444, sbi->s_proc,
 				ext4_seq_mb_stats_show, sb);
+		proc_create_seq_data("mb_structs_summary", 0444, sbi->s_proc,
+				&ext4_mb_seq_structs_summary_ops, sb);
 	}
 	return 0;
 }