Skip to content

Update target frameworks #662

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

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

Conversation

Joy-less
Copy link
Contributor

This pull request removes unsupported target frameworks (.NET Core, .NET 6.0) and simplifies conditional compilation so it supports NETSTANDARD (.NET Standard 2.0) and NET (.NET 8.0 and .NET 9.0).

@bitfaster
Copy link
Owner

Wow, thanks!

I had started to look at this here #638, and planned to go back and effectively make your PR (so I would go in stages update fwks changes, then take each feature as a follow PR).

I think the gates will fail on your change, I just started a run - my other PR has fixes for that stuff in the build yaml files.

I will take a proper look at this on the weekend.

@Joy-less Joy-less mentioned this pull request Feb 6, 2025
@bitfaster
Copy link
Owner

I updated the build scripts so that your changes can compile: #670.

@Joy-less
Copy link
Contributor Author

I updated the build scripts so that your changes can compile: #670.

I merged the changes.

@bitfaster
Copy link
Owner

Build is failing because deleting framework packages is not backwards compatible (i.e. a breaking change), so this would have to be a major release:

Error: C:\Program Files\dotnet\sdk\9.0.200\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ApiCompat.ValidatePackage.targets(39,5): error CP0002: Member 'System.Threading.Tasks.ValueTask<V> BitFaster.Caching.IAsyncCache<K, V>.GetOrAddAsync<TArg>(K, System.Func<K, TArg, System.Threading.Tasks.Task<V>>, TArg)' exists on [Baseline] lib/net6.0/BitFaster.Caching.dll but not on lib/netstandard2.0/BitFaster.Caching.dll [D:\a\BitFaster.Caching\BitFaster.Caching\BitFaster.Caching\BitFaster.Caching.csproj]

@Joy-less
Copy link
Contributor Author

Joy-less commented Mar 4, 2025

Build is failing because deleting framework packages is not backwards compatible (i.e. a breaking change), so this would have to be a major release

Is there going to be a major release soon? What's the plan?

@bitfaster
Copy link
Owner

Sorry I missed the notification. I plan to get back to this around the end of June when I have more time.

I have backlog of things I would like to clean up for next major release. It is disruptive for consumers to make breaking changes, so I was trying to store up all the API changes and make them in one go. Some of these will require doing detailed analysis of the JITted code and performance, so it will be a medium/large task - I prefer to take small steps and validate everything thoroughly at each step to avoid regressing performance.

Prior to this PR, my thinking was to add a .NET9 build target and implement the .NET9 specific functionality there. Unless there is a dependency on .NET9 APIs (which as of today there is not), there is no advantage to compiling a .NET8 or 9 build target. .NET6 is compatible with those runtimes and have identical performance - hence I did not want to rush into this and introduce regressions which are time consuming to root cause.

@Joy-less
Copy link
Contributor Author

Prior to this PR, my thinking was to add a .NET9 build target and implement the .NET9 specific functionality there. Unless there is a dependency on .NET9 APIs (which as of today there is not), there is no advantage to compiling a .NET8 or 9 build target. .NET6 is compatible with those runtimes and have identical performance - hence I did not want to rush into this and introduce regressions which are time consuming to root cause.

.NET 6.0 definitely does not have the same performance as .NET 9.0. I assume that what you mean is that a .NET 9.0 project will override the performance of the .NET 6.0 library. Anyways good luck.

@bitfaster
Copy link
Owner

bitfaster commented May 15, 2025

Stephen's post describes optimizations in the JIT at the beginning, before moving onto optimizations in the framework code. In his benchmarks, he compares the results of different versions of the JIT and framework. This is subtly different, the JIT changes are faster because the same IL input produces better assembly code, and the framework changes are faster because the C# code has been changed to make it more efficient.

In general, a .NET6 assembly executing on the .NET9 runtime will convert the IL code to assembly code with the .NET9 JIT, run on the .NET9 runtime, and call methods in the .NET9 framework code. Compiling the same C# code to a .NET9 target by itself will not result in any additional optimization because the same IL will be passed to the .NET9 JIT. In the end, identical assembly code will be executed by the CPU in both cases.

To my knowledge there are two possible situations where compiling on .NET9 is faster:

  1. The C# language version is updated to C#13, enabling the compiler to bind lock(object) to System.Threading.Lock instead of System.Threading.Monitor. Thus, the C# compiler will generate lowered code that invokes a .NET9 specific framework API. Last year I had actually diffed the IL from the different language versions to verify this, but from memory, for BitFaster.Caching, there are no other meaningful differences.
  2. The C# code contains regions within #if NET9_0 that invoke framework APIs that only exist in .NET9, such as the lock API described above.

Because I have no use of lock(object) on hot path methods, the first optimization does not materialize any improvement. I know this because I tested it. However, I do have use of explicit Monitor.TryEnter in ConcurrentLfu, this is an example where the second form of optimization can be used. You can see in the PR I linked my first reply to you has a very small gain due to this: #638.

In summary, when I tried running .NET6 vs .NET9 assemblies in a .NET9 executable, based on this code base, it is not measurably faster. I totally agree .NET9 is faster, but rebuilding the assembly is not the key to unlocking the improvements in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants