-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Closed
Labels
Milestone
Description
Description
Today LoggerMessage.Define is a high performance logging API that aims to reduce the overhead of logging by pre-parsing format strings and parameters holes to log. Today the values are stored in a LogValues<T0,...,TN> struct to avoid boxing. We do all of this work only to eventually box these arguments and allocate an array to turn this into a string. We should avoid the object[] and the boxing here.
Regression?
No
Data
using System;
using Microsoft.Extensions.Logging;
namespace ConsoleApp105
{
class Program
{
static void Main(string[] args)
{
var callback = LoggerMessage.Define<int, int>(LogLevel.Information, new(0, "Event"), "This is a {Value} and a {Score}");
var logger = new Logger();
Console.WriteLine("Waiting");
Console.ReadLine();
for (int i = 0; i < 10000; i++)
{
callback(logger, 1, 0, null);
}
Console.WriteLine("Done");
Console.ReadLine();
}
public class Logger : ILogger
{
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var value = formatter(state, exception);
LogToSomeplace(value);
}
private void LogToSomeplace(string value)
{
}
}
}
}| Type | Allocations | Bytes | Average Size (Bytes) |
|---|---|---|---|
| - System.Int32 | 20,010 | 480,240 | 24 |
| - System.String | 12,115 | 957,270 | 79.02 |
When I add a 4 int parameters:
| Type | Allocations | Bytes | Average Size (Bytes) |
|---|---|---|---|
| - System.String | 12,119 | 1,217,518 | 100.46 |
| - System.Int32 | 40,010 | 960,240 | 24 |
| - System.Object[4] | 10,000 | 560,000 | 56 |
Analysis
We need to implement non-allocating formatting for these calls
runtime/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LogValuesFormatter.cs
Lines 158 to 189 in 89498d8
| internal string FormatWithOverwrite(object?[]? values) | |
| { | |
| if (values != null) | |
| { | |
| for (int i = 0; i < values.Length; i++) | |
| { | |
| values[i] = FormatArgument(values[i]); | |
| } | |
| } | |
| return string.Format(CultureInfo.InvariantCulture, _format, values ?? Array.Empty<object>()); | |
| } | |
| internal string Format() | |
| { | |
| return _format; | |
| } | |
| internal string Format(object? arg0) | |
| { | |
| return string.Format(CultureInfo.InvariantCulture, _format, FormatArgument(arg0)); | |
| } | |
| internal string Format(object? arg0, object? arg1) | |
| { | |
| return string.Format(CultureInfo.InvariantCulture, _format, FormatArgument(arg0), FormatArgument(arg1)); | |
| } | |
| internal string Format(object? arg0, object? arg1, object? arg2) | |
| { | |
| return string.Format(CultureInfo.InvariantCulture, _format, FormatArgument(arg0), FormatArgument(arg1), FormatArgument(arg2)); | |
| } |
hartmair