Skip to main content

trace-lanefix

trace-lanefix rewrites Chrome/Kineto trace JSON so Perfetto can render slices that would otherwise be dropped because of crossing overlaps on the same (pid, tid) track.

It keeps properly nested slices on the same track, snaps tiny timestamp-boundary crossings, and moves genuine overlaps to synthetic lanes with collision-free thread ids. Open the rewritten trace in Perfetto.

Perfetto requires slices on the same (pid, tid) track to be disjoint or strictly nested. Crossing slices are dropped with SLICE_DROP_OVERLAPPING_COMPLETE_EVENT.

Install

pip install trace-lanefix

Before / After

Before:

Profile before lane fix

After:

Profile after lane fix

In Perfetto's trace overview, the rewritten trace reports TRACE ERRORS=0 instead of TRACE ERRORS=6, while IMPORT ERRORS and DATA LOSSES remain at 0. In this example, the JSON trace size changed from 452.76 KiB before rewriting (463,629 bytes) to 653.96 KiB after rewriting (669,651 bytes) because the output is pretty-printed for readability.

CLI

trace-lanefix input.json output.fixed.json

Tiny crossings below 5.0us are snapped by default. To use a different snap threshold:

trace-lanefix --snap-threshold-us 2.5 input.json output.fixed.json

The default threshold is calibrated against CUPTI boundary noise between consecutive same-stream kernels. In the sample trace, observed noise was below about 2.5us; kernels on one CUDA stream cannot physically overlap, so a small sub-threshold overlap is treated as timing noise.

Example output:

This run shows the two repair paths: tiny sub-5.0us timestamp crossings are snapped in place, while one genuine overlap is moved to a synthetic lane. Flow endpoints are then rewritten to follow the adjusted slice starts and lanes.

trace-lanefix trace.json trace_fixed.json
processing 3 track(s)
  pid=7334 tid=7334: 2 lane(s), 1 slice(s) moved, 11 snapped
  pid=0 tid=7: 1 lane(s), 0 slice(s) moved, 5 snapped
snapped 16 sub-5.0us crossing(s)
updated 15 slice(s): total |start shift|=6.195us, total |end shift|=5.240us, total |boundary shift|=11.436us
kernel timing summary (5 run(s) across 3 kernel name(s)):
  nvjet_sm120_tst_mma_256x112x64_2_64x56x64_tmaAB_bz_TNNN: runs=2, total delayed=2.848us, total trimmed=0.000us, total boundary shift=2.848us, moved=0, snapped=2
  nvjet_sm120_tst_mma_96x256x64_2_48x64x64_tmaAB_bz_TNNN: runs=2, total delayed=480ns, total trimmed=0.000us, total boundary shift=480ns, moved=0, snapped=2
  nvjet_sm120_tst_mma_128x256x64_2_64x64x64_tmaAB_bz_TNNN: runs=1, total delayed=384ns, total trimmed=0.000us, total boundary shift=384ns, moved=0, snapped=1
moved slices (1):
  ProfilerStep#5 pid=7334: moved to lane 1 (tid 7334 -> 7334001)
snapped slices (9):
  layer0_forward pid=7334 tid=7334: start delayed by 2.483us
  torch/autograd/profiler.py(843): __exit__ pid=7334 tid=7334: end trimmed by 2.855us
  torch/_ops.py(1079): __call__ pid=7334 tid=7334: end trimmed by 1.222us
  <built-in method  of pybind11_builtins.pybind11_detail_function_record_v1_system_libstdcpp_gxx_abi_1xxx_use_cxx11_abi_1 object at 0x719b5a7004b0> pid=7334 tid=7334: end trimmed by 1.162us
  contextlib.py(141): __exit__ pid=7334 tid=7334: end trimmed by 0.2ns
  profiling.py(19): trace pid=7334 tid=7334: end trimmed by 0.2ns
  torch/profiler/profiler.py(912): _transit_action pid=7334 tid=7334: end trimmed by 0.2ns
  torch/cuda/__init__.py(1161): synchronize pid=7334 tid=7334: end trimmed by 0.2ns
  torch/cuda/__init__.py(609): __exit__ pid=7334 tid=7334: end trimmed by 0.2ns
rewrote 5 flow endpoint(s) onto rewritten slice starts/lanes
wrote trace_fixed.json: 988 slices, 1 new lanes

How It Works

trace-lanefix resolves crossings with minimal visual disturbance:

  1. It places slices with nesting awareness. Each lane keeps a live stack of open slices, and nested children stay on their parent's lane.
  2. It snaps tiny crossings instead of creating a new lane. End-snap clamps a child end to its parent end; start-snap pushes a slice start to the previous boundary. The smaller shift wins, as long as it is below the configured snap threshold.
  3. It applies the same pass to every track. GPU streams keep the same lane behavior as simple non-nested timelines, while CPU threads can preserve real nesting.
  4. It creates collision-free synthetic lane ids. Numeric tids use tid * 1000 + lane when available, and fall back to string ids if that would collide with a real track.

Python API

from trace_lanefix import fix_overlaps

fix_overlaps("input.json", "output.fixed.json")
fix_overlaps("input.json", "output.fixed.json", snap_threshold_us=2.5)

Timestamp precision

The fixer uses the same time rounding as Perfetto, preventing tiny overlaps from reappearing during import. It preserves every slice and places parent slices first when start times match.

Metadata

Release files for trace-lanefix 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for trace-lanefix 0.1.1
File Size Uploaded
trace_lanefix-0.1.1.tar.gz 13.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for trace-lanefix 0.1.1
File Interpreter ABI Platform
trace_lanefix-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 22.9 kB

Release files / trace_lanefix-0.1.1.tar.gz

Download URL trace_lanefix-0.1.1.tar.gz
Size 13.2 kB
Tags Source
SHA-256 checksum
How to use checksums
1c276d36985d410ad9112dcdd5e12a0e42ba63d988ed8525595b3bdcad0f2c1d
BLAKE2b-256 checksum
How to use checksums
0e47fd9f31e63a41e5ed5c96b419ae035f3e0a0844c3940e0cffd53bed0faa98
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / trace_lanefix-0.1.1-py3-none-any.whl

Download URL trace_lanefix-0.1.1-py3-none-any.whl
Size 9.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ffa15d9f345a3b2b2efc153c1eca3b44664116c704ca7e58d530134bbdc5358f
BLAKE2b-256 checksum
How to use checksums
f2769e09cbcf973e0b2d84660d77becd83924ad436011d15da6fad58242f83c4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page