Repository navigation
perf(clr): fill with wide copies in HostBlitManager::fillBuffer - #12629
Conversation
HostBlitManager::fillBuffer called memcpy() once per pattern element. The pattern size is a runtime value, so every iteration is a real libc call that copies 1-4 bytes, and the per-call overhead dominates: a 64 MiB hipMemset made 67M calls. The time scaled with the element count rather than the byte count. Changes: - 1-byte patterns use a single memset(). - Wider patterns are replicated into a 4 KiB stack staging block, built by doubling and capped at the fill size, which is then copied out in block-sized memcpy() calls. - The destination is only ever written, never read back, since it may be write-combined memory. The fill result is unchanged, including the existing handling of a size that is not a multiple of the pattern size. Co-Authored-By: Claude <noreply@anthropic.com>
✅ All Policy Checks Passed
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
|
🚫 Please fix the failed policies before requesting reviews. The following policy checks failed:
The |
Fill patterns are capped at FillMemoryCommand::MaxFillPatterSize (128 bytes), so a pattern always fits in the 4 KiB staging block. Drop the fallback that copied straight from the pattern for larger patterns and assert the bound at compile time instead. Changes: - static_assert that MaxFillPatterSize fits in the staging block - Always copy out of the staging block; remove the conditional source - Shorten the doubling and copy-out loops Output is byte-identical to the per-element loop for every pattern size from 1 to 128 bytes across 25 fill sizes (0 to 1 MiB, odd sizes, unaligned destination, guard bytes checked). Speed is unchanged within noise. HIP 1D memset tests pass with a build where they take the host fill path. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The bounded staging algorithm preserves existing semantics and avoids reading write-combined destinations.
Review effort: Balanced
Findings: None
What changed in this PR
Optimizes host-accessible buffer fills by reducing small memcpy() calls.
Changes:
- Uses
memset()for single-byte patterns. - Replicates wider patterns into a 4 KiB staging block for bulk copies.
- Preserves existing partial-pattern behavior.
| File | Description |
|---|---|
projects/clr/rocclr/device/blit.cpp |
Implements wide-copy host buffer filling. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
🤖 AI-assisted pre-review (for @mangupta) Re-reviewed the updated head ( |
HostBlitManager::fillBuffer (#12629) [rocm-systems] ROCm/rocm-systems#12629 (commit d1e287a)
TheRock Submodule Bump ActivityNewest first
|
Motivation
HostBlitManager::fillBufferis slow for large fills because it callsmemcpy()once per pattern element. The host fill path is taken when the destination is directly accessible from the host, for example:hipMemset/hipMemsetAsynconhipHostMallocmemory.clEnqueueFillBufferon host-accessible buffers.Technical Details
The pattern size is a runtime value, so each loop iteration is a real libc
memcpy()call that copies a few bytes. The per-call overhead dominates, and fill time scales with the element count rather than the byte count. A 64 MiBhipMemsetmakes about 67M calls.The fill now uses wide copies:
memset().memcpy()calls. The block is built by doubling and capped at the fill size, so small fills stay cheap.FillMemoryCommand::MaxFillPatterSize(128 bytes), so a pattern always fits in the staging block. Astatic_assertenforces this.The result of the fill is unchanged, including the existing behaviour when the size is not a multiple of the pattern size.
Issue Tracking
JIRA ID: ROCM-32043
Test Plan
Test Result
Microbenchmark, time per fill (old loop -> new):
The output matched the old loop in all 3,200 comparison cases.
All 41 positive 1D memset tests in MemoryTest1/MemoryTest2 pass with the final code (D8/D16/D32, sync and async, unaligned, small and zero size). The 2D/3D memset, pitch and graph-capture memset tests also passed on the first commit; the second commit only restructures the staging loop.
Not tested on Windows or with OpenCL.
Submission Checklist
🤖 Generated with Claude Code