
    ni{                        % S r SSKrSSKrSSKrSSKJr  SSKJrJrJ	r	J
r
  SSKJr  SrSrSrS	rS
rS\-
  rSrSrSr1 SkrS\4S jrS\4S jrS\4S jrS\4S jrS\4S jrSS\S-  S\4S jjrSS\S\\
\\4      4S jjrSS\S\4S jjr SSSSSSSS
S.r!SS S!S".S#S
S$S".S%S&S'S".S(.r"S S!S
S$S).r#S
r$S*\%S+\%S\4S, jr&S-\%S\%4S. jr'\ " S/ S05      5       r(S1\(S\(4S2 jr) SS3\\%   S4\S0   S\%4S5 jjr*S6S7S8S8S9/ S:S;S<S=S=S=S=0 S>.S?S@S8S8S9/ S:S;S<S=S=S=S=0 S>.S?S@SASAS=SB/SBS;S<S=S=S=S=SCSD0S>.S?S@SASES=SB/SBS;S<S=S=S=S=SCSD0S>.S?S@SESES=SBSF/SFS;S<S=S9S=S=SDSGSH.S>.S?S@SESGS=SBSF/SFS;S<S=S9S=S=SDSGSH.S>.S?S?SGSGS=/ SIQSFS;S<S9S9S9S=SDSGSJS(.S>.S@S@SGSGS=/ SIQSKS;S<S9S9S9S=SDSGSJS(.S>.SL.r+\+SM   \+SN'   S\,4SO jr-SP r.SQ\,S\%4SR jr/SSS\\,   S\4ST jjr0SSQ\\,   S\(4SU jjr1SV\%S\%4SW jr2SX\%SY\\%   S\4SZ jr3S[\%S\\\%   S\\%   4S] jr4SV\%S^\,S\
\,\,4   4S_ jr5SS`\,Sa\%S\(4Sb jjr6SS\S\,4Sc jjr7S\,4Sd jr8   SSe\Sf\,Sa\%Sg\Sh\%S\,4Si jjr9Sj\,S4\(Sk\S\
\\%4   4Sl jr:Se\S4\(Sk\S\
\\%4   4Sm jr;SV\%S4\(S\
\\%4   4Sn jr<S4\(S\\%   4So jr=S4\(4Sp jr>SqSrSsStSuSvSwSxSL.r?\@" \?R                  5       5      rBS\%4Sy jrCSz\%S\(4S{ jrDSqE\\(   \FS|'   S\(4S} jrGS1\(4S~ jrHg)a  
GPU Configuration Module
Centralized GPU memory detection and adaptive configuration management

    Debug Mode:
        Set environment variable MAX_CUDA_VRAM to simulate different GPU memory sizes.
        Example: MAX_CUDA_VRAM=8 python acestep  # Simulates 8GB GPU

        For MPS testing, use MAX_MPS_VRAM to simulate MPS memory.
        Example: MAX_MPS_VRAM=16 python acestep  # Simulates 16GB MPS

    This is useful for testing GPU tier configurations on high-end hardware.
    N)	dataclass)OptionalListDictTuple)loggerMAX_CUDA_VRAMMAX_MPS_VRAMMAX_XPU_VRAMACESTEP_SAVE_MEMORY      ?      0@g      4@z&https://download.pytorch.org/whl/cu121z(https://download.pytorch.org/whl/rocm6.0>   ptmlxvllmreturnc                      [         R                  S:w  a  g SSKn [        U R                  S5      =(       a$    U R                  R
                  R                  5       $ ! [         a     gf = f)zCheck if running on macOS with MPS (Apple Silicon) available.

This is the canonical check used across the codebase to apply
Mac-specific configuration overrides (no compile, no quantization,
mlx backend, no offload, etc.).
darwinFr   Nmps)sysplatformtorchhasattrbackendsr   is_available	Exceptionr   s    1/mnt/workspace/ACE-Step-1.5/acestep/gpu_config.pyis_mps_platformr   ,   sV     ||xu~~u-S%..2D2D2Q2Q2SS s   AA 
A)(A)c                  `     SSK n U R                  R                  5       $ ! [         a     gf = f)z)Return whether CUDA runtime is available.r   NF)r   cudar   r   r   s    r   is_cuda_availabler"   =   s/    zz&&(( s     
--c                       SSK n [        U R                  S5      =(       a$    U R                  R                  R	                  5       $ ! [
         a     gf = f)z(Return whether MPS runtime is available.r   Nr   F)r   r   r   r   r   r   r   s    r   is_mps_availabler$   G   sE    u~~u-S%..2D2D2Q2Q2SS s   AA 
AAc                       SSK n [        U S5      =(       a    U R                  R                  5       $ ! [         a     gf = f)z(Return whether XPU runtime is available.r   NxpuF)r   r   r&   r   r   r   s    r   is_xpu_availabler'   Q   s;    ue$A)?)?)AA s   03 
A A c                       SSK n U R                  R                  5       =(       a5    [        U R                  S5      =(       a    U R                  R
                  SL$ ! [         a     gf = f)a  Return whether the active CUDA device is an AMD ROCm/HIP device.

On ROCm, PyTorch exposes the GPU as a CUDA device but also sets
``torch.version.hip``.  This function returns ``True`` only when
*both* conditions hold: a CUDA device is present **and** the build
is a ROCm/HIP build.
r   NhipF)r   r!   r   r   versionr)   r   r   s    r   is_rocm_availabler+   [   s_    	 JJ##% .u-.!!-	

  s   AA 
A)(A)device_indexc                      SSK nUR                  R                  5       (       d  gUR                  R                  U 5      u  p#US:  $ ! [         a     gf = f)z>Return whether a CUDA device supports native bfloat16 kernels.r   NF   r   r!   r   get_device_capabilityr   )r,   r   major_s       r   cuda_supports_bfloat16r3   o   sR    zz&&((::33LAz s   #A !A 
AAc                      SSK nUR                  R                  5       (       a  UR                  R                  U 5      $  g! [         a     gf = f)z>Return the active CUDA device capability tuple when available.r   Nr/   )r,   r   s     r   get_cuda_device_capabilityr5   |   sP    ::""$$::33LAA %   s   =A 
AAc                 j    [        U 5      nUSL=(       a    US   S:  =(       a    [        5       (       + $ )zDReturn True for pre-Volta CUDA GPUs that should avoid vLLM defaults.Nr      )r5   r+   )r,   
capabilitys     r   is_legacy_cuda_gpur9      s1    +L9JT!Sjma&7S@Q@S<SS    g@g      "@gQ?g333333?{Gz?)	dit_turbodit_basedit_xl_turbodit_xl_basevaetext_encodersilence_latentcuda_context333333?g333333?)weightskv_cache_2kkv_cache_4kg333333@      ?       @皙?g?0.6B1.7B4B)turbobasexl_turboxl_basetokenpathc                 <    [         R                  " SU  S3U5      SL$ )zCheck if *token* appears as a delimited word in *path*.

Matches when *token* is bounded by start/end of string or a common
path delimiter (``/``, ``\``, ``.``, ``_``, ``-``).
z(^|[\\/._-])z($|[\\/._-])N)research)rS   rT   s     r   _has_path_tokenrX      s#     99UG<8$?tKKr:   config_pathc                     U =(       d    SR                  5       n[        SU5      n[        SU5      (       a  SnOSnU(       a  SU 3$ U$ )a  Derive the DiT type key from a model checkpoint path.

Returns a string suitable for looking up ``MODEL_VRAM`` (prefixed with
``"dit_"``) and ``DIT_INFERENCE_VRAM_PER_BATCH``.

Examples::

    "acestep-v15-xl-turbo"  -> "xl_turbo"
    "acestep-v15-xl-base"   -> "xl_base"
    "acestep-v15-xl-sft"    -> "xl_base"   (sft shares base VRAM profile)
    "acestep-v15-turbo"     -> "turbo"
    "acestep-v15-base"      -> "base"
    "acestep-v15-sft"       -> "base"       (sft shares base VRAM profile)
 xlrO   rP   xl_)lowerrX   )rY   rT   is_xlvariants       r   get_dit_type_from_pathra      sO     2$$&DD$'Ew%% #S	?00r:   c                       \ rS rSr% Sr\\S'   \\S'   \\S'   \\S'   \\S'   \\S'   \	\S	'   \
\   \S
'   \\S'   \\S'   \\S'   \	\S'   \	\S'   \	\S'   \	\S'   \\\4   \S'   Sr\	\S'   Sr\\S'   Srg)	GPUConfig   z+GPU configuration based on available memorytiergpu_memory_gbmax_duration_with_lmmax_duration_without_lmmax_batch_size_with_lmmax_batch_size_without_lminit_lm_defaultavailable_lm_modelsrecommended_lm_modellm_backend_restrictionrecommended_backendoffload_to_cpu_defaultoffload_dit_to_cpu_defaultquantization_defaultcompile_model_defaultlm_memory_gbFsave_memory_mode   mlx_vae_chunk_size N)__name__
__module____qualname____firstlineno____doc__str__annotations__floatintboolr   r   ru   rw   __static_attributes__rx   r:   r   rc   rc      s    5
I     "" c"   ! 
  sEz""
 #d" "!r:   rc   configc                 l    [        5       (       a$  [        R                  " S5        SU l        SU l        U $ )z:Apply runtime hardware overrides for LM backend selection.zjLegacy CUDA GPU detected (pre-Volta compute capability): forcing 5Hz LM backend recommendation to PyTorch.pt_onlyr   )r9   r   inforn   ro   r   s    r   )_apply_lm_backend_compatibility_overridesr     s4    @	
 )2%%)"Mr:   requested_backend
gpu_configc                    U=(       d
    [        5       n[        USS5      n[        USS5      nU =(       d    SR                  5       R                  5       nU[        ;  a  UnU[        ;  a  SnUS:X  a  gUS:X  a  US:X  a  UnUS	;  a  SnU$ U$ )
zBResolve the LM backend against runtime compatibility restrictions.ro   r   rn   allr[   r   r   pt_mlx_only>   r   r   )get_global_gpu_configgetattrstripr^   VALID_LM_BACKENDS)r   r   r   ro   rn   backendfallbacks          r   resolve_lm_backendr     s    
 202F!&*?H$V-EuM &B--/557G''%++G*.7f3D&=(HNr:      h     Fr[   r   r   T)rg   rh   ri   rj   rk   rl   rm   rn   ro   rp   rq   rr   rs   rt     X     acestep-5Hz-lm-0.6BrL         acestep-5Hz-lm-1.7Br.   )rL   rM   )r   r   acestep-5Hz-lm-4B   r   )tier1tier2tier3tier4tier5tier6atier6b	unlimitedr   tier6c                     [         R                  R                  [        5      n U Gb   [	        U 5      n[
        R                  " SUS S[         S35         SSKnUR                  R                  5       (       a  UR                  R                  S5      R                  nUS-  nX:  a  [        R                  SS	5      n[        S	X-
  5      nXd-  n[        S
[        SU5      5      nUR                  R                  U5        [
        R                  " SUS SUS SUS SUS SUS S35        U$ [         R                  R                  [$        5      n	U	b0   [	        U	5      n[
        R                  " SUS S[$         S35        U$ [         R                  R                  [&        5      n
U
b0   [	        U
5      n[
        R                  " SUS S[&         S35        U$  SSKnUR                  R                  5       (       a  UR                  R                  S5      R                  nUS-  nUR                  R)                  S5      n[+        UR,                  S5      =(       a    UR,                  R.                  SLnU(       a7  [
        R0                  " SU SUS SUR,                  R.                   S35        U$ [
        R0                  " SU SUS S 35        U$ [+        US!5      (       a  UR2                  R                  5       (       ap  UR2                  R                  S5      R                  nUS-  n[5        UR2                  R                  S5      S"S#5      n[
        R0                  " S$U SUS S 35        U$ [+        UR6                  S%5      (       a  UR6                  R8                  R                  5       (       a  [5        US%S5      n Ub(  [+        US&5      (       a  UR;                  5       nUS-  nU$ Ub=  [+        US'5      (       a,  UR                  S5      n[5        US(S5      nU(       a  US-  nU$  SSKnUR?                  / S*QS+S+S,S-9n[A        URB                  RE                  5       5      nUS-  S.-  nU$ [G        U5        g! [          a$  n[
        R                  " SU 35         SnAU$ SnAff = f! ["         a%    [
        R                  " S[         SU  S35         GNf = f! ["         a%    [
        R                  " S[$         SU	 S35         GNf = f! ["         a%    [
        R                  " S[&         SU
 S35         GNnf = f! [          a$  n[
        R                  " S)U 35         SnAGNBSnAff = f! [          a!    [
        R                  " S/[$         S035         g1f = f! [          a#  n[
        R                  " S2U 35         SnAgSnAff = f)3a  
Get GPU memory in GB. Returns 0 if no GPU is available.

Debug Mode:
    Set environment variable MAX_CUDA_VRAM to override the detected GPU memory.
    Example: MAX_CUDA_VRAM=8 python acestep  # Simulates 8GB GPU

    For MPS testing, set MAX_MPS_VRAM to override MPS memory detection.
    Example: MAX_MPS_VRAM=16 python acestep  # Simulates 16GB MPS

    This allows testing different GPU tier configurations on high-end hardware.
Nu,   ⚠️ DEBUG MODE: Simulating GPU memory as .1fzGB (set via z environment variable)r      @rC   r   r;   rH   u/   ⚠️ DEBUG MODE: Set CUDA memory fraction to z.4fz (allocator_budget=.2fzGB, ref_context=zGB, target=z
GB, total=zGB) to enforce hard VRAM capu6   ⚠️ DEBUG MODE: Could not enforce CUDA memory cap: zInvalid z value: z
, ignoringu,   ⚠️ DEBUG MODE: Simulating MPS memory as u,   ⚠️ DEBUG MODE: Simulating XPU memory as r)   zROCm GPU detected:  (z	 GB, HIP )zCUDA GPU detected: z GB)r&   name	Intel XPUzIntel XPU detected: r   recommended_max_memoryget_device_propertiestotal_memoryzFailed to detect MPS memory: )sysctlz-nz
hw.memsizeT   )capture_outputtexttimeoutg      ?z0MPS available but total memory not exposed. Set z to enable tiering.rI   zFailed to detect GPU memory: )$osenvirongetDEBUG_MAX_CUDA_VRAM_ENVr   r   warningr   r!   r   r   r   
MODEL_VRAMmaxminset_per_process_memory_fractionr   
ValueErrorDEBUG_MAX_MPS_VRAM_ENVDEBUG_MAX_XPU_VRAM_ENVget_device_namer   r*   r)   r   r&   r   r   r   r   
subprocessrunr   stdoutr   _log_gpu_diagnostic_info)
debug_vramsimulated_gbr   total_bytestotal_gbREFERENCE_CONTEXT_GBallocator_budget_gbfractionedebug_mps_vramdebug_xpu_vramr   	memory_gbdevice_nameis_rocm
mps_modulepropsr   resulttotal_system_bytess                       r   get_gpu_memory_gbr     s     78J,	 ,LNN>|C>PP\]t\u  vL  M]::**,,"'**"B"B1"E"R"RK*g6H#. 0:~~nc/R,.1!D/+ $7#A#&tSh-?#@

BB8LMhWZ^ \11DS0I J++?*DKP\]`Oa b%%-cN2NP  
 ZZ^^$:;N!		 0LNN>|C>PP\]s\t  uK  L   ZZ^^$:;N!		 0LNN>|C>PP\]s\t  uK  L  G::""$$ ::;;A>KKL$0I**44Q7KemmU3U8I8IQU8UG)+b3yQVQ^Q^QbQbPccde
  1+b3tTUUE""uyy'='='?'? 99::1=JJL$0I!		//2FKK KK.{m2i_DQRU^^U++0B0B0O0O0Q0Q t4JD)g 8/ / $.#D#D#FL , 8I$$)g 7/ / '<<Q?E#*5.$#GL#$0G$<	((
!#2#'	 (  &))<)<)>%?"/7;tC	   %U+M  ]!WXYWZ[\\]  	NN238J<zR	  	NN12(>:J*U	  	NN12(>:J*U	^  D!>qcBCCD"  FG]F^^qr   6qc:;s   -R7 CR -R7 .S) ,.T CV, 7V, BV, 7AV, 	*U 4?U 5AU> :V, 
R4R/)R7 /R44R7 7+S&%S&)+TT+U
	U

U;U60V, 6U;;V, >(V)&V, (V))V, ,
W6WWc                    [         R                  " S5        [         R                  " S5        [         R                  " S5        [        U R                  S5      =(       a    U R                  R                  SLn[        U R                  S5      =(       a    U R                  R
                  SLnU(       Ga  [         R                  " S5        [         R                  " SU R                  R                   35        [         R                  " S5        [         R                  " S	5        [         R                  " S5        [         R                  " S
5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [        R                  R                  S5      nU(       a  [         R                  " SU 35        On[         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        [         R                  " S5        GOU(       Ga  [         R                  " S5        [         R                  " S U R                  R
                   35        [         R                  " S5        [         R                  " S	5        [         R                  " S5        [         R                  " S!5        [         R                  " S"5        [         R                  " S#5        [         R                  " S$5        [         R                  " S5        [         R                  " S5        [         R                  " S%5        [         R                  " S&5        [         R                  " S'5        [         R                  " S(5        [         R                  " S)[         35        GO[         R                  " S*5        [         R                  " S5        [         R                  " S+5        [         R                  " S5        [         R                  " S,5        [         R                  " S-[         35        [         R                  " S5        [         R                  " S.5        [         R                  " S/5        [         R                  " S0[         35        [         R                  " S5        [         R                  " S15        [         R                  " S5        g)2z
Log diagnostic information when GPU is not detected to help users troubleshoot.

Args:
    torch_module: The torch module to inspect for build information
zP================================================================================u0   ⚠️ GPU NOT DETECTED - DIAGNOSTIC INFORMATIONr)   Nr!   u   ✓ PyTorch ROCm build detectedz  HIP version: r[   u,   ❌ torch.cuda.is_available() returned Falsez Common causes for AMD/ROCm GPUs:z:  1. ROCm drivers not installed or not properly configuredz0  2. GPU not supported by installed ROCm versionzG  3. Missing or incorrect HSA_OVERRIDE_GFX_VERSION environment variablez.  4. ROCm runtime libraries not in system pathHSA_OVERRIDE_GFX_VERSIONz&  HSA_OVERRIDE_GFX_VERSION is set to: u,     ⚠️ HSA_OVERRIDE_GFX_VERSION is not setz5     For RDNA3 GPUs (RX 7000 series, RX 9000 series):zH       - RX 7900 XT/XTX, RX 9070 XT: set HSA_OVERRIDE_GFX_VERSION=11.0.0zD       - RX 7800 XT, RX 7700 XT: set HSA_OVERRIDE_GFX_VERSION=11.0.1z5       - RX 7600: set HSA_OVERRIDE_GFX_VERSION=11.0.2zTroubleshooting steps:z  1. Verify ROCm installation:z%     rocm-smi  # Should list your GPUz  2. Check PyTorch ROCm build:zB     python -c "import torch; print(f'ROCm: {torch.version.hip}')"z:  3. Set HSA_OVERRIDE_GFX_VERSION for your GPU (see above)zJ  4. On Windows: Use start_gradio_ui_rocm.bat which sets required env varszA  5. See docs/en/ACE-Step1.5-Rocm-Manual-Linux.md for Linux setupzB  6. See requirements-rocm.txt for Windows ROCm setup instructionsu   ✓ PyTorch CUDA build detectedz  CUDA version: zCommon causes for NVIDIA GPUs:z!  1. NVIDIA drivers not installedz3  2. CUDA runtime not installed or version mismatchz0  3. GPU not supported by installed CUDA versionz'  1. Verify NVIDIA driver installation:z'     nvidia-smi  # Should list your GPUz%  2. Check CUDA version compatibilityz)  3. Reinstall PyTorch with CUDA support:z#     pip install torch --index-url u#   ⚠️ PyTorch build type: CPU-onlyz1You have installed a CPU-only version of PyTorch!zFor NVIDIA GPUs:z   pip install torch --index-url zFor AMD GPUs with ROCm:z>  Windows: See requirements-rocm.txt for detailed instructionsz'  Linux: pip install torch --index-url z=For more information, see README.md section 'AMD / ROCm GPUs')r   r   r   r*   r)   r!   r   r   r   PYTORCH_CUDA_INSTALL_URLPYTORCH_ROCM_INSTALL_URL)torch_moduleis_rocm_buildis_cuda_buildhsa_overrides       r   r   r   ~  s    NN8
NNEF
NN8 	$$e,U1E1E1I1IQU1U  	$$f-W,2F2F2K2KSW2W  89)=)=)A)A(BCDrEFr9:STIJU	
 	GHr zz~~&@ANNCL>RSNNIJNNRSNNZ NNV NNRSr/078>?78R	
 	STX	
 	O	
 	P	
 
89),*>*>*C*C)DEFrEFr78:;LMIJr/0@A@A>?BC<=U<VWX 	<=rJKr)*9:R9STUr01WX56N5OP	
 	rVW
NN8r:   rf   c                     U S::  a  gU S::  a  gU S::  a  gU S::  a  gU S::  a  g	U [         :  a  g
U [        :  a"  U S:  a  [        R                  " SU S S35        gU S::  a  gg)z
Determine GPU tier based on available memory.

Args:
    gpu_memory_gb: GPU memory in GB

Returns:
    Tier string: "tier1", "tier2", "tier3", "tier4", "tier5", "tier6a", "tier6b", or "unlimited"
r   r   r      r   r.   r   r   r   r   r   z	Detected r   u&   GB VRAM — treating as 16GB class GPUr      r   r   )VRAM_16GB_MIN_GBVRAM_AUTO_OFFLOAD_THRESHOLD_GBr   r   )rf   s    r   get_gpu_tierr     s     	!		!		!		"		)	)	7	74KKM#..TU 	"	r:   mem_gbc                     [         R                  R                  S5      nUb   [        S[	        U5      5      $ U c
  [        5       n U S::  a  SnOU S::  a  SnOU S::  a  SnOS	n[        SU5      $ ! [
         a     NBf = f)
a   Select MLX VAE decode chunk size based on available unified memory.

The ``ACESTEP_MLX_VAE_CHUNK`` environment variable takes highest
priority.  Otherwise the chunk size is chosen from a memory-based
heuristic targeting Apple Silicon unified-memory configurations.

Args:
    mem_gb: GPU/unified memory in GB.  When ``None``, auto-detected
        via :func:`get_gpu_memory_gb`.

Returns:
    Chunk size as a positive integer (minimum 192, to keep
    ``stride = chunk - 2 * overlap`` positive with overlap=64).
ACESTEP_MLX_VAE_CHUNK         $   rv   @   i   i   )r   r   r   r   r   r   r   )r   env_valsizes      r   _auto_mlx_vae_chunk_sizer     s     jjnn45G	sCL)) ~"$|	2	2sD>  		s   A/ /
A<;A<c           	         U c
  [        5       n [        U 5      n[        U   n[        5       nU(       a  [        R
                  " SU S SU S35        [        S0 SU_SU _SUS   _SUS   _S	US	   _S
US
   _SUS   _SUS   _SUR                  SS5      _SU(       a  SOUR                  SS5      _SU(       a  SOUR                  SS5      _SU(       a  SOUR                  SS5      _SU(       a  SOUR                  SS5      _SU(       a  SOUR                  SS5      _SU(       a  SOUR                  SS5      _SUS   _SU(       a  [        U 5      OS_6n[        U5      $ )u  
Get GPU configuration based on detected or provided GPU memory.

On macOS with MPS (Apple Silicon), several overrides are applied
automatically regardless of the tier selected by memory size:

- ``compile_model_default = False`` — ``torch.compile`` is not supported
  on MPS and would error or silently fall back to eager mode.
- ``quantization_default = False`` — torchao INT8 quantization is
  incompatible with MPS / macOS.
- ``recommended_backend = "mlx"`` — MLX provides native Apple Silicon
  acceleration for the 5Hz LM; vllm requires CUDA.
- ``lm_backend_restriction = "pt_mlx_only"`` — vllm cannot run on MPS.
- ``offload_to_cpu_default = False`` — Apple Silicon uses unified memory;
  offloading to CPU provides no benefit and adds overhead.
- ``offload_dit_to_cpu_default = False`` — same reason.

Args:
    gpu_memory_gb: GPU memory in GB. If None, will be auto-detected.

Returns:
    GPUConfig object with all configuration parameters
zmacOS MPS detected (r   z GB unified memory, tier=zb). Applying Apple Silicon optimizations: no compile, no quantization, mlx backend, no CPU offload.re   rf   rg   rh   ri   rj   rk   rl   rm   r[   rn   r   r   ro   r   r   rp   FTrq   rr   rs   rt   rw   rv   rx   )
r   r   GPU_TIER_CONFIGSr   r   r   rc   r   r   r   )rf   re   r   _mpss       r   get_gpu_configr   -  s   0 )+&Dd#F D"="55Ntf U+ +	
  &&#& $$:;& !''@ A	&
  &&>?& #))D"E& 01& ##89& $ZZ(>C&   -ZZ0%8&  "ZZ-v6!&&   %ZZ0$7)&,  $)ZZ4d;/&4  #ZZ.57&>  $ZZ/6A&B N+C&H  4MBK&FN 5V<<r:   
model_pathc                 .    SU ;   a  gSU ;   a  gSU ;   a  gg)z
Extract LM model size from model path.

Args:
    model_path: Model path string (e.g., "acestep-5Hz-lm-0.6B", "acestep-5Hz-lm-0.6B-v4-fix")

Returns:
    Model size string: "0.6B", "1.7B", or "4B"
rL   rM   rN   rx   )r   s    r   get_lm_model_sizer   ~  s*     	:			 r:   disk_model_nametier_available_modelsc                 ^    U(       d  g[        U 5      nU H  nU[        U5      :X  d  M    g   g)a  
Check if a disk LM model is allowed by the tier's available models list.

Uses size-based matching so that variants like "acestep-5Hz-lm-0.6B-v4-fix"
are correctly matched against "acestep-5Hz-lm-0.6B" in the tier config.

Args:
    disk_model_name: Actual model directory name on disk (e.g., "acestep-5Hz-lm-0.6B-v4-fix")
    tier_available_models: List of tier-allowed model base names (e.g., ["acestep-5Hz-lm-0.6B"])

Returns:
    True if the model's size class is allowed by the tier
FT)r   )r   r   
model_size
tier_models       r   is_lm_model_size_allowedr    s4      !"?3J+
*:66 , r:   recommended_modeldisk_modelsc                     U (       a  U(       d  U(       a  US   $ S$ X;   a  U $ [        U 5      nU Vs/ s H  n[        U5      U:X  d  M  UPM     nnU(       a  [        U[        S9$ U(       a  US   $ S$ s  snf )a  
Find the best matching disk model for a recommended tier model.

If the exact recommended model exists on disk, return it.
Otherwise, find a disk model with the same size class (e.g., "0.6B").
Prefers models with version suffixes (e.g., "-v4-fix") as they are likely newer.

Args:
    recommended_model: Tier-recommended model name (e.g., "acestep-5Hz-lm-0.6B")
    disk_models: List of model names actually on disk

Returns:
    Best matching disk model name, or None if no match
r   N)key)r   r   len)r  r  target_sizem
candidatess        r   find_best_lm_model_on_diskr    s    " K!,{1~6$6 '   $$56K(P[,=a,@K,O![JP:3'' );q>2d2 Qs   A5
A5total_gpu_memory_gbc                 "   [        U 5      n[        R                  U[        S   5      nUS   nUS   nUnXE-   S-   nSn SSKn	U	R                  R                  5       (       Ga(  U	R                  R                  5       u  pU
S-  nUS-  n[        R                  R                  [        5      nUbc   [        U5      nX:  aR  [        R                  SS	5      n[        S	X-
  5      nU	R                  R                  5       S-  n[        SUU-
  5      nUnS
n[        SUU-
  [         -
  5      n[#        UU5      nX-
  nUU-   nUU-  n[#        S[        SU5      5      n[$        R&                  " SU SUS SUS SUS SUS SUS 35        UU4$  US:  a  [#        S[        SXq-  5      5      nUU4$ [#        S[        SXq-  5      5      nUU4$ ! [        [        4 a     Nf = f! [(         a$  n[$        R*                  " SU S35         SnAN}SnAff = f)a)  
Calculate GPU memory utilization ratio for LM model.

This function now uses *actually free* VRAM (via torch.cuda.mem_get_info)
when available, instead of computing the ratio purely from total VRAM.
This is critical because DiT, VAE, and text encoder are already loaded
when the LM initializes, so the "available" memory is much less than total.

Args:
    model_path: LM model path (e.g., "acestep-5Hz-lm-0.6B")
    total_gpu_memory_gb: Total GPU memory in GB (used as fallback)

Returns:
    Tuple of (gpu_memory_utilization_ratio, target_memory_gb)
rL   rE   rG   rD   Nr   r   rC   r   g      ?g?g?z [get_lm_gpu_memory_ratio] model=z, free=r   zGB, current_usage=zGB, lm_target=zGB, usable_for_lm=z
GB, ratio=z.3fz5[get_lm_gpu_memory_ratio] Failed to query free VRAM: z, using fallbackr   g?)r   LM_VRAMr   r   r!   r   mem_get_infor   r   r   r   r   r   memory_reservedr   	TypeErrorVRAM_SAFETY_MARGIN_GBr   r   r   r   r   )r   r  r  lm_infolm_weights_gblm_kv_cache_gb	target_gbtotal_target_gbfree_gbr   
free_bytesr   actual_total_gbr   r   ref_context_gbr   reserved_gbdit_reserve_gbusable_for_lmcurrent_usage_gbdesired_total_usageratior   s                           r   get_lm_gpu_memory_ratior#    so   $ #:.J kk*gfo6GI&M]+N I#4s:O G4
::""$$&+jj&=&=&?#J G,G)W5O (?@J%
#(#4L#5)3)L.1#|7T.U+&+jj&@&@&Bg&N"%a)<{)J"K*6 !N7^#;>S#STM  ?M
  /8"2]"B'/9ESe_-EKK2:,ggc] S!!1# 6n_UXDY Z!!.s 3:eC[J
 )##[ %h b CS/"GHI ) CS/"GHI)O #I. 8  
CA3FVW	
 	

s>   A0G  0A"G
 A8G  
GG  GG   
H*H		Htotal_vram_gbdit_typec           
         SU 3[         ;   a  SU 3OSn[         U   [         S   -   [         S   -   [         S   -   [         S   -   [        -   nX-
  nUS::  a  [        U 5      $ / n0 nS HZ  n[        U   nUS	   US
   -   n	[        R                  US5      n
X-   U::  d  M7  SU 3nUR                  U5        US	   US
   -   Xg'   M\     [        R                  US5      n
[        S[        XJ-  5      5      n[        US5      nU(       aH  [        UR                  5       5      S   nXm   nXN-
  n[        S[        X-  5      5      n[        US5      nOUnU S:  a  SnSnO0U S:  a  SnSnO%U S:  a  SnSnOU S:  a  SnSnOU S:  a  SnSnOSnSn[        U 5      n[        R                  U0 5      n[        S-0 SU_SU _SU_SU_SU_SU_S[        U5      _S U_S!UR                  S!U(       a  US   OS"5      _S#UR                  S#S$5      _S%UR                  S%S&5      _S'UR                  S'S(5      _S)UR                  S)S(5      _S*UR                  S*S(5      _S+UR                  S+S(5      _S,U_6n[!        U5      $ ).a  
Compute GPU configuration based on what actually fits in VRAM.

This is a VRAM-budget-based approach: instead of hard-coded tier boundaries,
we calculate how much memory each component needs and determine what fits.

Args:
    total_vram_gb: Total GPU VRAM in GB
    dit_type: DiT type key -- "turbo", "base", "xl_turbo", "xl_base", etc.
              (affects model weight size and inference VRAM due to CFG)

Returns:
    GPUConfig with parameters that fit within the VRAM budget
dit_r<   r@   rA   rC   rB   r   rK   rE   rG   rJ   zacestep-5Hz-lm-r   r.   r   r      r   r   r   r   r      re   rf   rg   rh   ri   rj   rk   rl   rm   r[   rn   r   ro   r   rp   Trq   rr   rs   rt   rx   )r   r  r   r  DIT_INFERENCE_VRAM_PER_BATCHr   appendr   r   r   listkeysr   r   rc   r   r   )r$  r%  dit_key
base_usage	availablerl   rt   size_keyr  lm_totalinference_per_batch
model_namemax_batch_no_lmlargest_lm_sizelm_usageremaining_for_inferencemax_batch_with_lm
max_dur_lmmax_dur_no_lmre   tier_configr   s                         r   compute_adaptive_configr>  .  s<     &*(#4
#BXJG7
U
	
^
$	% ^
$	% %
&		'
  	   *IA~m,, L*(#9%(>>:>>xM)Y6*8*5J&&z2%,Y%7'-:P%PL" + 7::8SI !S!@ABO/1-O |0023B70"+"63'>'T#UV 115+ 
	"	
	"	
	"	
	!	

&D"&&tR0K # ( !.	
  1 #2 01 0 )__"&9"r
  +/GO (OO,A6J  +/GN  $/??3OQU#V!" )__-CTJ#$ *oo.EtL%& "'F* 5V<<r:   c                 l    SSK n[        US5      (       Ga  UR                  R                  5       (       a  UR                  R	                  U 5      u  p#UR                  R                  U 5      nUR                  R                  U 5      n[        SXE-
  5      nX&-   n[        R                  R                  [        5      nUb^   [        U5      n	US-  n
X:  aG  [        R                  SS5      n[        SX-
  5      nUS-  nX-
  n[        X~5      n[        SUS-  5      $  [        SUS-  5      $ [        US5      (       a  UR"                  R                  5       (       a  [        UR"                  S	5      (       a#   UR"                  R	                  U 5      u  p/US-  $  UR"                  R'                  U 5      R(                  nUR"                  R                  U 5      n[        SX4-
  S-  5      $ g! [        [         4 a     Nf = f! [$         a     Nuf = f! [$         a     gf = f! [$         a     gf = f)
aT  
Get the effective free VRAM in GB, accounting for PyTorch allocator cache and
per-process memory fraction.

torch.cuda.mem_get_info() reports *device-level* free memory.  After models
are loaded, the PyTorch caching allocator may have reserved nearly all VRAM
from the OS perspective, making device_free_bytes appear near zero even though
the allocator can freely reuse its cached (reserved-but-not-allocated) blocks
for new tensors without going back to the OS.

This function computes:
    effective_free = device_free_bytes + pytorch_cache_free_bytes

where pytorch_cache_free_bytes = memory_reserved - memory_allocated.

When the MAX_CUDA_VRAM debug cap is active it additionally clamps to the
simulated allocator budget:
    effective_free = min(effective_free, allocator_budget - memory_allocated)

Returns 0 if no GPU is available or on error.
r   Nr!   r   rC   r           r&   r  )r   r   r!   r   r  r  memory_allocatedr   r   r   r   r   r   r   r   r   r  r&   r   r   r   )r,   r   device_free_bytesr   reserved_bytesallocated_bytespytorch_cache_free_byteseffective_free_bytesr   r   r   r  r   allocator_budget_bytesprocess_freer2   s                   r   get_effective_free_vram_gbrI    s%   ,85&!!ejj&=&=&?&?-2ZZ-D-D\-R*
 #ZZ77EN#jj99,GO'*1n.N'O$#4#O  (?@J%#(#4L*g6H#. *4)L.1#|7T.U+1D1P.'='O/23G/V,"3(<(HII / s0G<==UE""uyy'='='?'? uyy.11+099+A+A,+O(%,88
#ii==lKXX!&!:!:<!H3!=' JKK / #I.  !     s{   C H& AG0 H& /AH& ;!H AH 0H H& HH& 
HH& HH& 
H# H& "H##H& &
H32H3c                      [        5       $ )z
Get currently available (free) GPU VRAM in GB.
Returns 0 if no GPU is available or on error.

This is an alias for get_effective_free_vram_gb() that accounts for
per-process memory fraction caps.
)rI  rx   r:   r   get_available_vram_gbrK    s     &''r:   
batch_size
duration_swith_lmlm_sizec                 :   SU 3[         ;   a  SU 3OSn[         U   [         S   -   [         S   -   [         S   -   n[        R                  US5      n[        SUS-  5      nXp-  U-  n	S	n
U(       a  U[        ;   a  [        U   nUS
   US   -   n
Xi-   U
-   [
        -   $ )aS  
Estimate total VRAM needed for a generation request.

Args:
    batch_size: Number of samples to generate
    duration_s: Audio duration in seconds
    dit_type: DiT type key -- "turbo", "base", "xl_turbo", "xl_base", etc.
    with_lm: Whether LM is loaded
    lm_size: LM model size if with_lm is True

Returns:
    Estimated VRAM in GB
r'  r<   r@   rA   rC   rJ   rH   g      N@r@  rE   rG   )r   r+  r   r   r  r  )rL  rM  r%  rN  rO  r/  rP   	per_batchduration_factor	inferencelm_memr  s               r   estimate_inference_vramrU    s    * &*(#4
#BXJG7
U
	
^
$	% ^
$	% 	 -003?I#zD01O&8I F7g%'"#gm&<<f$'<<<r:   durationlm_initializedc                     U(       a  UR                   OUR                  nX:  a+  SU S SUR                  S SU SU(       a  SOS S	U S
3nSU4$ g)a  
Check if requested duration is within limits for current GPU configuration.

Args:
    duration: Requested duration in seconds
    gpu_config: Current GPU configuration
    lm_initialized: Whether LM is initialized

Returns:
    Tuple of (is_valid, warning_message)
u   ⚠️ Requested duration (z.0fz#s) exceeds the limit for your GPU (r   GB). Maximum allowed: s (withwithoutz" LM). Duration will be clamped to zs.FTr[   )rg   rh   rf   )rV  r   rW  max_durationwarning_msgs        r   check_duration_limitr`  %  s       	''//  )(3 8((--CL> R(i8 9++7.< 	 k!!r:   c                     U(       a  UR                   OUR                  nX:  a*  SU  SUR                  S SU SU(       a  SOS SU S	3nS
U4$ g)a  
Check if requested batch size is within limits for current GPU configuration.

Args:
    batch_size: Requested batch size
    gpu_config: Current GPU configuration
    lm_initialized: Whether LM is initialized

Returns:
    Tuple of (is_valid, warning_message)
u   ⚠️ Requested batch size (z") exceeds the limit for your GPU (r   rY  r   r[  r\  z$ LM). Batch size will be clamped to .Fr]  )ri   rj   rf   )rL  r   rW  max_batch_sizer_  s        r   check_batch_size_limitrd  E  s       	))11  "+J< 8((--CNCS T(i8 9--;,<A? 	 k!!r:   c                     UR                   (       d  SSUR                  S S34$ [        U 5      nUR                    H
  nX#;   d  M
    g   SSU  SU SUR                  S S	S
R                  UR                   5       34$ )z
Check if the specified LM model is supported for current GPU configuration.

Args:
    model_path: LM model path
    gpu_config: Current GPU configuration

Returns:
    Tuple of (is_supported, warning_message)
Fu   ⚠️ Your GPU (r   zVGB) does not have enough memory to run any LM model. Please disable LM initialization.r]  u   ⚠️ LM model r   z!) is not supported for your GPU (zGB). Available models: z, )rl   rf   r   join)r   r   r  available_models       r   is_lm_model_supportedrh  e  s     ))
 8 8= >E F
 	

 #:.J &99( : 
:,b 5$$S))@:KiKiAj@k	m r:   c                 D    U R                   (       d  gU R                   S   $ )z
Get recommended LM model for current GPU configuration.

Args:
    gpu_config: Current GPU configuration

Returns:
    Recommended LM model path, or None if LM is not supported
Nr(  )rl   r   s    r   get_recommended_lm_modelrk    s#     )) ))"--r:   c                    [         R                  " S5        [         R                  " SU R                  S S35        [         R                  " SU R                   35        [         R                  " SU R                   SU R                  S-   S	35        [         R                  " S
U R
                   SU R
                  S-   S	35        [         R                  " SU R                   35        [         R                  " SU R                   35        [         R                  " SU R                   35        [         R                  " SU R                  =(       d    S 35        g)z2Print GPU configuration information for debugging.zGPU Configuration:z  - GPU Memory: r   z GBz
  - Tier: z  - Max Duration (with LM): rZ  <   z min)z  - Max Duration (without LM): z  - Max Batch Size (with LM): z!  - Max Batch Size (without LM): z  - Init LM by Default: z  - Available LM Models: NoneN)
r   r   rf   re   rg   rh   ri   rj   rk   rl   rj  s    r   print_gpu_config_inforo    s)   
KK$&
KK":#;#;C"@DE
KK*Z__-./
KK
&z'F'F&Gs:KjKjnpKpJqqvw KK
)**L*L)MSQ[QsQswyQyPzz  	A KK01R1R0STU
KK
+J,P,P+QR KK*:+E+E*FGH
KK+J,J,J,Tf+UVWr:   u   tier1 (≤4GB)ztier2 (4-6GB)ztier3 (6-8GB)ztier4 (8-12GB)ztier5 (12-16GB)ztier6a (16-20GB)ztier6b (20-24GB)u   unlimited (≥24GB)c                  @    SSK n U R                  R                  5       (       a  U R                  R                  S5      $ [	        U S5      (       aG  U R
                  R                  5       (       a(  U R
                  R                  S5      n[        USS5      $ [	        U R                  S5      (       aL  U R                  R                  R                  5       (       a#   SSK
nUR                  5       =(       d    SnU S3$ g
! [         a     g	f = f! [         a     gf = f)z
Get the GPU device name string.

Returns:
    Human-readable GPU name, e.g. "NVIDIA GeForce RTX 4060 Ti",
    "Apple M2 Pro (MPS)", "CPU only", etc.
r   Nr&   r   r   r   zApple Siliconz (MPS)zApple Silicon (MPS)zCPU onlyzUnknown (PyTorch not available))r   r!   r   r   r   r&   r   r   r   r   r   	processorr   ImportError)r   r   r   chips       r   get_gpu_device_namert    s    1::""$$::--a00UE""uyy'='='?'?II33A6E5&+66U^^U++0B0B0O0O0Q0Q-))+>v&   -,-  101s=   =D  AD AD !D   
D
D DD 
DDre   c           	         U [         ;  a$  [        R                  " SU  S35        [        5       $ [	        5       n[         U    n[        5       nU(       a  [        R                  " SU  S35        [        S0 SU _SU_SUS   _SUS   _S	US	   _S
US
   _SUS   _SUS   _SUR                  SS5      _SU(       a  SOUR                  SS5      _SU(       a  SOUR                  SS5      _SU(       a  SOUR                  SS5      _SU(       a  SOUR                  SS5      _SU(       a  SOUR                  SS5      _SU(       a  SOUR                  SS5      _SUS   _SU(       a  [        U5      OS_6n[        U5      $ )a  
Create a GPUConfig for a specific tier, applying platform overrides.

This is used when the user manually selects a different tier in the UI.
The actual gpu_memory_gb is preserved from the real hardware detection,
but all tier-based settings come from the selected tier's config.

Args:
    tier: Tier key, e.g. "tier3", "tier6a", "unlimited"

Returns:
    GPUConfig with the selected tier's settings
zUnknown tier 'z'', falling back to auto-detected configzManual tier override to u2    on macOS MPS — applying Apple Silicon overridesre   rf   rg   rh   ri   rj   rk   rl   rm   r[   rn   r   r   ro   r   r   rp   FTrq   rr   rs   rt   rw   rv   rx   )r   r   r   r   r   r   r   rc   r   r   r   )re   real_gpu_memoryr   r   s       r   get_gpu_config_for_tierrw    s    ##v-TUV ()Od#FD&tf,^_	
    %  $$:;  !''@ A	 
  &&>?  #))D"E  01  ##89  $ZZ(>C    -ZZ0%8   "ZZ-v6 "   %ZZ0$7% (  $)ZZ4d;+ .  #ZZ.51 4  $ZZ/67 8 N+9 <  4OD? FB 5V<<r:   _global_gpu_configc                  &   [         c  [        5       q [        R                  R	                  [
        S5      R                  5       R                  5       n U S;   a5  S[         l        [        R                  " SR                  [
        U 5      5        [         $ )zGet the global GPU configuration, initializing if necessary.

Respects the ``ACESTEP_SAVE_MEMORY`` environment variable: when set to
``"1"`` or ``"true"``, ``save_memory_mode`` is enabled regardless of tier.
r[   )1trueyesTz/[gpu_config] Save-memory mode enabled via {}={})rx  r   r   r   r   SAVE_MEMORY_ENVr   r^   ru   r   r   format)r   s    r   r   r     sm     !+-**.."5;;=CCE**26/KKIPPQ`bijkr:   c                     U q g)z!Set the global GPU configuration.N)rx  r   s    r   set_global_gpu_configr  *  s
      r:   )N)r   )rO   )rO   FrL   )Ir}   r   rV   r   dataclassesr   typingr   r   r   r   logurur   r   r   r   r}  VRAM_16GB_TOLERANCE_GBr   r   r   r   r   r   r   r"   r$   r'   r+   r   r3   r5   r9   r   r  r+  r  r~   rX   ra   rc   r   r   r   r   r   r   r   r   r   r   r  r  r#  r>  rI  rK  rU  r`  rd  rh  rk  ro  GPU_TIER_LABELSr-  itemsGPU_TIER_CHOICESrt  rw  rx  r   r   r  rx   r:   r   <module>r     sZ   
 	 
 ! . .  * ' ' '  00  "&  D E )  "4 $ $ 4 (
t 
t 
	S 	%S/9R 	TS T T 	
 CDCD#c
B 	    L3 Lc Ld L1 1 16 1" 1" 1"h	i 	I 	 )-}% 	F !$#&"#%& ! ""'%"&&* $!%!, !$#&"#%& ! ""'%"&&* $!%#. !$#&"#%& 56 5"'%"&&* $!%#, !$#&"#%& 56 5"'%"&&* $!%!* !$#&"#%& 57LM 5"'%"&&+ $!%!"A.!, !$#&"#%& 57LM 5"'%"&&+ $!%!"A.#, !$#&"#%& 

 !6"'%"'&+ %!%!"AR8). !$#&"#%& 

 !4"'%"'&+ %!%!"AR8%MZ z -X6  _5 _DfR! !# !HXe_  DN=(5/ N=Y N=b# # *15c	2!3!3)-c!3c]!3H[[*/[
5%<[|l=5 l=C l=i l=^NS N Nb(u ( )=)=)= )= 	)=
 )= )=X!*<@
49@!*<@
49@c y U4QT9EU <. .x} ."Xi X*   &	 --/0 1S 1>==# ==) ==B +/ HY' .y   )  r:   