Skip to content

ci: cross-check RTL vs GVSoC cycle counts per tile#40

Draft
diaconuccalin wants to merge 6 commits into
mainfrom
cd/36-ci-test-for-profiling-match-between-rtl-and-gvsoc
Draft

ci: cross-check RTL vs GVSoC cycle counts per tile#40
diaconuccalin wants to merge 6 commits into
mainfrom
cd/36-ci-test-for-profiling-match-between-rtl-and-gvsoc

Conversation

@diaconuccalin

Copy link
Copy Markdown
Contributor

What

Adds a CI gate that compares per-tile cycle counts between the RTL (Modelsim) and GVSoC simulators for the same test binary, failing if any tile diverges by more than ±10%. Runs on the 14 RTL-CI tests for the 1×1 and 4×4 tile configs.

How

The same binary runs on both sims, so the instrumentation is platform-agnostic and read out differently per platform:

  • RTLsentinel_start()/sentinel_end() are no-ops on the core but detected by the MAGIA testbench (magia_vip.sv, PROFILE_SENTINEL, requires build_mode=profile), which prints per-tile (<N> clock cycles).
  • GVSoCxperf_end() prints the mcycle CSR delta as [XPERF] mhartid <id> CYCLES <n> (perf_get_cycles() does not work on RTL).

Both lines are keyed by mhartid → per-tile comparison.

Changes

  • xperf_start/xperf_end helper (targets/magia_v{1,2}/include/utils/performance_utils.h), gated by the new PROFILE_XPERF flag (default off; threaded through Makefile and both CMakeLists.txt like the existing PROFILE_* flags). When off, both calls compile to nothing, so default builds (regression, gvtest, other RTL tests) are byte-identical and emit no [XPERF] lines.
  • One xperf pair around the work region of the 14 tests.
  • scripts/ci/compare_cycles.py — per-tile ±10% comparison, hard fail.
  • .gitlab-ci.yml — build RTL with build_mode=profile, build tests with profile_xperf=1, namespace sim logs (.rtl.log/.gvsoc.log), add compare_tiles_4 / compare_tiles_1 stages.

Granularity

v1 is one region per test (one cycle number per tile). The path to ordered multi-segment profiling is documented but not implemented (the RTL testbench only decodes the generic sentinel pair, not the per-category sentinels).

To watch on first run

  • build_mode=profile + fast_sim=1 coexistence, and the testbench (clock cycles) lines landing in captured stdout.
  • test_helloworld's tiny cycle count may be noisy at ±10% — easy to widen or drop.

🤖 Generated with Claude Code

Add a CI gate that compares per-tile cycle counts between the RTL
(Modelsim) and GVSoC simulators for the same test binary, failing if any
tile diverges by more than 10%.

The same binary runs on both sims, so instrumentation is platform-agnostic
and read out differently per platform:
  - RTL: sentinel_start/end are detected by the MAGIA testbench
    (PROFILE_SENTINEL, requires build_mode=profile), which prints per-tile
    "(<N> clock cycles)".
  - GVSoC: xperf_end prints the mcycle CSR delta as
    "[XPERF] mhartid <id> CYCLES <n>".

Changes:
  - xperf_start/xperf_end helper (magia_v1 + v2 performance_utils.h),
    gated by the PROFILE_XPERF flag (default off; threaded through Makefile
    and both CMakeLists like the existing PROFILE_* flags). When off both
    calls compile to nothing, leaving default builds unchanged.
  - One xperf pair around the work region of the 14 RTL-CI tests.
  - scripts/ci/compare_cycles.py: per-tile ±10% comparison, hard fail.
  - .gitlab-ci.yml: build RTL with build_mode=profile, build tests with
    profile_xperf=1, namespace sim logs (.rtl.log/.gvsoc.log), add
    compare_tiles_4 / compare_tiles_1 stages for the 1x1 and 4x4 configs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@diaconuccalin diaconuccalin linked an issue Jun 16, 2026 that may be closed by this pull request
diaconuccalin and others added 5 commits June 16, 2026 17:48
xperf_end() uses get_hartid()/printf(), which were only available via
tile.h's include order. Drivers (e.g. idma32.c) pull performance_utils.h
through idma_isa_utils.h without magia_utils.h first, so with
profile_xperf=1 get_hartid() was implicitly declared and then conflicted
with its real definition, breaking the build.

Include magia_utils.h directly in performance_utils.h (v1 and v2); it
provides get_hartid() and transitively printf(), and nothing in that chain
includes performance_utils.h, so there is no include cycle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- github-ci.yml: upload the fetched gitlab-logs/ dir (full job traces plus
  the unzipped test_*.rtl.log / test_*.gvsoc.log artifacts) as a downloadable
  GitHub Actions artifact, and print the .log tails inline alongside traces.
- Reduce the RTL-vs-GVSoC cycle match tolerance from 10% to 5%
  (.gitlab-ci.yml COMPARE_TOL and compare_cycles.py --tol default).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The MAGIA testbench sentinel monitor (magia_vip.sv) inspects the WB stage
every cycle, so a sentinel instruction held in WB across a short pipeline
stall (a following CSR read / MMIO store / fsync) was counted more than
once. That produced spurious "sentinel end without corresponding start"
** Error messages, inflating Modelsim's "Errors: N" summary, which
sim_ret_errors.sh then read as a test failure (test_gemv, test_mm_is_2,
test_mm_ws_2) even though every tile reported 0 functional errors.

Pad each sentinel in xperf_start/xperf_end with 8 NOPs so it retires from
WB before any stalling instruction follows it. The padding sits outside the
GVSoC measurement points and adds a negligible, constant offset to the RTL
window (~16 cycles on ~11k), well within the 5% tolerance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@diaconuccalin diaconuccalin self-assigned this Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CI Test for Profiling Match between RTL and GVSoC

1 participant