Skip to content

Avoid boxing of TState #241

@jods4

Description

@jods4

[LoggerMessage] generate a struct state, in an attempt to reduce allocations.

For this to be meaningful, state should not be boxed, but it is in AsLoggableValue:

https://github.com/serilog/serilog-extensions-logging/blob/dev/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLogger.cs#L168-L174

// Current version:
static object? AsLoggableValue<TState>(TState state, Func<TState, Exception?, string>? formatter)
{
    object? stateObj = state;  // <- always boxing!!
    if (formatter != null)
        stateObj = formatter(state, null);
    return stateObj;
}

// Suggested:
static object? AsLoggableValue<TState>(TState state, Func<TState, Exception?, string>? formatter)
{
    object? stateObj = null;
    if (formatter != null)
        stateObj = formatter(state, null);
    return stateObj ?? state; // <- boxed only when needed
}

Note that in the case of [LoggerMessage] a formatter is always provided (to create the formatted string without boxing of its parameters), so stateObj will never be null and state will not be boxed.

For the curious mind, in PrepareWrite() the code if (state is IEnumerable<..> structure) does not result in boxing because JIT compiles each struct TState separately and statically optimizes these conditions and interfaces, as can be seen in this disassembly (call S.GetEnumerator):
https://sharplab.io/#v2:EYLgtghglgdgNAFxBAzmAPgAQEwEYCwAUJgAwAEmuAdAMID2ANgwKYDGCUdMKA3EaRVwAWPoSIoEAJwCu7MgGUyIQQGYAPAGlmATwBqEBtOYAFaJLWUScMnWAArNggB8TogG8iZLxRVkAkgCiMNJgzJIQCHTmWnoGRqZQ5pbWtg7sLmQA4swIQSFhEVEAFACUnt4ehN7VZAgAFpJ0AO5kMMwtAHJ0CH5gAA4soTAIzAAmAQAerMx9HFylotUAvkTlXoHBoeGRkqpU2bmbBTula2SVNd71jS1tnd29A8xDI+NTM3MwC2crhL/8vhwZBo5zOAG15HUIJI+gAZCDAKgAJWkwygoSoACkoAhsm1JFBWEUENo+sw6AAzIryEolAC6Z0wgNwADYKEIyABZNQAFScRR5ZAmJVBVRqUApZCKEzIUBQqk0On0hhMZgsuCsNnsjgyzDKYuqF0u3gpUWYEFYdSlADdoWQANbWvqymBkPVnS5G401SgATiKjr6VBiJUW3rIv0uke8vyWQA==

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions