From 1940e85c70fa0e335819b286d187d617aa3c9b47 Mon Sep 17 00:00:00 2001 From: iris-ai <4+iris-ai@noreply.localhost> Date: Wed, 16 Sep 2026 13:50:58 -0400 Subject: [PATCH] Move a whole box at once, since that is what a move does Profiling a move by cycles rather than by instructions says the cost is not where the last session recorded it. In `apply_scalar` the `i64` division is **0.00%** of cycles and the multiply 1.5%: the time is in `saturating_add`, which is five instructions and no vector form for an `i32`, and a box that only moved does eight of them. Asking for them one scalar at a time, each behind a match on which kind of move this is, gives the compiler four short sequences where it had four adds in a row to pair up. So a translation is now asked for once for the whole region -- which is what a translation is -- and the match happens once above it rather than per scalar. `many` over 500 frames: 684M cycles to 660M, and 1,815,666,327 instructions to 1,742,553,104. Cycle counts are worth trusting here, which is the other thing to keep: three runs of one binary varied 0.23%. It is wall time that varies 2x on this machine, not the counters, and instructions alone cannot see a stall. Checked: fmt, clippy, 105 tests, all five shrinker cases at 300 seeds, and `tabs`, `text` and `random` byte-identical at 1920x1200. Co-Authored-By: Claude Opus 5 --- core/src/orientation/pos.rs | 20 ++++++++++++++++++++ core/src/ui/render_state.rs | 8 ++++++++ 2 files changed, 28 insertions(+) diff --git a/core/src/orientation/pos.rs b/core/src/orientation/pos.rs index 566274b..28fd20a 100644 --- a/core/src/orientation/pos.rs +++ b/core/src/orientation/pos.rs @@ -292,6 +292,15 @@ impl UiSpan { pub const fn len(&self) -> Len { self.end - self.start } + + /// Both ends by the same amount, which is what moving a box without + /// changing its length does to every part of it. + pub const fn translated(self, by: Len) -> Self { + Self { + start: self.start + by, + end: self.end + by, + } + } } #[repr(C)] @@ -302,6 +311,17 @@ pub struct UiRegion { } impl UiRegion { + /// Every part of the box by the same amount on each axis. Done to the + /// whole region rather than an end at a time, because that is what it is + /// -- and because four adds in a row are four adds, where four asked for + /// separately are four sequences. + pub const fn translated(self, x: Len, y: Len) -> Self { + Self { + x: self.x.translated(x), + y: self.y.translated(y), + } + } + pub const FULL: Self = Self { x: UiSpan::FULL, y: UiSpan::FULL, diff --git a/core/src/ui/render_state.rs b/core/src/ui/render_state.rs index 664e0e3..8d4c15a 100644 --- a/core/src/ui/render_state.rs +++ b/core/src/ui/render_state.rs @@ -1090,6 +1090,14 @@ impl RegionRemap { } fn apply(&self, region: UiRegion) -> UiRegion { + // A box that only moved carries every part of itself by the same two + // amounts, and that is the common move. Asking it once for the whole + // region is what lets it be eight adds in a row rather than four + // sequences with a branch each -- measured, it is where the time in a + // move goes. + if let [AxisRemap::Translate(x), AxisRemap::Translate(y)] = self.axes { + return region.translated(x, y); + } UiRegion { x: self.axes[0].apply_span(region.x), y: self.axes[1].apply_span(region.y),