-
Notifications
You must be signed in to change notification settings - Fork 951
runtime: Simplify slice growing/appending code #4287
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
Conversation
90f998f
to
ec37a27
Compare
Some quick testing shows this makes the multiplication factor 1.125. However the expression doesn't seem to work for |
I'm not sure this actually saves us anything. I threw together a quick simulation and it seems that the new algorithm requires more calls to "grow" (since we're not growing as much, we need to do it more frequently, requiring more CPU) and ends up generating more garbage, because the additional calls to grow means we have to throw more stuff away. You can play with my sample code here: https://go.dev/play/p/QcHiMqnGlym |
Yup, that seems to be the case from some of the testing I did last week to understand why some tests were failing. I'm going to send a new version that does pretty much the same thing as before but keeps the cleanup.
…On Mon, Jul 22, 2024, at 11:53 AM, Damian Gryski wrote:
I'm not sure this actually saves us anything. I threw together a quick simulation and it seems that the new algorithm requires more calls to "grow" (since we're not growing as much, we need to do it more frequently, requiring more CPU) *and* ends up generating more garbage, because the additional calls to grow means we have to throw more stuff away.
You can play with my sample code here: https://go.dev/play/p/QcHiMqnGlym
—
Reply to this email directly, view it on GitHub <#4287 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAADVGKW2UBXOAKSZRH5APLZNVIKBAVCNFSM6AAAAABI7FV6YCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENBTGYYDSOJZHE>.
You are receiving this because you authored the thread.Message ID: ***@***.***>
|
ec37a27
to
fca77ff
Compare
fca77ff
to
a4b6cfe
Compare
Alright, @dgryski, pushed a new version, rebased on the current |
ec47ad5
to
06eb710
Compare
The failure inside the |
06eb710
to
4e2bdb8
Compare
The Index field of "want" for the reflect field |
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.
lgtm. nice to share the code in grow. just some (non merge blocking) questions
|
||
buf := alloc(oldCap*elemSize, nil) | ||
buf := alloc(newCap*elemSize, nil) |
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.
should this have some overflow check?
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.
Yes, it should. Even calculating the new newCap
can overflow. However, handling overflow conditions doesn't seem to be something that's done pervasively in TinyGo, so I didn't do it here so this is closer to the rest of the code.
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.
I think it is very unlikely to overflow in practice, but yes it would be a good idea to have some sort of check for this.
For 32-bit and 64-bit systems it would be possible to use math/bits for this: https://pkg.go.dev/math/bits#Add32
But maybe there are universal expressions for detecting such an overflow condition efficiently.
Right, and I have no idea why! I've spent some time in the reflect code, and @dgryski too, but we don't yet know what's happening here. Our best guesses is that there's either memory corruption somewhere, or that, although the code seems correct, its behavior is different from before, and the reflect code is probably depending on that somehow. |
Hmm, I was suggesting/agreeing with @dgryski that the test may be faulty and the old implementation matched. I think the expectation looks incorrect, though I have very little experience or deep knowledge of this code. |
If I understood the test correctly, it seems correct. The index is a slice of indices, starting with the current type, and following any nested type. So an index of The test defines two structs: I might be mistaken about how this works, though. |
Reading more of #tinygo-dev, feel free to ignore me. I didn't look closely enough at the |
So I copied the failing test to its own file, and |
Fixed the |
Alright, |
@lpereira Ok, so it does seem like the bug is somewhere in |
e0e9a35
to
a3c5eb5
Compare
This fixes the
I'll get this in as another PR and you can rebase against that with only the slice allocation changes. |
a3c5eb5
to
38095eb
Compare
I rebased this on top of #4387 (please merge it first!), and removed the commit changing |
I'll look at the |
The |
Nope; failure seems intermittent. |
This is due to memory fragmentation which (annoyingly) has different behaviour with the new growth algorithm. A smarter allocator that has free lists for small allocation sizes to reduce fragmentation would help here, but that's outside the scope of this PR. |
Refactor the slice appending function to rely on the slice growing function, and remove branches/loops to use a branchfree variant. Signed-off-by: L. Pereira <[email protected]>
Both branches were equivalent, so guard the overall logic in sliceAppend() with the more general condition. Signed-off-by: L. Pereira <[email protected]>
Use `bits.Len()` rather than `32 - bits.LeadingZeros32()`. They're equivalent, but the Len version is a bit easier to read. Signed-off-by: L. Pereira <[email protected]>
sliceGrow() will return the old slice if its capacity is large enough. Signed-off-by: L. Pereira <[email protected]>
38095eb
to
61c1425
Compare
Agreed. I've rebased on the current |
fragmentation because of not taking headers/meta into account was my point in #4287 (comment) |
sizediff failure is unrelated. |
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.
LGTM
Merging. Will close my PR that has the reflect fix. |
append(ll.index, int(i)), | ||
append(ll.index[:len(ll.index):len(ll.index)], int(i)), |
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 will force a new allocation on every append
, is that intentional?
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.
Yes. This fixes a test failure in reflect
that was triggered by the new slice allocation code which made this sometimes be a copy and sometimes not. (The old growth code made this always a copy in the test, but the new growth code expanded it more and so sometimes reused the old slice, which then had entries in the slice overwritten by later loop iterations, causing the faiure.)
Refactor the slice appending function to rely on the slice growing function, and remove branches/loops to use a branchfree variant.
CC @dgryski