linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Suren Baghdasaryan <surenb@google.com>
To: David Wang <00107082@163.com>
Cc: kent.overstreet@linux.dev, akpm@linux-foundation.org,
	 linux-kernel@vger.kernel.org, linux-mm@kvack.org
Subject: Re: [PATCH 2/2] alloc_tag: keep codetag iterator cross read() calls
Date: Fri, 9 May 2025 10:34:52 -0700	[thread overview]
Message-ID: <CAJuCfpFVdg5HkW03ZLFTyPHghW7cmYX=mA1TDajqRy8A4as42A@mail.gmail.com> (raw)
In-Reply-To: <20250509055313.922707-1-00107082@163.com>

On Thu, May 8, 2025 at 10:53 PM David Wang <00107082@163.com> wrote:
>
> When reading /proc/allocinfo, for each read syscall, seq_file would
> invoke start/stop callbacks. In start callback, a memory is alloced
> to store iterator and the iterator would start from beginning to
> walk to current read position.
>
> seq_file read() takes at most 4096 bytes, even if read with a larger
> user space buffer, meaning read out all of /proc/allocinfo, tens of read
> syscalls are needed. For example, a 306036 bytes allocinfo files need
> 76 reads:
>
>  $ sudo cat /proc/allocinfo  | wc
>     3964   16678  306036
>  $ sudo strace -T -e read cat /proc/allocinfo
>  ...
>  read(3, "        4096        1 arch/x86/k"..., 131072) = 4063 <0.000062>
>  ...
>  read(3, "           0        0 sound/core"..., 131072) = 4021 <0.000150>
>  ...
> For those n=3964 lines, each read takes about m=3964/76=52 lines,
> since iterator restart from beginning for each read(),
> it would move forward
>    m  steps on 1st read
>  2*m  steps on 2nd read
>  3*m  steps on 3rd read
>  ...
>    n  steps on last read
> As read() along, more iterator steps make read() calls slower and
> slower.  Adding those up, codetag iterator moves about O(n*n/m) steps,
> making data structure traversal take significant part of the whole reading.
> Profiling when stress reading /proc/allocinfo confirms it:
>
>  vfs_read(99.959% 1677299/1677995)
>      proc_reg_read_iter(99.856% 1674881/1677299)
>          seq_read_iter(99.959% 1674191/1674881)
>              allocinfo_start(75.664% 1266755/1674191)
>                  codetag_next_ct(79.217% 1003487/1266755)  <---
>                  srso_return_thunk(1.264% 16011/1266755)
>                  __kmalloc_cache_noprof(0.102% 1296/1266755)
>                  ...
>              allocinfo_show(21.287% 356378/1674191)
>              allocinfo_next(1.530% 25621/1674191)
> allocinfo_start() takes about 75% of seq_read().
>
> A private data alloced at open() time can be used to carry iterator
> alive across read() calls, and avoid the memory allocation and
> iterator reset for each read(). This way, only O(1) memory allocation
> and O(n) steps iterating, and `time` shows performance improvement
> from ~7ms to ~4ms.
> Profiling with the change:
>
>  vfs_read(99.865% 1581073/1583214)
>      proc_reg_read_iter(99.485% 1572934/1581073)
>          seq_read_iter(99.846% 1570519/1572934)
>              allocinfo_show(87.428% 1373074/1570519)
>                  seq_buf_printf(83.695% 1149196/1373074)
>                  seq_buf_putc(1.917% 26321/1373074)
>                  _find_next_bit(1.531% 21023/1373074)
>                  ...
>                  codetag_to_text(0.490% 6727/1373074)
>                  ...
>              allocinfo_next(6.275% 98543/1570519)
>              ...
>              allocinfo_start(0.369% 5790/1570519)
>              ...
> allocinfo_start taks less than 1%.
>
> Signed-off-by: David Wang <00107082@163.com>

I think you will be posting another version to address comments in the
first patch, but for this patch feel free to add:

Acked-by: Suren Baghdasaryan <surenb@google.com>

Thanks!

> ---
>  lib/alloc_tag.c | 29 ++++++++++-------------------
>  1 file changed, 10 insertions(+), 19 deletions(-)
>
> diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
> index 25ecc1334b67..fdd5887769a6 100644
> --- a/lib/alloc_tag.c
> +++ b/lib/alloc_tag.c
> @@ -45,21 +45,16 @@ struct allocinfo_private {
>  static void *allocinfo_start(struct seq_file *m, loff_t *pos)
>  {
>         struct allocinfo_private *priv;
> -       struct codetag *ct;
>         loff_t node = *pos;
>
> -       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> -       m->private = priv;
> -       if (!priv)
> -               return NULL;
> -
> -       priv->print_header = (node == 0);
> +       priv = (struct allocinfo_private *)m->private;
>         codetag_lock_module_list(alloc_tag_cttype, true);
> -       priv->iter = codetag_get_ct_iter(alloc_tag_cttype);
> -       while ((ct = codetag_next_ct(&priv->iter)) != NULL && node)
> -               node--;
> -
> -       return ct ? priv : NULL;
> +       if (node == 0) {
> +               priv->print_header = true;
> +               priv->iter = codetag_get_ct_iter(alloc_tag_cttype);
> +               codetag_next_ct(&priv->iter);
> +       }
> +       return priv->iter.ct ? priv : NULL;
>  }
>
>  static void *allocinfo_next(struct seq_file *m, void *arg, loff_t *pos)
> @@ -76,12 +71,7 @@ static void *allocinfo_next(struct seq_file *m, void *arg, loff_t *pos)
>
>  static void allocinfo_stop(struct seq_file *m, void *arg)
>  {
> -       struct allocinfo_private *priv = (struct allocinfo_private *)m->private;
> -
> -       if (priv) {
> -               codetag_lock_module_list(alloc_tag_cttype, false);
> -               kfree(priv);
> -       }
> +       codetag_lock_module_list(alloc_tag_cttype, false);
>  }
>
>  static void print_allocinfo_header(struct seq_buf *buf)
> @@ -249,7 +239,8 @@ static void __init procfs_init(void)
>         if (!mem_profiling_support)
>                 return;
>
> -       if (!proc_create_seq(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_seq_op)) {
> +       if (!proc_create_seq_private(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_seq_op,
> +                                    sizeof(struct allocinfo_private), NULL)) {
>                 pr_err("Failed to create %s file\n", ALLOCINFO_FILE_NAME);
>                 shutdown_mem_profiling(false);
>         }
> --
> 2.39.2
>


  reply	other threads:[~2025-05-09 17:35 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-07 17:55 [PATCH] alloc_tag: avoid mem alloc and iter reset when reading allocinfo David Wang
2025-05-07 18:19 ` David Wang
2025-05-07 23:42   ` [PATCH] " Suren Baghdasaryan
2025-05-08  0:01     ` Kent Overstreet
2025-05-08  3:06       ` David Wang
2025-05-08  3:31         ` Kent Overstreet
2025-05-08  3:35           ` David Wang
2025-05-08  4:07             ` Kent Overstreet
2025-05-08  5:51               ` David Wang
2025-05-08 13:33                 ` Kent Overstreet
2025-05-08 16:24                   ` David Wang
2025-05-08 16:34                     ` Kent Overstreet
2025-05-08 16:58                       ` David Wang
2025-05-08 17:17                         ` David Wang
2025-05-08 17:26                           ` Kent Overstreet
2025-05-08  2:24     ` David Wang
2025-05-07 23:36 ` Suren Baghdasaryan
2025-05-08  3:10   ` David Wang
2025-05-08 15:32   ` David Wang
2025-05-08 21:41     ` Suren Baghdasaryan
2025-05-09  5:53 ` [PATCH 2/2] alloc_tag: keep codetag iterator cross read() calls David Wang
2025-05-09 17:34   ` Suren Baghdasaryan [this message]
2025-05-09 17:45     ` David Wang
2025-05-09 17:39 ` [PATCH v2 2/2] alloc_tag: keep codetag iterator active between " David Wang
2025-05-09 18:33   ` Tim Chen
2025-05-09 19:36     ` Suren Baghdasaryan
2025-05-09 19:46       ` Tim Chen
2025-05-09 20:46         ` Suren Baghdasaryan
2025-05-09 21:15           ` Suren Baghdasaryan
2025-05-10  3:10             ` David Wang
2025-05-10  3:30               ` Suren Baghdasaryan
2025-05-10  3:58                 ` David Wang
2025-05-10  4:03                   ` Suren Baghdasaryan
2025-05-10  3:35         ` David Wang
2025-05-10  3:25     ` David Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAJuCfpFVdg5HkW03ZLFTyPHghW7cmYX=mA1TDajqRy8A4as42A@mail.gmail.com' \
    --to=surenb@google.com \
    --cc=00107082@163.com \
    --cc=akpm@linux-foundation.org \
    --cc=kent.overstreet@linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox