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

[AvTrace.cs] Use ReadOnlySpan<char>/Slice instead of String/Substring in AntiFormat #9361

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

h3xds1nz
Copy link

@h3xds1nz h3xds1nz commented Jul 5, 2024

Description

Improves performance of the AntiFormat function in AvTrace, reducing allocations and improving the overall performance up to 2 times in some cases. Also changes FormatChars from char[] to ReadOnlySpan<char>, occurrence I've missed in #9230.

Second commit features added documentation for the function. I've included some basic asserts at the Testing section.

Small strings within StringBuilder default capacity

Method Mean [ns] Error [ns] StdDev [ns] Gen0 Allocated [B]
PR__Edit 236.1 ns 4.75 ns 5.84 ns 0.0730 1224 B
Original 400.7 ns 8.04 ns 15.29 ns 0.1040 1744 B
Benchmark code
AntiFormat2("{aaaa}");
AntiFormat2("{aaaa}}");
AntiFormat2("{{aaaa}}");
AntiFormat2("{aa{{aa}}");
AntiFormat2("{aa{{aa}}ab}c}d");
AntiFormat2("aaaa}");
AntiFormat2("aaaa");
AntiFormat2("a{{{aaa");
AntiFormat2("a{{{aaa}}}");

Large strings, mostly without any replacements

Method Mean [ns] Error [ns] StdDev [ns] Gen0 Allocated [B]
PR__Edit 127.5 ns 1.29 ns 1.08 ns 0.0880 1472 B
Original 242.9 ns 4.87 ns 5.00 ns 0.1094 1832 B
Benchmark code
AntiFormat("aaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
AntiFormat("aaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
AntiFormat("aaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxa");
AntiFormat("aaaaxxxc ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc");
AntiFormat("aaaaabcd}yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy");
AntiFormat("aaaa}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
AntiFormat("aaaa}6666666666666666666666666666666666666666666666666666666666666");
AntiFormat("aaaa7777777777777777777777777777777777777777777777777777777777777");
AntiFormat("aaaaggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg");

Large strings, with replacements (up to two times the perf)

Method Mean [ns] Error [ns] StdDev [ns] Gen0 Allocated [B]
PR__Edit 394.7 ns 7.73 ns 10.05 ns 0.3271 5472 B
Original 798.9 ns 11.30 ns 10.57 ns 0.4425 7408 B
Benchmark code
AntiFormat("aaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}");
AntiFormat("aaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}");
AntiFormat("aaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxa}");
AntiFormat("aaaaxxxc ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc}");
AntiFormat("aaaaabcd}yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy");
AntiFormat("aaaa}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
AntiFormat("aaaa}6666666666666666666666666666666666666666666666666666666666666");
AntiFormat("aaaa7777777777777777777777777777777777777777777777777777777777777{");
AntiFormat("aaaaggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg}");
AntiFormat("aaaa77777777777777777777777777{}777777777777777777777777777777777{");
AntiFormat("aaaaggggggggggggggggggggggggggggggggggggggggggggggggg{gggggggggggggg}");

Customer Impact

Improved performance, decreased allocations.

Regression

No.

Testing

Local build, base testing between the two functions.

Assert.AreEqual(AntiFormat("{aaaa}}"), AntiFormat2("{aaaa}}"));
Assert.AreEqual(AntiFormat("{aa{{aa}}"), AntiFormat2("{aa{{aa}}"));
Assert.AreEqual(AntiFormat("{aa{{aa}}ab}c}d"), AntiFormat2("{aa{{aa}}ab}c}d"));
Assert.AreEqual(AntiFormat("aaaa}"), AntiFormat2("aaaa}"));
Assert.AreEqual(AntiFormat("aaaa"), AntiFormat2("aaaa"));
Assert.AreEqual(AntiFormat("a{{{aaa"), AntiFormat2("a{{{aaa"));
Assert.AreEqual(AntiFormat("a{{{aaa}}}"), AntiFormat2("a{{{aaa}}}"));
Assert.AreEqual(AntiFormat("{aaaa}"), AntiFormat2("{aaaa}"));
Assert.AreEqual(AntiFormat("{{aaaa}}"), AntiFormat2("{{aaaa}}"));
Assert.AreEqual(AntiFormat("{{{}aaaa}}"), AntiFormat2("{{{}aaaa}}"));
Assert.AreEqual(AntiFormat(string.Empty), AntiFormat2(string.Empty));
Assert.AreEqual(AntiFormat("a{{{}aaaa}}"), AntiFormat2("a{{{}aaaa}}"));
Assert.AreEqual(AntiFormat("a}aaaa}"), AntiFormat2("a}aaaa}"));
Assert.AreEqual(AntiFormat("}aaaa}"), AntiFormat2("}aaaa}"));

Risk

Low.

Microsoft Reviewers: Open in CodeFlow

@h3xds1nz h3xds1nz requested review from a team as code owners July 5, 2024 19:53
@dotnet-policy-service dotnet-policy-service bot added PR metadata: Label to tag PRs, to facilitate with triage Community Contribution A label for all community Contributions labels Jul 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Community Contribution A label for all community Contributions PR metadata: Label to tag PRs, to facilitate with triage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant