§
    9†Æj±  ã                   ó’   — d Z ddlZddlZddlZddlZddlZd\  ZZdddœZdZ	dZ
d	\  aad
ai Zd„ Zdd„Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ ZdS )a,  MMGP RAM allocator for PyTorch's CPU tensors (Windows and Linux, PyTorch 2.6 to 2.15).

    from mmgp.allocator import ram
    ram.install()     # after importing torch: the CPU tensors allocated from then on use it
    ram.release()     # the freed blocks it keeps go back to the system now (the end of a generation, a model release)

The CPU tensors of min_mb and more get their own pages, committed at their size, instead of a block of PyTorch's CPU allocator (mimalloc on
Windows, glibc's arenas on Linux), which keeps the memory of freed tensors for the rest of the process and on Windows commits up to twice
what a tensor of 1 to 64 MiB needs. The freed blocks are kept for reuse (a loop that allocates the same sizes again reuses pages already in
memory, without page faults), at most cache_gb of them. They go back to the system on demand, with release() (call it at the end of a
workload) or when the MMGP VRAM allocator would otherwise refuse to spill into RAM, and when the workload needs it: beyond cache_gb, or when
new pages are wanted while the system's available RAM is under pressure_gb, in the thread that frees or allocates: no background thread,
no timer, nothing runs while the GPU works. Smaller tensors keep PyTorch's allocator. The library also carries the hooks of the RAM debug mode (ram_debug.py).é    N)i   @i   zram_alloc_win_amd64.dllzram_alloc_linux_x86_64.so))Úwin32Úamd64)ÚlinuxÚx86_64))é   é   )r   é   )ÚenabledÚliveÚcachedÚpeakÚallocationsÚhitsÚfreshÚtrimsÚ	fallbacksÚreleasesÚreleased_bytesÚreserved)NNFc                  óØ  — t           €t          �t           t          fS t          d„ t          j                             d¦  «        d                              d¦  «        dd…         D ¦   «         ¦  «        } t                               t          j	        t          j
        ¦   «                              ¦   «         f¦  «        }|€dn^t          j                             t          j                             t          j                             t"          ¦  «        ¦  «        |¦  «        }|€%dt          j	        › dt          j
        ¦   «         › �a�n—t$          d         | cxk    rt$          d	         k    sn d
t          j        › d�a�n`t          j	                             d¦  «        rt          j        ¦   «         sda�n*t          j                             |¦  «        s|› d�a�n	 t-          j        |¦  «        }t,          j        t,          j        t,          j        f|j        _        t,          j        |j        _        t,          j        f|j        _        t-          j        t,          j        ¦  «        f|j        _        t-          j        t,          j         ¦  «        t,          j        f|j!        _        t,          j        |j!        _        |a n# tD          $ r}|› d|› d�aY d}~nd}~ww xY wt           t          fS )zJ(the library, None), or (None, the reason it cannot be used): loaded once.Nc              3   ó4   K  — | ]}t          |¦  «        V — Œd S ©N)Úint)Ú.0Úparts     ú:C:\Users\johnn\OneDrive\Documents\AI\mmgp\allocator\ram.pyú	<genexpr>zlibrary.<locals>.<genexpr>$   s(   è è € ÐYÐY $•C˜‘I”IÐYÐYÐYÐYÐYÐYó    ú+r   ú.r   zno library for ú é   zPyTorch z7 is not among the versions checked for it (2.6 to 2.15)r   z'this PyTorch build uses the old C++ ABIz, is missing (python -m mmgp.allocator.build)z could not be loaded (ú))#Ú_libÚ_reasonÚtupleÚtorchÚ__version__ÚsplitÚ
_LIBRARIESÚgetÚsysÚplatformÚmachineÚlowerÚosÚpathÚjoinÚdirnameÚabspathÚ__file__ÚTORCH_VERSIONSÚ
startswithÚcompiled_with_cxx11_abiÚisfileÚctypesÚCDLLÚc_int64Ú
ra_installÚargtypesÚc_intÚrestypeÚra_set_enabledÚPOINTERÚra_statsÚc_uint64Ú	ra_rangesÚOSError)ÚversionÚnamer1   ÚlibÚerrors        r   ÚlibraryrK      sf  € õ Ð�7Ð.Ý•Wˆ}ÐÝÐYÐY­%Ô*;×*AÒ*AÀ#Ñ*FÔ*FÀqÔ*I×*OÒ*OÐPSÑ*TÔ*TÐUWÐVWÐUWÔ*XÐYÑYÔYÑYÔY€GÝ�>Š>�3œ<­Ô)9Ñ);Ô);×)AÒ)AÑ)CÔ)CÐDÑEÔE€DØ�<ˆ4ˆ4¥R¤W§\¢\µ"´'·/²/Å"Ä'Ç/Â/ÕRZÑB[ÔB[Ñ2\Ô2\Ð^bÑ%cÔ%c€DØ€|ØG¥C¤LÐGÐGµ8Ô3CÑ3EÔ3EÐGÐGˆ‰Ý˜AÔ 'Ð>Ð>Ò>Ð>­^¸AÔ->Ò>Ð>Ð>Ð>Øg�UÔ.ÐgÐgÐgˆ‰Ý	Œ×	 Ò	  Ñ	)Ô	)ð µ%Ô2OÑ2QÔ2Qð Ø;ˆ‰ÝŒW�^Š^˜DÑ!Ô!ð ØÐGÐGÐGˆ‰ð	Ý”+˜dÑ#Ô#ˆCõ (.¤~µv´~ÅvÄ~Ð&VˆCŒNÔ#Ý%+¤\ˆCŒNÔ"Ý+1¬<¨/ˆCÔÔ'Ý%+¤^µF´NÑ%CÔ%CÐ$EˆCŒLÔ!Ý&,¤nµV´_Ñ&EÔ&EÅvÄ~Ð%VˆCŒMÔ"Ý$*¤NˆCŒMÔ!ØˆDˆDøõ ð 	>ð 	>ð 	>ØÐ=Ð=°UÐ=Ð=Ð=ˆGˆGˆGˆGˆGˆGøøøøð	>øøøõ •ˆ=Ðs   ÇJ? Ê?
KË	KËKr"   c                 ó’  — t          ¦   «         \  }}|€t          d|› d�¦  «        ‚ddl}|                     ¦   «         j        }|�t          |t          z  ¦  «        nt          dt          z  |dz  ¦  «        }|�t          |t          z  ¦  «        nt          dt          z  |dz  ¦  «        |z   }| 	                    t          | t          z  ¦  «        ||¦  «        dk    rt          d	¦  «        ‚d
at          ¦   «          t                               | t          |t          z  d¦  «        t          |t          z  d¦  «        ¬¦  «         dS )a¸  Makes the allocator PyTorch's CPU allocator for the tensors of min_mb and more. cache_gb: the most freed blocks kept for reuse (default:
    5% of the RAM, at most 2 GiB); pressure_gb: under this much available RAM, the freed blocks go back at once (default: the margin the VRAM
    allocator leaves before spilling into RAM, 10% of the RAM and at least 4 GiB, plus cache_gb). Raises RuntimeError when the allocator cannot
    be used here.Nz'The MMGP RAM allocator cannot be used: r    r   r   é   é   é
   zUThe MMGP RAM allocator cannot be used: PyTorch's CPU allocator could not be replaced.T)Úmin_mbÚcache_gbÚpressure_gb)rK   ÚRuntimeErrorÚpsutilÚvirtual_memoryÚtotalr   ÚGBÚminÚmaxr=   ÚMBÚactiveÚ_link_vram_allocatorÚsettingsÚupdateÚround)	rP   rQ   rR   rI   ÚreasonrT   ÚphysicalÚcacheÚpressures	            r   Úinstallrd   ?   s7  € õ ‘)”)�K€CˆØ
€{ÝÐNÀVÐNÐNÐNÑOÔOÐOØ€M€M€MØ×$Ò$Ñ&Ô&Ô,€HØ"*Ð"6�C��2‘ÑÔÐ½CÀÅBÁÈÐTVÉÑ<WÔ<W€EØ(3Ð(?�s�;¥Ñ#Ñ$Ô$Ð$ÅSÈÍRÉÐQYÐ]_ÑQ_ÑE`ÔE`ÐchÑEh€HØ
‡~‚~•c˜&¥2™+Ñ&Ô&¨¨xÑ8Ô8¸AÒ=Ð=ÝÐrÑsÔsÐsØ€FÝÑÔÐÝ‡O‚O˜6­E°%½"±*¸aÑ,@Ô,@ÍeÐT\Õ_aÑTaÐcdÑNeÔNe€OÑfÔfÐfÐfÐfr   c                  ó¤   — ddl m}  t          r@| �@|                      t	          j        t          j        t          j        ¦  «        ¦  «         d S d S d S )Nr"   )r$   )Ú r$   r[   Úvmm_set_ram_releaser:   ÚcastÚ
ra_releaseÚc_void_p)Úvram_librarys    r   r\   r\   S   s^   € à&Ð&Ð&Ð&Ð&Ð&Ýð X�,Ð*Ø×(Ò(­¬µT´_ÅfÄoÑ)VÔ)VÑWÔWÐWÐWÐWðXð XÐ*Ð*r   c                 óB   — t                                | rdnd¦  «         dS )zsNew CPU tensors use the allocator (True) or PyTorch's (False); the blocks it handed out are freed by it either way.r"   r   N)r$   rA   )r
   s    r   Úset_enabledrm   Z   s%   € å×Ò˜WÐ+˜˜¨!Ñ,Ô,Ð,Ð,Ð,r   c                  óJ   — t           rt                               ¦   «          dS dS )z:The freed blocks kept for reuse go back to the system now.N)r[   r$   ri   © r   r   Úreleaserp   _   s*   € åð Ý�ŠÑÔÐÐÐðð r   c                  óJ   — t           rt                               ¦   «          d S d S r   )r[   r$   Úra_reset_peakro   r   r   Ú
reset_peakrs   e   s,   € Ýð Ý×ÒÑÔÐÐÐðð r   c                  óØ   — t          j        t          t          ¦  «        z  ¦   «         } t          �t                               | ¦  «         t          t          t          | ¦  «        ¦  «        S )zäBytes in use (live), kept for reuse (cached), their peak, and counts: allocations, cache hits, fresh blocks, trimmed blocks, requests
    left to PyTorch's allocator (fallbacks), releases, released bytes, reserved address space.)r:   r<   ÚlenÚSTATSr$   rC   ÚdictÚzip)Úvaluess    r   Ústatsrz   j   sL   € õ Œn�s¥5™zœzÑ)Ñ,Ô,€FÝÐÝ�Š�fÑÔÐÝ••E˜6Ñ"Ô"Ñ#Ô#Ð#r   c                  óÊ   ‡— t           €g S t          j        dz  ¦   «         Št          dt                                ‰d¦  «        ¦  «        } ˆfd„t          | ¦  «        D ¦   «         S )z;The address ranges the allocator reserved, as (base, size).Ni   i   c                 óB   •— g | ]}‰d |z           ‰d |z  dz            f‘ŒS )r   r"   ro   )r   ÚindexÚouts     €r   ú
<listcomp>zranges.<locals>.<listcomp>y   s3   ø€ ÐKÐKÐK°UˆS��U‘Œ^˜S  U¡¨Q¡Ô/Ð0ÐKÐKÐKr   )r$   r:   rD   rX   rE   Úrange)Úcountr~   s    @r   Úrangesr‚   s   s\   ø€ å€|Øˆ	ÝŒ?˜TÑ!Ñ
$Ô
$€CÝ�•d—n’n S¨$Ñ/Ô/Ñ0Ô0€EØKÐKÐKÐK½eÀE¹l¼lÐKÑKÔKÐKr   )r"   NN)Ú__doc__r:   r0   r-   r,   r'   rW   rZ   r*   r6   rv   r$   r%   r[   r]   rK   rd   r\   rm   rp   rs   rz   r‚   ro   r   r   ú<module>r„      s  ððbð bð €€€Ø 	€	€	€	Ø €€€Ø 
€
€
€
à €€€à	�€€BØ";ÐRmÐnÐn€
Ø"€ð 	N€Ø�€€gØ	€Ø€ðð ð ð@gð gð gð gð(Xð Xð Xð-ð -ð -ð
ð ð ðð ð ð
$ð $ð $ðLð Lð Lð Lð Lr   