
    ^jqQ                         d Z ddlZddlmZ ddlmZ ddlZddlmZ ddl	m
Z
 dd	lmZ dd
lmZmZmZmZ ddlmZ dee   deeeeef      fdZ G d d      Zy)u  Centralized offloading logic for continuous batching.

Handles two offloading strategies when the GPU KV cache is full:
  1. CPU offloading: copy the KV cache to a pre-allocated pinned CPU buffer, preserving exact request state.
  2. Soft reset: discard the KV cache and re-prefill from scratch when the request is re-scheduled. This incurs no data
    transfer overhead, but we need to re-run prefill over all initial + generated tokens (so more compute overhead).

The CPU swap pool is a static set of pinned tensors allocated once at init (like vLLM/SGLang). Blocks are tracked
with a simple free set — no dynamic allocation or deallocation of tensors ever happens at runtime.
    N)nullcontext)chain   )is_psutil_available   )PagedAttentionCache)DistributedHelper)FutureRequestStateRequestStateRequestStatuslogger)	Schedulerindicesreturnc                     g }| s|S | d   x}}d}t        dt        |             D ]0  }| |   |dz   k7  r|j                  ||||z
  f       | |   |}}| |   }2 |j                  ||t        |       |z
  f       |S )zGroups an index list into (start_index, offset, length) runs of consecutive values, so scattered block copies
    can be performed as a few slice copies.r   r   )rangelenappend)r   runsstartprevoffsetis         /var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/transformers/generation/continuous_batching/offloading_manager.pycontiguous_runsr   &   s     D1:EDF1c'l# 1:!KKF
34#AJ6Eqz	
 	KKGv 567K    c                      e Zd ZdZdedededz  dedej                  j                  dz  de
d	dfd
Zdedz  ded	efdZd Zd	efdZdee   d	dfdZddeded	dfdZddZddZdee   d	ee   fdZded	eee   ee   f   fdZy)OffloadingManageru/  Manages request offloading and restoration for continuous batching.

    Owns a static CPU swap pool (pre-allocated pinned tensors mirroring the GPU cache layout), performs GPU↔CPU block
    copies, decides between CPU offloading and soft reset, and ensures cleanup on cancellation/failure/reset.
    cache	schedulercpu_offload_space_gibNsafety_thresholdcompute_streamdistributed_helperr   c                    || _         || _        || _        g | _        g | _        g | _        g | _        g | _        i | _        i | _	        | j                  ||      }t        j                  |t        j                  d      }t        |j                  |d      j!                               | _        |d uxr |dkD  }| j"                  dk(  r|rt%        j&                  d|dd       y | j"                  |j(                  |j*                  |j,                  f}	|j.                  D ]x  }
| j                  j1                  t        j2                  |	|j4                  d	             | j                  j1                  t        j2                  |	|j4                  d	             z d
|j(                  |j*                  |j,                  f}t7        |j.                  |j8                        D ]U  \  }}| j
                  j1                   |j:                  |        | j                  j1                   |j:                  |        W t=        t?        | j"                              | _        | j                  d   }d|jA                         z  |jC                         z  tE        |j.                        z  }t%        jF                  d| j"                   d|dz  dd       y )NcpudtypedeviceT)on_cpur   cpu_offload_space=.1fz8 GiB is too small for even one block. No CPU offloading.)r(   
pin_memory   zCPU swap pool initialized: z	 blocks (   @.2fz GiB pinned))$r   r    _compute_stream_cpu_key_cache_cpu_value_cache_gpu_key_views_gpu_value_views_free_cpu_blocks_request_id_to_cpu_blocks!_request_id_to_group_block_counts_compute_num_cpu_blockstorchtensorint32inttp_all_reduce_minitem_num_cpu_blocksr   warning
block_sizenum_key_value_headshead_dim	key_cacher   emptyr(   zipvalue_cacheviewlistr   numelelement_sizer   info)selfr   r    r!   r"   r#   r$   num_cpu_blocksoffloading_enabledcpu_cache_shape_block_shapek_cachev_cachecache_tensorsize_in_bytess                   r   __init__zOffloadingManager.__init__>   s    
"- 35462446+-?A&GI. 556KM]^nEKKPUV"#5#G#G_c#G#d#i#i#kl2$>\CX[\C\1$!()>s(C D) )   //1A1A5C\C\^c^l^lm 	kA&&u{{?%++bf'gh!!((_EKKdh)ij	k
 5++U-F-FW #EOOU5F5F G 	EGW&&|w||['AB!!(({)CD	E
 !%U4+?+?%@ A **1-L..00<3L3L3NNQTUZUdUdQee)$*>*>)?yZaIbcfHggst	
r   c                    |t        |dz        nd}t               r-ddl}|j                         j                  }t        ||z        }nd}|8|6||kD  rv|dz  }t        j                  d|dd|dddz  dd	|dd
	       |}nE|t        j                  d       n-| |}t        j                  d|dz  dd
       nt        d      dt        | j                  j                        z  | j                  j                  z  | j                  j                  z  | j                  j                  z  | j                  j                  j                  z  }|dk(  rt!        d      ||z  S )z?Returns the number of blocks that can fit in the CPU swap pool.Nr0   r   r+   r,   z GiB exceeds z.0%z of total RAM (z GiB). Clamping to z GiB.u{   psutil is not available — cpu_offload_space_safety_threshold cannot be enforced. Install psutil to enable the safety cap.z1Auto-sizing CPU swap pool from safety threshold: r1   ztcpu_offload_space=None requires psutil to auto-size the CPU swap pool. Install psutil or pass an explicit GiB value.r/   z9The number of bytes per block is 0. This is not possible.)r>   r   psutilvirtual_memory	availabler   rB   ImportErrorr   r   rF   rC   rD   rE   r(   itemsize
ValueError)	rO   r!   r"   offload_bytesr[   	total_ram	max_bytesclamped_gibbytes_per_blocks	            r   r:   z)OffloadingManager._compute_num_cpu_blocksy   s    CXBc1W=>im  --/99II(889II $)>y('73()>s(C=QabePf g!W-c22EkRUEVV[] !*&NN;
 "%MNNNy\cOdehNiinop &  $**&&'(jj##$ jj,,- jj!!	"
 jj''( 	 aXYY//r   c                     | j                   )t        j                  j                  | j                         S t	               S )zdReturns a context manager that runs enclosed ops on the compute stream, or a no-op when none is set.)r2   r;   cudastreamr   rO   s    r   _stream_ctxzOffloadingManager._stream_ctx   s1    :>:N:N:Zuzz  !5!56m`k`mmr   c                    | j                   }|j                  }|sy| j                  j                         }t	        d |D              }t        |j                        }g }||kD  r}|r{|t        |      z
  dkD  rj|j                         \  }}|j                  |       ||z  }|| j                  j                  |j                        z  }||kD  r|r|t        |      z
  dkD  rj|sy|j                          | j                  |      }	|D ]  }|j                  }
|
|	v rd|_        |j                  t        j                   k(  r|j"                  t        |j$                        t        |j&                        z   k(  r;|xj"                  dz  c_        |j&                  xs |j$                  d   }|g|_        n|j*                  dd |_        t        j,                  |_        |}n%|j/                         }t        j0                  |_        |j3                  |
       |j5                  |         d|_        t9        j:                  t<        j>                        ro| j                  j                         }t9        j@                  dt        |       dt        |	       d	t        |      t        |	      z
   d
t        |       d| d       t        |      S )a  Evict enough active requests that, at the next batch, every remaining starved request can allocate the
        blocks it needs. Victims are taken from the starved requests reported by the scheduler, newest first, so the
        batch that was just scheduled is never touched and the demand directly bounds the amount of offloading.
        Tries CPU offloading first; victims that do not fit in the pool are soft reset. Returns the number of evicted
        requests.r   c              3   &   K   | ]	  \  }}|  y w)N ).0rS   blocks_neededs      r   	<genexpr>z5OffloadingManager.offload_requests.<locals>.<genexpr>   s     C'7q-]Cs   r   r.   NTz
Offloaded z requests (z	 to CPU, z soft reset): z starved requests remain for z free blocks.)!r    starved_requestsr   get_num_free_blockssumr   active_requestspopr   blocks_in_use
request_idreverse_offload_to_cpuallocated_blocks_statusr   DECODINGposition_offsetinitial_tokensgenerated_tokensremaining_prefill_tokenstokens_to_processPENDING!create_equivalent_initial_requestFINISHEDfinish_requestadd_waiting_requestblock_new_requestsr   isEnabledForloggingINFOrN   )rO   r    starvedfree_blocksdemand
num_activevictimsstatero   cpu_offloadedrw   last_true_token	new_states                r   offload_requestsz"OffloadingManager.offload_requests   s    NN	,, jj446C7CC223
&({"w:G3Lq3P#*;;= E=NN5!m#F4::33E4D4DEEK	 {"w:G3Lq3P
  ,,W5 	5E))J]*)*&==M$:$:: ,,E4H4H0ICPUPfPfLg0gg--2-+0+A+A+YUEYEY[]*^:I9J6 :?9P9PQR9S6 !. 5 5!	!CCE	 - 6 6$$Z0)))41	54 (,	$w||,**88:KKKS\N+c-6H5ISVW^S_befsbtStRu v  #G~-J;-Wdf 7|r   requests_in_batchc                 <   | j                   }g }g }|D ]}  }|j                  }|j                  s| j                  j	                  |j
                        }| j                  j	                  |j
                        }|j                  |       d}	t        |      D ]a  \  }
}|j                  |
   j                  j                  |j
                  g       }|j                  |d|        t        |	t        |            }	c d|_        |	|_        |j                  r,|xj                   |j"                  |j$                  z  z  c_        t'        j(                  d|j
                   dt        |j*                         dt        |j,                         d        |syt        |      }t/        |      }| j                   }| j1                         5  t3        j4                  |t2        j6                        j9                  |j:                  d	
      }||j$                  |j<                  |j>                  f}t3        j@                  ||jB                  |j:                        }tE        | jF                  | jH                        }tE        | jJ                  | jL                        }tO        ||      D ]B  \  }}|D ]%  \  }}}||||z    jQ                  ||||z    d	
       ' |jS                  d||       D 	 ddd       tU        | jV                  |z         | _+        y# 1 sw Y   'xY w)zRestore KV caches from CPU for any CPU-offloaded requests in the scheduled batch. Indices are accumulated
        per group across all requests, then copied in one batched operation per layer.r   NFzRestored CPU-offloaded request z with z prefill tokens and z generated tokens.r(   Tnon_blockingr'   ),r   r   is_cpu_offloadedr8   ru   rw   r9   extend	enumerategroup_cache_managersblock_tablegetmaxr   rz   allow_block_sharingcomplete_blocksr}   rC   r   debugr~   r   r   rj   r;   	as_tensorlongtor)   rD   rE   rG   r(   r   r3   r4   r5   r6   rH   copy_index_copy_sortedr7   )rO   r   r   all_cpu_indicesall_gpu_indicesfuture_stater   cpu_indicesgroup_countsmax_allocated_blocks	group_idxn
gpu_blocksr   gpu_idsstaging_shapestaging
cpu_caches	gpu_views	cpu_cachegpu_viewr   r   lengths                           r   restore_scheduled_requestsz,OffloadingManager.restore_scheduled_requests   s    

%'%'- 	L &&E)) 88<<U=M=MNKAAEEeFVFVWL"";/ $%  ), 7 R	1"77	BNNRRSXScScegh
&&z"1~6 (++?Z'Q$R &+E"%9E"((,,0E0EIYIY0YY,LL1%2B2B1C6#eNbNbJcId e511233EG3	>   /

 		:oooUZZHKKELLgkKlG 0 0%2K2KU^^\Mkk-u{{5<<XGt22D4I4IJJd1143H3HII'*:y'A :#	8-1 r)E66FVf_5;;IeeV\n<]lp;qr$$Q9:		: !'t'<'<'N O		: 		:s   	D"LLr   keep_unsortedc                     |j                   r@| j                  |j                         d|_         |s| j                  j	                          yyy)z=Free CPU blocks for a single request (e.g., on cancellation).FN)r   _return_cpu_blocksrw   r7   sort)rO   r   r   s      r   free_request_cpu_cachez(OffloadingManager.free_request_cpu_cache,  sF    !!##E$4$45%*E" %%**, ! "r   c                     | j                   j                  j                         D ]  }| j                  |d        | j                  j                          y)zPFree all CPU-offloaded caches in the waiting queue (e.g., on fail_all or reset).T)r   N)r    waiting_requestsvaluesr   r7   r   )rO   r   s     r   free_all_waiting_cpu_cachesz-OffloadingManager.free_all_waiting_cpu_caches4  sK    ^^44;;= 	CE''T'B	C""$r   c                     | j                          | j                  j                          | j                  j                          t	        t        | j                              | _        y)z8Reset CPU offloading state for a new generation session.N)r   r8   clearr9   rK   r   rA   r7   ri   s    r   resetzOffloadingManager.reset:  sJ    ((*&&,,...446 $U4+?+?%@ Ar   r   c           	      D   g }g }t        | j                        }|D ]  }g }g }| j                  j                  D ]S  }|j                  j                  |j                  g       }	|j                  |	       |j                  t        |	             U |svt        |      t        |      z   |k  s|j                  |||f       |j                  |        |s
t               S t        |      }
| j                  d|
 }| j                  |
d | _        t        |      }| j                         5  t        j                  |t        j                        j                  | j                  j                   d      }t#        | j$                  | j&                        }t#        | j(                  | j*                        }t-        ||      D ]A  \  }}|j/                  d|      }|D ]%  \  }}}||||z    j1                  ||||z    d       ' C 	 ddd       d}|D ]\  \  }}}|||t        |      z    | j2                  |j                  <   || j4                  |j                  <   d|_        |t        |      z  }^ |D ch c]  \  }}}|j                   c}}S # 1 sw Y   xY wc c}}w )a  Copy the KV cache blocks of as many victims as fit in the CPU swap pool from GPU to the pool, in one
        batched, non-blocking copy per layer. Returns the request ids that were offloaded.

        All transfers are enqueued on the compute stream with pinned destinations, so the host never waits on them:
        correctness is guaranteed by stream ordering, since restores and cache writes go through the same stream.
        Nr   Tr   r   )r   r7   r   r   r   r   rw   r   r   setr   rj   r;   r   r   r   r)   r   r5   r6   r3   r4   rH   index_selectr   r8   r9   r   )rO   r   	offloadedr   free_pool_blocksr   gpu_indicesgroup_block_countscmblocksr   r   r   r   r   r   r   r   gathered_blocksr   r   r   rS   s                          r   ry   z!OffloadingManager._offload_to_cpuA  s    FH	%'t445 
	4EK!#jj55 7++E,<,<bA""6*"))#f+67
 s?3c+6FFJZZ  %6H!IJ&&{3
	4 5L  //3 $ 5 5ab 9/  		oooUZZHKKDJJL]L]lpKqGd1143H3HIIt22D4I4IJJ'*9j'A #)"*"7"77"C-1 )E66eefn5;;'&APT < 			 6? 	'2E; 2?NvX^adepaqXq?rD**5+;+;<GYD2253C3CD%)E"c+&&F		'
 5>>[UAq  >>%		 		$ ?s   )CJ5JJrw   c                     | j                   j                  |      }| j                  j                  |      }| j                  j	                  |       ||fS )z<Return CPU blocks to the free pool without copying anything.)r8   ru   r9   r7   r   )rO   rw   cpu_idsr   s       r   r   z$OffloadingManager._return_cpu_blocksw  sM    0044Z@==AA*M$$W-$$r   )F)r   N)__name__
__module____qualname____doc__r   r   floatr;   rg   Streamr	   rY   r>   r:   rj   r   rK   r
   r   r   boolr   r   r   r   strry   tupler   rm   r   r   r   r   7   s   9
"9
 9
  %t|	9

  9
 

))D09
 .9
 
9
v30UT\ 30]b 30gj 30jn># >@8PDAS<T 8PY] 8Pt-L - -Z^ -%B4?tL'9 4?c#h 4?l%S %U49d3i;O5P %r   r   )r   r   
contextlibr   	itertoolsr   r;   utilsr   r   r   distributedr	   requestsr
   r   r   r   r    r   rK   r>   r   r   r   rm   r   r   <module>r      s]   	  "   ( & * M M  T#Y 4c3m0D+E "E% E%r   