mbox series

[v4,00/34] Printbufs - new data structure for building strings

Message ID 20220620004233.3805-1-kent.overstreet@gmail.com (mailing list archive)
Headers show
Series Printbufs - new data structure for building strings | expand

Message

Kent Overstreet June 20, 2022, 12:41 a.m. UTC
Previous discussions:
https://lore.kernel.org/all/20220419203202.2670193-1-kent.overstreet@gmail.com/
https://lore.kernel.org/all/20220519172421.162394-1-kent.overstreet@gmail.com/
https://lore.kernel.org/all/20220604193042.1674951-1-kent.overstreet@gmail.com/

Git repo:
https://evilpiepirate.org/git/bcachefs.git/log/?h=printbuf_v4

Changes since v3:
  Bugfixes and performance improvements, the latest iteration of this patch
  series has been baking in the bcachefs tree and that shook out some bugs.

  Rasmus pointed out that -fno-strict-aliasing is going to cause gcc to generate
  nasty code, and indeed it unfortunately does but according to worst case
  scenario microbenchmarks it's not a problem for actual performance. Using
  memcpy() and memset() in the printbuf helpers _was_ a problem for performance,
  so that's been fixed.

-----------

Core idea: Wouldn't it be nice if we had a common data structure and calling
convention for outputting strings?

The core concept this patch series is aimed at cleaning up and standardizing is
that of a "pretty-printer", which is now a function like prt_foo() or
foo_to_text():

    void foo_to_text(struct printbuf *out, struct foo)

What this patch series does or enables:

 - It becomes quite a bit easier to write composable pretty printers! This is
   huge.

 - A ton of code that works in terms of raw char * pointers and lengths
   (snprintf style, and many weird variations) gets cleaned up, with error prone
   raw pointers arithmetic replaced by proper helpers

 - A ton of code that emits either directly via printk() or to other places
   (sysfs, debugfs) can now output to printbufs, and becomes more reusable and
   composable

 - Countesy of Matthew Wilcox, the new and very cool %pf() format string, which
   allows passing a pretty printer function and its arguments to sprintf() and
   family. This means we can now call type specific pretty-printers without
   adding them to lib/vsprintf.c and writing a bunch of crazy
   parsing-and-dispatch code. For example,

     printk("%pd", dentry);

   becomes

     printk("%pf(%p)", prt_dentry, dentry);

   My OOM debugging & reporting patch series that builds off of this uses this
   to solve a very real problem that Michal Hocko brought up at LSF - with this
   we write shrinkers_to_text(), slab_to_text() which can _also_ now be used for
   reporting in debugfs (which Roman has been working on), as well as in the
   show_mem() report - the "%pf()" syntax lets us print the output of those
   functions without allocating (and having to preallocate) a separate buffer.

 - Some new formatting helpers:
   
   Nicely aligned text is much easier to read, and something that we want a
   _lot, but outputting nicely aligned text with printf() is a pain in the ass.
   Printbufs add tabstops, which can be used for right or left justification -
   simple, easy. prt_tab() emits spaces up to the next tabstop, prt_tab_rjust()
   advances to the next tabstop right justifying text since the previous
   tabstop.

   Printbufs also add an indent level, obeyed by prt_newline() which can be very
   useful for multi line output.

   In the future, \n and \t in format strings may learn to obey these as well.

 - Optional heap allocation - no need to statically allocate buffers on the
   stack and guess at the output size.

 - Lots of consolidating and refactoring
   
   This series replaces seq_buf, which does basically what an earlier version of
   printbufs did.

   A good chunk of lib/string_helpers.c, as well as lib/hexdump.c are converted
   (and simplified!).

   Pretty printers in lib/vsprintf.c previously outputted to buffers on the
   stack and then copied _that_ to the actual output buffer, that's all gone
   (replaced by proper helpers for outputting chars and strings), and they also
   used printf_spec for argument passing in ad-hoc ways. This patch series does
   a lot towards converting them to more standard pretty printers that can be
   called via %pf() instead of having to live in lib/vsprintf.c. Still to do:
   format string decoding for argument passing is a mess that's scattered all
   over the place.

In the course of working on this patch series, I've spotted a _lot_ more
consolidation and refactoring that needs to be done - we've got a ton of API
fragmentation leading to lots of code duplication.

But I'm already really excited about what this patch series enables.

Cheers!

Kent Overstreet (34):
  lib/printbuf: New data structure for printing strings
  lib/string_helpers: Convert string_escape_mem() to printbuf
  vsprintf: Convert to printbuf
  lib/hexdump: Convert to printbuf
  vsprintf: %pf(%p)
  lib/string_helpers: string_get_size() now returns characters wrote
  lib/printbuf: Heap allocation
  lib/printbuf: Tabstops, indenting
  lib/printbuf: Unit specifiers
  lib/pretty-printers: prt_string_option(), prt_bitflags()
  vsprintf: Improve number()
  vsprintf: prt_u64_minwidth(), prt_u64()
  test_printf: Drop requirement that sprintf not write past nul
  vsprintf: Start consolidating printf_spec handling
  vsprintf: Refactor resource_string()
  vsprintf: Refactor fourcc_string()
  vsprintf: Refactor ip_addr_string()
  vsprintf: Refactor mac_address_string()
  vsprintf: time_and_date() no longer takes printf_spec
  vsprintf: flags_string() no longer takes printf_spec
  vsprintf: Refactor device_node_string, fwnode_string
  vsprintf: Refactor hex_string, bitmap_string_list, bitmap_string
  Input/joystick/analog: Convert from seq_buf -> printbuf
  mm/memcontrol.c: Convert to printbuf
  clk: tegra: bpmp: Convert to printbuf
  tools/testing/nvdimm: Convert to printbuf
  powerpc: Convert to printbuf
  x86/resctrl: Convert to printbuf
  PCI/P2PDMA: Convert to printbuf
  tracing: trace_events_synth: Convert to printbuf
  d_path: prt_path()
  ACPI/APEI: Add missing include
  tracing: Convert to printbuf
  Delete seq_buf

 Documentation/core-api/printk-formats.rst |   22 +
 arch/powerpc/kernel/process.c             |   16 +-
 arch/powerpc/kernel/security.c            |   75 +-
 arch/powerpc/platforms/pseries/papr_scm.c |   34 +-
 arch/x86/kernel/cpu/resctrl/rdtgroup.c    |   16 +-
 drivers/acpi/apei/erst-dbg.c              |    1 +
 drivers/clk/tegra/clk-bpmp.c              |   21 +-
 drivers/input/joystick/analog.c           |   23 +-
 drivers/pci/p2pdma.c                      |   21 +-
 fs/d_path.c                               |   35 +
 include/linux/dcache.h                    |    1 +
 include/linux/kernel.h                    |   12 +
 include/linux/pretty-printers.h           |   10 +
 include/linux/printbuf.h                  |  253 +++
 include/linux/seq_buf.h                   |  162 --
 include/linux/string.h                    |    5 +
 include/linux/string_helpers.h            |    8 +-
 include/linux/trace_events.h              |    2 +-
 include/linux/trace_seq.h                 |   17 +-
 kernel/trace/trace.c                      |   45 +-
 kernel/trace/trace_dynevent.c             |   34 +-
 kernel/trace/trace_events_filter.c        |    2 +-
 kernel/trace/trace_events_synth.c         |   32 +-
 kernel/trace/trace_functions_graph.c      |    6 +-
 kernel/trace/trace_kprobe.c               |    2 +-
 kernel/trace/trace_seq.c                  |  111 +-
 lib/Makefile                              |    4 +-
 lib/hexdump.c                             |  246 +--
 lib/pretty-printers.c                     |   60 +
 lib/printbuf.c                            |  253 +++
 lib/seq_buf.c                             |  397 -----
 lib/string_helpers.c                      |  224 +--
 lib/test_hexdump.c                        |   30 +-
 lib/test_printf.c                         |   33 +-
 lib/vsprintf.c                            | 1723 ++++++++++-----------
 mm/memcontrol.c                           |   68 +-
 tools/testing/nvdimm/test/ndtest.c        |   22 +-
 37 files changed, 2050 insertions(+), 1976 deletions(-)
 create mode 100644 include/linux/pretty-printers.h
 create mode 100644 include/linux/printbuf.h
 delete mode 100644 include/linux/seq_buf.h
 create mode 100644 lib/pretty-printers.c
 create mode 100644 lib/printbuf.c
 delete mode 100644 lib/seq_buf.c

Comments

David Laight June 20, 2022, 4:19 a.m. UTC | #1
From: Kent Overstreet
> Sent: 20 June 2022 01:42
> 
> Previous discussions:
> https://lore.kernel.org/all/20220419203202.2670193-1-kent.overstreet@gmail.com/
> https://lore.kernel.org/all/20220519172421.162394-1-kent.overstreet@gmail.com/
> https://lore.kernel.org/all/20220604193042.1674951-1-kent.overstreet@gmail.com/
> 
> Git repo:
> https://evilpiepirate.org/git/bcachefs.git/log/?h=printbuf_v4
> 
> Changes since v3:
>   Bugfixes and performance improvements, the latest iteration of this patch
>   series has been baking in the bcachefs tree and that shook out some bugs.
> 
>   Rasmus pointed out that -fno-strict-aliasing is going to cause gcc to generate
>   nasty code, and indeed it unfortunately does but according to worst case
>   scenario microbenchmarks it's not a problem for actual performance.

Just copy some of the structure members to local variables
and, if necessary, write them back at the end.

> Using
>   memcpy() and memset() in the printbuf helpers _was_ a problem for performance,
>   so that's been fixed.
> 
> -----------
> 
> Core idea: Wouldn't it be nice if we had a common data structure and calling
> convention for outputting strings?
> 
> The core concept this patch series is aimed at cleaning up and standardizing is
> that of a "pretty-printer", which is now a function like prt_foo() or
> foo_to_text():
> 
>     void foo_to_text(struct printbuf *out, struct foo)
> 
> What this patch series does or enables:
> 
>  - It becomes quite a bit easier to write composable pretty printers! This is
>    huge.
> 
>  - A ton of code that works in terms of raw char * pointers and lengths
>    (snprintf style, and many weird variations) gets cleaned up, with error prone
>    raw pointers arithmetic replaced by proper helpers
> 
>  - A ton of code that emits either directly via printk() or to other places
>    (sysfs, debugfs) can now output to printbufs, and becomes more reusable and
>    composable
> 
>  - Countesy of Matthew Wilcox, the new and very cool %pf() format string, which
>    allows passing a pretty printer function and its arguments to sprintf() and
>    family. This means we can now call type specific pretty-printers without
>    adding them to lib/vsprintf.c and writing a bunch of crazy
>    parsing-and-dispatch code. For example,
> 
>      printk("%pd", dentry);
> 
>    becomes
> 
>      printk("%pf(%p)", prt_dentry, dentry);
> 
>    My OOM debugging & reporting patch series that builds off of this uses this
>    to solve a very real problem that Michal Hocko brought up at LSF - with this
>    we write shrinkers_to_text(), slab_to_text() which can _also_ now be used for
>    reporting in debugfs (which Roman has been working on), as well as in the
>    show_mem() report - the "%pf()" syntax lets us print the output of those
>    functions without allocating (and having to preallocate) a separate buffer.

I really think that is a bad idea.
printk() already uses a lot of stack, anything doing a recursive
call is just making that worse.
Especially since these calls can often be in error paths
which are not often tested and can already be on deep stacks.

	David

> 
>  - Some new formatting helpers:
> 
>    Nicely aligned text is much easier to read, and something that we want a
>    _lot, but outputting nicely aligned text with printf() is a pain in the ass.
>    Printbufs add tabstops, which can be used for right or left justification -
>    simple, easy. prt_tab() emits spaces up to the next tabstop, prt_tab_rjust()
>    advances to the next tabstop right justifying text since the previous
>    tabstop.
> 
>    Printbufs also add an indent level, obeyed by prt_newline() which can be very
>    useful for multi line output.
> 
>    In the future, \n and \t in format strings may learn to obey these as well.
> 
>  - Optional heap allocation - no need to statically allocate buffers on the
>    stack and guess at the output size.
> 
>  - Lots of consolidating and refactoring
> 
>    This series replaces seq_buf, which does basically what an earlier version of
>    printbufs did.
> 
>    A good chunk of lib/string_helpers.c, as well as lib/hexdump.c are converted
>    (and simplified!).
> 
>    Pretty printers in lib/vsprintf.c previously outputted to buffers on the
>    stack and then copied _that_ to the actual output buffer, that's all gone
>    (replaced by proper helpers for outputting chars and strings), and they also
>    used printf_spec for argument passing in ad-hoc ways. This patch series does
>    a lot towards converting them to more standard pretty printers that can be
>    called via %pf() instead of having to live in lib/vsprintf.c. Still to do:
>    format string decoding for argument passing is a mess that's scattered all
>    over the place.
> 
> In the course of working on this patch series, I've spotted a _lot_ more
> consolidation and refactoring that needs to be done - we've got a ton of API
> fragmentation leading to lots of code duplication.
> 
> But I'm already really excited about what this patch series enables.
> 
> Cheers!
> 
> Kent Overstreet (34):
>   lib/printbuf: New data structure for printing strings
>   lib/string_helpers: Convert string_escape_mem() to printbuf
>   vsprintf: Convert to printbuf
>   lib/hexdump: Convert to printbuf
>   vsprintf: %pf(%p)
>   lib/string_helpers: string_get_size() now returns characters wrote
>   lib/printbuf: Heap allocation
>   lib/printbuf: Tabstops, indenting
>   lib/printbuf: Unit specifiers
>   lib/pretty-printers: prt_string_option(), prt_bitflags()
>   vsprintf: Improve number()
>   vsprintf: prt_u64_minwidth(), prt_u64()
>   test_printf: Drop requirement that sprintf not write past nul
>   vsprintf: Start consolidating printf_spec handling
>   vsprintf: Refactor resource_string()
>   vsprintf: Refactor fourcc_string()
>   vsprintf: Refactor ip_addr_string()
>   vsprintf: Refactor mac_address_string()
>   vsprintf: time_and_date() no longer takes printf_spec
>   vsprintf: flags_string() no longer takes printf_spec
>   vsprintf: Refactor device_node_string, fwnode_string
>   vsprintf: Refactor hex_string, bitmap_string_list, bitmap_string
>   Input/joystick/analog: Convert from seq_buf -> printbuf
>   mm/memcontrol.c: Convert to printbuf
>   clk: tegra: bpmp: Convert to printbuf
>   tools/testing/nvdimm: Convert to printbuf
>   powerpc: Convert to printbuf
>   x86/resctrl: Convert to printbuf
>   PCI/P2PDMA: Convert to printbuf
>   tracing: trace_events_synth: Convert to printbuf
>   d_path: prt_path()
>   ACPI/APEI: Add missing include
>   tracing: Convert to printbuf
>   Delete seq_buf
> 
>  Documentation/core-api/printk-formats.rst |   22 +
>  arch/powerpc/kernel/process.c             |   16 +-
>  arch/powerpc/kernel/security.c            |   75 +-
>  arch/powerpc/platforms/pseries/papr_scm.c |   34 +-
>  arch/x86/kernel/cpu/resctrl/rdtgroup.c    |   16 +-
>  drivers/acpi/apei/erst-dbg.c              |    1 +
>  drivers/clk/tegra/clk-bpmp.c              |   21 +-
>  drivers/input/joystick/analog.c           |   23 +-
>  drivers/pci/p2pdma.c                      |   21 +-
>  fs/d_path.c                               |   35 +
>  include/linux/dcache.h                    |    1 +
>  include/linux/kernel.h                    |   12 +
>  include/linux/pretty-printers.h           |   10 +
>  include/linux/printbuf.h                  |  253 +++
>  include/linux/seq_buf.h                   |  162 --
>  include/linux/string.h                    |    5 +
>  include/linux/string_helpers.h            |    8 +-
>  include/linux/trace_events.h              |    2 +-
>  include/linux/trace_seq.h                 |   17 +-
>  kernel/trace/trace.c                      |   45 +-
>  kernel/trace/trace_dynevent.c             |   34 +-
>  kernel/trace/trace_events_filter.c        |    2 +-
>  kernel/trace/trace_events_synth.c         |   32 +-
>  kernel/trace/trace_functions_graph.c      |    6 +-
>  kernel/trace/trace_kprobe.c               |    2 +-
>  kernel/trace/trace_seq.c                  |  111 +-
>  lib/Makefile                              |    4 +-
>  lib/hexdump.c                             |  246 +--
>  lib/pretty-printers.c                     |   60 +
>  lib/printbuf.c                            |  253 +++
>  lib/seq_buf.c                             |  397 -----
>  lib/string_helpers.c                      |  224 +--
>  lib/test_hexdump.c                        |   30 +-
>  lib/test_printf.c                         |   33 +-
>  lib/vsprintf.c                            | 1723 ++++++++++-----------
>  mm/memcontrol.c                           |   68 +-
>  tools/testing/nvdimm/test/ndtest.c        |   22 +-
>  37 files changed, 2050 insertions(+), 1976 deletions(-)
>  create mode 100644 include/linux/pretty-printers.h
>  create mode 100644 include/linux/printbuf.h
>  delete mode 100644 include/linux/seq_buf.h
>  create mode 100644 lib/pretty-printers.c
>  create mode 100644 lib/printbuf.c
>  delete mode 100644 lib/seq_buf.c
> 
> --
> 2.36.1

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Matthew Wilcox June 20, 2022, 4:54 a.m. UTC | #2
On Mon, Jun 20, 2022 at 04:19:31AM +0000, David Laight wrote:
> I really think that is a bad idea.
> printk() already uses a lot of stack, anything doing a recursive
> call is just making that worse.
> Especially since these calls can often be in error paths
> which are not often tested and can already be on deep stacks.

You made this complaint last time and I challenged you to provide data.
You have not, as yet, provided data.
David Laight June 20, 2022, 8 a.m. UTC | #3
From: Matthew Wilcox
> Sent: 20 June 2022 05:55
> 
> On Mon, Jun 20, 2022 at 04:19:31AM +0000, David Laight wrote:
> > I really think that is a bad idea.
> > printk() already uses a lot of stack, anything doing a recursive
> > call is just making that worse.
> > Especially since these calls can often be in error paths
> > which are not often tested and can already be on deep stacks.
> 
> You made this complaint last time and I challenged you to provide data.
> You have not, as yet, provided data.

There is already an issue with printk() needing 2k of stack and
'blowing' the stack in the stack overflow check.
This is with KASAN, but that that probably doesn't make
a massive difference - especially since it has more stack
to play with.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Kent Overstreet June 20, 2022, 3:07 p.m. UTC | #4
On Mon, Jun 20, 2022 at 04:19:31AM +0000, David Laight wrote:
> From: Kent Overstreet
> >   Rasmus pointed out that -fno-strict-aliasing is going to cause gcc to generate
> >   nasty code, and indeed it unfortunately does but according to worst case
> >   scenario microbenchmarks it's not a problem for actual performance.
> 
> Just copy some of the structure members to local variables
> and, if necessary, write them back at the end.

You must not have read any of the code - half the point of this patch series is
implementing proper helpers for printing chars, strings of bytes, etc. and that
doesn't work if we're not using actual types.

> >      printk("%pd", dentry);
> > 
> >    becomes
> > 
> >      printk("%pf(%p)", prt_dentry, dentry);
> > 
> >    My OOM debugging & reporting patch series that builds off of this uses this
> >    to solve a very real problem that Michal Hocko brought up at LSF - with this
> >    we write shrinkers_to_text(), slab_to_text() which can _also_ now be used for
> >    reporting in debugfs (which Roman has been working on), as well as in the
> >    show_mem() report - the "%pf()" syntax lets us print the output of those
> >    functions without allocating (and having to preallocate) a separate buffer.
> 
> I really think that is a bad idea.
> printk() already uses a lot of stack, anything doing a recursive
> call is just making that worse.
> Especially since these calls can often be in error paths
> which are not often tested and can already be on deep stacks.

We went over this before - this patch series drastically reduces stack usage of
sprintf by eliminating a bunch of stack allocated buffers. Do try to keep up...
David Laight June 20, 2022, 3:21 p.m. UTC | #5
From: Kent Overstreet
> Sent: 20 June 2022 16:07

> On Mon, Jun 20, 2022 at 04:19:31AM +0000, David Laight wrote:
> > From: Kent Overstreet
> > >   Rasmus pointed out that -fno-strict-aliasing is going to cause gcc to generate
> > >   nasty code, and indeed it unfortunately does but according to worst case
> > >   scenario microbenchmarks it's not a problem for actual performance.
> >
> > Just copy some of the structure members to local variables
> > and, if necessary, write them back at the end.
> 
> You must not have read any of the code - half the point of this patch series is
> implementing proper helpers for printing chars, strings of bytes, etc. and that
> doesn't work if we're not using actual types.

I'm talking about things like:
	out->buf[out->pos] = c;
(or whatever the field names are.)

Even without strict aliasing the compiler has to reread
'buf' and 'pos' every iteration.

Of course, you might find the compiler decides to 'optimise'
the loop to memcpy() or memset().

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Joe Perches June 21, 2022, 12:38 a.m. UTC | #6
On Mon, 2022-06-20 at 11:07 -0400, Kent Overstreet wrote:
> On Mon, Jun 20, 2022 at 04:19:31AM +0000, David Laight wrote:
> > I really think that is a bad idea.
> > printk() already uses a lot of stack, anything doing a recursive
> > call is just making that worse.
> > Especially since these calls can often be in error paths
> > which are not often tested and can already be on deep stacks.
> 
> We went over this before - this patch series drastically reduces stack usage of
> sprintf by eliminating a bunch of stack allocated buffers. Do try to keep up...

I generally agree with David.

I think Kent has not provided data that this actually _reduces_
stack usage.

Converting stack variables to call stack frames does not necessarily
reduce overall stack usage when the stack frame plus any locally
used stack in the called function is added together.
Kent Overstreet June 21, 2022, 12:57 a.m. UTC | #7
On Mon, Jun 20, 2022 at 05:38:51PM -0700, Joe Perches wrote:
> On Mon, 2022-06-20 at 11:07 -0400, Kent Overstreet wrote:
> > On Mon, Jun 20, 2022 at 04:19:31AM +0000, David Laight wrote:
> > > I really think that is a bad idea.
> > > printk() already uses a lot of stack, anything doing a recursive
> > > call is just making that worse.
> > > Especially since these calls can often be in error paths
> > > which are not often tested and can already be on deep stacks.
> > 
> > We went over this before - this patch series drastically reduces stack usage of
> > sprintf by eliminating a bunch of stack allocated buffers. Do try to keep up...
> 
> I generally agree with David.
> 
> I think Kent has not provided data that this actually _reduces_
> stack usage.

I think the people who are comfortable with reading C can discern that when
large stack allocated character arrays are deleted, frame size and stack usage
go down.
Joe Perches June 21, 2022, 1:26 a.m. UTC | #8
On Mon, 2022-06-20 at 20:57 -0400, Kent Overstreet wrote:
> On Mon, Jun 20, 2022 at 05:38:51PM -0700, Joe Perches wrote:
> > On Mon, 2022-06-20 at 11:07 -0400, Kent Overstreet wrote:
> > > On Mon, Jun 20, 2022 at 04:19:31AM +0000, David Laight wrote:
> > > > I really think that is a bad idea.
> > > > printk() already uses a lot of stack, anything doing a recursive
> > > > call is just making that worse.
> > > > Especially since these calls can often be in error paths
> > > > which are not often tested and can already be on deep stacks.
> > > 
> > > We went over this before - this patch series drastically reduces stack usage of
> > > sprintf by eliminating a bunch of stack allocated buffers. Do try to keep up...
> > 
> > I generally agree with David.
> > 
> > I think Kent has not provided data that this actually _reduces_
> > stack usage.
> 
> I think the people who are comfortable with reading C can discern that when
> large stack allocated character arrays are deleted, frame size and stack usage
> go down.

I am very comfortable reading C.

You have not provided any data.
Joe Perches June 21, 2022, 2:10 a.m. UTC | #9
On Mon, 2022-06-20 at 18:26 -0700, Joe Perches wrote:
> On Mon, 2022-06-20 at 20:57 -0400, Kent Overstreet wrote:
> > On Mon, Jun 20, 2022 at 05:38:51PM -0700, Joe Perches wrote:
> > > On Mon, 2022-06-20 at 11:07 -0400, Kent Overstreet wrote:
> > > > On Mon, Jun 20, 2022 at 04:19:31AM +0000, David Laight wrote:
> > > > > I really think that is a bad idea.
> > > > > printk() already uses a lot of stack, anything doing a recursive
> > > > > call is just making that worse.
> > > > > Especially since these calls can often be in error paths
> > > > > which are not often tested and can already be on deep stacks.
> > > > 
> > > > We went over this before - this patch series drastically reduces stack usage of
> > > > sprintf by eliminating a bunch of stack allocated buffers. Do try to keep up...
> > > 
> > > I generally agree with David.
> > > 
> > > I think Kent has not provided data that this actually _reduces_
> > > stack usage.
> > 
> > I think the people who are comfortable with reading C can discern that when
> > large stack allocated character arrays are deleted, frame size and stack usage
> > go down.
> 
> I am very comfortable reading C.
> 
> You have not provided any data.

In a brief looking around at stack uses in vsprintf, I believe
this is the largest stack declaration there.

Especially since KSYM_NAME_LEN was increased to 512 by 
commit 394dffa6680c ("kallsyms: increase maximum kernel symbol length to 512")

Perhaps this stack declaration should instead be an alloc/free
as it can be quite large.

I suppose one could quibble about the kzalloc vs kmalloc or the nominally
unnecessary initialization of sym.

I think this makes sense though and it reduces the #ifdef uses too.
---
 lib/vsprintf.c | 41 ++++++++++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 17 deletions(-)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index c414a8d9f1ea9..30113a30fd88a 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -980,30 +980,37 @@ char *symbol_string(char *buf, char *end, void *ptr,
 		    struct printf_spec spec, const char *fmt)
 {
 	unsigned long value;
-#ifdef CONFIG_KALLSYMS
-	char sym[KSYM_SYMBOL_LEN];
-#endif
+	char *sym = NULL;
 
 	if (fmt[1] == 'R')
 		ptr = __builtin_extract_return_addr(ptr);
 	value = (unsigned long)ptr;
 
-#ifdef CONFIG_KALLSYMS
-	if (*fmt == 'B' && fmt[1] == 'b')
-		sprint_backtrace_build_id(sym, value);
-	else if (*fmt == 'B')
-		sprint_backtrace(sym, value);
-	else if (*fmt == 'S' && (fmt[1] == 'b' || (fmt[1] == 'R' && fmt[2] == 'b')))
-		sprint_symbol_build_id(sym, value);
-	else if (*fmt != 's')
-		sprint_symbol(sym, value);
-	else
-		sprint_symbol_no_offset(sym, value);
+	if (IS_ENABLED(CONFIG_KALLSYMS) &&
+	    (sym = kzalloc(KSYM_SYMBOL_LEN, GFP_NOWAIT | __GFP_NOWARN))) {
+		char *rtn;
+
+		if (*fmt == 'B' && fmt[1] == 'b')
+			sprint_backtrace_build_id(sym, value);
+		else if (*fmt == 'B')
+			sprint_backtrace(sym, value);
+		else if (*fmt == 'S' &&
+			 (fmt[1] == 'b' ||
+			  (fmt[1] == 'R' && fmt[2] == 'b')))
+			sprint_symbol_build_id(sym, value);
+		else if (*fmt != 's')
+			sprint_symbol(sym, value);
+		else
+			sprint_symbol_no_offset(sym, value);
+
+		rtn = string_nocheck(buf, end, sym, spec);
+
+		kfree(sym);
+
+		return rtn;
+	}
 
-	return string_nocheck(buf, end, sym, spec);
-#else
 	return special_hex_number(buf, end, value, sizeof(void *));
-#endif
 }
 
 static const struct printf_spec default_str_spec = {
Kent Overstreet June 21, 2022, 2:31 a.m. UTC | #10
On Mon, Jun 20, 2022 at 06:26:58PM -0700, Joe Perches wrote:
> On Mon, 2022-06-20 at 20:57 -0400, Kent Overstreet wrote:
> > On Mon, Jun 20, 2022 at 05:38:51PM -0700, Joe Perches wrote:
> > > On Mon, 2022-06-20 at 11:07 -0400, Kent Overstreet wrote:
> > > > On Mon, Jun 20, 2022 at 04:19:31AM +0000, David Laight wrote:
> > > > > I really think that is a bad idea.
> > > > > printk() already uses a lot of stack, anything doing a recursive
> > > > > call is just making that worse.
> > > > > Especially since these calls can often be in error paths
> > > > > which are not often tested and can already be on deep stacks.
> > > > 
> > > > We went over this before - this patch series drastically reduces stack usage of
> > > > sprintf by eliminating a bunch of stack allocated buffers. Do try to keep up...
> > > 
> > > I generally agree with David.
> > > 
> > > I think Kent has not provided data that this actually _reduces_
> > > stack usage.
> > 
> > I think the people who are comfortable with reading C can discern that when
> > large stack allocated character arrays are deleted, frame size and stack usage
> > go down.
> 
> I am very comfortable reading C.
> 
> You have not provided any data.

It seems like neither of you have even bothered to check stack frame size in the
current code, and you guys are the one asserting that this is an issue.
Kent Overstreet June 21, 2022, 3:11 a.m. UTC | #11
On Mon, Jun 20, 2022 at 04:19:31AM +0000, David Laight wrote:
> I really think that is a bad idea.
> printk() already uses a lot of stack, anything doing a recursive
> call is just making that worse.
> Especially since these calls can often be in error paths
> which are not often tested and can already be on deep stacks.

So it seems this is something you never actually checked, and I naively assumed
that you might actually know what you were talking about - an understandable
mistake, I think, because vsprintf.c is _a fucking mess_ and high stack usage
would be believable.

But the main part we're concerned with here, snprint() or prt_printf(), has no
such stack usage problems. On v5.18, the frame size is under 64 bytes. On my
branch, it's 72 bytes - higher because we do need to save arguments on the stack
for the pretty-printer invocation, and there's no way around that without
dropping to asm - although I'm allowing up to 8 arguments (besides the printbuf
itself), which is probably excessive.

So I'm not seeing what you're talking about.

In the leaf functions, the individual pretty-printers/%p extensions, those are
doing completely ridiculous things and I have fixed them all except
symbol_string() on my branch, and I'll get to that one.

Having a proper string library with useful helpers really makes things easier,
it turns out.

As for recursive %pf() invocations blowing the stack? I seriously fucking doubt
it, once you're in a pretty-printer where you've already got a printbuf you can
output to there's not much reason to be doing recursive calls to prt_printf()
passing it yet another pretty printer - that's not where %pf() is convenient,
what it makes convenient is using pretty printers when you're calling printk()
directly. In a pretty printer fuction, if you want to do recursive
pretty-printer calls you'd just call it directly! prt_printf(out, "%pf(%p)"),
foo_to_text, foo) is silly when you can just call foo_to_text(out, foo).

Now, I ask both of you please take your bureaucratic nitpicky nonsense and,
kindly, pretty please with sugar on top - stuff it. I much prefer to work with
people who don't waste my time, and who have actual _taste_.
Rasmus Villemoes June 21, 2022, 6:11 a.m. UTC | #12
On 20/06/2022 02.41, Kent Overstreet wrote:

>   Rasmus pointed out that -fno-strict-aliasing is going to cause gcc to generate
>   nasty code, and indeed it unfortunately does but according to worst case
>   scenario microbenchmarks it's not a problem for actual performance. 

Well, that's not how I interpreted those numbers, but, except if they
showed an improvement, how much is acceptable is of course always a
matter of judgment.

However, what's really annoying and somewhat dishonest is that you're
not including those numbers, nor the methodology, in either the cover
letter or commit itself.

Rasmus
Kent Overstreet June 21, 2022, 8:01 a.m. UTC | #13
On Tue, Jun 21, 2022 at 08:11:49AM +0200, Rasmus Villemoes wrote:
> On 20/06/2022 02.41, Kent Overstreet wrote:
> 
> >   Rasmus pointed out that -fno-strict-aliasing is going to cause gcc to generate
> >   nasty code, and indeed it unfortunately does but according to worst case
> >   scenario microbenchmarks it's not a problem for actual performance. 
> 
> Well, that's not how I interpreted those numbers, but, except if they
> showed an improvement, how much is acceptable is of course always a
> matter of judgment.
> 
> However, what's really annoying and somewhat dishonest is that you're
> not including those numbers, nor the methodology, in either the cover
> letter or commit itself.

There's nothing dishonest about it, and I wasn't claiming an improvement; merely
no regressions (some were a 5-10% percent up, some down by around the same
amount, overall it was a wash).

My priority simply isn't microoptimizing everything. I find that programmers who
chase optimizing every loop and are constantly trying to shave instructions
everywhere they can end up with code where the large scale structure is a mess,
and that's where you miss out on the _real_ performance opportunities.

My priority is clean, readable, simple, easy to work on code, because _that_ is
the code that becomes fast in the long run.

Premature optimization really is the root of all evil, and I am _absolutely_
going to try to drive the discussion away from shaving cycles when there's new
APIs to get right and messy refactorings to complete.
Joe Perches June 26, 2022, 7:53 p.m. UTC | #14
In a reply to the printbufs thread, I wrote a proposal to use an
alloc to reduce stack in vsprintf when CONFIG_KALLSYMS is enabled.

No one has replied to this but I think it's somewhat sensible.

Thoughts?

On Mon, 2022-06-20 at 19:10 -0700, Joe Perches wrote:

> In a brief looking around at stack uses in vsprintf, I believe
> this is the largest stack declaration there.
> 
> Especially since KSYM_NAME_LEN was increased to 512 by 
> commit 394dffa6680c ("kallsyms: increase maximum kernel symbol length to 512")
> 
> Perhaps this stack declaration should instead be an alloc/free
> as it can be quite large.
> 
> I suppose one could quibble about the kzalloc vs kmalloc or the nominally
> unnecessary initialization of sym.
> 
> I think this makes sense though and it reduces the #ifdef uses too.
> ---
>  lib/vsprintf.c | 41 ++++++++++++++++++++++++-----------------
>  1 file changed, 24 insertions(+), 17 deletions(-)
> 
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index c414a8d9f1ea9..30113a30fd88a 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -980,30 +980,37 @@ char *symbol_string(char *buf, char *end, void *ptr,
>  		    struct printf_spec spec, const char *fmt)
>  {
>  	unsigned long value;
> -#ifdef CONFIG_KALLSYMS
> -	char sym[KSYM_SYMBOL_LEN];
> -#endif
> +	char *sym = NULL;
>  
>  	if (fmt[1] == 'R')
>  		ptr = __builtin_extract_return_addr(ptr);
>  	value = (unsigned long)ptr;
>  
> -#ifdef CONFIG_KALLSYMS
> -	if (*fmt == 'B' && fmt[1] == 'b')
> -		sprint_backtrace_build_id(sym, value);
> -	else if (*fmt == 'B')
> -		sprint_backtrace(sym, value);
> -	else if (*fmt == 'S' && (fmt[1] == 'b' || (fmt[1] == 'R' && fmt[2] == 'b')))
> -		sprint_symbol_build_id(sym, value);
> -	else if (*fmt != 's')
> -		sprint_symbol(sym, value);
> -	else
> -		sprint_symbol_no_offset(sym, value);
> +	if (IS_ENABLED(CONFIG_KALLSYMS) &&
> +	    (sym = kzalloc(KSYM_SYMBOL_LEN, GFP_NOWAIT | __GFP_NOWARN))) {
> +		char *rtn;
> +
> +		if (*fmt == 'B' && fmt[1] == 'b')
> +			sprint_backtrace_build_id(sym, value);
> +		else if (*fmt == 'B')
> +			sprint_backtrace(sym, value);
> +		else if (*fmt == 'S' &&
> +			 (fmt[1] == 'b' ||
> +			  (fmt[1] == 'R' && fmt[2] == 'b')))
> +			sprint_symbol_build_id(sym, value);
> +		else if (*fmt != 's')
> +			sprint_symbol(sym, value);
> +		else
> +			sprint_symbol_no_offset(sym, value);
> +
> +		rtn = string_nocheck(buf, end, sym, spec);
> +
> +		kfree(sym);
> +
> +		return rtn;
> +	}
>  
> -	return string_nocheck(buf, end, sym, spec);
> -#else
>  	return special_hex_number(buf, end, value, sizeof(void *));
> -#endif
>  }
>  
>  static const struct printf_spec default_str_spec = {
>
Kent Overstreet June 26, 2022, 8:06 p.m. UTC | #15
On Sun, Jun 26, 2022 at 12:53:26PM -0700, Joe Perches wrote:
> In a reply to the printbufs thread, I wrote a proposal to use an
> alloc to reduce stack in vsprintf when CONFIG_KALLSYMS is enabled.
> 
> No one has replied to this but I think it's somewhat sensible.
> 
> Thoughts?

As functions get converted to printbufs the separate stack allocated buffers
become unnecessary, because printbufs have helpers that do bounds checking and
make outputting to the vsprintf buffer painless. So it's not necessary - I
haven't fully converted symbol_string() yet but I'll do so by the time I mail
out the next round of patches.
Joe Perches June 26, 2022, 8:13 p.m. UTC | #16
On Sun, 2022-06-26 at 16:06 -0400, Kent Overstreet wrote:
> On Sun, Jun 26, 2022 at 12:53:26PM -0700, Joe Perches wrote:
> > In a reply to the printbufs thread, I wrote a proposal to use an
> > alloc to reduce stack in vsprintf when CONFIG_KALLSYMS is enabled.
> > 
> > No one has replied to this but I think it's somewhat sensible.
> > 
> > Thoughts?
> 
> As functions get converted to printbufs the separate stack allocated buffers
> become unnecessary, because printbufs have helpers that do bounds checking and
> make outputting to the vsprintf buffer painless. So it's not necessary - I
> haven't fully converted symbol_string() yet but I'll do so by the time I mail
> out the next round of patches.

_If_ the printfbufs patch series gets applied.
I think that series is not great yet.

Even if applied via something like the printbufs series, the
stack use of this function needs/could use attending.

~700 bytes of stack use here isn't great.
Linus Torvalds June 26, 2022, 8:19 p.m. UTC | #17
On Sun, Jun 26, 2022 at 12:53 PM Joe Perches <joe@perches.com> wrote:
>
> In a reply to the printbufs thread, I wrote a proposal to use an
> alloc to reduce stack in vsprintf when CONFIG_KALLSYMS is enabled.
>
> No one has replied to this but I think it's somewhat sensible.

I think that's a bad idea.

Those things are *literally* called from panic situations, which may
be while holding core memory allocation locks, or similar.

The last thing we want to do is make a hard-to-debug panic be even
*harder* to debug because you get a deadlock when oopsing.

(And yes, I realize that the symbol name lookup can have problems too,
but thats' kind of fundamental to %pS, while a kzmalloc isn't.

Now, you are correct that the stack buffer is annoying. But I think
the proper way to fix that is to say "we already *have* the target
buffer, let's use it".

That does require teaching the sprint_symbol() functions that they
need to take a "length of buffer" and return how much they used, but
that would seem to be a sensible thing anyway, and what the code
should always have done?

It's bad policy to just pass in a buffer without length, and I think
it was always broken. Nasty. That KSYM_SYMBOL_LEN is magically taking
care of it all, but it's ugly as heck, wouldn't you say?

NOTE! The attached patch is completely broken.  I did not do that
interface change to the kallsyms code. The patch is literally meant to
be just an explanation of what I mean, not a working patch.

                  Linus
Joe Perches June 26, 2022, 8:39 p.m. UTC | #18
On Sun, 2022-06-26 at 13:19 -0700, Linus Torvalds wrote:
> On Sun, Jun 26, 2022 at 12:53 PM Joe Perches <joe@perches.com> wrote:
> > 
> > In a reply to the printbufs thread, I wrote a proposal to use an
> > alloc to reduce stack in vsprintf when CONFIG_KALLSYMS is enabled.
> > 
> > No one has replied to this but I think it's somewhat sensible.
> 
> I think that's a bad idea.

Somewhat sensible not sensible...

> Those things are *literally* called from panic situations, which may
> be while holding core memory allocation locks, or similar.

True, and special_hex_number was used on alloc failure.

> Now, you are correct that the stack buffer is annoying. But I think
> the proper way to fix that is to say "we already *have* the target
> buffer, let's use it".

OK, and that's true for all the temp stack buffers in every %p<foo>.

> That does require teaching the sprint_symbol() functions that they
> need to take a "length of buffer" and return how much they used, but
> that would seem to be a sensible thing anyway, and what the code
> should always have done?

Unnecessary stack and/or unnecessary buffers for printbufs are
just unnecessary. 

> It's bad policy to just pass in a buffer without length, and I think
> it was always broken. Nasty. That KSYM_SYMBOL_LEN is magically taking
> care of it all, but it's ugly as heck, wouldn't you say?

Yup.
Kent Overstreet June 26, 2022, 8:51 p.m. UTC | #19
On Sun, Jun 26, 2022 at 01:39:01PM -0700, Joe Perches wrote:
> On Sun, 2022-06-26 at 13:19 -0700, Linus Torvalds wrote:
> > On Sun, Jun 26, 2022 at 12:53 PM Joe Perches <joe@perches.com> wrote:
> > > 
> > > In a reply to the printbufs thread, I wrote a proposal to use an
> > > alloc to reduce stack in vsprintf when CONFIG_KALLSYMS is enabled.
> > > 
> > > No one has replied to this but I think it's somewhat sensible.
> > 
> > I think that's a bad idea.
> 
> Somewhat sensible not sensible...
> 
> > Those things are *literally* called from panic situations, which may
> > be while holding core memory allocation locks, or similar.
> 
> True, and special_hex_number was used on alloc failure.
> 
> > Now, you are correct that the stack buffer is annoying. But I think
> > the proper way to fix that is to say "we already *have* the target
> > buffer, let's use it".
> 
> OK, and that's true for all the temp stack buffers in every %p<foo>.

Serious question: why are you trying to half-ass just _one_ of these functions
when I've been working on solving stack allocations in all of them? I've already
killed every single stack buffer in the last patch series that was posted except
for symbol_string(). I would welcome the help if you wanted to tackle that one.

It's not completely trivial because while kallsyms_expand_symbol() can be
trivially converted to printbufs - it just outputs one char at a time, so that
becomes prt_char() - it's not a output-once-and-done algorithm:
cleanup_symbol_name() then goes back over the output buffer and modifies it in
place (ew), because of weird clang things that it's got #ifdefs for.

Specifically, it's truncating the output at the first period (easy to convert;
just stop when we see a period) but then it truncates at the last $ - why? do we
have symbols when building with gcc that legitimately have dollar signs in them?
One would hope we could drop the #ifdefs but that needs to be checked.

That's as far as I got looking at it just now. It will be some time before I
have time to do it properly and run tests and research what I'm doing (because
I am completely buried in bcachefs bugs to work through at the moment, and
getting sucked into working on test automation _again_ when I have a million
more valuable things I could be working on because the test infrastructure story
for the kernel is still a shitshow, but that's another rant).

Anayways, I'm trying to take the time to do this stuff right, but there's a
_lot_ of work involved, so if you want to help out instead of just slag what I'm
doing... well, it'd be nice...

Cheers,
Kent
Linus Torvalds June 26, 2022, 8:54 p.m. UTC | #20
On Sun, Jun 26, 2022 at 1:39 PM Joe Perches <joe@perches.com> wrote:
>
> OK, and that's true for all the temp stack buffers in every %p<foo>.

Yup.

A lot of them are simply due to it just being simple, and when the
temp buffer is of a fairly limited size, "simple is good".

But yeah, that KSYM_SYMBOL_LEN thing was questionable before, and as
it grows with KSYM_NAME_LEN growing, it's getting pretty ridiculous.

For example, the buffer in "number()" looks very reasonable to me,
since it's not only pretty small (24 bytes on 64-bit architectures).
it has that special alignment requirement too.

So I don't think those temporary stack buffers are necessarily wrong
in general, but there's a point where they go from "ok, there's being
_simple_ and then there's _overly_simplistic_".

                   Linus
Joe Perches June 26, 2022, 9:02 p.m. UTC | #21
On Sun, 2022-06-26 at 16:51 -0400, Kent Overstreet wrote:
> On Sun, Jun 26, 2022 at 01:39:01PM -0700, Joe Perches wrote:
> > On Sun, 2022-06-26 at 13:19 -0700, Linus Torvalds wrote:
> > > On Sun, Jun 26, 2022 at 12:53 PM Joe Perches <joe@perches.com> wrote:
> > > > 
> > > > In a reply to the printbufs thread, I wrote a proposal to use an
> > > > alloc to reduce stack in vsprintf when CONFIG_KALLSYMS is enabled.
> > > > 
> > > > No one has replied to this but I think it's somewhat sensible.
> > > 
> > > I think that's a bad idea.
> > 
> > Somewhat sensible not sensible...
> > 
> > > Those things are *literally* called from panic situations, which may
> > > be while holding core memory allocation locks, or similar.
> > 
> > True, and special_hex_number was used on alloc failure.
> > 
> > > Now, you are correct that the stack buffer is annoying. But I think
> > > the proper way to fix that is to say "we already *have* the target
> > > buffer, let's use it".
> > 
> > OK, and that's true for all the temp stack buffers in every %p<foo>.
> 
> Serious question: why are you trying to half-ass just _one_ of these functions
> when I've been working on solving stack allocations in all of them?

Because the stack use in _this_ function is quite large.
Backporting to stable would be trivial.
No so with printbufs.

> if you want to help out instead of just slag what I'm
> doing... well, it'd be nice...

Also nice to _be_ nice.
Honestly Kent, I haven't seen much of that from you.
Kent Overstreet June 26, 2022, 9:10 p.m. UTC | #22
On Sun, Jun 26, 2022 at 02:02:31PM -0700, Joe Perches wrote:
> Because the stack use in _this_ function is quite large.
> Backporting to stable would be trivial.
> No so with printbufs.

Yeah, I'm not so sure "do what's easiest to backport to stable" makes any sense
to me.
David Laight June 27, 2022, 8:25 a.m. UTC | #23
From: Linus Torvalds
> Sent: 26 June 2022 21:19
..
> That does require teaching the sprint_symbol() functions that they
> need to take a "length of buffer" and return how much they used, but
> that would seem to be a sensible thing anyway, and what the code
> should always have done?

It needs to return the 'length it would have used'.
While occasionally useful I'm pretty sure this is actually
a side effect of the was that libc snprintf() was originally
implemented (sprintf() had an on-stack FILE).

In any case it might be simplest to pass all these functions
the write pointer and buffer limit and have them return the
new write pointer.
It is likely to generate much better code that passing
a structure by reference.

Only the original caller needs to know where the buffer starts.
The original caller is also the only place that needs to
ensure that the string is correctly terminated.

You'd get helpers like:

char *add_char(char *wp, const char *lim, char add)
{
	if (lim < wp)
		*wp = add;
	return wp + 1;
}

char *add_chars(char *wp, const char *lim, const char *add, long int count)
{
	long int space = lim - wp;
	long int i;

	if (space > count)
		space = count;
	for (i = i; i < space; i++)
		wp[i] = add[i];
	
	return wp + count;
}

char *add_str(char *wp, const char *lim, const char *add)
{
	while (*add) {
		if (wp >= lim)
			return wp + strlen(add);
		*wp++ = *add++;
	}
	
	return wp;
}

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Kent Overstreet June 28, 2022, 2:56 a.m. UTC | #24
On 6/27/22 04:25, David Laight wrote:
> From: Linus Torvalds
>> Sent: 26 June 2022 21:19
> ..
>> That does require teaching the sprint_symbol() functions that they
>> need to take a "length of buffer" and return how much they used, but
>> that would seem to be a sensible thing anyway, and what the code
>> should always have done?
> 
> It needs to return the 'length it would have used'.
> While occasionally useful I'm pretty sure this is actually
> a side effect of the was that libc snprintf() was originally
> implemented (sprintf() had an on-stack FILE).
> 
> In any case it might be simplest to pass all these functions
> the write pointer and buffer limit and have them return the
> new write pointer.
> It is likely to generate much better code that passing
> a structure by reference.

I've said it before, and now I'm going to say it again more forcefully:

This obsession with perfect machine code in every situation, regardless 
of whether it's shown up in benchmarks or profiles, regardless of what 
it does to the readability of the C code that we humans work with, has 
to stop.

Has. To. Stop. Full stop.

We have to be thinking about the people who come after us and have to 
read and maintain this stuff. Linux should still be in use 50, 100 years 
from now, and if it's not it's because we _fucked up_, and in software 
the way you fuck up is by writing code no one can understand - by 
writing code that people become afraid to touch without breaking it.

This happens, routinely, and it's _painful_ when it does.

A big learning experience for me when I was a much younger engineer, 
freshly starting at Google, was working next to a bunch of guys who were 
all chasing and fixing bugs in ext4 - and they weren't exactly enjoying 
it. bcache uncovered one or two of them too, and I got to debug that and 
then had to argue that it wasn't a bug in bcache (we were calling 
bio->bi_endio in process context, which uncovered a locking bug in 
ext4). The codebase had become a mess that they were too scared to 
refactor, in part because there were too many options that were 
impossible to test - my big lesson from that is that the code you're 
scared to refactor, that's the code that needs it the most.

And I could name some very senior kernel people who write code that's 
too brittle in the name of chasing performance - in fact I will name 
one, because I know he won't take it personally: the writeback 
throttling code that Jens wrote was buggy for _ages_ and at least one of 
my users was regularly tripping over it and I couldn't make out what the 
hell that code was trying to do, and not for lack of trying.

Other code nightmares:
  - The old O_DIRECT code, which was a huge performance sink but no one 
could touch it without breaking something (I spent months on a beautiful 
refactoring that cut it in half by LOC and improved performance 
drastically, but I couldn't get it to completely pass xfstests. That 
sucked).
  - The old generic_file_buffered_read(), which was a 250 line monster 
filled with gotos - all in the name of performance, mind you - that 
people barely touched, and when people absolutely had to they'd do so in 
the most minimal way possible that ended up just adding to the mess 
(e.g. the IOCB_NOWAIT changes) - up until I finally cut it apart, then 
curiously right after that a ton more patches landed. It's almost like 
cleaning stuff up and prioritizing readability makes it easier for 
people to work on.
  - merge_bvec_fn was also quite the tale - also done in the name of 
performance, noticing a theme here?

I like to write fast code too. Of course I do, I'm a kernel engineer, I 
wouldn't be a real one if I didn't.

But that means writing code that is _optimizable_, which means writing 
code that's easy to go back and modify and change when profiling 
discovers something. Which means keeping things as simple as is 
reasonably possible, and prioritizing good data types and abstractions 
and structure.

When I'm first writing code and thinking about performance, here's what 
I think about:
  - algorithmic complexity
  - good data structures (vectors instead of lists, where it matters - 
it often doesn't)
  - memory layout: keep pointer indirection at an absolute minimum
    memory layout matters
  - locking

And honestly, not much else. Because on modern machines, with the type 
of code we feed our CPUs running in the kernel, memory layout and 
locking are what matter and not much else. Not shaving every cycle.

I already demonstrated this with actual numbers in the printbuf 
discussion, to Rasmus - yes, the compiler constantly reloading is a 
shame and it shows up in the text size, and perhaps we'll want to 
revisit the -fno-strict-aliasing thing someday (I'm fully in agreement 
with Linus on why he hates strict aliasing, it was something the 
compiler people sprung on everyone else without discussion or a clear 
escape hatch or _tooling to deal with existing codebases_ but the 
tooling has improved since thing, it might not be complete insanity anymore)

...but if you look at the actual microbenchmarks I showed Rasmus? It 
turns out to not affect performance pretty much at all, it's in the 
noise. Waiting on loads from memory is what matters to us, and not much 
else.
Steven Rostedt July 19, 2022, 11:15 p.m. UTC | #25
On Sun, 19 Jun 2022 20:41:59 -0400
Kent Overstreet <kent.overstreet@gmail.com> wrote:

> Core idea: Wouldn't it be nice if we had a common data structure and calling
> convention for outputting strings?

Because seq_buf gives us this already, the cover letter really just needs
to state exactly what the benefit is to replace seq_buf with printbuf (and
why seq_buf can not be simply extended to do some extra features).

I just applied your series and ran the tracing selftests and several of
them failed.

 # cd tools/testing/selftests/ftrace/
 # ./ftracetest

This means that this is not a simple replacement and that there's going to
be regressions with this change. The question is, is the added benefits of
doing the change greater than the fallout of the regressions?

-- Steve
Kent Overstreet July 19, 2022, 11:43 p.m. UTC | #26
On 7/19/22 19:15, Steven Rostedt wrote:
> On Sun, 19 Jun 2022 20:41:59 -0400
> Kent Overstreet <kent.overstreet@gmail.com> wrote:
> 
>> Core idea: Wouldn't it be nice if we had a common data structure and calling
>> convention for outputting strings?
> 
> Because seq_buf gives us this already, the cover letter really just needs
> to state exactly what the benefit is to replace seq_buf with printbuf (and
> why seq_buf can not be simply extended to do some extra features).

  - seq_buf has the wrong semantics on overflow for what vsnprintf needs.
  - seq_buf is somewhat unnecessarily coupled to tracing needs - the 
readpos member has nothing to do with outputting formatting strings, and 
some of the pretty-printers are tracing specific and don't really belong 
in a generic pretty-printing library.

And, when I tried to talk to you about changing seq_buf to be more 
suitable you didn't respond - you just dropped off the IRC discussion we 
were having.

> 
> I just applied your series and ran the tracing selftests and several of
> them failed.
> 
>   # cd tools/testing/selftests/ftrace/
>   # ./ftracetest

Thank you for telling me where to find the tests. It would've saved us 
some back and forth (and I could've gotten on this sooner) if you'd 
responded when I asked before.

It may seem like the perfectly natural place to look to you - who works 
on the code - but to someone who works on a variety of subsystems, each 
of which puts their test code (if they have any!) in a different place, 
it wasn't.

However, when I enabled all the tracing kernel config options, your 
tests are now failing to run at all with:

db_root: cannot open: /etc/target

So now I've got to debug your tests, too. Gah.
Steven Rostedt July 20, 2022, 12:05 a.m. UTC | #27
On Tue, 19 Jul 2022 19:43:46 -0400
Kent Overstreet <kent.overstreet@gmail.com> wrote:

> On 7/19/22 19:15, Steven Rostedt wrote:
> > On Sun, 19 Jun 2022 20:41:59 -0400
> > Kent Overstreet <kent.overstreet@gmail.com> wrote:
> >   
> >> Core idea: Wouldn't it be nice if we had a common data structure and calling
> >> convention for outputting strings?  
> > 
> > Because seq_buf gives us this already, the cover letter really just needs
> > to state exactly what the benefit is to replace seq_buf with printbuf (and
> > why seq_buf can not be simply extended to do some extra features).  
> 
>   - seq_buf has the wrong semantics on overflow for what vsnprintf needs.

More specific please.

>   - seq_buf is somewhat unnecessarily coupled to tracing needs - the 
> readpos member has nothing to do with outputting formatting strings, and 
> some of the pretty-printers are tracing specific and don't really belong 
> in a generic pretty-printing library.

That's not really a benefit between the two.

> 
> And, when I tried to talk to you about changing seq_buf to be more 
> suitable you didn't respond - you just dropped off the IRC discussion we 
> were having.

I told you I've been swamped and this wasn't the best time for me. I
can't drop everything for you.

> 
> > 
> > I just applied your series and ran the tracing selftests and several of
> > them failed.
> > 
> >   # cd tools/testing/selftests/ftrace/
> >   # ./ftracetest  
> 
> Thank you for telling me where to find the tests. It would've saved us 
> some back and forth (and I could've gotten on this sooner) if you'd 
> responded when I asked before.

It's in kernel selftests, they are not hard to find.

> 
> It may seem like the perfectly natural place to look to you - who works 
> on the code - but to someone who works on a variety of subsystems, each 
> of which puts their test code (if they have any!) in a different place, 
> it wasn't.

All the subsystems tests should be in tools/testing/selftests this
isn't just where tracing goes. It's the standard place.

> 
> However, when I enabled all the tracing kernel config options, your 
> tests are now failing to run at all with:
> 
> db_root: cannot open: /etc/target
> 
> So now I've got to debug your tests, too. Gah.

WTF?

-- Steve
Kent Overstreet July 20, 2022, 12:17 a.m. UTC | #28
On 7/19/22 20:05, Steven Rostedt wrote:
> On Tue, 19 Jul 2022 19:43:46 -0400
> Kent Overstreet <kent.overstreet@gmail.com> wrote:
> 
>> On 7/19/22 19:15, Steven Rostedt wrote:
>>> On Sun, 19 Jun 2022 20:41:59 -0400
>>> Kent Overstreet <kent.overstreet@gmail.com> wrote:
>>>    
>>>> Core idea: Wouldn't it be nice if we had a common data structure and calling
>>>> convention for outputting strings?
>>>
>>> Because seq_buf gives us this already, the cover letter really just needs
>>> to state exactly what the benefit is to replace seq_buf with printbuf (and
>>> why seq_buf can not be simply extended to do some extra features).
>>
>>    - seq_buf has the wrong semantics on overflow for what vsnprintf needs.
> 
> More specific please.

Steve, look at the man page for snprintf if you don't see what I mean. 
This discussion has become entirely too tedious, and your _only_ 
contribution to the discussion on pretty-printers has been "why isn't 
this using this thing I made?".

You haven't been contributing to the discussion, you haven't been 
helping figure out what the APIs, helpers, data structures should look 
like, IOW _actually_ building something that could serve as a low level 
string formatting library.

I get that you're busy - but look, we all are, and this patch series has 
already been set back what, a month and a half while I was waiting on you.

I've got the tests now, I'll CC you when v5 is posted.
Steven Rostedt July 20, 2022, 1:11 a.m. UTC | #29
On Tue, 19 Jul 2022 20:17:45 -0400
Kent Overstreet <kent.overstreet@gmail.com> wrote:

> > More specific please.  
> 
> Steve, look at the man page for snprintf if you don't see what I mean. 
> This discussion has become entirely too tedious, and your _only_ 
> contribution to the discussion on pretty-printers has been "why isn't 
> this using this thing I made?".

No, my response is, why should we replace something that is working
just fine?

The burden is on you. For this to get accepted you have to show why a
risk of regression in the Linux kernel is worth the update. We don't
just say "hey this is better, take it!". That's not how this works.
There needs to be real needs to be met.

> 
> You haven't been contributing to the discussion, you haven't been 
> helping figure out what the APIs, helpers, data structures should look 
> like, IOW _actually_ building something that could serve as a low level 
> string formatting library.

What exactly is it that is better. In stead of yelling about what I
haven't done, tell me what you plan on doing that will make *our* lives
better. Code is "pulled" not "pushed". If all you can do is push, then
you are going to end up being quite disappointed.

What exactly is the use case here?

> 
> I get that you're busy - but look, we all are, and this patch series has 
> already been set back what, a month and a half while I was waiting on you.

Sorry, but I did warn you. I did start a new job and then I had several
conferences that I was writing code to present. That is, the things I
was talking about wasn't even finished yet. So those were very *hard*
deadlines (on top of my day job). I told you upfront that it may be
months before I can look at it. I was fully transparent.

> 
> I've got the tests now, I'll CC you when v5 is posted.

And I expect you to have an explanation on why this is worth the effort.

-- Steve
Kent Overstreet July 20, 2022, 1:31 a.m. UTC | #30
On 7/19/22 21:11, Steven Rostedt wrote:
> On Tue, 19 Jul 2022 20:17:45 -0400
> Kent Overstreet <kent.overstreet@gmail.com> wrote:
> 
>>> More specific please.
>>
>> Steve, look at the man page for snprintf if you don't see what I mean.
>> This discussion has become entirely too tedious, and your _only_
>> contribution to the discussion on pretty-printers has been "why isn't
>> this using this thing I made?".
> 
> No, my response is, why should we replace something that is working
> just fine?
For you. For your code.

Look, Steve, I've tried to work with you. And I've given you reasons why 
seq_buf doesn't work for vsprintf.c, and more general cases. You have 
not responded _at all_ with technical reasons or discussion, all you've 
done from the very start is lecture me on process.

And, to be blunt, the time to have the printbuf vs. seq_buf discussion 
was months ago. I tried to start that discussion with you, and you 
ghosted on IRC when I started talking about the things in seq_buf that 
would have to change.

Like I said, I'll CC you when v5 is posted.
Steven Rostedt July 20, 2022, 1:37 a.m. UTC | #31
On Tue, 19 Jul 2022 21:31:49 -0400
Kent Overstreet <kent.overstreet@gmail.com> wrote:

> > No, my response is, why should we replace something that is working
> > just fine?  
> For you. For your code.

For the current working kernel.

> 
> Look, Steve, I've tried to work with you. And I've given you reasons why 
> seq_buf doesn't work for vsprintf.c, and more general cases. You have 

Please post the lore links, I'll go back and read them.

> not responded _at all_ with technical reasons or discussion, all you've 
> done from the very start is lecture me on process.

That's because process *is* the way things get into upstream. I guess
you fail to understand that.

> 
> And, to be blunt, the time to have the printbuf vs. seq_buf discussion 
> was months ago. I tried to start that discussion with you, and you 
> ghosted on IRC when I started talking about the things in seq_buf that 
> would have to change.

Look, that was when I was traveling. And when I'm traveling I pretty
much do not respond to IRC.

> 
> Like I said, I'll CC you when v5 is posted.

OK.

-- Steve