Skip to content

[XPU] add in scheduler.avg with patch, not dependent on verl-core - #32

Merged
physics31415926 merged 11 commits into
verl-project:mainfrom
kahlun:experiment/xpu-monkeypatch-reduce-avg-attention
Sep 30, 2026
Merged

physics31415926 merged 11 commits into
verl-project:mainfrom
kahlun:experiment/xpu-monkeypatch-reduce-avg-attention

Conversation

@kahlun

@kahlun kahlun commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Open question for reviewers, up front

reduce_avg_allreduce_patch.py patches torch.distributed.all_reduce when op=AVG — the only mechanism available for verl-core's 3 raw dist.all_reduce(op=ReduceOp.AVG) call sites, since there's no per-site wrapper to hook into and this plugin doesn't own those call sites. It's scoped to dist.get_backend(group) == "xccl", so a gloo/nccl group in the same process (e.g. a CPU-only Ray actor's coordination group alongside a GPU worker's xccl group) is untouched and keeps native AVG — this was originally unscoped (any group, any backend) and has been fixed to check the backend per call. What's left: anyone reading verl-core's source still can't see, from that source alone, that an xccl group's ReduceOp.AVG silently becomes SUM+divide, for as long as the process runs (there's no narrower call-boundary available — see Changes below for why). That's a real design smell, not a clean win, and is the one piece here still worth a narrow core-hook ask if that's judged unacceptable — happy to split it into its own PR against #7917 if so.

Summary

Plugin-side replacement for is_reduce_avg_supported() — implemented with zero verl-core changes: no new PlatformBase hook, no dependency on verl-project/verl#7917.

Motivation

verl-hardware-plugin#26 asked maintainers whether Intel XPU should extend PlatformBase in verl-core (the TPU precedent) or stay entirely inside this plugin via monkeypatch (the MLU precedent). The maintainer's answer (2026-09-23): default to the plugin, keep #7917 narrowed to only what truly can't be done from here.

is_reduce_avg_supported/all_reduce_avg has just been dropped from #7917 and from #22 on that basis -- the underlying reduce_avg problem doesn't need a core hook to work around. (Correction from an earlier version of this PR: the reason isn't "xccl doesn't implement ReduceOp.AVG" -- per this review-thread investigation on real 4xB60 hardware, oneCCL implements AVG on its SYCL-kernel path but not its scheduler path, and path selection is internal and not capability-aware, so an AVG request can abort mid-collective rather than reliably succeed or fail. Fix tracked for oneCCL 2022.2 / torch 2.15. Same mechanism below, corrected reasoning.) This PR is the plugin-side replacement.

attention_utils_module() and the profiler hooks passed the maintainer's bar and stay as PlatformBase hooks — implemented for XPU in #22, which this PR does not touch or duplicate. (An earlier draft of this branch also monkeypatched attention as a "how far can pure monkeypatch go" comparison; dropped once it was clear the hook was staying and a plugin-only alternative for it served no purpose.)

Changes

  • verl_hardware_plugin/engines/fsdp_xpu.py: extend the existing (non-hook, non-patch) initialize() override to call set_force_sum_reduction_for_comms(True) on the FSDP2 root and every individually-wrapped transformer layer, not just the root — each fully_shard()'d module has independent FSDP state. This is ordinary method-override behavior on the plugin's own EngineRegistry-registered engine, not a monkeypatch, so it's robust regardless of import order. Also fixes an unrelated self.model→self.module attribute bug in the same function (FSDPEngineWithLMHead/WithValueHead expose the wrapped model as self.module, never self.model) — [XPU] feat(xpu): add VTune (ITT) profiler backend #22 had picked up the same fix independently since it lives in the same lines; dropped from [XPU] feat(xpu): add VTune (ITT) profiler backend #22 in favor of this PR's superset version (root + per-layer, vs. root-only).
  • verl_hardware_plugin/patches/reduce_avg_allreduce_patch (new): monkeypatches torch.distributed.all_reduce(op=AVG) → SUM + manual divide, scoped to xccl process groups (dist.get_backend(group) == "xccl"), for the three remaining raw dist.all_reduce(op=ReduceOp.AVG) call sites in verl-core (sft_trainer.py, engine_workers.py, profiler/performance.py::reduce_timing). See the open question above. async_op=True call sites are intentionally left unpatched (falls through to original behavior) rather than risk returning a wrong result before the collective completes.
  • verl_hardware_plugin/patches/__init__.py (new): plain package docstring, no code — holds reduce_avg_allreduce_patch as the one patch module. No generic apply_all() aggregator: it had exactly one caller and one module, so it wasn't earning its keep (see the platform_xpu.py bullet below).
  • verl_hardware_plugin/platforms/platform_xpu.py: PlatformXPU.__init__ calls reduce_avg_allreduce_patch.apply() directly. Deliberately not called from the shared verl_hardware_plugin/__init__.py (that file is common to every vendor this plugin supports) — PlatformXPU() is only constructed once verl.plugin.platform.platform_manager._create_platform() has actually selected "intel" as the platform for this process. Calling it from the shared top-level __init__.py instead would fire on any host where torch.xpu merely happens to be importable, even if a different platform ends up selected for the run — e.g. a mixed host with VERL_PLATFORM=nvidia explicitly set would still get its process-wide all_reduce semantics changed for no reason. (Two earlier drafts of this PR had this wired the wrong way, then routed through an unnecessary same-package apply_all() wrapper — both fixed.)

Testing

  • pytest tests/ -v passes (76 passed), including new coverage:
    • PlatformXPU() instantiation triggers reduce_avg_allreduce_patch.apply(); the shared plugin __init__.py no longer binds any patch call directly (regression guard against re-introducing the wrong wiring).
    • reduce_avg_allreduce_patch: op=AVG on an xccl group → SUM + divide by world size; op=AVG on a non-xccl group (e.g. gloo) passes through untouched; other ops pass through unchanged; async_op=True + AVG falls through unpatched; no-op when XPU unavailable; idempotent (calling apply() twice doesn't double-wrap).
  • Manually verified on target hardware (B60):
    What's new here is the method-override framing
    • reduce_avg_allreduce_patch.py's actual collective behavior is unit-tested

Acceptance Baseline (for new hardware adaptation PRs)

  • Ran scripts/baseline_grpo_gsm8k.sh on target hardware (8 devices)
  • Training completed all epochs without error
  • critic/rewards/mean shows clear upward trend in first 100 steps
  • Curve is consistent with NVIDIA reference

Checklist

  • Code follows the project's style and passes pre-commit checks
  • Documentation updated — folded into this description rather than a docs/design/ file; this repo has no precedent for keeping RFC/experiment-verdict docs in the merged tree
  • No secrets or credentials included

Split out of experiment/xpu-monkeypatch-no-core-hooks: covers
is_reduce_avg_supported (FSDP2 per-layer loop, no patch needed; raw
dist.all_reduce(AVG), patched) and attention_utils_module. Both work
with zero verl-core changes, independent of the VTune profiler half
(docs/design/xpu-monkeypatch-vtune-profiler.md), which still has an
open blocker.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…atch

attention_utils_module() is staying a PlatformBase hook (see PR #22, and
verl-project/verl#7917's updated description) -- it passed the maintainer's
bar on verl-hardware-plugin#26 for a genuinely hardware-agnostic capability
that couldn't be done cleanly from the plugin alone. Carrying a monkeypatch
alternative for it here too just duplicates an already-accepted, working
solution with no benefit.

is_reduce_avg_supported() didn't pass that bar and is this branch's actual
job: the xccl AVG gap can be fully handled from the plugin (FSDP2 via an
engine-level method override, the 3 remaining raw dist.all_reduce(op=AVG)
sites via a scoped, documented monkeypatch).

Renamed the design doc to match (xpu-monkeypatch-reduce-avg.md) and folded
in a note that this branch is now the sole owner of the fsdp_xpu.py
self.model->self.module fix -- it's been dropped from #22's smaller,
root-only version of the same fix now that #22 no longer touches this file
for any other reason.
kahlun added a commit to kahlun/verl-hardware-plugin-fork that referenced this pull request Sep 24, 2026
…erl-project#32

Redundant scope: this PR no longer touches fsdp_xpu.py for any AVG-related
reason (is_reduce_avg_supported was dropped in the previous commit), and
that file's only remaining purpose here was this one attribute fix, which
lives entirely in the pre-existing (pre-#22) reduce_avg workaround code.

experiment/xpu-monkeypatch-reduce-avg-attention already carries the same
fix as part of a strict superset (root + every per-layer FSDP2 wrapper, vs.
this PR's root-only version) -- keeping both risks two PRs racing to fix
the same lines. Leaving this PR to attention_utils_module and the VTune
profiler hooks only.
@kahlun kahlun changed the title [XPU] draft: reduce_avg + attention support via pure monkeypatch, no core changes [XPU] draft: reduce_avg support via pure monkeypatch, no core changes Sep 24, 2026
verl_hardware_plugin/__init__.py is shared across every vendor in this
plugin, so calling apply_all_patches() there fired the patch on any host
where torch.xpu merely happened to be importable -- regardless of which
platform verl actually selected for the run. A mixed host with e.g.
VERL_PLATFORM=nvidia set explicitly would still get its process-wide
torch.distributed.all_reduce(op=AVG) semantics changed for no reason,
compounding the design smell this patch already carries.

verl.plugin.platform.platform_manager._create_platform() only constructs
PlatformXPU() once platform detection has actually picked "intel" for this
process, so moving the call into PlatformXPU.__init__ ties it to real
platform selection instead. The narrow remaining edge case -- auto-detection
probing PlatformXPU() to check availability, then falling through to a
different platform -- is self-mitigating: the patch's own _xpu_available()
gate fails in the same underlying probe that made is_platform_available()
fail.

Also:
- Add unit tests for both the new wiring (PlatformXPU() triggers the patch;
  the plugin's top-level __init__ no longer binds it directly) and the
  reduce_avg_allreduce_patch_xpu wrapper itself (AVG -> SUM+divide, other
  ops pass through unchanged, async_op=True falls through unpatched,
  no-op when XPU unavailable, idempotent). 75 passed.
- Remove docs/design/xpu-monkeypatch-reduce-avg.md. This repo has no
  precedent for keeping RFC/experiment-verdict docs in the merged tree
  (confirmed: no docs/design/ directory exists on main, in any prior PR).
  Its reasoning already lives in this PR's description.
…irectly

apply_all() had exactly one caller (PlatformXPU.__init__) and exactly one
patch module (reduce_avg_allreduce_patch_xpu) -- no other vendor in this
plugin has any monkeypatches. The generic "apply every patch" name and loop
implied a cross-vendor aggregator like register_all_platforms()/
register_all_engines(), which genuinely do need to register every vendor up
front since verl-core's registries look classes up by name after the fact.
Patches don't share that constraint: they only ever matter to the one
platform that already got selected, so each platform's own __init__ calling
its own patch module directly is both simpler and more honest about what's
actually happening than routing through a same-package wrapper that only
ever had one real implementation behind it.

verl_hardware_plugin/patches/__init__.py is now a plain package docstring
pointing at reduce_avg_allreduce_patch_xpu, with no code. Updated the wiring
test to mock the real target (reduce_avg_allreduce_patch_xpu.apply) instead
of the removed wrapper. 75 passed.
_patched_all_reduce only checked op != AVG and async_op -- it never checked
which backend the target group actually uses. Once applied, it silently
intercepted op=AVG for every process group in the process, not just xccl
ones: a gloo group in the same process (e.g. a CPU-only Ray actor's
coordination group alongside a GPU worker's xccl group) would get routed
through SUM+divide too, even though gloo/nccl handle AVG natively and never
needed the workaround.

Added dist.get_backend(group) != "xccl" to the short-circuit condition so
non-xccl groups fall through to the original, untouched. Short-circuit
evaluation means only the actual substitution path needs get_backend
mocked in tests -- the passthrough tests (non-AVG op, async_op=True) never
reach it, since op != AVG or async_op already short-circuits first.

Added a test for a gloo-backed group with op=AVG to confirm it now passes
through unpatched. 76 passed.
Per kahlun's review-thread investigation on verl-project/verl#7917
(measured on real 4xB60 hardware, not reasoned from source): xccl does not
uniformly lack ReduceOp.AVG. oneCCL implements it on its SYCL-kernel
execution path but not on its scheduler path; path selection is internal
to oneCCL and isn't capability-aware, so an AVG request can abort
mid-collective ("average operation is not supported for the scheduler
path") rather than reliably succeed or reliably fail. Fix tracked for
oneCCL 2022.2 / torch 2.15, not yet available on the stack this plugin
targets.

Also note the separate, narrower double-division bug on very small
messages (intel/torch-xpu-ops#3020) is fixed on that same stack and is not
what either the FSDP2 engine override or this patch works around -- easy to
conflate the two since both are filed against xccl's AVG support.

The blanket "xccl does not support ReduceOp.AVG" phrasing this replaces was
accurate enough to justify the workaround but not accurate about why, and
was written before this investigation existed. Same mechanism, same
correctness -- corrected reasoning only. platform_xpu.py has the same
blanket phrasing but predates both this branch and #22; left alone here
since fixing it isn't part of this PR's diff.

76 passed.
@kahlun
kahlun marked this pull request as ready for review September 25, 2026 03:36
@kahlun kahlun changed the title [XPU] draft: reduce_avg support via pure monkeypatch, no core changes [XPU] add in scheduler.avg with patch, not dependent on verl-core Sep 28, 2026
@kahlun

kahlun commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator Author

@wuxibin89 @physics31415926 plugin-only ReduceOp.AVG patch for XPU/xccl, following the direction confirmed in #26 (no core changes).

One open design question is called out in the PR description if you want to weigh in on it specifically; otherwise it should be good to merge as-is.

@physics31415926
physics31415926 merged commit 58becfb into verl-project:main Sep 30, 2026
2 checks passed
physics31415926 pushed a commit that referenced this pull request Oct 13, 2026
## Summary

Adds Intel VTune (ITT) profiling support for Intel XPU, plus the XPU
user guide
that fills the stub `docs/accelerators/xpu/README.md`.

After the rework described below, this PR implements exactly **one**
`PlatformBase` hook — `profiler_markers()` — and does everything else
from the
plugin side:

- `PlatformXPU.profiler_markers()` → ITT range markers, so verl core can
emit
  trace ranges without knowing about ITT or XPU.
- `VtuneProfiler(DistProfiler)`, selected by `profiler.tool: vtune`,
registered
  by a plugin-side monkeypatch over `DistProfiler.__init__`
(`verl_hardware_plugin/accelerators/xpu/profilers/register_vtune.py`) —
no core hook.

## What changed since this PR was opened

Two rounds of narrowing, both driven by the ruling on
[#26](#26)
(2026-09-23) that new `PlatformBase` hooks are reserved for capabilities
that
genuinely can't be done from the plugin:

1. **`is_reduce_avg_supported()` dropped** — the xccl `ReduceOp.AVG` gap
doesn't
   meet that bar. Its plugin-only replacement landed as
[#32](#32)
(merged):
a monkeypatch over `torch.distributed.all_reduce`, scoped to xccl
groups.
2. **`attention_utils_module()` and `dist_profiler_cls()` dropped**
(2026-10-08,
commit `439503c`), following the narrowed hook surface in the rework of

[verl-project/verl#7917](verl-project/verl#7917):
- `attention_utils_module()`: nothing is needed from the plugin. verl
core
     routes every backend without a `flash_attn` build through its own
pure-PyTorch `attention_padding_utils` (the former
`npu_flash_attn_utils`,
renamed device-neutral) — the same `bert_padding` port this hook pointed
at.
- `dist_profiler_cls()`: it added a second dispatch mechanism alongside
     core's hardcoded if/elif, so `VtuneProfiler` is now claimed by the
`register_vtune.py` monkeypatch instead. The patch is double-gated —
applied from `PlatformXPU.__init__`, not at import time, and behind a
live
`torch.xpu.is_available()` check, because verl's platform auto-detection
     instantiates every registered platform to probe it.
- `profiler_markers()` is kept: core's module-level markers are imported
by
the trainer at module scope, so there is no plugin-side seam for them.

`verl_hardware_plugin/accelerators/xpu/engines/fsdp_xpu.py` is untouched
by this PR.

## Motivation

Add in profiling of step annotation for intel gpu

## Changes

- `verl_hardware_plugin/accelerators/xpu/platform_xpu.py`: add
`profiler_markers()`;
apply the VTune registration patch from `__init__` behind a live-device
check.
- `verl_hardware_plugin/accelerators/xpu/profilers/itt_profile_xpu.py`
(new): ITT range markers
(`mark_start_range`/`mark_end_range`/`mark_annotate`/`marked_timer`) and
  `VtuneProfiler(DistProfiler)`.
- `verl_hardware_plugin/accelerators/xpu/profilers/register_vtune.py`
(new): claims the `vtune`
  tool name by wrapping `DistProfiler.__init__`.
- `verl_hardware_plugin/accelerators/xpu/profilers/__init__.py` (new):
docstring note
  on registration.
- `tests/test_plugin_registration.py` (new): hook + registration tests
that run
  on a CPU-only host.
- `docs/accelerators/xpu/{install_guidance,quick_start,profiling}.md`
(new) and an
  updated `README.md`.

## verl-core dependency

`profiler_markers()` only exists on verl-core builds that include #7917.
Against
stock `verl-project/verl:main` the plugin still installs and runs, but
the hook
has no base method to override, so ITT ranges aren't emitted; #7917 also
lifts
the `tool_config` allowlist in `engine_workers.py`, without which a
`tool_config.vtune` entry is dropped. `VtuneProfiler` registration
itself is
pure monkeypatch and works either way. Use the pinned ref in
`docker/intel_gpu/` for a known-good combination until #7917 merges.

## Testing

- [x] `pytest tests/` — 199 passed on a CPU-only host (`torch
2.13.0+xpu`),
      including the new registration tests. Re-run after merging the
      accelerator reorganization (#41), which moved these modules to
      `accelerators/xpu/`.
- [x] Smoke-checked on 1x Arc Pro B60 against a verl-core build
*without*
#7917, i.e. the degraded path described above: `PlatformXPU` selected
(`xpu`/`intel`/`xccl`); ITT markers execute; `profiler.tool: vtune`
gives
`DistProfiler._impl = VtuneProfiler` with `start`/`step`/`stop` running,
while `tool: torch` still resolves to core's own profiler; and with no
#7917 the hook is absent, markers stay generic and the `tool_config`
      allowlist stays gated — a silent fallback, not an error.
- [x] ITT emission is real on this stack, not a stub:
`torch.profiler.itt.is_available()` is `True` and `torch._C._itt`
exposes
      `rangePush`/`rangePop`/`mark`.

**Not covered:** viewing the ranges in a VTune result. VTune attaches as
an
external collector, so `profiler_start`/`profiler_stop` are no-ops by
design and
there is no code path here that only a capture would exercise. It is
also not
runnable in the Intel GPU image: its oneAPI 2026.1 ships no `vtune`
component and no `libittnotify`. Installing the collector is an image
change,
independent of this PR — written up in
`docs/accelerators/xpu/profiling.md`
(Prerequisites + Troubleshooting).

## Acceptance Baseline (for new hardware adaptation PRs)

- [x] GRPO / PPO / GRPO+colocated-RM / SFT
(`tests/special_intel_gpu/*.sh`)
completed full training steps on B60 with this branch's platform changes
      live in the tree
- [ ] `critic/rewards/mean` upward trend / NVIDIA-reference curve from
      `scripts/baseline_grpo_gsm8k.sh` specifically — **TODO: paste the
      SwanLab/log link, or re-run that script.**

**SwanLab or training log link**: TODO

## Checklist

- [x] Code follows the project's style and passes `pre-commit` checks
- [x] Documentation updated
- [x] No secrets or credentials included

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
askhat-g pushed a commit to askhat-g/verl-hardware-plugin that referenced this pull request Nov 1, 2026
## Summary

Adds Intel VTune (ITT) profiling support for Intel XPU, plus the XPU
user guide
that fills the stub `docs/accelerators/xpu/README.md`.

After the rework described below, this PR implements exactly **one**
`PlatformBase` hook — `profiler_markers()` — and does everything else
from the
plugin side:

- `PlatformXPU.profiler_markers()` → ITT range markers, so verl core can
emit
  trace ranges without knowing about ITT or XPU.
- `VtuneProfiler(DistProfiler)`, selected by `profiler.tool: vtune`,
registered
  by a plugin-side monkeypatch over `DistProfiler.__init__`
(`verl_hardware_plugin/accelerators/xpu/profilers/register_vtune.py`) —
no core hook.

## What changed since this PR was opened

Two rounds of narrowing, both driven by the ruling on
[verl-project#26](verl-project#26)
(2026-09-23) that new `PlatformBase` hooks are reserved for capabilities
that
genuinely can't be done from the plugin:

1. **`is_reduce_avg_supported()` dropped** — the xccl `ReduceOp.AVG` gap
doesn't
   meet that bar. Its plugin-only replacement landed as
[verl-project#32](verl-project#32)
(merged):
a monkeypatch over `torch.distributed.all_reduce`, scoped to xccl
groups.
2. **`attention_utils_module()` and `dist_profiler_cls()` dropped**
(2026-10-08,
commit `439503c`), following the narrowed hook surface in the rework of

[verl-project/verl#7917](verl-project/verl#7917):
- `attention_utils_module()`: nothing is needed from the plugin. verl
core
     routes every backend without a `flash_attn` build through its own
pure-PyTorch `attention_padding_utils` (the former
`npu_flash_attn_utils`,
renamed device-neutral) — the same `bert_padding` port this hook pointed
at.
- `dist_profiler_cls()`: it added a second dispatch mechanism alongside
     core's hardcoded if/elif, so `VtuneProfiler` is now claimed by the
`register_vtune.py` monkeypatch instead. The patch is double-gated —
applied from `PlatformXPU.__init__`, not at import time, and behind a
live
`torch.xpu.is_available()` check, because verl's platform auto-detection
     instantiates every registered platform to probe it.
- `profiler_markers()` is kept: core's module-level markers are imported
by
the trainer at module scope, so there is no plugin-side seam for them.

`verl_hardware_plugin/accelerators/xpu/engines/fsdp_xpu.py` is untouched
by this PR.

## Motivation

Add in profiling of step annotation for intel gpu

## Changes

- `verl_hardware_plugin/accelerators/xpu/platform_xpu.py`: add
`profiler_markers()`;
apply the VTune registration patch from `__init__` behind a live-device
check.
- `verl_hardware_plugin/accelerators/xpu/profilers/itt_profile_xpu.py`
(new): ITT range markers
(`mark_start_range`/`mark_end_range`/`mark_annotate`/`marked_timer`) and
  `VtuneProfiler(DistProfiler)`.
- `verl_hardware_plugin/accelerators/xpu/profilers/register_vtune.py`
(new): claims the `vtune`
  tool name by wrapping `DistProfiler.__init__`.
- `verl_hardware_plugin/accelerators/xpu/profilers/__init__.py` (new):
docstring note
  on registration.
- `tests/test_plugin_registration.py` (new): hook + registration tests
that run
  on a CPU-only host.
- `docs/accelerators/xpu/{install_guidance,quick_start,profiling}.md`
(new) and an
  updated `README.md`.

## verl-core dependency

`profiler_markers()` only exists on verl-core builds that include #7917.
Against
stock `verl-project/verl:main` the plugin still installs and runs, but
the hook
has no base method to override, so ITT ranges aren't emitted; #7917 also
lifts
the `tool_config` allowlist in `engine_workers.py`, without which a
`tool_config.vtune` entry is dropped. `VtuneProfiler` registration
itself is
pure monkeypatch and works either way. Use the pinned ref in
`docker/intel_gpu/` for a known-good combination until #7917 merges.

## Testing

- [x] `pytest tests/` — 199 passed on a CPU-only host (`torch
2.13.0+xpu`),
      including the new registration tests. Re-run after merging the
      accelerator reorganization (verl-project#41), which moved these modules to
      `accelerators/xpu/`.
- [x] Smoke-checked on 1x Arc Pro B60 against a verl-core build
*without*
#7917, i.e. the degraded path described above: `PlatformXPU` selected
(`xpu`/`intel`/`xccl`); ITT markers execute; `profiler.tool: vtune`
gives
`DistProfiler._impl = VtuneProfiler` with `start`/`step`/`stop` running,
while `tool: torch` still resolves to core's own profiler; and with no
#7917 the hook is absent, markers stay generic and the `tool_config`
      allowlist stays gated — a silent fallback, not an error.
- [x] ITT emission is real on this stack, not a stub:
`torch.profiler.itt.is_available()` is `True` and `torch._C._itt`
exposes
      `rangePush`/`rangePop`/`mark`.

**Not covered:** viewing the ranges in a VTune result. VTune attaches as
an
external collector, so `profiler_start`/`profiler_stop` are no-ops by
design and
there is no code path here that only a capture would exercise. It is
also not
runnable in the Intel GPU image: its oneAPI 2026.1 ships no `vtune`
component and no `libittnotify`. Installing the collector is an image
change,
independent of this PR — written up in
`docs/accelerators/xpu/profiling.md`
(Prerequisites + Troubleshooting).

## Acceptance Baseline (for new hardware adaptation PRs)

- [x] GRPO / PPO / GRPO+colocated-RM / SFT
(`tests/special_intel_gpu/*.sh`)
completed full training steps on B60 with this branch's platform changes
      live in the tree
- [ ] `critic/rewards/mean` upward trend / NVIDIA-reference curve from
      `scripts/baseline_grpo_gsm8k.sh` specifically — **TODO: paste the
      SwanLab/log link, or re-run that script.**

**SwanLab or training log link**: TODO

## Checklist

- [x] Code follows the project's style and passes `pre-commit` checks
- [x] Documentation updated
- [x] No secrets or credentials included

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

2 participants