Summary
hipMemcpyPeer segfaults (SIGSEGV, exit 139) specifically when an R9700 attached via a Thunderbolt/USB4 eGPU dock is the source device (hip:0) copying to an integrated Strix Halo APU (hip:1). The reverse direction (Strix Halo as source) works cleanly every time. This blocks the dual-GPU asymmetric expert parallelism DS4 path (dflash_server with DFLASH_DS4_MOE_TP_INPROC=1), which requires the discrete GPU as the initiating hip:0 device.
Isolated with a minimal ~90-line standalone HIP program — zero Lucebox code — so this looks like a box/driver-level HIP peer-access defect specific to this eGPU/iGPU pairing, not an application bug. Filing here first since the repro was found while qualifying this exact hardware pairing against DS4.md's documented setup, and to check whether your own reference R9700+Strix Halo machine uses a native PCIe slot or an eGPU dock — that topology difference may be the actual variable.
Environment
- AMD Ryzen AI Max+ 395 (Strix Halo),
gfx1151, 128GB unified memory
- AMD Radeon AI PRO R9700,
gfx1201, 32GB GDDR6, attached via a Thunderbolt/USB4 eGPU dock (not a native PCIe slot)
- ROCm 6.4.1, HIP backend,
ghcr.io/luce-org/lucebox-hub:rocm image (also reproduced with a bare hipcc-compiled standalone program, no container-specific dependency)
- Dual-arch
dflash_server build: -DDFLASH27B_HIP_ARCHITECTURES='gfx1151;gfx1201' -DGGML_HIP_GRAPHS=ON -DCMAKE_BUILD_TYPE=Release
- Models:
DeepSeek-V4-Flash-ROCMFP2-STRIX.gguf (102.3GB) + DeepSeek-V4-Flash-DSpark-draft-Q4RMFP4-denseF16.gguf (11.3GB), matching DS4.md's documented "qualified R9700 + Strix Halo machine" setup exactly
What happens with dflash_server
With container HIP device ordering corrected so the R9700 lands on hip:0 (HIP_VISIBLE_DEVICES=1,0 — see note below on why this isn't 0,1), the server gets well into real placement logic:
[deepseek4] hybrid placement: gpu_total=31.86 GiB gpu_free=28.14 GiB core=3.72 GiB kv=0.89 GiB
warm=0.25 GiB safety=0.50 GiB expert_budget=11.43 GiB hot/layer=32
[deepseek4] placement expert_memory: total=91.38 GiB uniform_round=365.50 MiB hot=1376 11.42 GiB
cold=9632 79.95 GiB
[deepseek4-moe-tp] peer access hip:0 <-> hip:1: enabled
— then segfaults immediately after peer access is reported enabled, before any cross-device data transfer completes and before any measurable VRAM increase. Reproduced twice, identically: once via serve_ds4_dual_rocm_128k.sh, once invoking dflash_server directly with DS4.md's minimal-activation env vars (omitting --peer-access didn't help — DFLASH_DS4_MOE_TP_INPROC=1 triggers cross-device access internally regardless of that flag).
No stack trace on stdout (release build, no signal handler). coredumpctl shows SIGSEGV inaccessible for dflash_server at both crash timestamps. GPUs are fully healthy immediately after every crash (rocm-smi --showuse 0% busy both, no fault/IOMMU/DMAR entries in journalctl -k).
Minimal repro, no Lucebox code
To rule out an application bug, wrote a ~90-line standalone HIP C++ program: hipGetDeviceCount → per-device hipGetDeviceProperties → hipDeviceCanAccessPeer both directions → hipSetDevice/hipDeviceEnablePeerAccess both directions → hipMalloc on each device → hipMemcpyPeer (1MB) → exit, with fflush after every step. Compiled with hipcc --offload-arch=gfx1151 --offload-arch=gfx1201.
Each ordering run twice (4 runs total), 100% reproducible both times:
HIP_VISIBLE_DEVICES=1,0 (R9700 on hip:0, Strix on hip:1): crashes, SIGSEGV, both runs. Device enumeration, hipDeviceCanAccessPeer (both directions report 1), hipSetDevice, and both hipDeviceEnablePeerAccess calls (both report success) all print cleanly. Crash happens inside/immediately around hipMemcpyPeer(d1 <- d0, 1MB) — the last line printed both times was Attempting hipMemcpyPeer(d1 <- d0, 1MB)...; the result line never appears.
HIP_VISIBLE_DEVICES=0,1 (Strix on hip:0, R9700 on hip:1): succeeds cleanly, exit 0, both runs. hipMemcpyPeer -> no error and TEST COMPLETED WITHOUT CRASHING. both print.
Both orderings report hipDeviceCanAccessPeer = 1 in both directions and both report hipDeviceEnablePeerAccess succeeding in both directions — the crash isn't caught by either capability check, only by an actual hipMemcpyPeer data transfer, and only when the R9700 initiates it.
coredumpctl confirms the identical SIGSEGV inaccessible signature as the three dflash_server crashes above, at the exact timestamps of the two HIP_VISIBLE_DEVICES=1,0 runs.
Note: container HIP device ordering is inverted from host rocm-smi ordering (unrelated but adjacent gotcha)
Host-level rocm-smi --showproductname shows GPU[0] = R9700, GPU[1] = Strix Halo. Inside a container, KFD topology node numbering puts Strix Halo at HIP device 0 and R9700 at HIP device 1, regardless of --device bind-mount order — this is a kernel-global property. So HIP_VISIBLE_DEVICES=0,1 (matching host-level GPU numbering) actually puts the 128GB unified Strix Halo card on hip:0, not the R9700 the DS4 script expects there — worth calling out in DS4.md if it isn't already, since it produces an immediate, different, and more confusing crash (right after model metadata, before real placement logic) than the peer-DMA bug above.
Question for maintainers
Is your own qualified R9700 + Strix Halo reference machine using a native PCIe slot for the R9700, or an eGPU dock (Thunderbolt/USB4/OCuLink)? DS4.md doesn't say. My working hypothesis is that peer DMA between a Thunderbolt-tunneled discrete GPU and an integrated GPU is an architecturally unusual path that may not be exercised by your own qualification hardware if it's native PCIe — happy to help narrow this down further (e.g. testing with DFLASH_DS4_MOE_TP_INPROC disabled, or with a smaller allocation) if useful, or to move the R9700 to a native M.2 slot if one becomes available, to confirm whether topology is the actual variable.
Full writeup with additional log excerpts and methodology available on request.
Summary
hipMemcpyPeersegfaults (SIGSEGV, exit 139) specifically when an R9700 attached via a Thunderbolt/USB4 eGPU dock is the source device (hip:0) copying to an integrated Strix Halo APU (hip:1). The reverse direction (Strix Halo as source) works cleanly every time. This blocks the dual-GPU asymmetric expert parallelism DS4 path (dflash_serverwithDFLASH_DS4_MOE_TP_INPROC=1), which requires the discrete GPU as the initiatinghip:0device.Isolated with a minimal ~90-line standalone HIP program — zero Lucebox code — so this looks like a box/driver-level HIP peer-access defect specific to this eGPU/iGPU pairing, not an application bug. Filing here first since the repro was found while qualifying this exact hardware pairing against DS4.md's documented setup, and to check whether your own reference R9700+Strix Halo machine uses a native PCIe slot or an eGPU dock — that topology difference may be the actual variable.
Environment
gfx1151, 128GB unified memorygfx1201, 32GB GDDR6, attached via a Thunderbolt/USB4 eGPU dock (not a native PCIe slot)ghcr.io/luce-org/lucebox-hub:rocmimage (also reproduced with a barehipcc-compiled standalone program, no container-specific dependency)dflash_serverbuild:-DDFLASH27B_HIP_ARCHITECTURES='gfx1151;gfx1201' -DGGML_HIP_GRAPHS=ON -DCMAKE_BUILD_TYPE=ReleaseDeepSeek-V4-Flash-ROCMFP2-STRIX.gguf(102.3GB) +DeepSeek-V4-Flash-DSpark-draft-Q4RMFP4-denseF16.gguf(11.3GB), matching DS4.md's documented "qualified R9700 + Strix Halo machine" setup exactlyWhat happens with
dflash_serverWith container HIP device ordering corrected so the R9700 lands on
hip:0(HIP_VISIBLE_DEVICES=1,0— see note below on why this isn't0,1), the server gets well into real placement logic:— then segfaults immediately after peer access is reported enabled, before any cross-device data transfer completes and before any measurable VRAM increase. Reproduced twice, identically: once via
serve_ds4_dual_rocm_128k.sh, once invokingdflash_serverdirectly with DS4.md's minimal-activation env vars (omitting--peer-accessdidn't help —DFLASH_DS4_MOE_TP_INPROC=1triggers cross-device access internally regardless of that flag).No stack trace on stdout (release build, no signal handler).
coredumpctlshowsSIGSEGV inaccessiblefordflash_serverat both crash timestamps. GPUs are fully healthy immediately after every crash (rocm-smi --showuse0% busy both, no fault/IOMMU/DMAR entries injournalctl -k).Minimal repro, no Lucebox code
To rule out an application bug, wrote a ~90-line standalone HIP C++ program:
hipGetDeviceCount→ per-devicehipGetDeviceProperties→hipDeviceCanAccessPeerboth directions →hipSetDevice/hipDeviceEnablePeerAccessboth directions →hipMallocon each device →hipMemcpyPeer(1MB) → exit, withfflushafter every step. Compiled withhipcc --offload-arch=gfx1151 --offload-arch=gfx1201.Each ordering run twice (4 runs total), 100% reproducible both times:
HIP_VISIBLE_DEVICES=1,0(R9700 onhip:0, Strix onhip:1): crashes, SIGSEGV, both runs. Device enumeration,hipDeviceCanAccessPeer(both directions report1),hipSetDevice, and bothhipDeviceEnablePeerAccesscalls (both report success) all print cleanly. Crash happens inside/immediately aroundhipMemcpyPeer(d1 <- d0, 1MB)— the last line printed both times wasAttempting hipMemcpyPeer(d1 <- d0, 1MB)...; the result line never appears.HIP_VISIBLE_DEVICES=0,1(Strix onhip:0, R9700 onhip:1): succeeds cleanly, exit 0, both runs.hipMemcpyPeer -> no errorandTEST COMPLETED WITHOUT CRASHING.both print.Both orderings report
hipDeviceCanAccessPeer=1in both directions and both reporthipDeviceEnablePeerAccesssucceeding in both directions — the crash isn't caught by either capability check, only by an actualhipMemcpyPeerdata transfer, and only when the R9700 initiates it.coredumpctlconfirms the identicalSIGSEGV inaccessiblesignature as the threedflash_servercrashes above, at the exact timestamps of the twoHIP_VISIBLE_DEVICES=1,0runs.Note: container HIP device ordering is inverted from host
rocm-smiordering (unrelated but adjacent gotcha)Host-level
rocm-smi --showproductnameshowsGPU[0]= R9700,GPU[1]= Strix Halo. Inside a container, KFD topology node numbering puts Strix Halo at HIP device 0 and R9700 at HIP device 1, regardless of--devicebind-mount order — this is a kernel-global property. SoHIP_VISIBLE_DEVICES=0,1(matching host-level GPU numbering) actually puts the 128GB unified Strix Halo card onhip:0, not the R9700 the DS4 script expects there — worth calling out in DS4.md if it isn't already, since it produces an immediate, different, and more confusing crash (right after model metadata, before real placement logic) than the peer-DMA bug above.Question for maintainers
Is your own qualified R9700 + Strix Halo reference machine using a native PCIe slot for the R9700, or an eGPU dock (Thunderbolt/USB4/OCuLink)? DS4.md doesn't say. My working hypothesis is that peer DMA between a Thunderbolt-tunneled discrete GPU and an integrated GPU is an architecturally unusual path that may not be exercised by your own qualification hardware if it's native PCIe — happy to help narrow this down further (e.g. testing with
DFLASH_DS4_MOE_TP_INPROCdisabled, or with a smaller allocation) if useful, or to move the R9700 to a native M.2 slot if one becomes available, to confirm whether topology is the actual variable.Full writeup with additional log excerpts and methodology available on request.