This changeset renders and flushes log messages in a dedicated thread, preventing the originating thread from blocking (or failing) on fwrite, fflush, or the various string manipulations done on log messages. Originating threads push log messages into a buffer that is continually flushed.
Benchmarks live in the comments below.
Open questions:
- Do we want this behavior by default? I think so, given that it seems safer and more performant than doing log processing synchronously with Important Stuff.
- Do we want to allow an opt-out configuration option that makes log processing synchronous again?
- The ring buffer implementation allows either overwriting existing data or blocking when at full capacity. In the case of logging, I’ve set it to block and wait for capacity instead of dropping messages. Does this seem right?
Future work:
- Reconcile this change with #13168 in case that’s merged first (I have a patch)
- Even when logging is disabled, buffer debug logs without flushing and then handle SIGSEGV et al by flushing the log buffer (idea being to give the user crash diagnostics).