2222#include " ggml-alloc.h"
2323
2424#include < algorithm>
25+ #include < atomic>
2526#include < cinttypes>
2627#include < cmath>
2728#include < cstdlib>
@@ -76,7 +77,8 @@ static bool dflash_is_cuda_compatible_tensor(const ggml_tensor * t) {
7677 return false ;
7778 }
7879 const char * name = ggml_backend_buffer_name (t->buffer );
79- return name && (std::strncmp (name, " CUDA" , 4 ) == 0 || std::strncmp (name, " ROCm" , 4 ) == 0 );
80+ return name && (std::strncmp (name, " CUDA" , 4 ) == 0 || std::strncmp (name, " ROCm" , 4 ) == 0 ||
81+ std::strncmp (name, " Vulkan" , 6 ) == 0 );
8082}
8183
8284static bool dflash_tensor_span_in_bounds (const ggml_tensor * t, size_t offset_bytes, size_t n_bytes) {
@@ -2003,10 +2005,18 @@ void llama_context::dflash_ensure_recurrent_setup() {
20032005 dflash_capture->tape_name_map [" v_conv_predelta-" + il_str] = {idx, DFLASH_TAPE_V };
20042006 dflash_capture->tape_name_map [" gate-" + il_str] = {idx, DFLASH_TAPE_GATE };
20052007 dflash_capture->tape_name_map [" beta-" + il_str] = {idx, DFLASH_TAPE_BETA };
2008+ // qwen3next (Qwen3-Coder-Next) names the beta tensor "b" instead of "beta"
2009+ dflash_capture->tape_name_map [" b-" + il_str] = {idx, DFLASH_TAPE_BETA };
20062010 dflash_capture->tape_name_map [" qkv_mixed_pretranspose-" + il_str] = {idx, DFLASH_TAPE_QKV };
2007- // Qwen3Next emits pre-conv QKV under these names. Without one of
2008- // them, DFlash conv replay skips every recurrent layer and leaves
2009- // r_l frozen at the pre-draft backup state.
2011+ // qwen3next (Qwen3-Coder-Next) builds the pre-conv (pre-transpose) QKV via two
2012+ // code paths in build_qkvz(), both projecting the layer INPUT (pre-conv1d):
2013+ // wqkv path: "linear_attn_qkv_mixed-" (qwen3next.cpp:304) [used by Qwen3-Coder-Next]
2014+ // ssm_in legacy: "qkv_mixed-" (qwen3next.cpp:364) [concat of q/k/v flats]
2015+ // Both are the input to build_conv_state() (qwen3next.cpp:440), i.e. PRE-conv.
2016+ // Without recording one of these, tape_replay_conv skips every layer (empty
2017+ // qkv_mixed) and the conv state (r_l) is never advanced, so the conv state stays
2018+ // frozen at the backup value and the target output is garbled (0% acceptance).
2019+ // Verified: 504/504 conv layers OK after this fix; conv state matches re-decode ref.
20102020 dflash_capture->tape_name_map [" linear_attn_qkv_mixed-" + il_str] = {idx, DFLASH_TAPE_QKV };
20112021 dflash_capture->tape_name_map [" qkv_mixed-" + il_str] = {idx, DFLASH_TAPE_QKV };
20122022 }
@@ -2624,9 +2634,13 @@ void llama_context::set_active_dflash_slot(int slot_idx) {
26242634 }
26252635}
26262636
2627- void llama_context::tape_replay (llama_seq_id seq_id, int n_accepted) {
2637+ int llama_context::tape_replay (llama_seq_id seq_id, int n_accepted) {
26282638 if (!dflash_capture || n_accepted <= 0 ) {
2629- return ;
2639+ return 0 ;
2640+ }
2641+
2642+ if (const char * env = std::getenv (" GGML_DFLASH_FORCE_REDECODE" ); env && std::atoi (env) != 0 ) {
2643+ return n_accepted;
26302644 }
26312645
26322646 // ensure any previous async replay is complete before launching a new one
@@ -2639,7 +2653,7 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
26392653 n_accepted <= gpu_tape->n_tokens );
26402654
26412655 if (!use_gpu_tape && dflash_capture->tape_layers .empty ()) {
2642- return ;
2656+ return 0 ;
26432657 }
26442658
26452659 auto * mem_recurrent = dynamic_cast <llama_memory_recurrent *>(memory.get ());
@@ -2651,7 +2665,7 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
26512665 }
26522666 if (!mem_recurrent) {
26532667 LLAMA_LOG_WARN (" %s: tape replay requires recurrent memory\n " , __func__);
2654- return ;
2668+ return n_accepted ;
26552669 }
26562670
26572671 const auto & hparams = model.hparams ;
@@ -2668,7 +2682,7 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
26682682 }
26692683 if (cell_idx < 0 ) {
26702684 LLAMA_LOG_WARN (" %s: no active cell for seq %d\n " , __func__, seq_id);
2671- return ;
2685+ return n_accepted ;
26722686 }
26732687
26742688 const uint32_t n_embd_s = hparams.n_embd_s ();
@@ -2686,7 +2700,7 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
26862700 if (!gpu_backend) {
26872701 tape_replay_cpu (mem_recurrent, cell_idx, n_accepted);
26882702 tape_replay_conv (mem_recurrent, cell_idx, n_accepted, seq_id);
2689- return ;
2703+ return 0 ;
26902704 }
26912705
26922706 // partial offload: if any recurrent layer's state lives on CPU, fall back to CPU replay
@@ -2696,7 +2710,7 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
26962710 if (s_tensor && s_tensor->buffer && ggml_backend_buffer_is_host (s_tensor->buffer )) {
26972711 tape_replay_cpu (mem_recurrent, cell_idx, n_accepted);
26982712 tape_replay_conv (mem_recurrent, cell_idx, n_accepted, seq_id);
2699- return ;
2713+ return 0 ;
27002714 }
27012715 }
27022716
@@ -2709,14 +2723,14 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
27092723 dflash_capture->replay_cell_idx = cell_idx;
27102724 dflash_capture->replay_seq_id = seq_id;
27112725 dflash_capture->replay_mem_recurrent = mem_recurrent;
2712- return ;
2726+ return 0 ;
27132727 }
27142728
27152729 const bool multi_gpu_target = model.n_devices () > 1 ;
27162730 if (multi_gpu_target) {
27172731 if (tape_replay_gdn_direct_from_cpu_tape (mem_recurrent, cell_idx, n_accepted)) {
27182732 tape_replay_conv (mem_recurrent, cell_idx, n_accepted, seq_id);
2719- return ;
2733+ return 0 ;
27202734 }
27212735 if (!dflash_capture->multi_gpu_replay_fallback_logged ) {
27222736 LLAMA_LOG_WARN (" %s: multi-GPU target detected (%zu devices); exact CUDA DFlash replay unavailable, using CPU recurrent replay fallback\n " ,
@@ -2725,7 +2739,7 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
27252739 }
27262740 tape_replay_cpu (mem_recurrent, cell_idx, n_accepted);
27272741 tape_replay_conv (mem_recurrent, cell_idx, n_accepted, seq_id);
2728- return ;
2742+ return 0 ;
27292743 }
27302744
27312745 // GPU tape replay: build a ggml graph with GDN ops for all recurrent layers
@@ -2872,7 +2886,7 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
28722886 if (!use_gpu_tape) {
28732887 tape_replay_cpu (mem_recurrent, cell_idx, n_accepted);
28742888 tape_replay_conv (mem_recurrent, cell_idx, n_accepted, seq_id);
2875- return ;
2889+ return 0 ;
28762890 }
28772891 goto conv_rebuild;
28782892 }
@@ -2900,7 +2914,7 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
29002914 ggml_free (ctx);
29012915 tape_replay_cpu (mem_recurrent, cell_idx, n_accepted);
29022916 tape_replay_conv (mem_recurrent, cell_idx, n_accepted, seq_id);
2903- return ;
2917+ return 0 ;
29042918 }
29052919
29062920 // assign tensors within the persistent buffer
@@ -2955,8 +2969,9 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
29552969 if (!use_gpu_tape) {
29562970 tape_replay_cpu (mem_recurrent, cell_idx, n_accepted);
29572971 tape_replay_conv (mem_recurrent, cell_idx, n_accepted, seq_id);
2972+ return 0 ;
29582973 }
2959- return ;
2974+ return n_accepted ;
29602975 }
29612976 if (dflash_capture->profile ) {
29622977 const uint64_t elapsed = ggml_time_us () - t_replay_enqueue_us;
@@ -2976,11 +2991,12 @@ void llama_context::tape_replay(llama_seq_id seq_id, int n_accepted) {
29762991 dflash_capture->replay_cell_idx = cell_idx;
29772992 dflash_capture->replay_seq_id = seq_id;
29782993 dflash_capture->replay_mem_recurrent = mem_recurrent;
2979- return ; // conv rebuild deferred to tape_replay_sync()
2994+ return 0 ; // conv rebuild deferred to tape_replay_sync()
29802995 }
29812996
29822997conv_rebuild:
29832998 tape_replay_conv (mem_recurrent, cell_idx, n_accepted, seq_id);
2999+ return 0 ;
29843000}
29853001
29863002bool llama_context::tape_replay_gdn_direct_gpu (llama_memory_recurrent * mem_recurrent, int32_t cell_idx, int n_accepted) {
@@ -3944,11 +3960,11 @@ void llama_context::tape_replay_cpu(llama_memory_recurrent * mem_recurrent, int3
39443960 }
39453961}
39463962
3947- void llama_context::dflash_rollback (llama_seq_id seq_id, llama_seq_id seq_backup, int n_past_before, int n_accepted) {
3963+ int llama_context::dflash_rollback (llama_seq_id seq_id, llama_seq_id seq_backup, int n_past_before, int n_accepted) {
39483964 auto * mem_hybrid = dynamic_cast <llama_memory_hybrid *>(memory.get ());
39493965 if (!mem_hybrid) {
39503966 LLAMA_LOG_WARN (" %s: dflash_rollback requires hybrid memory\n " , __func__);
3951- return ;
3967+ return n_accepted ;
39523968 }
39533969
39543970 const bool profile = dflash_capture && dflash_profile_has (dflash_capture->profile_flags , DFLASH_PROFILE_COPY );
@@ -3997,7 +4013,7 @@ void llama_context::dflash_rollback(llama_seq_id seq_id, llama_seq_id seq_backup
39974013 profile_lap (recurrent_restore_us);
39984014
39994015 // Replay DeltaNet state updates for accepted tokens
4000- tape_replay (seq_id, n_accepted);
4016+ const int n_redecode = tape_replay (seq_id, n_accepted);
40014017 profile_lap (tape_launch_us);
40024018
40034019 if (profile) {
@@ -4019,6 +4035,7 @@ void llama_context::dflash_rollback(llama_seq_id seq_id, llama_seq_id seq_backup
40194035 tape_launch_us / 1e3 ,
40204036 (ggml_time_us () - t_start_us) / 1e3 );
40214037 }
4038+ return n_redecode;
40224039}
40234040
40244041void llama_context::dflash_prepare_branch (llama_seq_id seq_id, llama_seq_id seq_backup, int depth) {
@@ -8644,8 +8661,8 @@ bool llama_dflash_memory_seq_cp_recurrent_ordered(
86448661 return ctx ? ctx->dflash_memory_seq_cp_recurrent_ordered (seq_id_src, seq_id_dst, p0, p1) : false ;
86458662}
86468663
8647- void llama_dflash_rollback (llama_context * ctx, llama_seq_id seq_id, llama_seq_id seq_backup, int n_past_before, int n_accepted) {
8648- ctx->dflash_rollback (seq_id, seq_backup, n_past_before, n_accepted);
8664+ int llama_dflash_rollback (llama_context * ctx, llama_seq_id seq_id, llama_seq_id seq_backup, int n_past_before, int n_accepted) {
8665+ return ctx->dflash_rollback (seq_id, seq_backup, n_past_before, n_accepted);
86498666}
86508667
86518668void llama_dflash_prepare_branch (llama_context * ctx, llama_seq_id seq_id, llama_seq_id seq_backup, int depth) {
0 commit comments