Skip to content

Commit

Permalink
Avoid string/StringBuilder/char[] allocation in LogValuesFormatter's …
Browse files Browse the repository at this point in the history
…ctor (#44746)

This is producing thousands of allocations at ASP.NET startup, due to almost 1000 call sites to LoggerMessage.Define.
  • Loading branch information
stephentoub authored Nov 17, 2020
1 parent f6bfec0 commit 69d6127
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ internal class LogValuesFormatter
private readonly string _format;
private readonly List<string> _valueNames = new List<string>();

// NOTE: If this assembly ever builds for netcoreapp, the below code should change to:
// - Be annotated as [SkipLocalsInit] to avoid zero'ing the stackalloc'd char span
// - Format _valueNames.Count directly into a span

public LogValuesFormatter(string format)
{
if (format == null)
Expand All @@ -29,35 +33,42 @@ public LogValuesFormatter(string format)

OriginalFormat = format;

var sb = new StringBuilder();
var vsb = new ValueStringBuilder(stackalloc char[256]);
int scanIndex = 0;
int endIndex = format.Length;

while (scanIndex < endIndex)
{
int openBraceIndex = FindBraceIndex(format, '{', scanIndex, endIndex);
if (scanIndex == 0 && openBraceIndex == endIndex)
{
// No holes found.
_format = format;
return;
}

int closeBraceIndex = FindBraceIndex(format, '}', openBraceIndex, endIndex);

if (closeBraceIndex == endIndex)
{
sb.Append(format, scanIndex, endIndex - scanIndex);
vsb.Append(format.AsSpan(scanIndex, endIndex - scanIndex));
scanIndex = endIndex;
}
else
{
// Format item syntax : { index[,alignment][ :formatString] }.
int formatDelimiterIndex = FindIndexOfAny(format, FormatDelimiters, openBraceIndex, closeBraceIndex);

sb.Append(format, scanIndex, openBraceIndex - scanIndex + 1);
sb.Append(_valueNames.Count.ToString(CultureInfo.InvariantCulture));
vsb.Append(format.AsSpan(scanIndex, openBraceIndex - scanIndex + 1));
vsb.Append(_valueNames.Count.ToString());
_valueNames.Add(format.Substring(openBraceIndex + 1, formatDelimiterIndex - openBraceIndex - 1));
sb.Append(format, formatDelimiterIndex, closeBraceIndex - formatDelimiterIndex + 1);
vsb.Append(format.AsSpan(formatDelimiterIndex, closeBraceIndex - formatDelimiterIndex + 1));

scanIndex = closeBraceIndex + 1;
}
}

_format = sb.ToString();
_format = vsb.ToString();
}

public string OriginalFormat { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
<EnableDefaultItems>true</EnableDefaultItems>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
Expand All @@ -12,6 +13,13 @@
Link="Common\src\Extensions\Logging\NullExternalScopeProvider.cs" />
<Compile Include="$(CommonPath)Extensions\Logging\NullScope.cs"
Link="Common\src\Extensions\Logging\NullScope.cs" />
<Compile Include="$(CommonPath)System\Text\ValueStringBuilder.cs"
Link="Common\System\Text\ValueStringBuilder.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Buffers" Version="$(SystemBuffersVersion)" />
<PackageReference Include="System.Memory" Version="$(SystemMemoryVersion)" />
</ItemGroup>

</Project>

0 comments on commit 69d6127

Please sign in to comment.