• Andrii Nakryiko's avatar
    fs/procfs: extract logic for getting VMA name constituents · acd4b2ec
    Andrii Nakryiko authored
    Patch series "ioctl()-based API to query VMAs from /proc/<pid>/maps", v6.
    
    Implement binary ioctl()-based interface to /proc/<pid>/maps file to allow
    applications to query VMA information more efficiently than reading *all*
    VMAs nonselectively through text-based interface of /proc/<pid>/maps file.
    
    Patch #2 goes into a lot of details and background on some common patterns
    of using /proc/<pid>/maps in the area of performance profiling and
    subsequent symbolization of captured stack traces.  As mentioned in that
    patch, patterns of VMA querying can differ depending on specific use case,
    but can generally be grouped into two main categories: the need to query a
    small subset of VMAs covering a given batch of addresses, or
    reading/storing/caching all (typically, executable) VMAs upfront for later
    processing.
    
    The new PROCMAP_QUERY ioctl() API added in this patch set was motivated by
    the former pattern of usage.  Earlier revisions had a patch adding a tool
    that faithfully reproduces an efficient VMA matching pass of a symbolizer,
    collecting a subset of covering VMAs for a given set of addresses as
    efficiently as possible.  This tool served both as a testing ground, as
    well as a benchmarking tool.  It implements everything both for currently
    existing text-based /proc/<pid>/maps interface, as well as for newly-added
    PROCMAP_QUERY ioctl().  This revision dropped the tool from the patch set
    and, once the API lands upstream, this tool might be added separately on
    Github as an example.
    
    Based on discussion on earlier revisions of this patch set, it turned out
    that this ioctl() API is competitive with highly-optimized text-based
    pre-processing pattern that perf tool is using.  Based on perf discussion,
    this revision adds more flexibility in specifying a subset of VMAs that
    are of interest.  Now it's possible to specify desired permissions of VMAs
    (e.g., request only executable ones) and/or restrict to only a subset of
    VMAs that have file backing.  This further improves the efficiency when
    using this new API thanks to more selective (executable VMAs only)
    querying.
    
    In addition to a custom benchmarking tool, and experimental perf
    integration (available at [0]), Daniel Mueller has since also implemented
    an experimental integration into blazesym (see [1]), a library used for
    stack trace symbolization by our server fleet-wide profiler and another
    on-device profiler agent that runs on weaker ARM devices.  The latter
    ARM-based device profiler is especially sensitive to performance, and so
    we benchmarked and compared text-based /proc/<pid>/maps solution to the
    equivalent one using PROCMAP_QUERY ioctl().
    
    Results are very encouraging, giving us 5x improvement for end-to-end
    so-called "address normalization" pass, which is the part of the
    symbolization process that happens locally on ARM device, before being
    sent out for further heavier-weight processing on more powerful remote
    server.  Note that this is not an artificial microbenchmark.  It's a full
    end-to-end API call being measured with real-world data on real-world
    device.
    
      TEXT-BASED
      ==========
      Benchmarking main/normalize_process_no_build_ids_uncached_maps
      main/normalize_process_no_build_ids_uncached_maps
    	  time:   [49.777 µs 49.982 µs 50.250 µs]
    
      IOCTL-BASED
      ===========
      Benchmarking main/normalize_process_no_build_ids_uncached_maps
      main/normalize_process_no_build_ids_uncached_maps
    	  time:   [10.328 µs 10.391 µs 10.457 µs]
    	  change: [−79.453% −79.304% −79.166%] (p = 0.00 < 0.02)
    	  Performance has improved.
    
    You can see above that we see the drop from 50µs down to 10µs for
    exactly the same amount of work, with the same data and target process.
    
    With the aforementioned custom tool, we see about ~40x improvement (it
    might vary a bit, depending on a specific captured set of addresses).  And
    even for perf-based benchmark it's on par or slightly ahead when using
    permission-based filtering (fetching only executable VMAs).
    
    Earlier revisions attempted to use per-VMA locking, if kernel was compiled
    with CONFIG_PER_VMA_LOCK=y, but it turned out that anon_vma_name() is not
    yet compatible with per-VMA locking and assumes mmap_lock to be taken,
    which makes the use of per-VMA locking for this API premature.  It was
    agreed ([2]) to continue for now with just mmap_lock, but the code
    structure is such that it should be easy to add per-VMA locking support
    once all the pieces are ready.
    
    One thing that did not change was basing this new API as an ioctl()
    command on /proc/<pid>/maps file.  An ioctl-based API on top of pidfd was
    considered, but has its own downsides.  Implementing ioctl() directly on
    pidfd will cause access permission checks on every single ioctl(), which
    leads to performance concerns and potential spam of capable() audit
    messages.  It also prevents a nice pattern, possible with
    /proc/<pid>/maps, in which application opens /proc/self/maps FD (requiring
    no additional capabilities) and passed this FD to profiling agent for
    querying.  To achieve similar pattern, a new file would have to be created
    from pidf just for VMA querying, which is considered to be inferior to
    just querying /proc/<pid>/maps FD as proposed in current approach.  These
    aspects were discussed in the hallway track at recent LSF/MM/BPF 2024 and
    sticking to procfs ioctl() was the final agreement we arrived at.
    
      [0] https://github.com/anakryiko/linux/commits/procfs-proc-maps-ioctl-v2/
      [1] https://github.com/libbpf/blazesym/pull/675
      [2] https://lore.kernel.org/bpf/7rm3izyq2vjp5evdjc7c6z4crdd3oerpiknumdnmmemwyiwx7t@hleldw7iozi3/
    
    
    This patch (of 6):
    
    Extract generic logic to fetch relevant pieces of data to describe VMA
    name.  This could be just some string (either special constant or
    user-provided), or a string with some formatted wrapping text (e.g.,
    "[anon_shmem:<something>]"), or, commonly, file path.  seq_file-based
    logic has different methods to handle all three cases, but they are
    currently mixed in with extracting underlying sources of data.
    
    This patch splits this into data fetching and data formatting, so that
    data fetching can be reused later on.
    
    There should be no functional changes.
    
    Link: https://lkml.kernel.org/r/20240627170900.1672542-1-andrii@kernel.org
    Link: https://lkml.kernel.org/r/20240627170900.1672542-2-andrii@kernel.orgSigned-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Acked-by: default avatarLiam R. Howlett <Liam.Howlett@Oracle.com>
    Cc: Alexey Dobriyan <adobriyan@gmail.com>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Cc: Christian Brauner <brauner@kernel.org>
    Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Cc: Mike Rapoport (IBM) <rppt@kernel.org>
    Cc: Suren Baghdasaryan <surenb@google.com>
    Cc: Andi Kleen <ak@linux.intel.com>
    Cc: Arnd Bergmann <arnd@arndb.de>
    Cc: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    acd4b2ec
task_mmu.c 69 KB