Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions changelog.d/changed/0780-nolint-cluster-refactor-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## NOLINT cluster audit and refactor plan (ADR-0780)

Swept all 218 NOLINT annotations in `core/src/` for clusters of five or more identical
suppressions per file. Identified five clusters (71 annotations total):

- **SYCL stride arithmetic** (`bugprone-implicit-widening`, 12 annotations): scheduled
for removal via explicit `(ptrdiff_t)` casts — no semantic change.
- **GPU slab allocator** (`performance-no-int-to-ptr`, 21 annotations): missing ADR
citations (ADR-0278 non-compliant); scheduled for consolidation behind a shared
`SLAB_FIELD` macro in `core/src/feature/gpu_slab.h`.
- **SYCL `misc-const-correctness`** (14 annotations): fold into existing per-file
`NOLINTBEGIN`/`NOLINTEND` block; no new annotation site needed.
- **CPU ADM band-processing** (`readability-function-size`, 13 bare annotations):
scheduled for `NOLINTBEGIN` block consolidation with ADR-0141 citation.
- **SYCL kernel entry-points** (`readability-function-size`, 11 annotations):
load-bearing per ADR-0141; no change.

Research digest: `docs/research/nolint-cluster-audit-2026-05-29.md`.
Follow-up PRs A–C are independent and can be executed in parallel worktrees.
73 changes: 73 additions & 0 deletions docs/adr/0780-nolint-cluster-refactor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# ADR-0780: NOLINT Cluster Refactor Plan — Slab Allocator, SYCL Stride, and ADM Band-Size

- **Status**: Proposed
- **Date**: 2026-05-29
- **Deciders**: lusoris
- **Tags**: `ci`, `simd`, `cuda`, `sycl`, `hip`, `lint`

## Context

A sweep of the 218 `NOLINT` annotations under `core/src/` (PR #61, ADR-0278 citation
closeout) identified five clusters where more than five suppressions of the same
category appear in a single file or tightly related file group. Three of these clusters
are refactorable: (1) bare `performance-no-int-to-ptr` annotations in GPU slab
allocators violate ADR-0278 (no citation) and could be eliminated by a shared macro;
(2) `bugprone-implicit-widening-of-multiplication-result` in SYCL stride arithmetic
could be eliminated entirely by adding explicit `(ptrdiff_t)` casts; (3) bare
`readability-function-size` annotations in `integer_adm.c` also lack citations and
could be consolidated into NOLINTBEGIN/NOLINTEND blocks. The remaining two clusters
(SYCL `misc-const-correctness` and SYCL `readability-function-size`) are either
consolidation opportunities or load-bearing per ADR-0141.

The user requested a cluster digest and a plan for follow-up refactor PRs; this ADR
records the decision to proceed with the three-PR sequence described in the research
digest (`docs/research/nolint-cluster-audit-2026-05-29.md`).

## Decision

We will execute three independent follow-up PRs:

- **PR A** (`sycl-stride-cast`): Replace implicit-widening SYCL stride multiplications
with explicit `(ptrdiff_t)` casts in `integer_adm_sycl.cpp` and
`integer_vif_sycl.cpp`, eliminating 12 suppressions entirely.
- **PR B** (`gpu-slab-macro`): Introduce `core/src/feature/gpu_slab.h` with a
`SLAB_FIELD(ptr, type)` macro; migrate `hip/integer_vif_hip.c`,
`cuda/integer_vif_cuda.c`, and `cuda/integer_adm_cuda.c`, eliminating 21 bare
uncited annotations.
- **PR C** (`adm-nolint-consolidation`): Extend SYCL `NOLINTBEGIN` blocks to include
`misc-const-correctness`; add a `NOLINTBEGIN(readability-function-size)` block with
ADR-0141/ADR-0278 citations in `integer_adm.c`, eliminating 27 inline annotations.

The SYCL `readability-function-size` cluster (11 annotations) is load-bearing per
ADR-0141 §2 and is not touched.

## Alternatives considered

| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
| Add citations only (no structural change) | Minimal diff | Leaves 47 annotations in place; doesn't reduce visual noise | Less clean than eliminating or consolidating |
| Single mega-PR with all changes | One review round | Three unrelated files; harder to bisect if one change regresses | Independent PRs allow staged CI |
| Suppress at `.clang-tidy` project level | Smallest diff | Hides legitimate future violations | Too broad; defeats the per-site rationale |

## Consequences

- **Positive**: 47 of 71 clustered annotations eliminated or consolidated; `gpu_slab.h`
establishes a reusable pattern for future GPU backends; SYCL files become easier to
read without repeated identical suppressions.
- **Negative**: `gpu_slab.h` is a new dependency for GPU feature files; must be kept
in sync with any future slab layout changes.
- **Neutral / follow-ups**: PRs A–C can be dispatched in parallel worktrees. Each PR
is lint-clean and bit-exact (no semantic change to the C/SYCL arithmetic).

## References

- Research digest: `docs/research/nolint-cluster-audit-2026-05-29.md`
- ADR-0141 (touched-file cleanup + load-bearing NOLINT rule)
- ADR-0278 (NOLINT citation closeout)
- Related: `core/src/feature/sycl/integer_vif_sycl.cpp`,
`core/src/feature/sycl/integer_adm_sycl.cpp`,
`core/src/feature/hip/integer_vif_hip.c`,
`core/src/feature/integer_adm.c`
- Source: user direction (paraphrased): sweep for NOLINT clusters larger than 5 in
the same area; assess root cause, refactor feasibility, and ADR-0278 compliance;
produce digest and open a ready PR.
1 change: 1 addition & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -778,3 +778,4 @@ ADRs may exist there for local session continuity, but the tracked
| [ADR-0810](0810-adr-0108-compliance-audit-2026-05-29.md) | ADR-0108 six-deliverables compliance audit (2026-05-29): 93 % pass rate on 5 PRs; D3 AGENTS.md gap fixes for PR #1571 (repo rename) and PR #1583 (HTTP transport) | Accepted | 2026-05-29 | docs, agents, process |
| [ADR-0811](0811-security-codeql-go-pvr.md) | Security hardening: CodeQL Go coverage, codeql-config.yml conflict resolution, Dependabot/Renovate posture | Accepted | 2026-05-29 | ci, security, codeql, go, dependabot, ossf |
| [ADR-0805](0805-lint-config-tighten-2026-05-29.md) | Lint config tightening: fix `.clang-tidy` HeaderFilterRegex (`libvmaf/` → `core/`), bump clang-format/ruff hooks, add `UP` pyupgrade rule, auto-fix 48 violations | Accepted | 2026-05-29 | lint, build, python, ci, fork-local |
| [ADR-0780](0780-nolint-cluster-refactor.md) | NOLINT cluster refactor plan: three-PR sequence to eliminate or consolidate 47 of 71 clustered suppressions — SYCL stride explicit casts (12), GPU slab SLAB_FIELD macro (21), ADM band-size NOLINTBEGIN consolidation (14). SYCL kernel-size cluster (11) is load-bearing per ADR-0141 and unchanged. | Proposed | 2026-05-29 | ci, lint, simd, cuda, sycl, hip, fork-local |
170 changes: 170 additions & 0 deletions docs/research/nolint-cluster-audit-2026-05-29.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# NOLINT Cluster Audit — 2026-05-29

**Scope**: all `NOLINT` / `NOLINTNEXTLINE` / `NOLINTBEGIN`…`NOLINTEND` annotations
under `core/src/` with five or more occurrences of the same suppression category in a
single file or closely related group of files.

**Total annotations found**: 218 across 62 files.

---

## Cluster 1 — SYCL `misc-const-correctness` (atomic_ref variables)

**Files**: `core/src/feature/sycl/integer_vif_sycl.cpp` (8),
`core/src/feature/sycl/integer_adm_sycl.cpp` (6)

**Root cause**: clang-tidy's `misc-const-correctness` check cannot trace writes
through `sycl::atomic_ref<>` or sub-group reduction intrinsics. Variables that
accumulate via atomic operations are flagged as "could be const" even though they are
mutated at runtime. This is a well-known analyser limitation (the analyser sees the
variable type, not the aliased atomic write path).

**Refactor candidate**: a single file-scope comment block at the top of each SYCL TU
covered by an existing `NOLINTBEGIN(misc-const-correctness)` … `NOLINTEND` pair would
collapse all inline suppressions into one guarded region, matching the existing
`misc-use-anonymous-namespace` / `misc-use-internal-linkage` pattern already in use at
the top and bottom of both files. This would reduce 14 inline annotations to 0 (folded
into the block already present) with no semantic change.

**Justifiable?** Yes — but could be tighter. The existing BEGIN/END block at the file
boundary could be extended to also cover `misc-const-correctness`. The inline
suppressions are redundant given the file-level block approach.

**Recommendation**: extend the `NOLINTBEGIN` / `NOLINTEND` blocks in both SYCL TUs
to include `misc-const-correctness`. Remove the 14 inline annotations. ADR-0278
(NOLINT citation closeout) already sanctions this category for SYCL.

---

## Cluster 2 — SYCL `bugprone-implicit-widening-of-multiplication-result` (stride arithmetic)

**Files**: `core/src/feature/sycl/integer_adm_sycl.cpp` (8),
`core/src/feature/sycl/integer_vif_sycl.cpp` (4)

**Root cause**: SYCL global-id / stride index computations multiply two
`int`-width operands; clang-tidy warns that the product could overflow before
widening. These are kernel `nd_range` bounds that are architecturally bounded,
so the widening is the correct intent, not a bug.

**Refactor candidate**: wrap each multiplication as `(ptrdiff_t)(a) * (b)` to make
the widening explicit and satisfy the linter without a suppression. This is a
mechanical one-line fix per site — no semantic change, no performance impact, and it
eliminates the need for the suppression entirely. 12 annotations across two files
could be deleted.

**Justifiable?** Suppression is defensible but unnecessary — a cast is cleaner and
more portable to future analysers.

**Recommendation**: replace every `(size_t)a * b`-style SYCL stride expression with
`(ptrdiff_t)(a) * (ptrdiff_t)(b)` or equivalent explicit-width cast. Remove the
12 suppressions. No ADR needed (straightforward cast fix).

---

## Cluster 3 — SYCL `readability-function-size` (kernel entry points)

**Files**: `integer_adm_sycl.cpp` (6), `integer_vif_sycl.cpp` (5)

**Root cause**: SYCL kernel-launch entry points are structurally large because they
must declare all accessors and capture them in a single `parallel_for` lambda. Any
split would either require a helper free function that the compiler cannot inline back
into device code, or a macro expansion that trades line-count for readability.
This is the pattern documented in ADR-0141 §2 as a load-bearing invariant.

**Refactor candidate**: none viable. The existing citations (ADR-0141, ADR-0278) are
correct. These 11 suppressions are justified.

**Recommendation**: no change needed. Suppressions are load-bearing.

---

## Cluster 4 — `performance-no-int-to-ptr` in slab allocators

**Files**: `core/src/feature/hip/integer_vif_hip.c` (16),
`core/src/feature/cuda/integer_vif_cuda.c` (3),
`core/src/feature/cuda/integer_adm_cuda.c` (2)

**Root cause**: GPU backends use a single contiguous `malloc` slab partitioned by
bumping a `uint8_t *ptr` pointer, then casting sub-ranges to typed pointers
(`uint16_t *`, `uint32_t *`, etc.). This is the standard arena/slab allocator
pattern; `performance-no-int-to-ptr` fires because the cast goes through pointer
arithmetic, not from an integer value.

**Problem**: these suppressions carry **no ADR citations** — they are bare
`/* NOLINTNEXTLINE(performance-no-int-to-ptr) */` with no justification comment. This
violates ADR-0278 (every NOLINT must cite an ADR / research digest / rebase
invariant inline).

**Refactor candidate A (preferred)**: add a named helper macro or inline function
`SLAB_FIELD(ptr, type)` that wraps the cast and moves the suppression to one
definition site. This reduces 16+3+2 = 21 inline annotations to a single guarded
definition. The macro pattern is already used in `core/src/feature/integer_adm.c`
for `bugprone-macro-parentheses` (lines 262–747 block).

**Refactor candidate B (minimal)**: add inline citations to the existing
suppressions, referencing the slab-allocation pattern and an appropriate ADR
(e.g. ADR-0278 itself, or a new ADR if the slab pattern needs its own entry).

**Justifiable?** Yes — slab allocation is a legitimate use of pointer arithmetic,
but the missing citations make it non-compliant with ADR-0278.

**Recommendation**: implement the `SLAB_FIELD` macro in a shared GPU helper header
(e.g. `core/src/feature/gpu_slab.h`) and migrate all three files. This eliminates
21 bare NOLINTs and establishes a reusable pattern for future GPU backend additions
(HIP, Vulkan).

---

## Cluster 5 — `readability-function-size` in `integer_adm.c` (CPU scalar)

**File**: `core/src/feature/integer_adm.c` (13 bare annotations, lines 752–3580)

**Root cause**: ADM has intrinsically large band-processing functions (one per
scale × decomposition pass). Each function is a tight numerical loop with a fixed
structure; splitting would require passing 15–20 local variables or packaging them
in a struct, adding indirection that the compiler cannot always eliminate.

**Problem**: all 13 suppressions are **bare** (`// NOLINTNEXTLINE(readability-function-size)`)
with no ADR citations. ADR-0278 non-compliant.

**Refactor candidate**: the NOLINTBEGIN/NOLINTEND block already present at lines
262–747 for `bugprone-macro-parentheses` + `bugprone-implicit-widening` demonstrates
that block-form suppression is acceptable here. Extending the block (or adding a
second block) to cover `readability-function-size` for the band-processing functions
would consolidate 13 individual annotations and require only one citation comment.

**Recommendation**: add a `NOLINTBEGIN(readability-function-size)` /
`NOLINTEND(readability-function-size)` block around the band-processing section with
a single citation comment (ADR-0141 §2 / ADR-0278), replacing 13 individual bare
annotations. Alternatively, add inline citations to each existing annotation.

---

## Summary table

| Cluster | File(s) | Count | Root cause | Refactorable? | Priority |
|---|---|---|---|---|---|
| SYCL misc-const-correctness | `sycl/integer_{vif,adm}_sycl.cpp` | 14 | Analyser blind to atomic_ref writes | Extend NOLINTBEGIN block | Medium |
| SYCL bugprone-implicit-widening | `sycl/integer_{adm,vif}_sycl.cpp` | 12 | Stride mult without explicit cast | Replace with explicit cast (remove NOLINT) | High |
| SYCL readability-function-size | `sycl/integer_{adm,vif}_sycl.cpp` | 11 | SYCL kernel-launch pattern (load-bearing, ADR-0141) | No — justified | None |
| GPU slab `performance-no-int-to-ptr` | `hip/integer_vif_hip.c`, `cuda/*` | 21 | Slab allocator, missing citations | `SLAB_FIELD` macro in shared header | High |
| CPU ADM `readability-function-size` | `integer_adm.c` | 13 | Band-processing functions, missing citations | Extend NOLINTBEGIN block | Medium |

**Total refactorable**: 47 of 71 clustered annotations (66%). The remaining 24
(SYCL readability-function-size) are load-bearing and correctly cited.

---

## Recommended implementation sequence

1. **PR A**: Add explicit `(ptrdiff_t)` casts to SYCL stride arithmetic in
`integer_adm_sycl.cpp` and `integer_vif_sycl.cpp` — removes 12 NOLINTs
without any semantic change.
2. **PR B**: Introduce `core/src/feature/gpu_slab.h` with `SLAB_FIELD` macro;
migrate `hip/integer_vif_hip.c`, `cuda/integer_vif_cuda.c`,
`cuda/integer_adm_cuda.c` — removes 21 bare NOLINTs, adds one cited definition.
3. **PR C**: Extend SYCL `NOLINTBEGIN` blocks to cover `misc-const-correctness`;
extend or add `NOLINTBEGIN(readability-function-size)` in `integer_adm.c` with
ADR citations — removes 14+13 = 27 inline annotations.

PRs A–C are independent (different files) and can be staged in parallel worktrees.
Loading