Review: std.logger
Johannes Pfau via Digitalmars-d
digitalmars-d at puremagic.com
Fri Jul 25 00:49:38 PDT 2014
Am Fri, 25 Jul 2014 01:23:21 +0000
schrieb "Jakob Ovrum" <jakobovrum at gmail.com>:
> On Thursday, 24 July 2014 at 23:40:56 UTC, Jakob Ovrum wrote:
> > How often have you seen a formatted log message logged in a
> > loop? I'd wager that happens quite often. Using `format` is a
> > no-go as it completely thrashes the GC, it needs to use
> > `formattedWrite` to write directly to the underlying buffer
> > (such as a file).
>
> To eloborate on this: using `format` like std.logger currently
> does, for short-lived strings that are consumed and discared
> almost immediately in a higher stack frame, is extremely
> inefficient as every string needs at least one heap memory
> allocation (though `format` can easily do *multiple* in one
> call). It's a good way to quickly thrash and fragment the GC
> heap, putting an extreme amount of stress on the collector.
>
> Even C has fprintf. If we don't provide efficient formatted
> writing, people will not use our abstractions.
>
> The solution is to use `formattedWrite` for custom allocation
> behaviour. When I've used `formattedWrite` for this kind of
> problem before, it has generally come down to the following
> patterns; let's assume the underlying sink is a file:
>
> * One solution is to use `formattedWrite` to write to the file
> directly. Of course, Logger doesn't provide an interface for
> writing partial log messages, or writing log messages in chunks,
> so this would require modifying the basic API. Also,
> `formattedWrite` doesn't guarantee any minimum chunk size, so in
> the worst case, it might result in one write operation per
> character, which is very inefficient.
>
> * Another solution is to use `formattedWrite` to write to a
> stack-allocated character buffer, then subsequently pass it to
> `writeLogMsg`. This is a leaky abstraction because it puts an
> arbitrary upper limit on how long log entries can be. A practical
> compromise is to revert to a heap allocation for entries that
> don't fit in the stack buffer, but we can do better;
>
> * The best solution is a hybrid one. Use `formattedWrite` to
> write to a stack-allocated buffer, then whenever it's full, write
> the contents of the buffer to the underlying sink (this is easily
> doable by passing a delegate to `formattedWrite` that sees the
> stack buffer as an upvalue). Yes, this does require modifying the
> basic logger API to support partial writes, but it gives us
> optimal performance.
>
> The last solution gives us no dynamic memory allocations unless
> an exception is thrown, while still minimizing the number of
> writes to the underlying sink, which is important when writes can
> be expensive, such as writes to a file or a socket.
https://github.com/burner/logger/pull/9
More information about the Digitalmars-d
mailing list