-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
FileStream Flush(true) significant performance degradation in .NET 8 when buffer size is bigger than the payload #100229
Comments
What I find interesting is that its actually .NET 7 and when the data is less that the buffer capacity that is the odd one out. As soon as .NET 7 hits the buffer capacity, there is a huge jump in the time it takes to flush the data and it goes on par with .NET 8, .NET seems to stay more stable.
Since all writes would fit inside a single block, it's not strange to me that there isn't any noticeable difference in the time it takes to write the data. |
If I've understood your report correctly, this is by design. The purpose of Flush(true) is to flush to disk, but it wasn't in some cases in .NET 6/7. #77384 fixed that. |
@stephentoub Y, I was actually beginning to wonder if this was actually due to a bug fix. Lets link the bug as well: #77373 Considering dispose also happens, I assume the data would still end up on the disk with .NET 7.0, but the penalty was just paid asynchronously later, was that by the disk (e.g. we are just writing to the disks buffers but not ensuring that it flushes those) or was it something underlying in the OS? (unless a catastrophic crash was encountered, which would leave the file "corrupt" I assume, which in turn is why this fix is actually important). |
FileStream.Dispose ensures that anything buffered in the FileStream's byte[] buffer would be written to the OS, but it doesn't guarantee that the OS will turn have flushed everything to persisted storage. |
cc: @adamsitnik |
So it corresponds to |
Yes. runtime/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/BufferedFileStreamStrategy.cs Line 126 in 1fecfbc
runtime/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/BufferedFileStreamStrategy.cs Line 754 in 1fecfbc
|
I am closing this issue. The bug fix introduced the performance penalty, but it is by design. |
Description
The original issue was identified in apache/lucenenet#933; nevertheless, after deeper analysis, the root cause was narrowed down to the
FileStream
class, pointing towards a framework issue.Below is the source code that reproduces the issue.
Project configuration
Configuration
.NET 8, or .NET 9
macOS
ARM64
Regression?
The issue is reproducible in .NET 8 and .NET 9.
Data
Notice when the buffer size is bigger than the payload, performance degrades ~150x.
Also, if we disable the buffering altogether,
bufferSize: 0
, then the performance between .NET 7 and .NET 8 is on par.Analysis
After enabling tracing, it seems the problem is in the
fsync()
call; at least, this is the difference between buffered, non-buffered and buffer size less than the payload stack trace.Buffered (buffer size larger than the payload) stack trace (slow performance):
Non-buffered stack trace (fast performance):
Buffered (buffer size less than payload) (fast performance):
In summary, the DotNet Framework seems to call the
fsync()
method when the buffer is bigger than the payload, which leads to severe performance degradation.@paulirwin, @eladmarg, @jeme
The text was updated successfully, but these errors were encountered: