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

Lower interpolation into a call to concat #16556

Merged
merged 25 commits into from
Feb 22, 2024
Merged

Conversation

abonie
Copy link
Member

@abonie abonie commented Jan 19, 2024

Description

Optimization that lowers string interpolation into a call to concat iff there are at most 4 string parts and all fill expressions are strings.

Fixes #16247

Benchmarks

Run a benchmark like in this gist with and without the feature flag set.

Results without the flag (no optimization):


BenchmarkDotNet v0.13.12, Windows 11 (10.0.22621.3155/22H2/2022Update/SunValley2)
11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK 8.0.300-preview.24101.10
  [Host]     : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI DEBUG
  DefaultJob : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI


Method Mean Error StdDev Gen0 Allocated
SingleVariable 70.49 ns 1.214 ns 1.136 ns 0.0107 136 B
JustLiterals 145.61 ns 1.443 ns 1.350 ns 0.0215 272 B
Variables 144.05 ns 0.959 ns 0.897 ns 0.0215 272 B
Function 116.73 ns 1.557 ns 1.381 ns 0.0191 240 B
LongString 363.35 ns 2.838 ns 2.654 ns 0.4330 5432 B

Results with the flag set (with optimization):


BenchmarkDotNet v0.13.12, Windows 11 (10.0.22621.3155/22H2/2022Update/SunValley2)
11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK 8.0.300-preview.24101.10
  [Host]     : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI DEBUG
  DefaultJob : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI


Method Mean Error StdDev Median Gen0 Allocated
SingleVariable 0.0004 ns 0.0013 ns 0.0011 ns 0.0000 ns - -
JustLiterals 12.0562 ns 0.0719 ns 0.0673 ns 12.0500 ns 0.0032 40 B
Variables 11.9894 ns 0.0810 ns 0.0718 ns 12.0101 ns 0.0032 40 B
Function 12.2912 ns 0.1201 ns 0.1124 ns 12.3161 ns 0.0032 40 B
LongString 206.0906 ns 2.4311 ns 2.0301 ns 206.5404 ns 0.4158 5216 B

Checklist

  • Test cases added
  • Performance benchmarks added in case of performance changes
  • Release notes entry updated

Copy link
Contributor

github-actions bot commented Jan 19, 2024

❗ Release notes required


✅ Found changes and release notes in following paths:

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/8.0.300.md
LanguageFeatures.fsi docs/release-notes/.Language/preview.md

@abonie abonie force-pushed the str-interp-to-concat branch 3 times, most recently from a44ceed to e9e4f4b Compare February 5, 2024 19:28
@abonie abonie force-pushed the str-interp-to-concat branch 3 times, most recently from 79260a2 to fdea8a5 Compare February 14, 2024 16:45
Sanity check that lowering to concat does not break these simple cases
Initial attempt with many TODOs, also not sure whether it should be done
in checking, but it seems that later we would have to again parse the
string (since CheckExpressions is going from AST version of an
interpolated string to a sprintf call basically)
Cannot really optimize this way if width and other flags are specified.
Typed interpolated expressions should be possible to support, but
skipping them for now (TODO).
E.g. $"{x}{y}" has 5 string parts, including 3 empty strings
There were false positives before
@abonie
Copy link
Member Author

abonie commented Feb 15, 2024

Also, if anyone is curious about same benchmarks but with server GC:
No optimization:

Method Mean Error StdDev Gen0 Allocated
SingleVariable 78.08 ns 1.021 ns 0.905 ns 0.0005 136 B
JustLiterals 157.44 ns 2.675 ns 2.502 ns 0.0010 272 B
Variables 151.16 ns 1.498 ns 1.401 ns 0.0010 272 B
Function 125.50 ns 1.239 ns 1.099 ns 0.0010 240 B
LongString 641.34 ns 2.861 ns 2.536 ns 0.0219 5432 B

With optimization:

Method Mean Error StdDev Median Gen0 Allocated
SingleVariable 0.0064 ns 0.0103 ns 0.0096 ns 0.0000 ns - -
JustLiterals 14.8223 ns 0.1345 ns 0.1258 ns 14.8525 ns 0.0001 40 B
Variables 14.1441 ns 0.1240 ns 0.1099 ns 14.1558 ns 0.0001 40 B
Function 14.2070 ns 0.1159 ns 0.1028 ns 14.2344 ns 0.0001 40 B
LongString 508.0675 ns 6.9382 ns 6.1506 ns 507.0075 ns 0.0210 5216 B

@abonie abonie changed the title [WIP] Lower interpolation into a call to concat Lower interpolation into a call to concat Feb 15, 2024
@abonie abonie marked this pull request as ready for review February 16, 2024 16:18
@abonie abonie requested a review from a team as a code owner February 16, 2024 16:18
@abonie abonie requested a review from T-Gro February 16, 2024 18:32
Copy link
Member

@psfinaki psfinaki left a comment

Choose a reason for hiding this comment

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

Good and clear PR :)

A question for my education. Ideologically, how is this optimization different from the string optimization that Optimizer does in MakeOptimizedSystemStringConcatCall?

Co-authored-by: Petr <psfinaki@users.noreply.github.com>
@abonie
Copy link
Member Author

abonie commented Feb 20, 2024

A question for my education. Ideologically, how is this optimization different from the string optimization that Optimizer does in MakeOptimizedSystemStringConcatCall?

I am not really familiar with it, but on a quick glance, it is something else entirely - it (makes and) optimizes a call to System.String.Concat (while this change will make it so that there is a call to Concat in the first place)

@psfinaki
Copy link
Member

I am not really familiar with it, but on a quick glance, it is something else entirely - it (makes and) optimizes a call to System.String.Concat (while this change will make it so that there is a call to Concat in the first place)

Well yeah I just noticed that it also deals with <5 parts so I wonder if your PR doesn't somehow supersede that thing.

@abonie
Copy link
Member Author

abonie commented Feb 20, 2024

Well yeah I just noticed that it also deals with <5 parts so I wonder if your PR doesn't somehow supersede that thing.

It doesn't supersede it for sure. MakeOptimizedSystemStringConcatCall deals with situations where there was a call to Concat in the source code AFAICT. And the reason for the 5 parts thing is that there are optimized overloads for Concat for 2-4 arguments. That's why in my PR if there are more than 4 parts, we don't even want to do Concat, it would be slower.

@psfinaki
Copy link
Member

Alright then, thanks for the explanation there :)

src/Compiler/Checking/CheckExpressions.fs Outdated Show resolved Hide resolved
src/Compiler/Checking/CheckExpressions.fs Outdated Show resolved Hide resolved
@psfinaki
Copy link
Member

/run fantomas

  Co-authored-by: psfinaki <5451366+psfinaki@users.noreply.github.com>
Copy link
Contributor

@abonie
Copy link
Member Author

abonie commented Feb 22, 2024

/azp run

Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@abonie abonie enabled auto-merge (squash) February 22, 2024 16:02
@abonie abonie merged commit 2de1f68 into dotnet:main Feb 22, 2024
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Optimization for string interpolation - simple scenarios: unfolding constants and lowering to concatenation
5 participants