Skip to content

fix(amdsmi): make the ABI compliance check catch real breaks - #14425

Merged
marifamd merged 1 commit into
developfrom
users/marifamd/amdsmi-abi-check-fix
Oct 30, 2026
Merged

marifamd merged 1 commit into
developfrom
users/marifamd/amdsmi-abi-check-fix

Conversation

@marifamd

Copy link
Copy Markdown
Contributor

Motivation

The ABI compliance check never flags a break. check_report_content() matches text that abi-compliance-checker 2.3 does not print, so every report reads as clean, and major mode passes with a warning even when the checker exits 1. It passed #8575 (removed amdsmi_gpu_driver_reload) and #11821 (grew amdsmi_driver_info_t from 768 to 1792 bytes, reverted in #13926).

Technical Details

Report parser (tests/abi_check/abi_check.py):

  • Read the counts from the report's section headings (<h2>Removed Symbols <span class='failed'>&nbsp;1&nbsp;</span>)
  • Fail on removed symbols, High or Medium severity problems, and any Size of this type has been changed row, naming the type
  • The checker rates struct growth Low because it assumes the library allocates the struct; amd-smi callers allocate their output structs, so growth breaks binaries built against the old header
  • Fail major mode when the checker exits non-zero; it used to finish "with warnings" and pass

Baseline (tests/abi_check/abi_check.py):

  • Compare against git merge-base <base> HEAD instead of the base branch tip. Without this, once the check can fail, a PR that forked before an API landed on develop is reported as removing it

Tests and docs:

  • tests/abi_check/abi_check_test.py: fixtures are fragments of real abi-compliance-checker 2.3 reports; adds merge-base and pass/fail tests
  • .pre-commit-config.yaml: run abi_check_test.py when tests/abi_check/ changes, so the LSTT Formatting job runs it; no workflow ran it before
  • tests/README.md: describe both

Not changed: abi-compliance-check.yml. The check stays non-blocking and still reports through the MAJOR ABI BREAKAGE / MINOR ABI BREAKAGE labels. The workflow runs the base branch's abi_check.py, so this PR's own ABI jobs still use the old parser.

Issue Tracking

Related: #11821, #13926

Test Plan

  • abi_check_test.py on Python 3.6, 3.10 and 3.14, against develop's abi_check.py and this branch
  • develop's and this branch's abi_check.py with abi-compliance-checker 2.3 on Ubuntu 22.04 (the CI job's tool and OS), major and minor mode, on real amdsmi.h pairs, each in a throwaway git repo so git merge-base and git show behave as in CI
  • pre-commit run --from-ref origin/develop --to-ref HEAD from projects/amdsmi, as the LSTT Formatting job runs it

Test Result

  • abi_check_test.py: the new tests fail on develop's abi_check.py (3 failures, 5 errors) and all 16 pass with this change on every Python version

Real abi-compliance-checker 2.3 runs, exit code (major / minor):

amdsmi.h change develop This PR This PR reports
#8575: removed amdsmi_gpu_driver_reload 0 / 1 1 / 1 Removed Symbols: 1
#11821: grew amdsmi_driver_info_t 0 / 1 1 / 1 amdsmi_driver_info_t 768 to 1792 bytes
release/therock-10.0 to release/therock-10.1 0 / 1 1 / 1 amdsmi_enumeration_info_t 276 to 280 bytes
release/therock-10.1 to release/therock-10.2 0 / 1 1 / 1 Medium data type problems; amdsmi_driver_info_t, amdsmi_fabric_info_t and its fabric_info_ union grew
#12804: added APIs 0 / 0 0 / 0
#11471: added APIs 0 / 1 0 / 1
AMDSMI_LIB_VERSION_MINOR bump 0 / 1 0 / 1
No change 0 / 0 0 / 0
PR forked before #12804, base branch then gained it 0 / 1 0 / 0

Minor mode keeps its meaning (any change the checker reports with -strict); only its baseline changed.

Submission Checklist

@marifamd
marifamd requested a review from a team October 27, 2026 23:08
@therock-pr-bot

Copy link
Copy Markdown

✅ All Policy Checks Passed

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —

🎉 All policy checks passed!

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

- Parse the abi-compliance-checker 2.3 report markup; the old patterns
  never matched it, so every report read as clean
- Fail on removed symbols, High or Medium problems, and any type size
  change. The checker rates struct growth Low because it assumes the
  library allocates the struct, but amd-smi callers allocate theirs
- Fail major mode when the checker exits non-zero instead of passing
  with a warning
- Compare against the merge base with the base branch, so APIs merged
  after a PR forked are not reported as removed by that PR
- Rewrite abi_check_test.py around real report markup and run it from
  pre-commit when tests/abi_check changes; no workflow ran it before

Signed-off-by: Maisam Arif <Maisam.Arif@amd.com>
@marifamd
marifamd force-pushed the users/marifamd/amdsmi-abi-check-fix branch from fd41276 to 6b1dfe6 Compare October 28, 2026 23:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The ABI-check script’s use of text=True causes an uncaught TypeError on Python 3.6, which is included in the test plan, while mocked subprocess calls hide the incompatibility in the new tests.

1 open issue
What changed in this PR

Strengthens amd-smi’s ABI compliance checks to detect breaking header changes and avoid false reports caused by newer changes on the base branch.

Changes:

  • Parses checker report headings and type-size changes, and fails when the checker exits non-zero.
  • Compares headers against the merge base rather than the base branch tip.
  • Expands regression tests, adds a pre-commit test hook, and updates test documentation.
File Description
projects/​amdsmi/​tests/​README.md Documents the merge-base comparison and ABI test hook.
projects/​amdsmi/​tests/​abi_check/​abi_check.py Fixes report parsing, baseline selection, and failure handling.
projects/​amdsmi/​tests/​abi_check/​abi_check_test.py Adds report fixtures, merge-base tests, and pass/fail checks.
projects/​amdsmi/​.pre-commit-config.yaml Runs ABI checker tests when their directory changes.

Review effort: Max

@charis-poag-amd charis-poag-amd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Reading counts from the section headings, failing on struct size changes, and baselining on the merge base are the right fixes, and the real-report test table is convincing. Flagging amdsmi_enumeration_info_t (276 to 280 bytes in therock-10.0 to 10.1) as a break is correct.

Inline comments are non-blocking. The main one: a checker error (non-zero exit other than 1) is now reported as an ABI break, which could produce a false MAJOR ABI BREAKAGE label if the old header can't be fetched.

Since the workflow runs the base branch's abi_check.py, this PR's own ABI jobs use the old parser. Worth a follow-up check in CI after merge.

@marifamd
marifamd merged commit 2157e9d into develop Oct 30, 2026
182 of 186 checks passed
@marifamd
marifamd deleted the users/marifamd/amdsmi-abi-check-fix branch October 30, 2026 15:52
dmitrii-galantsev added a commit that referenced this pull request Oct 30, 2026
Follow-up to #14425 and its review.

abi-compliance-checker exits 1 for incompatible changes and other codes
when it cannot compare, for example 11 for the empty old header that
prepare_headers() wrote when git show failed. #14425 reported any
non-zero exit as a break, which would add a false MAJOR ABI BREAKAGE
label. abi_check.py now exits 2 for a checker error, a missing merge
base, an old header it cannot fetch, or a report without the 2.3
summary table, and the workflow records that as "error", which leaves
the labels alone. Falling back to the base branch tip when the merge
base is missing would report everything the branch gained as removed,
so that is an error too.

The x86_64 library is built with ENABLE_ESMI_LIB, but the checker
parsed amdsmi.h without it and skipped the CPU API: 69 functions, 12
types and the SPD and power-efficiency limits. Define it at the top of
both copies of the header.

Callers size buffers and check limits with amdsmi.h constants when they
are built, so raising AMDSMI_MAX_MM_IP_COUNT from 8 to 16 breaks old
binaries. The checker rates that Low, so the check passed it. Fail on
any changed non-string constant in the binary compatibility report,
which already leaves out AMDSMI_LIB_VERSION_*.

Also: a size row no longer inherits the type name from an earlier
section, merge_base() works on Python 3.6, and the tests cover High
severity, symbol problems and Low type problems that are not size
changes.
dmitrii-galantsev added a commit that referenced this pull request Oct 30, 2026
Follow-up to #14425 and its review.

abi-compliance-checker exits 1 for incompatible changes and other codes
when it cannot compare, for example 11 for the empty old header that
prepare_headers() wrote when git show failed. #14425 reported any
non-zero exit as a break, which would add a false MAJOR ABI BREAKAGE
label. abi_check.py now exits 2 for a checker error, a missing merge
base, an old header it cannot fetch, or a report without the 2.3
summary table, and the workflow records that as "error", which leaves
the labels alone. Falling back to the base branch tip when the merge
base is missing would report everything the branch gained as removed,
so that is an error too.

The x86_64 library is built with ENABLE_ESMI_LIB, but the checker
parsed amdsmi.h without it and skipped the CPU API: 69 functions, 12
types and the SPD and power-efficiency limits. Define it at the top of
both copies of the header.

Callers size buffers and check limits with amdsmi.h constants when they
are built, so raising AMDSMI_MAX_MM_IP_COUNT from 8 to 16 breaks old
binaries. The checker rates that Low, so the check passed it. Fail on
any changed non-string constant in the binary compatibility report,
which already leaves out AMDSMI_LIB_VERSION_*.

Also: a size row no longer inherits the type name from an earlier
section, merge_base() works on Python 3.6, and the tests cover High
severity, symbol problems and Low type problems that are not size
changes.
@systems-assistant

Copy link
Copy Markdown
Contributor

TheRock Submodule Bump Activity

Newest first

erman-gurses pushed a commit that referenced this pull request Nov 4, 2026
## Motivation

Callers allocate most amdsmi structs and load the library by name, so a
changed layout corrupts memory in programs built against the old header
instead of failing to load. Recent examples:
- #11741 grew `amdsmi_fabric_info_t` from 320 to 552 bytes.
- #11821 grew `amdsmi_driver_info_t` from 768 to 1792 bytes.
- #10226 grew `amdsmi_enumeration_info_t` from 276 to 280 bytes.

All three landed within SONAME 27. #14425 made the existing `ABI
Compliance Check` report such changes, but it only labels a PR and
cannot block it. This PR also covers the follow-ups from #14425's
review.

## Technical Details

**ABI Compliance Check (#14425 follow-ups)**
- `abi_check.py` exits 1 for a break and 2 when it could not compare.
That covers a checker error, a missing merge base, an old header it
cannot fetch, or a report without the 2.3 summary table.
`abi-compliance-check.yml` records exit 2 as `error`, which leaves the
labels unchanged instead of adding a false `MAJOR ABI BREAKAGE`.
- It defines `ENABLE_ESMI_LIB` before parsing, so the CPU API (69
functions, 12 types) is checked.
- It fails on a changed non-string constant, such as
`AMDSMI_MAX_MM_IP_COUNT` going from 8 to 16.
- Smaller fixes:
  - a size row no longer inherits a type name from an earlier section;
  - it works on Python 3.6;
  - the patterns point at `ACC_COMMIT`;
- new tests cover High severity, symbol problems and Low type problems
that are not size changes.

**AMDSMI ABI Gate (new, blocking once required)**
- `tests/abi_check/abi_gate.py` parses `amdsmi.h` with libclang and
records:
  - each type's size, alignment and field offsets;
  - enumerator values and function signatures;
  - integer macros;
- the units, sentinel values and in/out directions in field and
parameter doc comments.

It compares the PR with its base and the newest `release/therock-*`
branch, each read from git. Additions pass, and so do fields carved from
`reserved*` arrays or bitfields when the struct keeps its size.
- An intended break is recorded with `abi_gate.py acknowledge --why
"#NNNN: ..."`, which adds one line per change (path, old and new value,
reason) to `projects/amdsmi/abi/abi_exceptions.json`, together with a
CHANGELOG line naming it. The owners of `projects/amdsmi/` review both.
The file starts with the three `%` units #13540 documented on develop
that 10.2 does not have.
- `.github/workflows/amdsmi-abi-gate.yml` runs on every PR to develop
and `release/therock-*`, on merge groups, and on pushes to develop.
  - It has a read-only token and no secrets.
- It runs the checker from the base commit, or from develop when the
base has none, such as an older release branch.
- There is no `paths:` filter, so it can become a required check. PRs
that do not touch amdsmi's headers pass in seconds.

**TheRock CI**
- `.github/skip-ci-config.toml` skips the TheRock build for
`projects/amdsmi/abi/*` and `projects/amdsmi/tests/abi_check/*`, which
no build reads.

This PR does not make the gate required. That is a ruleset change after
an advisory period, together with a "require workflows" rule, because on
pull requests GitHub runs the PR's own copy of the workflow file.

## Issue Tracking

JIRA ID: TBD
Follows up #14425.

## Test Plan

- `abi_check_test.py`, `abi_gate_test.py` and the amdsmi pre-commit
hooks.
- `abi_check.py` with abi-compliance-checker 2.3 on real headers: no
change, an enum value change, a header that does not compile, and a
missing base ref.
- Gate replay on the 73 develop commits that changed `amdsmi.h` in the
last 12 months, the `release/therock-*` transitions, and 25 bypass
fixtures.
- The gate workflow run locally with `act` for same-repo and fork PRs,
merge groups and pushes to develop.

## Test Result

- 29 and 86 unit tests pass.
- `abi_check.py` exits 0, 1, 2 and 2 for the four headers.
- The gate blocks all 19 layout and API breaks in the replay and misses
none. Among them: #11741, #11821, #13926, #8575, #10226, the
`AMDSMI_LINK_TYPE_PCIE`/`XGMI` value swap, and the same-size
`amdsmi_version_t` change.
- It also blocks 4 doc-only unit corrections, which pass once
acknowledged.
- A PR that replaces the checker with `exit 0` still fails.

## Submission Checklist

- [ ] Look over the contributing guidelines at
https://github.com/ROCm/rocm-systems/blob/develop/CONTRIBUTING.md.

---------

Signed-off-by: Maisam Arif <Maisam.Arif@amd.com>
Co-authored-by: Maisam Arif <Maisam.Arif@amd.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants