-
Notifications
You must be signed in to change notification settings - Fork 770
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
SDK: Use Volatile.Read over Interlocked.Read #3384
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
From the docs:
Does |
public class VolatileBenchmarks
{
private long value;
[Benchmark]
public long UsingVolatile()
{
var v = Volatile.Read(ref value);
return v;
}
} Is the best way to test the performance here? I'm not sure if there is any possibility of reordering of memory operations here as there is only one memory read operation and moreover the benchmarks are not run on multiple threads. |
I think
|
Interlocked provides thread level guarantee, regardless of single vs. multiple CPU/cores: https://docs.microsoft.com/dotnet/api/system.threading.interlocked Provides atomic operations for variables that are shared by multiple threads. |
I'm basing this basically off this: https://stackoverflow.com/a/72508084
|
My question is mainly around "freshness" of data since the docs for volatile read clearly state that:
We would want to get the latest value written to the memory location for our scenarios, right? (otherwise, we might get some value that the processor cached)? Also, if Interlocked ensures that we would get the latest value written to that memory location by any processor, then we would want to use Interlocked, right? |
Personally, I find using
Side note: finding issues using Additional reference: https://www.albahari.com/threading/part4.aspx#_Nonblocking_Synchronization |
TBH, I don't know. It seems like a bug with the docs. If @noahfalk Any insight you can share on this? |
I assume when the docs say you aren't guaranteed to get the latest value, they mean Volatile.Read isn't going to do an IPI like FlushProcessWriteBuffers. Interlocked.Read also doesn't do an IPI so I don't think either one is giving you a stronger guarantee of freshness. Anything that did do that IPI would be very expensive and it is rare to have algorithms which require it for correctness. Looking at the generated code the difference between them is that Volatile.Read gaurantees it won't reorder with any following read/write whereas Interlocked.Read is giving you a guarantee it won't be reordered with any read/write before or after. Which ordering guarantees you need depend on the algorithm being implemented. Both of them are also giving you an atomicity guarantee. Oddly I see that Volatile.Read docs fail to mention the atomicity guarantee and Interlocked.Read docs fail to mention the ordering guarantee. If your goal is to be safe, Interlocked.Read is giving you a strict super-set of the guarantees from Volatile.Read, so replacing Volatile.Read -> Interlocked.Read should always be safe. However if you are trying to optimize for performance, Volatile.Read is going to be faster in situations where you only need lesser reordering guarantee. Your benchmark above shows the best case performance for Interlocked.Read because it is single threaded. If you make another benchmark where Interlocked.Read of the same location is being executed frequently from 2 or more threads I would expect that cost to go up 10-30x whereas Volatile.Read cost won't go up. |
Codecov Report
@@ Coverage Diff @@
## main #3384 +/- ##
==========================================
+ Coverage 85.83% 86.25% +0.42%
==========================================
Files 271 258 -13
Lines 9523 9269 -254
==========================================
- Hits 8174 7995 -179
+ Misses 1349 1274 -75
|
This PR was marked stale due to lack of activity and will be closed in 7 days. Commenting or Pushing will instruct the bot to automatically remove the label. This bot runs once per day. |
Closed as inactive. Feel free to reopen if this PR is still being worked on. |
Noticed working on #3349 that Volatile.Read has an optimization for 64bit systems that make it faster than Interlocked.Read. This PR updates some of the other places where
Interlocked.Read
was being used.Simple benchmark:
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
12th Gen Intel Core i9-12900HK, 1 CPU, 20 logical and 14 physical cores
.NET SDK=6.0.400-preview.22301.10
[Host] : .NET 6.0.6 (6.0.622.26707), X64 RyuJIT
DefaultJob : .NET 6.0.6 (6.0.622.26707), X64 RyuJIT