You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I looked into this by adding a bulk VirtualMemory::write_bytes() operation and letting CodeBlock::write_bytes() call it, instead of emitting slices byte by byte. It takes over the page-bounding from the single-byte implementation and returns written bytes along with the error on failure.
A quick test on ARM64 shows that this reduces median LIR compilation time by 3–7% across the three 30k_* ruby-bench workloads, and total compilation time by 1–2.3%. I would be checking x86-64 next. Is this within the expected margin?
Does this match what you intended here, or were you thinking more of a scoped/buffered writer (which seems especially suited for x86-64 instruction encoders, after a quick look) that also batches separate write_byte calls?
Both are acceptable, probably? I'm not sure. I would expect some amount of "page buffering" so to speak which should drop the check to at least 1 in 4k instead of once per byte. I would also expect a bulk API.
This kind of change can be kind of dicy to implement cleanly. You are more than welcome to submit a PR (please let me know if you want to claim the issue and I'll assign it), but please ensure your expectations are set accordingly: there will be probably a decent amount of API review and it may not end up getting merged for one reason or another. But if it strikes the right balance, we would be overjoyed to merge/land such a PR.
Both are acceptable, probably? I'm not sure. I would expect some amount of "page buffering" so to speak which should drop the check to at least 1 in 4k instead of once per byte. I would also expect a bulk API.
Yeah, I only started with the bulk-writer because I could quickly test ARM64 emission on my MBP. In the workloads I measured, all writes are either 4 or 8 bytes, so they could benefit immediately, but I was surprised by such gains from even these small writes.
A writer that could amortize the fast-path overhead over multiple consecutive writes was an obvious next optimization, especially on x86-64 with many single-byte writes.
So, I started with an explicit "CodeWriter" that holds the memory borrow and caches a validated writable span across calls. On span hits, this replaces repeated borrowing, page derivation, and per-byte call/result handling with a cheap span-size test, a store, and the cursor advance. For multibyte slices, I kept the bulk stores rather than repeated byte writes.
This kind of change can be kind of dicy to implement cleanly. You are more than welcome to submit a PR (please let me know if you want to claim the issue and I'll assign it), but please ensure your expectations are set accordingly: there will be probably a decent amount of API review and it may not end up getting merged for one reason or another. But if it strikes the right balance, we would be overjoyed to merge/land such a PR.
That's a fair warning, and I appreciate it. I will create a draft PR tomorrow that contains my current implementation state with a few numbers I gathered from running the 30k_* ruby-bench workloads. If you have time, I would appreciate feedback on the current API, any potential consequences, and whether the optimizations go in a direction you agree with.
You can assign the issue to me; I think that the current implementation is at a point where a first review could make sense, and if no one else is currently looking into this, then that justifies at least a temporary claim :-)
It got quite big (sorry), but most of it isn't behaviorally significant; a large part is type changes and related name changes (I wrestled with whether they should be in the initial PR).
In any case, please don't take this as me being pushy. I just forgot the repos belong to different orgs, and I have no idea how notifications are set up to align PRs with related issues across orgs. So this is mostly bookkeeping, with no intent to signal any urgency.
Activity
supervacuus commentedon Oct 16, 2026
I looked into this by adding a bulk
VirtualMemory::write_bytes()operation and lettingCodeBlock::write_bytes()call it, instead of emitting slices byte by byte. It takes over the page-bounding from the single-byte implementation and returnswrittenbytes along with the error on failure.A quick test on ARM64 shows that this reduces median LIR compilation time by 3–7% across the three
30k_*ruby-bench workloads, and total compilation time by 1–2.3%. I would be checking x86-64 next. Is this within the expected margin?Does this match what you intended here, or were you thinking more of a scoped/buffered writer (which seems especially suited for x86-64 instruction encoders, after a quick look) that also batches separate
write_bytecalls?tekknolagi commentedon Oct 16, 2026
Both are acceptable, probably? I'm not sure. I would expect some amount of "page buffering" so to speak which should drop the check to at least 1 in 4k instead of once per byte. I would also expect a bulk API.
This kind of change can be kind of dicy to implement cleanly. You are more than welcome to submit a PR (please let me know if you want to claim the issue and I'll assign it), but please ensure your expectations are set accordingly: there will be probably a decent amount of API review and it may not end up getting merged for one reason or another. But if it strikes the right balance, we would be overjoyed to merge/land such a PR.
supervacuus commentedon Oct 18, 2026
Thank you for the quick response, @tekknolagi.
Yeah, I only started with the bulk-writer because I could quickly test ARM64 emission on my MBP. In the workloads I measured, all writes are either 4 or 8 bytes, so they could benefit immediately, but I was surprised by such gains from even these small writes.
A writer that could amortize the fast-path overhead over multiple consecutive writes was an obvious next optimization, especially on x86-64 with many single-byte writes.
So, I started with an explicit "
CodeWriter" that holds the memory borrow and caches a validated writable span across calls. On span hits, this replaces repeated borrowing, page derivation, and per-byte call/result handling with a cheap span-size test, a store, and the cursor advance. For multibyte slices, I kept the bulk stores rather than repeated byte writes.That's a fair warning, and I appreciate it. I will create a draft PR tomorrow that contains my current implementation state with a few numbers I gathered from running the
30k_*ruby-bench workloads. If you have time, I would appreciate feedback on the current API, any potential consequences, and whether the optimizations go in a direction you agree with.You can assign the issue to me; I think that the current implementation is at a point where a first review could make sense, and if no one else is currently looking into this, then that justifies at least a temporary claim :-)
supervacuus commentedon Oct 20, 2026
@tekknolagi, only wanted to ping here that I created a PR: ruby#19430
It got quite big (sorry), but most of it isn't behaviorally significant; a large part is type changes and related name changes (I wrestled with whether they should be in the initial PR).
In any case, please don't take this as me being pushy. I just forgot the repos belong to different orgs, and I have no idea how notifications are set up to align PRs with related issues across orgs. So this is mostly bookkeeping, with no intent to signal any urgency.
tekknolagi commentedon Oct 20, 2026
We've seen it, don't worry—we're looking