Skip to content

Commit a4d581a

Browse files
committed
fix: enable exact cross-page trace links
1 parent b4f4f0c commit a4d581a

2 files changed

Lines changed: 40 additions & 37 deletions

File tree

src/interpret-tc.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -864,15 +864,6 @@ static void tc_online_finish(tc_context<STATE_ACCESS> *c, int32_t cycle, bool cl
864864
if (const auto *const successor = tc_online_find(o, predecessor.successor); successor != nullptr) {
865865
const bool crosses_page =
866866
(predecessor.head >> LOG2_PAGE_SIZE) != (successor->head >> LOG2_PAGE_SIZE);
867-
// Cross-page straight links are off by default: with the
868-
// generated code-translation node in place, a full Linux boot
869-
// charges 22 cycles more than it retires instructions, so the
870-
// mechanism is not yet exact. Same-page links, side links and
871-
// the register-preserving edge are all gated bit-exact.
872-
static const bool cross_page_links = std::getenv("TC_LIGHTNING_XPAGE") != nullptr;
873-
if (crosses_page && !cross_page_links) {
874-
continue;
875-
}
876867
predecessor.link_fn = crosses_page ? successor->call_fn : successor->fn;
877868
if (successor->linked_predecessor == &predecessor && tc_lightning_fast_links_enabled()) {
878869
predecessor.fast_link_fn = successor->linked_fn;

tail-call.md

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,18 +1447,14 @@ shell cost +66% with tracing idle).
14471447
exit while this stage links only normal straight-trace ends. The four qsort
14481448
links therefore do not form its hot partition/comparator/return cycle.
14491449

1450-
SUPERSEDED IN PART. The cross-page half of this item is not exact. The
1451-
x86-64 campaign of item 9 gated the three linking mechanisms separately
1452-
and found that same-page links, side links, and the register-preserving
1453-
edge all reproduce stock byte for byte, while enabling cross-page links
1454-
makes a full Linux boot charge 22 cycles more than it retires
1455-
instructions (54,783,044 against the stock 54,783,022) and mismatches
1456-
sieve, zlib, and hash. The defect is in shared logic, not in the x86-64
1457-
port, so the AArch64 gates of this item did not exercise whatever it is:
1458-
the boot path is where cross-page successors are common. Cross-page
1459-
links are therefore compiled but not patched unless
1460-
`TC_LIGHTNING_XPAGE=1` is set, and the mechanism is isolated but not yet
1461-
diagnosed. Everything else in this item stands.
1450+
The initial x86-64 campaign attributed a 22-cycle full-boot divergence to
1451+
cross-page links and temporarily disabled them. That attribution did not
1452+
survive the completed fix set. With the cyclic call-target trim fixed
1453+
(item 9), cross-page links reproduce the default build byte for byte on
1454+
ARM64 and emulated x86-64 boots and on the three workloads originally
1455+
reported as failures (sieve, zlib, and hash). Reintroducing the cyclic trim
1456+
bug makes both linked and unlinked runs diverge. Cross-page links are
1457+
therefore enabled again; they were not the cause.
14621458

14631459
8. NEXT, TRANSACTIONAL CHAINS AND SIDE EXITS. Record page-bounded successor
14641460
fragments into provisional pool slots, invisible to the exact head map.
@@ -1555,9 +1551,9 @@ shell cost +66% with tracing idle).
15551551
back-edge into an unconditional one that both skipped the closing
15561552
branch and retired one instruction per iteration without charging
15571553
for it. It is now refused for cyclic traces.
1558-
- Cross-page trace linking remains inexact; see the amendment to item
1559-
7. It is the one mechanism of this stage that no longer runs by
1560-
default.
1554+
- The first gated run misattributed the cyclic-trim divergence to
1555+
cross-page trace linking. Retesting after the complete fix set shows
1556+
cross-page links exact; see the amendment to item 7.
15611557

15621558
The bisection switches that found these are retained as environment
15631559
variables on cold paths (`TC_LIGHTNING_NO_SPILL`, `NO_CYCLE`,
@@ -1606,7 +1602,7 @@ shell cost +66% with tracing idle).
16061602
few percent and receives nothing, which is the shape every uncovered
16071603
workload will have until coverage grows.
16081604

1609-
## 8c. The register-budget series: filed ideas and the queued campaign
1605+
## 8c. The register-budget series: filed ideas and the four-slot campaign
16101606

16111607
Section 5.16 established what each of the six slots is for: three
16121608
irreducibles (accessor, insn, pc), the fetch-cache pair whose eviction
@@ -1676,7 +1672,7 @@ same amortization traces collect at block lengths of tens instead of
16761672
four; if their ceilings do not clear a few percent, the trace path
16771673
collects the same win anyway and they stay filed.
16781674

1679-
### The queued Raptor campaign
1675+
### The four-slot x86-64 campaign
16801676

16811677
Two phases per compiler with the usual gates. Phase one is the landing
16821678
gate: main stock against branch stock, which that machine has never
@@ -1702,17 +1698,33 @@ defaults, so the campaign measures the shipped shape: the tail-call
17021698
translation unit compiles with -fno-stack-protector, and the pre-load
17031699
default follows the pinned shape alone.
17041700

1705-
The campaign is currently blocked on the branch, and the block is a
1706-
build error rather than a scheduling one: the argument-passing shape
1707-
does not compile. `TC_HOT_PARAMS` was not carried through the typed fast
1708-
pc of 5.19 in its non-pinned, non-segment form, so the outer loop hands
1709-
the handler three arguments where the signature declares four and passes
1710-
a `host_addr` where it declares `uint64_t`. Every column of the
1711-
two-by-two above except the pinned rows therefore fails to build, and
1712-
`make tailcall=yes` on x86-64, the shipped default for that
1713-
architecture, fails with it. Repairing that signature is the
1714-
prerequisite for the whole campaign and is independent of everything
1715-
else in this document.
1701+
The argument-signature build error was repaired on the x86-64 fixes
1702+
branch. A subsequent run on a different x86-64 processor measured the
1703+
four-slot argument shape both without and with the next-instruction
1704+
pre-load (`PL`):
1705+
1706+
| workload | stock | four-slot | four-slot + PL | four-slot vs stock | PL vs four-slot |
1707+
|---|---:|---:|---:|---:|---:|
1708+
| sieve | 7.57 | 6.80 | 8.27 | -10.2% | +21.7% |
1709+
| qsort | 10.13 | 10.36 | 11.45 | +2.3% | +10.5% |
1710+
| zlib | 18.49 | 17.87 | 21.90 | -3.4% | +22.6% |
1711+
| hash | 2.24 | 2.16 | 2.36 | -3.6% | +9.6% |
1712+
| double | 22.41 | 22.76 | 22.71 | +1.6% | -0.2% |
1713+
| syscall | 3.29 | 3.31 | 3.56 | +0.7% | +7.5% |
1714+
| **total** | **64.12** | **63.26** | **70.25** | **-1.3%** | **+11.1%** |
1715+
1716+
The four-slot shape is therefore the fastest portable x86-64 result in
1717+
this run, slightly ahead of stock in aggregate. The hoped-for pre-load
1718+
reversal did not occur: it loses 11.1% overall and loses materially on
1719+
five of the six workloads. Four argument slots describe only the values
1720+
crossing the handler boundary. Pre-load then keeps the predicted word and
1721+
dispatch target live across the current execute body, consuming the
1722+
capacity that the reduced signature freed. Earlier six-slot counters and
1723+
disassembly identified spill traffic as the loss there, but these timings
1724+
alone do not establish the residual four-slot mechanism. Distinguishing
1725+
spills and moves from front-end pressure or discarded predictions requires
1726+
disassembly and hardware counters from this measured build on the same
1727+
processor; until then the cause remains open and PL stays disabled.
17161728

17171729
One anchor from the campaign's target hardware does exist, taken as a
17181730
by-product of the backend port (8b, item 9): on the i9-14900K under GCC

0 commit comments

Comments
 (0)