Repository navigation
Description
Summary
A cross-card probe currently subtracts a timestamp taken on the sender from a timestamp taken on the receiver. On an 8-device 910B2 host, this produces a stable per-device offset of roughly -3 to +6 us. The resulting D'(s -> R) matrix looks like a receiver-side NUMA latency problem: even-NUMA devices appear slow as receivers and fast as senders. Same-clock controls and an independent ping-pong RTT probe show that the dominant effect is timestamp comparability, not an extra receive-path delay.
This matters for any microsecond-level cross-card latency attribution based on device swimlane timestamps.
Environment and workload
- Host: 8 x 910B2; experiments use four-card groups, with the logical-to-physical mapping recorded in the attached sanitized package.
- Workload: TP=4
decode_o_proj.l3_decode_attention_collectives_fixturewith a manual signal probe, 25 dispatches per block, 5 warmups, 20 measured rounds. - cross-device timestamp probe blocks: 12 four-card rank/device mappings, including contiguous, odd/even, and overlapping groups.
- same-clock RTT probe blocks: three overlapping four-card groups.
- The final sanitized package contains the DFX snapshots, analysis scripts, reports, and the figure; it contains no host paths, usernames, runtime logs, PIDs, generated kernels, or binary caches.
Measurements
| Control | Observation | Interpretation |
|---|---|---|
| Cross-device timestamp probe (joint fit) | 72 equations, RMS 0.24 us, max residual 0.81 us | A stable additive per-device timestamp offset explains the cross-card matrix |
| Cross-device timestamp probe (corrected receive columns) | NUMA even 12.8 us vs odd 12.5 us | The original 17.2 vs 10.1 us signature collapses after offset and probe-position correction |
Same-clock control (T) |
Receiver excess stays within about +/-0.2 us | No 5–9 us receiver detection penalty is present |
Same-clock RTT probe (RTT/2) |
15.85–19.83 us, device-touching inflation between -0.95 and +0.76 us | No device-specific receive slowdown; the visible slope is probe-position serialization |
| Same-clock RTT probe (offset cross-check) | Three overlapping pair differences: 8.03 vs 8.19 us; 6.65 vs 6.82 us; 5.75 vs 6.54 us | Same-clock RTT independently reproduces the cross-device timestamp probe's offset differences |
Same-clock control (T) |
Per-receiver excess remains within -1.08 to +0.64 us | Receive-path hypothesis remains falsified |
The same-clock RTT probe's absolute per-device gauge is weak for devices that occur in only one block; the physical pair differences and the overlapping-device checks are the robust comparison. The full reports contain the exact matrices and residuals.
Validation on the live environments
The sanitized package was freshly extracted on pypto-dev after a host reboot and run in two four-card configurations on the same 8-device host. The exact logical-to-physical mappings and complete logs remain in the internal validation record and package data.
| Environment | Python | PyPTO | Loaded runtime / Simpler | PTO-ISA | PTOAS | Cross-device timestamp probe | Same-clock RTT probe |
|---|---|---|---|---|---|---|---|
| Known-good historical runtime | 3.10 |
4b01d98c7b2ae1b0859754fd38d4b7e128fb576a |
93adc3865e65fd72655f571f2e4165cf5ac02616 |
cd4a3d3f7a1a27fcfe536f617e9bca3008929664 |
0.57 |
25/25 passed | 25/25 passed |
| New c540 runtime | 3.10 |
4fde258f18bd527bb2f8d61cac91f11c110ba177 |
declared 799640e68294372d3ebe0034c70596e2c94e3f68; loaded c540572d8db96bb25e47c756d0bd63f40adcc867 |
5a4f74cbf627d4aac2e0ce10d5e0d8b118343265 |
0.57 |
Both four-card groups compile and pass tensor validation, then stall after failed task outcomes; an earlier identical run reported finalize_native_run failed with code 507018 |
A previous identical run stalled after failed task outcomes at run 12 |
This A/B note establishes the live compatibility boundary: the package completes with the historical runtime, while the new c540/PTO-ISA combination does not complete the same probe. The full runtime logs remain in the internal validation record; the issue includes the failure boundary so maintainers can inspect it.
New-runtime failure to inspect
The new environment reaches compilation and in-process tensor correctness, then fails during repeated live dispatch. The clean four-card control reproduces the same boundary on a previously unused card group. Earlier runs with the same loaded runtime recorded:
finalize_native_run failed with code 507018
comm_release_domain_windows failed with code -1
Please confirm whether the PyPTO 4fde258f, loaded runtime c540572d, PTO-ISA 5a4f74c, and PTOAS 0.57 combination is supported for this probe. If it is supported, please help identify why the run stalls after failed task outcomes and whether there is a known regression or required runtime/build pairing. This runtime failure is reported as a separate compatibility boundary from the timestamp measurement conclusion.
Why the current subtraction is unsafe
The cross-device timestamp probe metric is:
D'(s -> R) = stamp_s.start(R) - notify.start(s)
The two timestamps come from different device clocks. A per-device additive offset therefore appears as a sender row plus a receiver column. The same-clock RTT probe uses:
RTT(s, R) = pp_stamp_b_R.start(s) - pp_notify.start(s)
Both timestamps are on the source device clock, so the additive clock offset cancels. The same-clock receiver quantity T provides a second control.
Reproduction package
The package is attached separately as pypto-cross-card-timing-repro-20260920.tar.gz.
SHA-256:
e24340122f13d7c0545b96f29b53bc1fb788eef059530436342ecd13bd39026f
Offline replay from a fresh extraction passes:
python3 scripts/checks/test_clock_forensics.py
python3 scripts/clock-forensics.py data
python3 scripts/analyze-link-probe.py data/link-b1 data/link-c3-mix
python3 scripts/rtt-forensics.py data/pp1-d4567 data/pp2-d0123 data/pp3-d2345For a live run, use a matching PyPTO/Simpler/PTO-ISA checkout, set PYPTO_ROOT, PYPTO_LIB, PYPTO_MODEL, PYPTO_EXP_ROOT, PYTHON_BIN, and PTOAS_ROOT, then run:
# Cross-device timestamp subtraction probe
PILOT_BLOCK=link-b1 scripts/run-link-probe-v5.sh
# Same-clock round-trip probe
PILOT_BLOCK=pp1-d4567 scripts/run-pingpong-v6.shEach runner snapshots and restores the model file and writes below PYPTO_EXP_ROOT.
Expected behavior
On a topology with the same clock-offset pattern:
- The cross-device timestamp probe's raw receive columns follow the physical device mapping rather than rank position.
- The same-clock
M/Tcontrols do not show a matching receiver penalty. - Same-clock RTT probe (
RTT/2) does not show a device-specific inflation, whileD' - RTT/2reproduces the per-device offset differences.
Questions for maintainers
- Are cross-device device timestamps from the swimlane records guaranteed to share a common epoch or calibration after runtime initialization?
- If they are not guaranteed to be comparable, can the runtime expose a clock-domain ID and an offset/correlation record, or document that cross-device subtraction is unsupported?
- Is there an official device-clock synchronization or calibration API for measuring one-way cross-card latency?
- Can you confirm whether the observed stable offset and its NUMA parity correlation are expected from the device/driver synchronization path, and recommend the supported measurement method?
Attachment
Attach assets/fig-clock-offset-en.png as the issue image (upload it separately from the archive).
The figure is a visual summary only; the archive contains the raw DFX snapshots and analysis scripts used to generate the numbers above.
Activity
Mewtwo-Jieyu commentedon Sep 20, 2026
pypto-cross-card-timing-repro-20260920.tar.gz
Attachments:
fig-clock-offset-en.png— visual summarypypto-cross-card-timing-repro-20260920.tar.gz— sanitized reproduction packageSHA-256:
e24340122f13d7c0545b96f29b53bc1fb788eef059530436342ecd13bd39026fChaoZheng109 commentedon Sep 22, 2026
First: your analysis is correct. Cross-device timestamp subtraction is not valid on this runtime, the stable per-device offset is real, and the NUMA-shaped receive penalty it produces is an artifact. Thank you for the controls — the falsification work is what makes this actionable rather than a guess.
Q1 — Are cross-device timestamps guaranteed to share a common epoch?
No, and this is by design, not a regression.
aclrtEventGetTimestampreturns device-uptime microseconds — each device's origin is its own power-on instant. The swimlane records useget_sys_cnt, which shares that epoch after frequency normalization (verified on a2a3 silicon):There is no cross-device clock synchronization step anywhere in runtime initialization. Cross-device subtraction of swimlane timestamps is unsupported.
Q2 — Can the runtime expose a clock-domain ID and an offset/correlation record?
clock_anchorsis serialized into every capture taken withCallConfig.capture_clock_anchors(set automatically for an L3 chip-swimlane capture). See the "existing mechanism" section below.metadata.host_clock_domain_id(derived from the Linux boot ID) exists and is used to refuse cross-host merges. There is no device-side equivalent. The host-side precedent could be copied if this is pursued, but it would be a new feature request.Q3 — Is there an official device-clock synchronization or calibration API?
No. The only timestamp-related surfaces in the ACL headers are:
Worth stating explicitly because the naming misleads: every
aclrtSynchronize*entry point is execution synchronization, not clock synchronization. There is no cross-device clock sync or calibration API.Q4 — Is the offset expected, and is the NUMA correlation expected?
What is and is not measurable — the algebra
This bounds what any calibration can deliver. With a four-timestamp ping-pong (
t11send on A,t21receive on B,t22send on B,t12receive on A), writingo = o_B - o_A:RTT = d1 + d2 = (t12 - t11) - (t22 - t21)is exact and assumption-free — two same-clock differences,onever enters. Your same-clock RTT probe already computes this correctly.d1andoare not separately identifiable. Two equations, three unknowns. Adding more timestamps does not help:ocan only enter through a cross-clock term, and every cross-clock term brings in a newd.So
RTT/2is the supported limit today, and its residual is exactly(d1 - d2)/2. YourD'(s -> R)is thet21 - t11term,= d1 + o, which is why the matrix shows a sender row plus a receiver column.One blind spot worth flagging in your own controls
Your overlapping-group closure checks are good practice, but they cannot detect the residual above. Modelling one-way latency as
L(s -> R) = T_s + P + R_R:This is a per-device difference — algebraically the same form as a clock offset. Two consequences:
oin the joint fit, so your RMS 0.24 us does not bound it.Both of your methods (joint fit and
RTT/2) traverse the inter-card link and assume link symmetry, so they share this blind spot and their mutual agreement does not constrain it. That is not a criticism of the work — it is a limit of any link-based method.What exists today for cross-card alignment (coarse scale)
simpler_setup.tools.swimlane_converteralready merges multiple ranks onto one hostCLOCK_MONOTONICtimeline:python -m simpler_setup.tools.swimlane_converter \ build_output/<case>/dfx_outputs --dispatch-id RUN_ID:TASK_SLOTIt works by span containment, not calibration: each rank's device block is placed at the earliest host ns its
runner_runwindow allows, and the spare width is published asslack_nsper rank pluscross_rank_uncertainty_ns(the sum of the two widest slacks). The guarantee is one-sided — containment cannot be wrong, only loose.This will not help you at microsecond scale. For a capture-enabled run the collector teardown falls inside
runner_run, so slack is absorbed and can reach hundreds of milliseconds. We mention it because its failure mode is the opposite of naive subtraction: a correct-but-useless interval rather than a confidently wrong number.Existing mechanism: host-anchored clock correlation (available now)
We have already implemented a host-anchored sampler, which is the construction that can close the missing equation — it never traverses the inter-card link and therefore introduces no new
d. It lives insrc/common/platform/onboard/host/clock_correlation.cppand is gated byCallConfig.capture_clock_anchors:Once each device is referenced to the host, the devices are aligned to each other transitively: in
o_A - o_Bthe common host reference cancels exactly, and so does every host-side overhead common to all devices. Simultaneous sampling across devices is not required.ocarries error too, and this is the important part. The error model:[h0, h1], soo_truelies in[Td - h1, Td - h0]. This is a hard bound, not an estimate — path asymmetry is contained within it rather than being an extra unbounded term.|error| <= (h1 - h0) / 2; for a pairwise difference the two half-widths add.aclrtEventGetTimestamp: roughly 1 us per device, 2 us pairwise. That floor is independent of the sample count.You do not have to rely on our numbers — this error is already serialized per sample in your own captures.
chip_swimlane_collector.cppwritesrtt_nsanduncertainty_ns = (rtt_ns+1)/2for every anchor sample, plus a run-levelhost_timeline_origin_ns. Enablecapture_clock_anchors, run once, and readclock_anchors.samples[].uncertainty_nsto get the actual error magnitude in your environment.Three known limitations of the current implementation, which you may want to address first if you pursue this:
aclrtSynchronizeEvent, whose wakeup latency lands inside[h0, h1]. Derived from the documented anchor cost (475-696 us per launch, 6 samples, cold sample 83-89%), the warm bracket is approximately 15 us — large relative to a 3-6 us signal. This is a derivation from published cost figures, not a direct measurement. Spinning onaclrtQueryEventStatusinstead would replace the wakeup latency with a single query round trip.aclrtEventGetTimestampis currently called beforeh1. Since the timestamp is frozen when the event executes on device and a later read returns the same instant, moving the call afterh1removes the readback cost from the bracket at no cost.kClockAnchorSamplesPerPosition = 3is too few for interval intersection. Every sample's interval provably contains the true offset, so intersecting them remains a hard bound while being strictly tighter — that is the correct way to tighten it, rather than averaging.Also note that the offline tools no longer consume
clock_anchors(placement moved to span containment, seedocs/dfx/chip-swimlane-profiling.md:613). The data and schema are still produced, but you would need to parse them yourself.Whether that error is adequate is your call
We cannot judge this for you — it depends on the magnitude you need to resolve:
The value of this mechanism is independence, not precision: your estimate is precise but may carry an unmeasured common bias, whereas a host-anchored bound is coarse but provably contains the truth. The two are complementary.
We are not planning further verification on our side. If you decide to pursue this and need the three changes above, please say so. Until then,
RTT/2remains the only supported microsecond-scale method, and one-way cross-card latency has no supported measurement path.On the
507018failure — separate issue, and we need more dataPlease treat this as unrelated to the timestamp question.
507018is a generic host-side code (aclrtSynchronizeStreamWithTimeout failed) that masks several distinct on-device mechanisms, so it cannot be classified from the host error alone. Could you re-run with the device log redirected and attach it:Also useful: the
error detail:/orch_error_code=/sched_error_code=/sub_class=fields from the host log. The distinguishing signatures are an allocator/poolFATAL: ... Deadlock, aTimeout (N cycles): producer/consumers ...,log_stall_diagnostics, or onlyHandleTaskTimeout/kill aicpu-sd— the last of which indicates a long or stalled op rather than a proven deadlock. Whether that specific PyPTO / runtime / PTO-ISA / PTOAS combination is a supported pairing needs a separate check against the release matrix.Mewtwo-Jieyu commentedon Sep 22, 2026
Thank you — the reply settles the measurement questions for us, and the algebra (RTT/2 exact, one-way not identifiable, the per-device
(T_A - R_A) - (T_B - R_B)term being indistinguishable fromo) is clear.Clock-anchor changes: yes, please. We would use the host-anchored correlation as an independent check on our fitted offsets (3-6 us scale), not as a precision one-way measurement — so the +/-2 us hard bound is the right target for us. If you proceed, all three changes are welcome:
aclrtQueryEventStatusinstead of the blockingaclrtSynchronizeEvent(the ~15 us wakeup-dominated bracket is the current blocker);aclrtEventGetTimestampcall afterh1;kClockAnchorSamplesPerPositionand intersect the per-sample intervals rather than averaging.We understand the offline tools no longer consume
clock_anchors, so we will parseclock_anchors.samples[](includinguncertainty_ns) ourselves — no tooling work is needed on your side beyond the three changes above. We will also state in our own notes that this bound cannot resolve 0.3 us-scale differences such as the corrected 12.8 vs 12.5 us columns.507018: reproduction with device logs attached. We re-ran the probe per your instructions, with
ASCEND_PROCESS_LOG_PATHredirected, on a previously idle card group:4fde258f, loaded runtimec540572d, PTO-ISA5a4f74cb, PTOAS0.57.e24340122f13d7c0545b96f29b53bc1fb788eef059530436342ecd13bd39026f).run_id=22on dev=6 raised the same chain:finalize_native_run failed with code 507018-> lane poisoned ->release_domain(allocation_id=0)failed on 4/4 chips ->comm_release_domain_windows failed with code -1-> exit code 139 (SIGSEGV).Device-log signatures (from
$ASCEND_PROCESS_LOG_PATH/debug/device-6/, times UTC+8):chip_swimlane_aicpu_complete_task failed for task 0x100000001 / 0x100000004(Core 29 / Core 32,scheduler_completion.cpp:268)HandleTaskTimeout: opsimpler_aicpu_exec, serialNo=22, stream_id=43, task_id=21, elapsed 45.3 s vs the 45 s op-execute timeout; tsdaemon kills aicpu-sdFATAL: ... Deadlock, aTimeout (N cycles): producer/consumerscycle, orlog_stall_diagnostics.By your classification guide this lands in the "long or stalled op" bucket rather than a proven deadlock. Two additional observations we could not classify ourselves:
error detail:/orch_error_code=/sched_error_code=/sub_class=fields do not appear in our host log at default verbosity; the full host traceback is in the attachment instead. If there is a runtime log level that emits them, we can re-run with it.chip_swimlane_collector_aicpu.cpplogs ERROR-levelfree_queue is empty during init!lines on all four devices during every collector (re-)init, including ones that precede dispatches that succeed. Is that expected noise for an L3 capture?The release-matrix question from the issue still stands: is the PyPTO
4fde258f+ runtimec540572d+ PTO-ISA5a4f74c+ PTOAS0.57pairing supported for this probe?Attachment:
attachment-507018-20260922.tar.gzSHA-256:
249805fe673f58a6f2f04848e340e480f1090cb2a8ff99d2a2377d3b374f4febContents: host run/driver logs (personal absolute root replaced by
<ROOT>), exit code,npu-smibefore/after, and the fullascend/run/+ascend/debug/device and plog files (unmodified; container-internal PIDs kept for cross-log correlation).attachment-507018-20260922.tar.gz
ChaoZheng109 commentedon Oct 16, 2026
The clock-domain question has been clarified. For the separate
507018failure, there are currently three possible explanations:These possibilities are not mutually exclusive. In particular, an execution timeout could expose a separate cleanup defect.
We could not reproduce the reported failure with the current mainline collective cases and matching pinned toolchain on A3. This differs from the original 910B2 setup with custom probes, so it does not establish that the original failure has been fixed. Successful execution also does not validate teardown after a timeout.
We are closing this issue now that the timestamp question has been answered. If the runtime failure persists on current mainline, please track it in a separate issue with the exact versions, reproducer, and host/device logs.