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

Spanify AntiFormat function in AvTrace, decrease allocations, improve perf #9361

Merged
merged 2 commits into from
Apr 1, 2025

Conversation

h3xds1nz
Copy link
Member

@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
@h3xds1nz h3xds1nz changed the title [AvTrace.cs] Use ReadOnlySpan<char>/Slice instead of String/Substring in AntiFormat Spanify AntiFormat function in AvTrace, decrease allocations, improve perf Sep 1, 2024
siagupta0202
siagupta0202 previously approved these changes Mar 31, 2025
@siagupta0202
Copy link
Contributor

@h3xds1nz the PR looks good to be merged, can you please resolve the merge conflicts?

@siagupta0202 siagupta0202 self-assigned this Mar 31, 2025
@h3xds1nz
Copy link
Member Author

@siagupta0202 Done, now if we could finally get #9468 done that would be wonderful.

Copy link

codecov bot commented Mar 31, 2025

Codecov Report

Attention: Patch coverage is 0% with 27 lines in your changes missing coverage. Please review.

Project coverage is 11.41679%. Comparing base (2a8258a) to head (63b10e2).
Report is 5 commits behind head on main.

Additional details and impacted files
@@                 Coverage Diff                 @@
##                main       #9361         +/-   ##
===================================================
+ Coverage   11.25210%   11.41679%   +0.16469%     
===================================================
  Files           3353        3353                 
  Lines         668062      668060          -2     
  Branches       74980       74980                 
===================================================
+ Hits           75171       76271       +1100     
+ Misses        591642      590439       -1203     
- Partials        1249        1350        +101     
Flag Coverage Δ
Debug 11.41679% <0.00000%> (+0.16469%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@siagupta0202 siagupta0202 merged commit fdd1169 into dotnet:main Apr 1, 2025
8 checks passed
@siagupta0202
Copy link
Contributor

@siagupta0202 Done, now if we could finally get #9468 done that would be wonderful.

Sure, I will start working on that PR soon 😊 and thank you for your contribution as well!

@h3xds1nz
Copy link
Member Author

h3xds1nz commented Apr 1, 2025

@siagupta0202 Thank you, glad to hear :)

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.

3 participants