Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

string -> ROM #101

Merged
merged 19 commits into from
Jan 20, 2021
Merged

string -> ROM #101

merged 19 commits into from
Jan 20, 2021

Conversation

sungam3r
Copy link
Member

@sungam3r sungam3r commented Jan 10, 2021

This PR brings System.Memory bits into lexer and parser. Also redesigned to reduce the number of memory allocations. Lexer has stopped allocating memory on the heap at all (with rare exceptions for escaped symbols handling). The parser still allocates memory, since it builds AST, but already noticeably less. Benchmarks, however, do not show the unconditional leadership of the new version in terms of execution time. I have noticed that my results vary from run to run.

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.16299.726 (1709/FallCreatorsUpdate/Redstone3)
Intel Core i7 CPU 920 2.67GHz (Nehalem), 1 CPU, 8 logical and 4 physical cores
Frequency=2607423 Hz, Resolution=383.5204 ns, Timer=TSC
.NET Core SDK=5.0.101
  [Host]     : .NET Core 3.1.10 (CoreCLR 4.700.20.51601, CoreFX 4.700.20.51901), X64 RyuJIT
  DefaultJob : .NET Core 3.1.10 (CoreCLR 4.700.20.51601, CoreFX 4.700.20.51901), X64 RyuJIT

Lexer before/after

Method name Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Lex escapes 99,603.5 ns 64.93 ns 60.74 ns 3.9063 - - 16384 B
Lex github 4,346,489.0 ns 3,373.87 ns 3,155.92 ns 179.6875 - - 783024 B
Lex hero 659.9 ns 0.77 ns 0.65 ns 0.0362 - - 152 B
Lex introspection 22,313.3 ns 15.03 ns 13.33 ns 0.8240 - - 3560 B
Lex kitchen 18,486.7 ns 15.56 ns 14.56 ns 0.6409 - - 2736 B
Lex params 11,780.0 ns 13.36 ns 12.50 ns 0.7629 - - 3248 B
Method name Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Lex escapes 89,692.2 ns 122.49 ns 114.58 ns 1.7090 - - 7344 B
Lex github 4,406,522.9 ns 1,651.93 ns 1,289.72 ns - - - 4 B ?
Lex hero 788.0 ns 1.49 ns 1.39 ns - - - -
Lex introspection 23,013.3 ns 20.99 ns 19.63 ns - - - -
Lex kitchen 20,923.3 ns 2.84 ns 2.65 ns - - - -
Lex params 16,792.0 ns 8.95 ns 8.37 ns - - - -

Parser before/after

Method name Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Parse escapes 100.903 μs 0.1188 μs 0.1053 μs 4.0283 0.1221 - 17312 B
Parse github 9,620.084 μs 12.3197 μs 11.5239 μs 390.6250 187.5000 - 2492766 B
Parse hero 1.355 μs 0.0011 μs 0.0009 μs 0.2308 - - 968 B
Parse introspection 35.247 μs 0.0318 μs 0.0297 μs 3.9063 0.0610 - 16432 B
Parse kitchen 29.227 μs 0.0204 μs 0.0181 μs 3.0823 0.0305 - 12960 B
Parse params 18.617 μs 0.0109 μs 0.0097 μs 2.3499 0.0305 - 9944 B
Method name Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Parse escapes 83.919 μs 0.0319 μs 0.0266 μs 1.9531 - - 8288 B
Parse github 6,264.506 μs 28.3585 μs 25.1391 μs 296.8750 148.4375 - 1824992 B
Parse hero 1.421 μs 0.0013 μs 0.0012 μs 0.1965 - - 824 B
Parse introspection 33.082 μs 0.0199 μs 0.0186 μs 3.1738 - - 13512 B
Parse kitchen 29.282 μs 0.0267 μs 0.0236 μs 2.5330 - - 10696 B
Parse params 22.740 μs 0.0215 μs 0.0191 μs 1.5564 - - 6592 B

@Shane32 Please try run LexerBenchmark and ParserBenchmark.

# Conflicts:
#	src/GraphQLParser.Benchmarks/Benchmarks/LexerBenchmark.cs
#	src/GraphQLParser.Benchmarks/Benchmarks/ParserBenchmark.cs
@sungam3r sungam3r added the BREAKING Breaking changes in either public API or runtime behavior label Jan 10, 2021
@github-actions github-actions bot added documentation An issue or pull request regarding documentation improvements performance test Pull request that adds new or changes existing tests labels Jan 10, 2021
@sungam3r
Copy link
Member Author

sungam3r commented Jan 10, 2021

It should also be noted that this PR opens the way for further optimizations at the GraphQL.NET level. We can now reuse the same portions of the pooled memory over and over. Of course this will require changes to GraphQL.NET because it manipulates strings from the parser. Now there are no strings, only ROM. In principle, it is feasible to achieve not spawning strings at all. Public API hasn't changed much. After that, we can evaluate the final performance

src/GraphQLParser/Lexer.cs Outdated Show resolved Hide resolved
@Shane32
Copy link
Member

Shane32 commented Jan 10, 2021

develop

Method name Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Lex escapes 49,942.7 ns 146.38 ns 136.93 ns 2.5635 0.0610 - 16385 B
Lex github 2,223,245.5 ns 2,710.56 ns 2,402.84 ns 121.0938 - - 783027 B
Lex hero 325.9 ns 4.64 ns 4.34 ns 0.0238 - - 152 B
Lex introspection 11,655.1 ns 20.61 ns 18.27 ns 0.5646 - - 3560 B
Lex kitchen 9,004.7 ns 29.17 ns 27.29 ns 0.4272 - - 2736 B
Lex params 5,791.0 ns 14.21 ns 12.60 ns 0.5112 - - 3248 B
Method name Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Parse escapes 49,589.0 ns 93.14 ns 82.57 ns 2.7466 0.1831 - 17312 B
Parse github 4,808,853.2 ns 25,318.60 ns 23,683.03 ns 390.6250 195.3125 - 2492666 B
Parse hero 659.3 ns 1.94 ns 1.81 ns 0.1535 0.0010 - 968 B
Parse introspection 18,018.1 ns 58.53 ns 54.75 ns 2.5940 0.2441 - 16432 B
Parse kitchen 13,738.3 ns 24.74 ns 23.15 ns 2.0599 0.1678 - 12960 B
Parse params 9,047.5 ns 33.89 ns 31.70 ns 1.5717 0.0763 - 9944 B

rom

Method name Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Lex escapes 40,819.0 ns 103.86 ns 92.07 ns 1.1597 - - 7344 B
Lex github 1,672,438.0 ns 3,247.28 ns 3,037.51 ns - - - 1 B
Lex hero 313.1 ns 0.81 ns 0.72 ns - - - -
Lex introspection 8,533.6 ns 36.76 ns 30.70 ns - - - -
Lex kitchen 7,602.5 ns 13.55 ns 12.68 ns - - - -
Lex params 7,300.1 ns 11.00 ns 9.75 ns - - - -
Method name Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Parse escapes 42,115.1 ns 127.52 ns 119.28 ns 1.2817 - - 8288 B
Parse github 3,204,992.1 ns 6,662.95 ns 6,232.53 ns 289.0625 144.5313 - 1825017 B
Parse hero 753.2 ns 2.06 ns 1.92 ns 0.1307 - - 824 B
Parse introspection 17,010.6 ns 48.40 ns 45.28 ns 2.1362 0.0916 - 13512 B
Parse kitchen 13,869.9 ns 32.25 ns 28.59 ns 1.6937 0.0610 - 10696 B
Parse params 11,333.2 ns 28.86 ns 27.00 ns 1.0376 0.0153 - 6592 B

@sungam3r
Copy link
Member Author

Thanks. I updated results in my initial comment after making Lexer and Parser static.

@Shane32
Copy link
Member

Shane32 commented Jan 10, 2021

Thanks. I updated results in my initial comment after making Lexer and Parser static.

Ditto

@Shane32
Copy link
Member

Shane32 commented Jan 10, 2021

I looked through the code once. Is it ready to be merged or are you still working on it? I would like to take another look. Also, I think we should not publish this to nuget until 4.0 is ready to be released, as we may find more changes we want to make. We can reference the development build via nuget from GraphQL.NET

sungam3r and others added 2 commits January 11, 2021 09:28
Co-authored-by: Shane Krueger <shane@acdmail.com>
Co-authored-by: Shane Krueger <shane@acdmail.com>
@sungam3r
Copy link
Member Author

Finally! I was able to achieve a noticeable improvement by throw helpers to allow code inlining. I updated results in my initial comment.

@sungam3r
Copy link
Member Author

Also interesting dotnet/runtime#13347

# Conflicts:
#	src/GraphQLParser.ApiTests/ApiApprovalTests.cs
#	src/GraphQLParser.ApiTests/GraphQL-Parser.approved.txt
#	src/GraphQLParser/AST/GraphQLDocument.cs
#	src/GraphQLParser/LexerContext.cs
#	src/GraphQLParser/Parser.cs
#	src/GraphQLParser/ParserContext.cs
# Conflicts:
#	src/GraphQLParser.ApiTests/GraphQL-Parser.approved.txt
#	src/GraphQLParser/Parser.cs
#	src/GraphQLParser/ParserContext.cs
src/GraphQLParser/Parser.cs Outdated Show resolved Hide resolved
private List<GraphQLNamedType>? ParseImplementsInterfaces()
{
List<GraphQLNamedType>? types = null;
if (_currentToken.Value?.Equals("implements") == true)
if (_currentToken.Value == "implements")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Shane32 With new syntax sugar all conditions look better.

}

/// <inheritdoc/>
public override int GetHashCode()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taken from string implementation.

@sungam3r sungam3r mentioned this pull request Jan 18, 2021
sungam3r and others added 2 commits January 20, 2021 22:49
Co-authored-by: Shane Krueger <shane@acdmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BREAKING Breaking changes in either public API or runtime behavior documentation An issue or pull request regarding documentation improvements performance test Pull request that adds new or changes existing tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants