mbox series

[RFC,v5,00/28] dynamic debug diet plan

Message ID 20210511185057.3815777-1-jim.cromie@gmail.com (mailing list archive)
Headers show
Series dynamic debug diet plan | expand


Jim Cromie May 11, 2021, 6:50 p.m. UTC
DYNAMIC_DEBUG has extra weight/memory in its data table/section; its
(module,filename,function) columns have ordered, repeating data
(90%,55%,45%), and is highly compressible (~110/300) with simple RLE.

On my i7 laptop, the compressible chunk is ~70kb, This patchset
prepares for compression, but doesn't try it; RFC.  Using that RLE
compression estimate, we could save ~45kb; Id hope for better with ZSTD.

Series Overview:

1st, split the struct _ddebug & __dyndbg elf section into 2, moving
compressible fields into their own section/array/block.  A temporary
site pointer connects the 2 halves of the composite callsite, it will
be obsoleted later, after we verify our replacement against it, we can
drop the .site pointer.

table change:
 from:	[ key,mod,func,filenm,fmt,ln,flg ]
 into:	[ key,fmt,ln,flg,site-> ]	[ mod,func,filenm ]

2nd, make the 'site' data optional.  The "module:function:line"
log-message prefix is fundamentally an optional decoration, if we can
do without it, we simplify codepath, and we could drop the storage in
those cases, possibly reducing memory footprint.

 into:	[ key,fmt,ln,flg,site->? ]  0
Then things get more interesting:

3rd, make kernel/module handle "__dyndbg_sites" ELF section (which was
added in 1) as is already done for "__dyndbg".

Hide/replace ->site with site_get/_put api
this will let us retrieve site info from compressed storage.

Add _index.
gives us the fixed offset from __dyndbg[N] to __dyndbg[0].

 into:	[ key,fmt,ln,flg,_index,site->? ]  0

Add table/header record-pair.
These 2 records are created into ".gnu.linkonce.dyndbg*" sections.
The linker script places these 2 sections in front of their respective
"__dyndbg*" sections.
So this header-pair becomes __dyndbg[0], __dyndbg_sites[0].
we can use __dyndbg[0]->site[N] to get the site info.

module.lds.h - insert ".gnu.linkonce.dyndbg*" sections into "__dyndbg*".
Without this, headers arent part of the sections that kernel/module loads.

validate ddebug_site_get() invariants.
prove that our indirection to ->site[N] is correct.
BUG_ON uses survived 0-day tests.
they go away with !SITE_CHK

    0: 	[ ...,_index,site-> ]		--->  0:[ ... ]
  ..N:  [ key,fmt,ln,flg,_index ]	      N:[ ... ]

specialize header from _ddebug, keep header.site, drop _ddebug.site
RFC: needs refinement, better type choices?

  recent revs passed 0day compile grind, including BUG_ONs
  I got one KASAN report, quick reproduction failed, none more recently
  memory footprint is same as master.

Whats Next ? Compression: RFC !!!

POC: could compress during __init, decompress on-demand.  Doing this
would give something to decompress, to build out that code.

ISTM Compression during build is best, but targets are unclear:
initrd, initramfs, cpio, FW-blob all seem suitable at some level, but
so does (ro) zram & zswap.  How should I think about this ?

Also, I understand that support exists for compressed elf sections, I
dunno if/how kernel uses it currently, which would considerably ease
this.  Builtin __dyndbg_site data is in .data, probably needs to be
moved to a separate elf section to get generic tool support for
compressed sections.

It would be nice if a compressed "__dyndbg_sites" elf section could be
loaded by unchanged kernel/module.c.  A magic number in the attached
memory block could distinguish it from the current elf block.  There
is room in the 2 header records for new private data; we could store
decompression contexts there while iterating thru a block.

Decompression - a few use-cases:

= for builtins, each loadable module:
1- stream, for `cat control` etc.
   these are 1 visit and forget
2- `module foo +mfp > control` - enable contiguous blocks w decorations
3- pr_debug - semi-random access - by (ptr - _index)
   [0-5k] for builtin pr-debugs, [0-20] for most loadable modules
   _index is 16 bit currently

Simplest, minimum-memory strategy is late-fetch; to wait until a
pr_debug is actually called, then check flags before fetching the
site-rec, and save it to a hash on modname+_index (and delete on -p).
Without the save, it works for (1) too.

The only downside with late-fetch is that during pr_debug, a 1st fetch
of site-info maybe cant come from io/zswap without locking/latency
concerns.  A forced-prefetch ala (2) with a new flag '!' could work
around this, but might look like a wart.

So thats it. I hope its clear and concise.

Jim Cromie (28):

trivial cleanup:
  dyndbg: avoid calling dyndbg_emit_prefix when it has no work
  dyndbg: drop uninformative vpr_info

split to 2 vectors of callsite:
  dyndbg: split struct _ddebug's display fields to new _ddebug_site
  dyndbg: __init iterate over __dyndbg & __dyndbg_site in parallel

make site info optional:
  dyndbg: refactor part of ddebug_change to ddebug_match_site
  dyndbg: accept null site in ddebug_match_site
  dyndbg: hoist ->site out of ddebug_match_site
  dyndbg: accept null site in ddebug_change
  dyndbg: accept null site in dynamic_emit_prefix
  dyndbg: accept null site in ddebug_proc_show
  dyndbg: refactor ddebug_alter_site out of ddebug_change
  dyndbg: allow deleting site info via control interface

  dyndbg+module: expose ddebug_sites to modules
  dyndbg: add ddebug_site(_get|_put) abstraction
  dyndbg: ddebug_add_module avoid adding empty modules
  dyndbg: add _index to struct _ddebug
  dyndbg: prevent build bugs via -DNO_DYNAMIC_DEBUG_TABLE
  dyndbg: RFC handle __dyndbg* sections in module.lds.h
  dyndbg: ddebug_add_module() handle headers.
  dyndbg: validate ddebug_site_get invariants
  dyndbg: fix NULL deref after deleting sites
  dyndbg: dont show header records in control
  dyndbg: make site pointer and checks on it optional (not quite)
  dyndbg: swap WARN_ON for BUG_ON see what 0-day says
  dyndbg: fixup protect header when deleting site
  dyndbg: unionize _ddebug*_headers with struct _ddebug*
  dyndbg: drop _ddebug.site pointer

 arch/arm/boot/compressed/Makefile     |   2 +
 arch/sparc/vdso/Makefile              |   2 +
 arch/x86/boot/compressed/Makefile     |   1 +
 arch/x86/entry/vdso/Makefile          |   3 +
 arch/x86/purgatory/Makefile           |   1 +
 drivers/firmware/efi/libstub/Makefile |   3 +-
 include/asm-generic/module.lds.h      |  12 +-
 include/asm-generic/vmlinux.lds.h     |  24 +-
 include/linux/dynamic_debug.h         | 135 ++++++++--
 kernel/module-internal.h              |   1 +
 kernel/module.c                       |   9 +-
 lib/dynamic_debug.c                   | 363 +++++++++++++++++++-------
 12 files changed, 437 insertions(+), 119 deletions(-)