-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Prefer Buffer.Memmove over Array.Copy in some scenarios #35733
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
Prefer Buffer.Memmove over Array.Copy in some scenarios #35733
Conversation
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs
Outdated
Show resolved
Hide resolved
|
Any measurable improvements? |
|
Quick benchmark, showing an approx. 10% savings in public class ArrayRunner
{
private object[] _objects;
[Params(0, 1, 4, 12, 24, 128)]
public int ArrayLength { get; set; }
[GlobalSetup]
public void Setup()
{
_objects = Enumerable.Range(0, 128).Select(i => i.ToString()).ToArray();
}
[Benchmark]
public object[] ArrSlice()
{
return _objects[..ArrayLength];
}
}
|
|
Interesting. I'd have expected a fixed overhead reduction. Is the savings scaling with length? |
|
@stephentoub I would've expected a fixed-size reduction as well. Maybe something's off on my test box? Here's the benchmarks for public class ArrayRunner
{
private int[] _ints;
[Params(0, 1, 4, 12, 24, 128)]
public int ArrayLength { get; set; }
[GlobalSetup]
public void Setup()
{
_ints = Enumerable.Range(0, 32).ToArray();
}
[Benchmark]
public int[] ArrResize()
{
int[] ints = _ints;
Array.Resize(ref ints, ArrayLength);
return ints;
}
[Benchmark]
public uint[] ArrResizeCompatibleValueType()
{
uint[] uints = Unsafe.As<uint[]>(_ints); // safe, but avoid 'castclass' for benchmark
Array.Resize(ref uints, ArrayLength);
return uints;
}
}
|
|
I guess there is noise from GC or alignment. |
stephentoub
left a comment
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.
Seems worthwhile even if just for small array sizes. Thanks.
|
Looking into why CI's on the floor. I don't think it's related to this PR but want to double-check. |
Merge latest master
|
Interesting that it's only the Mono debug builds failing. I don't see these tests failing in other PRs. Might be some weirdness in introducing |
|
/azp run runtime |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
@marek-safar we have a few unit tests that are failing only in mono debug builds. Would you be able to assign somebody to take a look? There appears to be some weirdness in calling |
|
@vargaz could you please help them with Mono side |
|
This looks like a problem in Mono's implementation of BulkMoveWithWriteBarrier. Our old Memmove implementation had a type argument because it used different different copy/write barrier functions for different types, but the .netcore version doesn't have this argument. |
|
@vargaz If you point me to the mono-preferred implementation I can send a PR to split these back out. Thanks! |
|
/azp run runtime |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
@vargaz Looks like mono debug tests are still failing, even after merging in your latest changes. See https://github.com/dotnet/runtime/pull/35733/checks. Ideas? |
|
/azp run runtime |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Failing leg seems to have been pulled from current CI runs, and on rerun today everything that ran was green. Going ahead with the merge. |
Minor perf optimizations to
Array.Resize<T>andRuntimeHelpers.GetSubArray. In both of these methods it's safe to useBuffer.Memmoverather than bouncing through the more heavyweightArray.Copy. Due to the nature of how we're constructing the arrays we know these operations to be valid.