Skip to content

fish_drama3: device_sampling (default since #1063) aborts on HIP with ARGSORT invalid configuration #1071

Closed

Description

@Ramon-Balaguer

Summary

On HIP, Fish Audio Drama 3 aborts on the first non-greedy request when fish_drama3.device_sampling is enabled, which has been the default since #1063:

ggml_cuda_compute_forward: ARGSORT failed
ROCm error: invalid configuration argument
  current device: 0, in function ggml_cuda_compute_forward at external/ggml/src/ggml-cuda/ggml-cuda.cu:3372
  err
external/ggml/src/ggml-cuda/ggml-cuda.cu:106: ROCm error

The server process exits after this, and every request fails until it is restarted. With "fish_drama3.device_sampling": false everything works.

Environment

  • AMD Radeon 8060S (Strix Halo, gfx1151), 96 GiB VRAM carve-out (UMA), ROCm 10.0.0 (HIP 7.15.26333, AMD clang 23.0.0git), Debian 13 LXC.
  • audio.cpp main at dd92e32b, built with scripts/build_linux.sh --backend hip --gpu-targets gfx1151 --model-set custom --models fish_drama3 --target audiocpp_server --build-type Release. Reproduced with both GGML_HIP_HIPBLASLT ON and OFF.
  • On this iGPU the model only loads with Stage HIP device weight uploads through a bounded host buffer #1070 applied; without it the weight upload stalls first. The crash itself happens later, during generation.
  • Model: drama-3-backbone-4bit-experts-Q4_K_S.gguf (Jmica/Drama-3-GGUF).

Reproduce

Server config entry (backend: hip):

{"id": "drama-3", "family": "fish_drama3", "task": "tts", "mode": "offline",
 "path": ".../drama-3-backbone-4bit-experts-Q4_K_S.gguf",
 "session_options": {"fish_drama3.cpu_expert_layers": 0, "fish_drama3.context_length": 4096}}
curl -s http://127.0.0.1:8002/v1/audio/speech -H 'Content-Type: application/json' \
  -d '{"model":"drama-3","input":"Hello, this is a quick test.","voice":"<preset>","response_format":"wav"}'

The same happens in mode: streaming with stream_format: sse. Adding "fish_drama3.device_sampling": false to session_options avoids it.

Likely cause (from reading the code)

  • With device sampling, the tower samples each codebook in the backend graph and sorts the full codebook: src/community_models/fish_drama3/tower.cpp, ggml_argsort(ctx, logits, GGML_SORT_ORDER_DESC) over codebook_size = 4096 logits.
  • On HIP, GGML_CUDA_USE_CUB is never defined (external/ggml/src/ggml-cuda/common.cuh, #if !defined(GGML_USE_HIP) && ...). As a result, ggml_cuda_op_argsort always takes the bitonic path.
  • argsort_f32_i32_cuda_bitonic launches one block of next_power_of_2(ncols) threads per row (block_dims(ncols_pad, 1, 1)), so 4096 threads here. HIP allows at most 1024 threads per block, so the launch fails with invalid configuration argument.

On CUDA the same row length goes through CUB (ncols > 1024), which would explain why the problem only shows up on HIP. Greedy decoding (temperature 0 or top_k 1) uses ggml_argmax instead of ggml_argsort and should not be affected; I have not tested that.

Possible fixes (untested suggestions)

  • Default fish_drama3.device_sampling to false on HIP until a large-row argsort exists there.
  • Or give ggml's HIP backend an argsort path for rows longer than 1024, such as hipCUB/rocPRIM or a multi-block bitonic sort, or make it fail with a clear error before the launch.

I can test a patch on gfx1151 if that helps.

Activity

  1. 0xShug0 commented on Oct 24, 2026

    @0xShug0
    Owner

    @Ramon-Balaguer Thanks for reporting the issue! I'll revert the default for better compatibility as a workaround, but I still plan to add the missing path. For larger models, device-side sampling can significantly improve performance and should be the standard approach going forward.

  2. 0xShug0 commented on Oct 24, 2026

    @0xShug0
    Owner

    @Ramon-Balaguer Could you test #1076?

  3. ZeroDot1 commented on Oct 25, 2026

    @ZeroDot1
    Contributor

    I tested PR #1076 on an AMD Radeon RX 9070 XT (gfx1201, 16 GiB VRAM), ROCm 7.2.53211, Linux x86_64. I built the same upstream base in isolated /tmp worktrees, once without the PR and once with only the PR changes, using Release + HIP/gfx1201.

    Results

    • The PR build passed all 110 ARGSORT correctness cases on ROCm0, including ascending and descending sorts at 4,096, 4,097, and 32,768 values, multi-row shapes, and repeated graph execution.
    • With the PR build, Fish Drama 3 Q2 ran using the default fish_drama3.device_sampling=true. It generated a 60.511 s mono WAV at 44.1 kHz in 65.539 s (RTF 1.08), without aborting in the large-row sampler.
    • The Fish Drama timing log contained 16 drama3.sampling_ms observations: 7.68 ms median, ranging from 6.43 to 17.56 ms. For context, drama3.backbone_step_ms had a 3,212.51 ms median and drama3.tower_ms a 1,046.56 ms median. These are logged model timing windows, not isolated per-token measurements; in this run, ARGSORT was not the dominant measured cost.
    • Separately, Stable Audio 3 Small Music Q8_0 generated exactly 60.000 s stereo at 44.1 kHz in 2.985 s (RTF 0.05; 20.1× realtime). The Fish Drama run was repeated after clearing VRAM; I did not use the earlier overlapping run.
    • The PR backend performance case ARGSORT(ne=[65000,16,1,1]) completed 4,130 repetitions at 440.76–442.85 µs/run across three clean runs (median 442.67 µs/run, approximately 17.5 GB/s). The baseline reports this large HIP ARGSORT as “not supported”, so this measures the newly enabled path; it is not a before/after speedup comparison.

    Conclusion

    The fix works on gfx1201 and enables the missing HIP path. I found no evidence of a material performance regression in these tests. The results support the correctness fix, but they do not establish a speedup over the baseline because the baseline cannot run these large rows.

    Possible follow-up optimization to measure

    The HIP path currently uses segmented radix sort even for a single row. For nrows == 1, a non-segmented hipcub::DeviceRadixSort path could avoid allocating and initializing the segment-offset array. This is an optimization hypothesis only; it needs profiling and correctness tests before adoption.

    Sketch:

    if (nrows == 1) {
        return hipcub::DeviceRadixSort::SortPairs(
            storage, storage_bytes,
            x, keys.get(),
            indices.get(), dst,
            ncols, 0, sizeof(float) * 8, stream);
    }
    
    // Keep DeviceSegmentedRadixSort for multiple rows.

    A useful follow-up benchmark would separate hipCUB setup, temporary-buffer acquisition, and sort execution with HIP events, then compare one-row and multi-row cases around 1,024/1,025, 4,096/4,097, and 32,768 values. I would keep the current bitonic path at or below 1,024 unless measurements show a benefit from changing that threshold.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions