-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
More WriteGather fixes #109826
More WriteGather fixes #109826
Conversation
adamsitnik
commented
Nov 14, 2024
•
edited
Loading
edited
- don't run these tests in parallel, as each test cases uses more than 4 GB ram and disk
- fix the test: handle incomplete reads that should happen when we hit the max buffer limit
- incomplete write fix:
- pin the buffers only once
- when re-trying, do that only for the actual reminder
- handle Int32 overflow on macOS
…4 GB ram and disk!
…the max buffer limit
- pin the buffers only once - when re-trying, do that only for the actual reminder
Tagging subscribers to this area: @dotnet/area-system-io |
ReadOnlyMemory<byte> buffer = buffers[i]; | ||
totalBytesToWrite += buffer.Length; | ||
|
||
MemoryHandle memoryHandle = buffer.Pin(); |
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.
So far, for incomplete writes we were pinning the memory for every retry attempt. I am not sure if this can create some kind of edge case bugs, but I think we can do it just once, before we enter the main loop
{ | ||
if (asyncMethod) | ||
{ | ||
await RandomAccess.WriteAsync(sfh, writeBuffers, fileOffset); | ||
bytesRead = await RandomAccess.ReadAsync(sfh, readBuffers, fileOffset); |
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.
this was a test bug, the test assumed that the read won't ever be a partial read
/azp run runtime-libraries-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
…han Int32.MaxValue
/azp run runtime-libraries-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
long bytesWritten; | ||
Span<Interop.Sys.IOVector> left = vectors.Slice(buffersOffset); | ||
Span<Interop.Sys.IOVector> left = vectors.Slice(buffersOffset, buffersCount - buffersOffset); |
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.
Would it make sense to change L171 to stackalloc Interop.Sys.IOVector[IovStackThreshold].Slice(0, buffersCount)
, and then vectors
will have Length == buffersCount and you won't need the second argument here, since vectors will always be correctly sized?
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.
It looks better, thanks!
{ | ||
int n = buffers[i].Length; | ||
int n = buffers[buffersOffset].Length; |
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.
Is there anything that could go horribly wrong if the caller-provided IReadOnlyList changed between accesses? It looks ok, just confirming. We'd want to avoid a concurrency bug becoming a memory safety bug.
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.
this was great question! since we perform a "copy" for the purpose of pinning and IOV, I was able to read that value from the copy.
|
||
totalLength += vectors[i].Count; | ||
|
||
if (totalLength > INT_MAX) |
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.
Can size_t be 32-bit, in which case totalLength might overflow above?
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.
It can be 32-bit (on 32 bit systems), but it's unsigned so for:
- inputs that are
> int.MaxValue && < uint.MaxValue
there will be no overflow - valid inputs that are
> uint.MaxValue
should not be possible, as it's impossible to allocate more thanuint.MaxValue
memory on 32 bit systems.
/azp run runtime-libraries-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/ba-g unrelated job timeout (Started 8h 28m 8s ago and still runinng) |
* don't run these tests in parallel, as each test cases uses more than 4 GB ram and disk! * fix the test: handle incomplete reads that should happen when we hit the max buffer limit * incomplete write fix: - pin the buffers only once - when re-trying, do that only for the actual reminder * Use native memory to get OOM a soon as we run out of memory (hoping to avoid the process getting killed on Linux when OOM happens) * For macOS preadv and pwritev can fail with EINVAL when the total length of all vectors overflows a 32-bit integer. * add an assert that is going to warn us if vector.Count is ever more than Int32.MaxValue --------- Co-authored-by: Michał Petryka <35800402+MichalPetryka@users.noreply.github.com>
* don't run these tests in parallel, as each test cases uses more than 4 GB ram and disk! * fix the test: handle incomplete reads that should happen when we hit the max buffer limit * incomplete write fix: - pin the buffers only once - when re-trying, do that only for the actual reminder * Use native memory to get OOM a soon as we run out of memory (hoping to avoid the process getting killed on Linux when OOM happens) * For macOS preadv and pwritev can fail with EINVAL when the total length of all vectors overflows a 32-bit integer. * add an assert that is going to warn us if vector.Count is ever more than Int32.MaxValue --------- Co-authored-by: Michał Petryka <35800402+MichalPetryka@users.noreply.github.com> # Conflicts: # src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteGatherAsync.cs
* don't run these tests in parallel, as each test cases uses more than 4 GB ram and disk! * fix the test: handle incomplete reads that should happen when we hit the max buffer limit * incomplete write fix: - pin the buffers only once - when re-trying, do that only for the actual reminder * Use native memory to get OOM a soon as we run out of memory (hoping to avoid the process getting killed on Linux when OOM happens) * For macOS preadv and pwritev can fail with EINVAL when the total length of all vectors overflows a 32-bit integer. * add an assert that is going to warn us if vector.Count is ever more than Int32.MaxValue --------- Co-authored-by: Michał Petryka <35800402+MichalPetryka@users.noreply.github.com>