Compare two traces in TraceLens#
2026-07-21
6 min read time
This topic shows how to quantify the impact of a change by comparing two TraceLens reports side by side — for example, a baseline against a candidate after a code, library, or hardware change.
TraceLens offers two ways to compare traces, depending on how precise you need the matching to be:
Perf-report comparison: compares two finished reports by op name, matching each sheet’s rows (per-op aggregates, kernels, and modelled ops like GEMM/SDPA) across the two reports. CLI-driven, and produces a side-by-side Excel workbook.
TraceDiff comparison: an SDK that compares traces by their morphological tree structure, matching ops at the lowest common node. Use it when op names differ between traces (for example, across hardware, libraries, or framework versions) or when you need finer-grained, programmatic analysis. For an end-to-end analysis, the Comparative TraceLens Agent wraps TraceDiff in an agentic workflow that automates the comparison and provides optimization recommendations.
Before you begin#
TraceLens installed (see Install TraceLens).
For perf-report comparison: two generated reports (
.xlsx), one per configuration. Generate them with TraceLens_generate_perf_report_pytorch.
Perf-report comparison#
This approach compares two already-generated reports by matching rows on op name within each sheet — per-op aggregates, kernel summaries, and modelled ops such as GEMM and SDPA in the roofline groups.
Step 1: Generate the two reports#
TraceLens_generate_perf_report_pytorch --profile_json_path traces/baseline.json --output_xlsx_path baseline.xlsx
TraceLens_generate_perf_report_pytorch --profile_json_path traces/candidate.json --output_xlsx_path candidate.xlsx
Step 2: Run the comparison#
TraceLens_compare_perf_reports_pytorch \
baseline.xlsx candidate.xlsx \
--names baseline candidate \
--sheets all \
-o comparison.xlsx
--namessets the display tags used in the comparison sheets (the count must match the number of reports).--sheetsselects sheet groups:gpu_timeline,ops_summary,kernel_summary,ops_all,roofline, orall.-osets the output workbook path; add--output_csvs_dirto also emit CSVs.
Expected output: comparison.xlsx, a workbook with side-by-side columns for
each report. Rows are matched by op name, so this works best when the two runs
share the same op names (typically the same workload across configurations). When
names diverge — for example across hardware or library versions — use the
TraceDiff comparison instead.
You can also pass directories of per-sheet .csv files instead of .xlsx
reports, and compare more than two reports at once.
Step 3: Read the comparison sheets#
The output workbook contains one sheet per group you requested with --sheets:
Sheet |
When you get it |
What it shows |
|---|---|---|
|
|
GPU activity by type (compute, memcpy, and so on) with per-report timings plus |
|
|
Per-op aggregates keyed on |
|
|
Kernel-level summary for rocprof reports keyed on |
|
|
Three sheets per variant tag: |
|
|
Same intersect / only-baseline / only-variant breakdown for each roofline group: |
For every tracked metric, the comparison adds two columns:
metric__<tag>_diff # variant - baseline
metric__<tag>_pct # 100 * diff / baseline
Things to know when reading the workbook:
Outer merge, never inner: if an op exists in only one report it still appears (in the
only_baseline/only_variantsheets), so you can see ops that vanished or were newly introduced.Baseline is the first report you pass: choose its order deliberately.
Column prefixing: every metric is written as
<tag>::metric, so multiple reports can be compared safely.Noise is hidden, not deleted: columns like
median,std,min,max, andex_UIDare hidden in Excel for readability; unhide them if you need them.
Use these to find operations or categories that regressed or improved, shifts in the GPU-timeline breakdown (more idle time or exposed communication), and changes in roofline efficiency.
TraceDiff comparison (morphological)#
Where the perf-report comparison matches rows by op name, TraceDiff compares
the two traces by their morphological tree structure. It is an SDK you call
directly, giving finer-grained, programmatic analysis.
Why morphological diffing#
Unlike a leaf-level operation comparison, TraceDiff considers the morphological
structure of each trace to find the lowest common node between them. This
matters when the same logical operation lowers to different leaf ops — for
example, aten::convolution becomes aten::miopen_convolution on ROCm and
aten::cudnn_convolution on CUDA. A leaf-level diff would treat these as
unrelated; TraceDiff matches them at the convolution level, making it suitable
for comparing across hardware, libraries, or framework versions.
Compare two traces with the SDK#
from TraceLens import TreePerfAnalyzer, TraceDiff
# Build a tree for each trace
tree1 = TreePerfAnalyzer.from_file("/path/to/baseline.json").tree
tree2 = TreePerfAnalyzer.from_file("/path/to/candidate.json").tree
td = TraceDiff(tree1, tree2) # tree1 is the baseline
td.generate_tracediff_report() # builds DataFrames; writes no files
td.print_tracediff_report_files("rprt_diff", prune_non_gpu=True) # writes files
generate_tracediff_report() populates the result DataFrames in memory;
print_tracediff_report_files() writes them to disk (pass prune_non_gpu=True
to drop subtrees with no GPU work).
Note
TraceDiff operates on PyTorch profiler JSON traces, which it builds into the
TraceToTree objects it compares.
Output files#
print_tracediff_report_files() writes the following files to disk.
File |
Contents |
|---|---|
|
Text visualization of the merged tree, showing matched and unmatched nodes. |
|
Detailed per-op-instance statistics: input shapes, types, kernel times, and kernel names. |
|
Statistics aggregated per op name plus unique argument combination. |
|
Per-trace map from each CPU op to its kernels. |
Access DataFrames and UID mapping#
After generate_tracediff_report(), the same data is available as DataFrames,
and merged_uid_map cross-references events between the two trees:
df_stats = td.diff_stats_df # detailed per-op
df_args = td.diff_stats_unique_args_summary_df # per op name + unique args
# Find the tree2 UID corresponding to a tree1 UID (-1 if no match)
uid1 = next(iter(td.baseline.cpu_root_nodes))
uid2 = td.get_corresponding_uid(1, uid1)
Inline diff during report generation#
To run TraceDiff automatically while generating the primary PyTorch report, pass
--comparison_json_path. This adds speedup, delta, and lowest common ancestor (LCA) columns to
unified_perf_summary, plus a diff_stats sheet:
TraceLens_generate_perf_report_pytorch \
--profile_json_path traces/candidate.json \
--comparison_json_path traces/baseline.json
See the
trace_diff_example.ipynb
notebook for a worked example.
TraceLens Agent (comparative mode)#
The Comparative TraceLens Agent is an agentic workflow that uses TraceDiff to analyze traces and outputs a prioritized, stakeholder-facing optimization report. It’s best used when you want automated gap analysis with concrete optimization recommendations rather than raw data tables. For more information, see TraceLens Agent.