[WIP] [no merge] Support limiting the buffer size in LargeArrayBuilder.#14006
[WIP] [no merge] Support limiting the buffer size in LargeArrayBuilder.#14006jamesqo wants to merge 6 commits intodotnet:masterfrom
Conversation
There was a problem hiding this comment.
Since the old Add(T) was marked with AggressiveInlining, should this new version be marked too?
There was a problem hiding this comment.
I think I found in my experiments a while ago that the JIT inlines methods sequentially; it will recognize the body of Add(T) is small, then inline it. Then it will recognize the body of Add(T, int) is small, and inline it. Consequently, you only need to apply AggressiveInlining once.
There was a problem hiding this comment.
Why is limit passed on every call to Add? Is it expected to change? If not, shouldn't it be passed in the constructor and then stored in a field? Or is the cost of one more field too high?
There was a problem hiding this comment.
Well, the size of the struct is already 40 bytes. I didn't want to penalize other cases where we're not using this parameter, e.g. Select or Concat. No, it's not expected to change,
There was a problem hiding this comment.
Well, the size of the struct is already 40 bytes
Why does the size of this struct matter? In all usage I can remember, it's only used on the stack, it's not passed around, etc., in which case the difference between 40 and 44 bytes doesn't matter.
There was a problem hiding this comment.
@stephentoub Future-proofing. I have been thinking of using it in Reverse, for example, in which case it would need to be stored in a field.
There was a problem hiding this comment.
I have been thinking of using it in Reverse, for example
Where would it need to be stored in a field? If you mean using it instead of using Buffer and storing the array, you're likely going to run into other complications.
Future-proofing
While it's good to think about future usage, from my perspective this change makes existing code harder to understand, unnecessarily. We should only do so if/when there's known good reason to do so.
Let's only add such support at the same time such support is consumed, so that we can actually see what real impact it has, and determine whether it's really worth the added complexity. |
|
@stephentoub Sure. Will close for now until the the other PRs are merged |
There are certain Linq methods, such as
WhereandTake, where we cannot pinpoint the exact number of elements the iterator will contain, but we can establish an upper bound on how many elements there are. For example,list.Where(p)can have at mostlist.Countelements, ande.Take(5)can have at most 5 elements.Currently, when we call
ToArrayon any of these iterators, the resizing pattern will be to allocate 4, then 8, then 16, etc. size buffers. This can be wasteful because e.g. if the source enumerable inWherecontains 100 elements, we allocate space for 128 elements even though those last 28 slots will never be used.This PR adds support to
LargeArrayBuilder<T>to limit how many elements we allocate, so there is no extra space wasted. It should help drive down allocations inWhere,Where.Select, &Takewhen the maximum count is far from the next power of 2.Waiting on: #12703, #13628