From 1d0082c7f419eb6c6e04ae177fad01b2747f4b38 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:04:35 -0700 Subject: [PATCH 1/5] Source generator: avoid performance issue with syntax list containing many items --- .../LoggerMessageGeneratorParserTests.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs index 3cbcc2e539e02..68c33ad2a6996 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs @@ -742,6 +742,40 @@ partial class C Assert.Equal(21, generatedSources[0].SourceText.Lines.Count); } + [Fact] + public static void SyntaxListWithManyItems() + { + const int nItems = 200000; + var builder = new System.Text.StringBuilder(); + builder.AppendLine( + """ + using Microsoft.Extensions.Logging; + class Program + { + [LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = "M1")] + static partial void M1(ILogger logger) + { + """); + builder.AppendLine(" int[] values = new[] { "); + for (int i = 0; i < nItems; i++) + { + builder.Append("0, "); + } + builder.AppendLine("};"); + builder.AppendLine("}"); + builder.AppendLine("}"); + + string source = builder.ToString(); + Compilation compilation = CompilationHelper.CreateCompilation(source); + LoggerMessageGenerator generator = new LoggerMessageGenerator(); + + (ImmutableArray diagnostics, _) = + RoslynTestUtils.RunGenerator(compilation, generator); + + Assert.Single(diagnostics); + Assert.Equal(DiagnosticDescriptors.LoggingMethodHasBody.Id, diagnostics[0].Id); + } + private static async Task> RunGenerator( string code, bool wrap = true, From a8355e01350b320602833cb0ce7b3b77f3c5123c Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:22:25 -0700 Subject: [PATCH 2/5] Iterate through child list forward first --- .../SyntaxValueProvider_ForAttributeWithSimpleName.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libraries/Common/src/Roslyn/SyntaxValueProvider_ForAttributeWithSimpleName.cs b/src/libraries/Common/src/Roslyn/SyntaxValueProvider_ForAttributeWithSimpleName.cs index 3e6f947065a1d..a85f2b583aa57 100644 --- a/src/libraries/Common/src/Roslyn/SyntaxValueProvider_ForAttributeWithSimpleName.cs +++ b/src/libraries/Common/src/Roslyn/SyntaxValueProvider_ForAttributeWithSimpleName.cs @@ -334,7 +334,15 @@ void processMember( // For any other node, just keep recursing deeper to see if we can find an attribute. Note: we cannot // terminate the search anywhere as attributes may be found on things like local functions, and that // means having to dive deep into statements and expressions. - foreach (var child in node.ChildNodesAndTokens().Reverse()) + var childNodesAndTokens = node.ChildNodesAndTokens(); + + // Avoid performance issue (in .NET 7 and earlier) iterating the child list in reverse + // by iterating forward first, to populate the cache. + foreach (var childNode in childNodesAndTokens) + { + } + + foreach (var child in childNodesAndTokens.Reverse()) { if (child.IsNode) nodeStack.Append(child.AsNode()!); From 6a711de0694362c36a58c1a4971bee400a9ea9b6 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Wed, 15 Mar 2023 21:36:26 -0700 Subject: [PATCH 3/5] Update comment --- .../Roslyn/SyntaxValueProvider_ForAttributeWithSimpleName.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/Roslyn/SyntaxValueProvider_ForAttributeWithSimpleName.cs b/src/libraries/Common/src/Roslyn/SyntaxValueProvider_ForAttributeWithSimpleName.cs index a85f2b583aa57..6ecbc1b35baaa 100644 --- a/src/libraries/Common/src/Roslyn/SyntaxValueProvider_ForAttributeWithSimpleName.cs +++ b/src/libraries/Common/src/Roslyn/SyntaxValueProvider_ForAttributeWithSimpleName.cs @@ -336,8 +336,9 @@ void processMember( // means having to dive deep into statements and expressions. var childNodesAndTokens = node.ChildNodesAndTokens(); - // Avoid performance issue (in .NET 7 and earlier) iterating the child list in reverse - // by iterating forward first, to populate the cache. + // Avoid performance issue in ChildSyntaxList when iterating the child list in reverse + // (see https://github.com/dotnet/roslyn/issues/66475) by iterating forward first to + // ensure child nodes are realized. foreach (var childNode in childNodesAndTokens) { } From 4e4a1ae27693e8a6781b86778e1b7dd719053331 Mon Sep 17 00:00:00 2001 From: Eric StJohn Date: Tue, 21 Mar 2023 14:17:49 -0700 Subject: [PATCH 4/5] Enable Json and Logging in servicing --- .../src/Microsoft.Extensions.Logging.Abstractions.csproj | 3 ++- src/libraries/System.Text.Json/src/System.Text.Json.csproj | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj index 15ea95cef4256..51eab127e40e0 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj @@ -17,7 +17,8 @@ Microsoft.Extensions.Logging.LogLevel Microsoft.Extensions.Logging.Logger<T> Microsoft.Extensions.Logging.LoggerMessage Microsoft.Extensions.Logging.Abstractions.NullLogger - 3 + true + 4 diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 693de7b106f78..ff1de810a35d4 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -9,7 +9,8 @@ enable true true - 7 + true + 8 Provides high-performance and low-allocating types that serialize objects to JavaScript Object Notation (JSON) text and deserialize JSON text to objects, with UTF-8 support built-in. Also provides types to read and write JSON text encoded as UTF-8, and to create an in-memory document object model (DOM), that is read-only, for random access of the JSON elements within a structured view of the data. Commonly Used Types: From b96c4863dd64adf89922ad01b9c2f5ed70bee20d Mon Sep 17 00:00:00 2001 From: Eric StJohn Date: Tue, 21 Mar 2023 14:52:43 -0700 Subject: [PATCH 5/5] Fix multi-line string literal in C# 10 --- .../LoggerMessageGeneratorParserTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs index 68c33ad2a6996..228a386c834af 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs @@ -748,14 +748,14 @@ public static void SyntaxListWithManyItems() const int nItems = 200000; var builder = new System.Text.StringBuilder(); builder.AppendLine( - """ + @" using Microsoft.Extensions.Logging; class Program { - [LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = "M1")] + [LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = ""M1"")] static partial void M1(ILogger logger) { - """); + "); builder.AppendLine(" int[] values = new[] { "); for (int i = 0; i < nItems; i++) {