Repository navigation
Stride aware Fixnum Arrays - #1087
AlexaCampusano wants to merge 2 commits into
Conversation
| } | ||
| else { | ||
| FL_UNSET_EMBED(result); | ||
| ary_heap_narrow_copy(result, ary, offset, len, |
There was a problem hiding this comment.
I'm concerned about this part here, I'm currently talking to the llm about it.
I don't see why we can't also share the root's buffer if it's narrowed, we should be able to do CoW for this as well.
The shared view would just need to know the root's stride to read it. I might have to change a few things to make narrow arrays shareable, mostly around how a view stops sharing without touching the root's buffer. That way we avoid this, having to create new buffers when we read an array partially or when evaluating array literals and shared templates, and those stay O(1) like they are today in the normal path.
There was a problem hiding this comment.
Added changes in 7d5b74b to support doing this.
Basically the change is:
Everything inside array.c and the VM works at the element width: reads decode, writes encode, slices share, GC skips. Nothing internal ever needs the buffer as VALUEs. Everything is stride aware.
When something external asks for the buffer as a VALUE * (RARRAY_CONST_PTR, RARRAY_PTR, the public RARRAY_AREF, i.e. C extensions), the array has to produce one, and what happens depends on what the array is:
- Owns its buffer, mutable: widened in place. It stays wide after that.
- A view: unshares into its own wide buffer. The root and sibling views are untouched.
- Frozen: never changes. It gets a wide copy it keeps alongside the narrow buffer, so views into it and other Ractors reading it are unaffected.
37586b0 to
3bc9d14
Compare
| FL_UNSET_EMBED(ary); | ||
| ARY_SET_PTR(ary, ptr); | ||
| ARY_SET_HEAP_LEN(ary, len); | ||
| /* Try to narrow on embedded→heap transition */ |
There was a problem hiding this comment.
So far I've been avoiding embedded arrays. I'm only narrowing when an array gets a heap buffer (the embed→heap spill, or the first write into a buffer that was allocated up front), because the stride can only change the size of the malloc'ed buffer. The object itself is allocated in a slot picked from its capacity, and I can't change that, those are fixed.
Buuut, I was thinking, and maybe this is obvious, but I've had it in my mind as well: the slot payload is just bytes. We could narrow the embedded elements too and fit much more in the slot the GC already gave that Array, and delay having to malloc at all because more packed values fit embedded. A 40-byte slot has 24 bytes of payload: 3 VALUEs today, but the same bytes could hold 24 8bit integers or 12 16bit ones.
Is there a reason not to do that?
There was a problem hiding this comment.
It could also be a follow up if we think it will add complexity and needs discussion
3bc9d14 to
7d5b74b
Compare
Related read Storage Strategies for Collectionsin Dynamically Typed Languages
What are we trying to do?
This PR is a proposal to add fixnums stride information into the array object, so heap arrays have more information about the data it's storing and we can optimize it.
Prior Art: #1081
In this PR I'm targetting all fixnum arrays, not just frozen ones. This PR affects these common paths:
duparray. Now it narrows that template if it's all fixnums, and at runtime duparray copies the narrow buffer into a new narrow array instead of handing out a shared view of the template. The literal owns its own (small) buffer, and the template is collected with its iseq. There are concerns I have with this approach, that I'd like to discuss.dup,clone,a[i, n],first(n),last(n),pop(n),replace,sort_by!copy the narrow buffer rather than sharing it, so neither the source nor the copy gets widened by being read from.Some numbers!!!!
More narrowed paths exercised vs the previous #1081 work.