Skip to content

Conversation

@Therzok
Copy link
Contributor

@Therzok Therzok commented Feb 15, 2020

No description provided.

@Therzok Therzok changed the title Use Array.Empty where possible and fallback to new T[0] on ns1.0 Use Array.Empty where possible and fallback to new T[0] on netstandard1.0 Feb 15, 2020
@jkotas
Copy link
Member

jkotas commented Feb 15, 2020

This will introduce performance regression when Empty is called from generic code and T is reference type.

The current JIT has inlining limitations for cases like these. @davidwrighton is trying to fix them in #31833 . Once it is fixed, it should be ok to make this change - but only for netcoreapp5.0+ builds of this library.

@jkotas
Copy link
Member

jkotas commented Feb 15, 2020

Actually, scratch my comment. I have not noticed that Empty is a field. It would apply only if Empty was a property.

Still, it is not obvious whether this is an improvement. It saves allocation of one tiny object on GC heap, but introduces more code. It is likely a net regression when looking at the total memory consumption.

@Therzok
Copy link
Contributor Author

Therzok commented Feb 15, 2020

The disabled CA1825 caught my eye, which is why I opened the PR.

Looking at the IL, the Array.Empty<T> version looks one byte shorter: https://sharplab.io/#gist:a3adeca56fd97a06a564ced10c670c32

And from the looks of it, even the JIT is smaller.
https://sharplab.io/#gist:e1b441ef8346b2ece83abf48dd00cf12

@jkotas
Copy link
Member

jkotas commented Feb 15, 2020

Small generic types and methods have non-trivial overhead in the runtime datastructures that is easy to miss.

Here is a micro-benchmark that demonstrates the impact of this PR https://gist.github.com/jkotas/6b5d2c7088b2a8d8c6332b2c7d74ce74#file-arraywrapper

Without Array.Empty(), the working set is 44,724,224 bytes (Windows x64). With Array.Empty(), the working set is 51,097,600 bytes. So this PR is increasing footprint of typical ImmutableArray instantiation by ~600 bytes. This hit is going to be slightly lower because of there will be Array.Empty() instantiated from other uses that the ImmutableArray gets for "free", but there is no way to turn this into an improvement for a typical app.

@jkotas
Copy link
Member

jkotas commented Feb 15, 2020

If you agree, I think this PR can be closed.

@Therzok
Copy link
Contributor Author

Therzok commented Feb 15, 2020

@jkotas Thanks for that benchmark, that's really interesting info.

Instead of closing, can I repurpose the PR to add a comment on that behaviour so this won't be PR'd again in the future?

@jkotas
Copy link
Member

jkotas commented Feb 15, 2020

Yep, adding a comment on this would be great!

@Therzok Therzok changed the title Use Array.Empty where possible and fallback to new T[0] on netstandard1.0 Add a comment explaining why not to switch ImmutableArray.Empty to Array.Empty Feb 16, 2020
@Therzok Therzok force-pushed the immutable-array-empty branch from c1d6ec1 to 2f13ac4 Compare February 16, 2020 00:50
@Therzok
Copy link
Contributor Author

Therzok commented Feb 16, 2020

Now it's all a single comment added.

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@jkotas jkotas merged commit d534ef0 into dotnet:master Feb 16, 2020
@Therzok Therzok deleted the immutable-array-empty branch February 16, 2020 04:47
@ghost ghost locked as resolved and limited conversation to collaborators Dec 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants