§
    ’Þj®5  ã                   óR  — d Z ddlZddlmZ ddlmZ ddlZ ej        ¦   «         Z ej        ¦   «         Z	i Z
 edd¬¦  «        Zed„ ¦   «         Zd„ Zd	„ Zd
„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zdd„Zd„ Z ej        ¦   «         Z ej        ¦   «         Zd„ Zd„ Zd„ Z d„ Z!dS )zQModel-facing execution services, independent of MMGP's offload/compilation hooks.é    N)Úcontextmanager)Ú
ContextVarÚmmgp_execution_checkpoint)Údefaultc              #   óº   K  — t                                | ¦  «        }	 dV — t                                |¦  «         dS # t                                |¦  «         w xY w)zESupply a local cancellation check for long MMGP residency operations.N)Ú_execution_checkpointÚsetÚreset)Ú
checkpointÚtokens     ú4C:\Users\johnn\OneDrive\Documents\AI\mmgp\runtime.pyÚexecution_scoper      s^   è è € õ "×%Ò% jÑ1Ô1€Eð+Øˆˆˆå×#Ò# EÑ*Ô*Ð*Ð*Ð*øÕ×#Ò# EÑ*Ô*Ð*Ð*øøøs	   ž> ¾Ac                  óT   — t                                ¦   «         } | � | ¦   «          d S d S ©N)r   Úget)Úcallbacks    r   r   r      s0   € Ý$×(Ò(Ñ*Ô*€HØÐØˆ‰
Œ
ˆ
ˆ
ˆ
ð Ðó    c                 ó~   — t                                | t          ¦   «         ¦  «                             ||f¦  «         dS )aŽ  Tie a shared execution resource to a model's GPU residency.

    prepare(device) runs before its first owner loads, outside graph warmup;
    release() runs after its last owner unloads and its graphs are destroyed.
    Register before profiling, with the same callback pair for models sharing the resource. Neither
    callback may retain the model or allocate resources at registration time.
    N)Ú
_resourcesÚ
setdefaultr	   Úadd)ÚmoduleÚprepareÚreleases      r   Úregister_resourcer       s7   € õ ×Ò˜&¥#¡%¤%Ñ(Ô(×,Ò,¨g°wÐ-?Ñ@Ô@Ð@Ð@Ð@r   c           	      ó°  — | j         |         }| j        |         D ]º}t                               |t	          j        ¦   «         ¦  «        }| }|                     |¦  «         |rrddlm} | 	                    ¦   «         5   |d         t          j        dt          j                             ¦   «         ¦  «        ¦  «         d d d ¦  «         n# 1 swxY w Y   Œ»d S )Né   )Ú	allocatorr   Úcuda)ÚmodelsÚruntime_resourcesÚ_resource_usersr   ÚweakrefÚWeakSetr   Ú r   Únormal_allocationsÚtorchÚdevicer   Úcurrent_device)ÚmanagerÚmodel_idÚmodelÚresourceÚusersÚfirstr   s          r   Ú_load_resourcesr0   +   s+  € ØŒN˜8Ô$€EØÔ-¨hÔ7ð Oð OˆÝ×*Ò*¨8µW´_Ñ5FÔ5FÑGÔGˆØ�	ˆØ�	Š	�%ÑÔÐØð 	OØ#Ð#Ð#Ð#Ð#Ð#Ø×-Ò-Ñ/Ô/ð Oð OØ�˜”�EœL¨µ´×1JÒ1JÑ1LÔ1LÑMÔMÑNÔNÐNðOð Oð Oñ Oô Oð Oð Oð Oð Oð Oð Oøøøð Oð Oð Oð OøðOð Os   Á=AC
Ã
C	ÃC	c                 óâ   — |D ]k}| j         |         }| j        |         D ]N}t                               |¦  «        }|€Œ|                     |¦  «         |s |d         ¦   «          t          |= ŒOŒld S )Nr   )r    r!   r"   r   Údiscard)r*   Ú	model_idsr+   r,   r-   r.   s         r   Ú_unload_resourcesr4   7   s�   € Øð 	.ð 	.ˆØ”˜xÔ(ˆØÔ1°(Ô;ð 	.ð 	.ˆHÝ#×'Ò'¨Ñ1Ô1ˆEØˆ}ØØ�MŠM˜%Ñ Ô Ð Øð .Ø�˜”‘”�Ý# HÐ-øð	.ð	.ð 	.r   c                 ó”  ‡ — ˆ fd„|D ¦   «         }i ‰ _         |                     ¦   «         D ]r\  }}t          ¦   «         x}‰ j         |<   |                     ¦   «         D ]@}||         t          |<   |                     t                               |d¦  «        ¦  «         ŒAŒs|                     ¦   «         D ]\  }}||         t          |<   Œd S )Nc                 ó>   •— i | ]}|t          j        ‰¦  «        |f“ŒS © )r#   Úref)Ú.0r+   r*   s     €r   ú
<dictcomp>z_register.<locals>.<dictcomp>E   s*   ø€ ÐPÐPÐP¸Xˆh�œ WÑ-Ô-¨xÐ8ÐPÐPÐPr   r7   )r!   Úitemsr	   ÚmodulesÚ_ownersÚupdater   r   )r*   r    Úownersr+   r,   Ú	resourcesr   s   `      r   Ú	_registerrA   D   sÛ   ø€ ØPÐPÐPÐPÈÐPÑPÔP€FØ "€GÔØ!Ÿ<š<™>œ>ð 9ð 9‰ˆ�%Ý:=¹%¼%Ð?ˆ	�GÔ-¨hÑ7Ø—m’m‘o”oð 	9ð 	9ˆFØ$ XÔ.�G�F‰OØ×Ò�ZŸ^š^¨F°BÑ7Ô7Ñ8Ô8Ð8Ð8ð	9ð "Ÿ<š<™>œ>ð *ð *‰ˆ�%Ø Ô)��‰ˆð*ð *r   c                 óŒ   — t          t                               ¦   «         ¦  «        D ]\  }\  }} |¦   «         | u rt          |= Œd S r   )Úlistr=   r;   )r*   r   Ú	referenceÚ_s       r   Ú_unregisterrF   Q   sM   € Ý"&¥w§}¢}¡¤Ñ"7Ô"7ð  ð  Ñˆ‘�˜AØˆ9‰;Œ;˜'Ð!Ð!Ý˜�øð ð  r   c                 óz   — t                                | ¦  «        }|€d S  |d         ¦   «         }|€d n	||d         fS )Nr   r   )r=   r   )r   Úentryr*   s      r   Ú_ownerrI   W   sC   € Ý�KŠK˜ÑÔ€EØ€}ØˆtØˆe�AŒh‰jŒj€GØ�?ˆ4ˆ4¨°%¸´(Ð(;Ð;r   c                 ób  — ddl m} t          | |¦  «        rt          j        d¦  «        S t          | ¦  «        �t          j        d¦  «        S t          |                      ¦   «         d¦  «        }|€"t          |                      ¦   «         d¦  «        }|€t          j        d¦  «        n|j        S )zÞReturn the execution device, even while managed weights are on CPU.

    An unmanaged module uses its first parameter/buffer's device, or CPU if empty.
    Registration is removed when its offload manager is released.
    r   )Ú
ExpertBankÚcpuNr   )	ÚexpertsrK   Ú
isinstancer'   r(   rI   ÚnextÚ
parametersÚbuffers)r   rK   Útensors      r   Úexecution_devicerS   _   s¨   € ð $Ð#Ð#Ð#Ð#Ð#Ý�&˜*Ñ%Ô%ð #ÝŒ|˜EÑ"Ô"Ð"Ýˆf�~„~Ð!ÝŒ|˜FÑ#Ô#Ð#Ý�&×#Ò#Ñ%Ô% tÑ,Ô,€FØ€~Ý�f—n’nÑ&Ô&¨Ñ-Ô-ˆØ"( .�5Œ<˜ÑÔÐ°f´mÐCr   c                  ó   — | D ]	}d|_         Œ
dS )a[  Mark modules that MMGP computes on the CPU, their weights kept in RAM, never in VRAM: a token table only gathers the rows of a
    prompt, the same values as on the GPU, without moving the whole table (2 GB for an umT5 or a Gemma 3) at each load. Their tensor
    inputs go to the CPU and their output comes back to the execution device. Call it on the loaded modules, before the offload
    profile: a quantized table (a module whose tensors are not plain) keeps the GPU path of its qtype. A module tied to a marked one
    (a head sharing the table) must be marked too, with unused when it never runs.TN)Ú
_mm_on_cpu©r<   r   s     r   Úlookup_on_cpurW   p   s(   € ð ð !ð !ˆØ ˆÔÐð!ð !r   c                  ó   — | D ]	}d|_         Œ
dS )a  Mark modules whose parameters MMGP keeps in reserved RAM mapped in the GPU's address space, never in VRAM: their kernels read the
    rows they need in place, over the bus, inside CUDA graphs too and with indices computed on the GPU (a token table read for a few tokens
    at each step). The parameters stay the modules' own, as CUDA views of their RAM, outside the blocks, base and budgets; the RAM is
    charged to the reserved RAM while it exists. Parameters of other modules sharing their tensors follow them: never mark a table that a
    module reads whole at each call (a head tied to it), which would read it over the bus. Call it on the loaded modules, before the offload
    profile; without CUDA, or without reserved RAM left, the modules keep their usual placement.TN)Ú
_mm_mappedrV   s     r   Ú
map_in_ramrZ   z   s(   € ð ð !ð !ˆØ ˆÔÐð!ð !r   c                 ó$   — ddl m}  || ¦  «        S )zdTrue for a parameter kept in mapped RAM (map_in_ram): a CUDA view of RAM, whose reads cross the bus.r   )Ú	is_mapped)Úmappedr\   )rR   r\   s     r   r\   r\   …   s$   € à!Ð!Ð!Ð!Ð!Ð!Øˆ9�VÑÔÐr   c                  ó   — | D ]	}d|_         Œ
dS )aC  Mark modules that never run, such as the output head of a language model whose hidden states condition a generator (called through
    its base model): MMGP keeps their weights in RAM, out of VRAM, pinning and budgets, quantized or not, and raises if one runs. Call it on
    the loaded modules, before the offload profile.TN)Ú
_mm_unusedrV   s     r   Úunusedr`   ‹   s(   € ð ð !ð !ˆØ ˆÔÐð!ð !r   c                 ó`   — t          | ¦  «        }|�|\  }}|                     |¦  «         dS dS )zñLoad a managed model's base/preloaded weights; leave block swapping to MMGP.

    Use before custom entry points that read weights without calling a hooked
    forward. Unmanaged modules are unchanged. This does not pin a model in VRAM.
    N)rI   Úensure_model_loaded©r   Úownerr*   r+   s       r   Úensure_loadedre   “   sA   € õ �6‰NŒN€EØÐØ!Ñˆ�Ø×#Ò# HÑ-Ô-Ð-Ð-Ð-ð Ðr   ÚstateFc           
      ó>  ‡ ‡‡— ddl m} t          ‰ ¦  «        }|€L |t          ‰ ¦  «        t	          j        dt          j                             ¦   «         ¦  «        d|‰ ¬¦  «        S |\  }Št          ˆ fd„|j	        ‰          
                    ¦   «         D ¦   «         ¦  «        dz   Šˆˆfd„t          t          ‰ ¦  «        ¦  «        D ¦   «         } |t          ‰ ¦  «        t	          j        dt          j                             ¦   «         ¦  «        ||‰ ‰||¬	¦  «        S )
a¦  A state ring (mmgp.state_ring.StateRing) for tensors a model computes once per block and reads at every pass (a cached attention
    prefix), blocks: the model's blocks (a ModuleList, called one by one). Kept in RAM and streamed block by block on the transfer stream of
    the model's offload object, with the weights, following MMGP's schedule for these blocks (its prefetch window; records locked for the
    blocks whose weights are pinned, then, for a model MMGP pins, for those kept in VRAM, as far as the reserved RAM allows; the others moved
    ahead through MMGP's staging ring with their blocks): each block's forward fetches its state. The model calls store(block, tensors) once per block, and release() at the end.
    resident: blocks whose weights MMGP keeps in VRAM may keep their state there too, in the room their preload leaves (see mmgp.state_ring;
    the model then reads the lists store() returns at each pass).r   )Ú	StateRingNr   )r<   c              3   ó*   •K  — | ]\  }}|‰u ¯	|V — Œd S r   r7   )r9   Únamer   Úblockss      €r   ú	<genexpr>zstate_ring.<locals>.<genexpr>¬   s3   øè è € ÐhÐh™<˜4 ÐW]ÐagÐWgÐWg�$ÐWgÐWgÐWgÐWgÐhÐhr   ú.c                 ó"   •— g | ]}‰› d ‰› |› �‘ŒS )ú/r7   )r9   Úindexr+   Úprefixs     €€r   ú
<listcomp>zstate_ring.<locals>.<listcomp>­   s,   ø€ ÐMÐMÐM°�(Ð,Ð,˜VÐ, UÐ,Ð,ÐMÐMÐMr   )r<   r+   ÚentriesÚresident)Ú
state_ringrh   rI   Úlenr'   r(   r   r)   rO   r    Únamed_modulesÚrange)	rk   rj   rt   rh   rd   r*   rs   r+   rq   s	   `      @@r   ru   ru   Ÿ   s-  øøø€ ð &Ð%Ð%Ð%Ð%Ð%Ý�6‰NŒN€EØ€}Øˆy�˜V™œ¥e¤l°6½5¼:×;TÒ;TÑ;VÔ;VÑ&WÔ&WÐY]Ð_cÐmsÐtÑtÔtÐtØÑ€GˆXÝÐhÐhÐhÐh¨7¬>¸(Ô+C×+QÒ+QÑ+SÔ+SÐhÑhÔhÑhÔhÐknÑn€FØMÐMÐMÐMÐM½%ÅÀFÁÄÑ:LÔ:LÐMÑMÔM€GØˆ9•S˜‘[”[¥%¤,¨vµu´z×7PÒ7PÑ7RÔ7RÑ"SÔ"SÐU\Ð^bÐlrð  ~Fð  PWØ&ð(ñ (ô (ð (r   c                 óB  ‡ ‡‡‡— t          ‰ ¦  «        }|€dS |\  }Š‰|j        vrdS t                               |¦  «        }|€i x}t          |<   |j        ‰         }|                     ‰t          ‰ ¦  «        f¦  «        }|€v‰dz   ‰ |u rdn/t          ˆ fd„|                     ¦   «         D ¦   «         ¦  «        dz   z   Šˆˆfd„|j         	                    ¦   «         D ¦   «         x}|‰t          ‰ ¦  «        f<   |j
        ‰         Št          ˆfd	„|D ¦   «         ¦  «        S )
að  Whether the weights of a managed module are all in VRAM now (its model loaded, none of the blocks under the module streamed; expert
    banks aside): an MMGP graph stage that runs this module may then span several of its blocks (see cuda_graphs.run). For a submodule
    (e.g. the language model of a larger model), only its own blocks count: blocks the stage never runs may stay out of VRAM. Check it at
    each call: a dynamic preload can release blocks between calls. Unmanaged modules: True.NTFro   r%   c              3   ó*   •K  — | ]\  }}|‰u ¯	|V — Œd S r   r7   )r9   rj   Úmr   s      €r   rl   z#weights_resident.<locals>.<genexpr>Ã   s4   øè è € ÐB|ÐB|ÉGÈDÐRSÐpqÐu{Ðp{Ðp{À4Ðp{Ðp{Ðp{Ðp{ÐB|ÐB|r   rm   c                 óx   •— g | ]6\  }}|¯|                      ‰¦  «        ¯|t          ‰¦  «        d z   d…         ‘Œ7S )r   N)Ú
startswithrv   )r9   rj   Úsizer+   rq   s      €€r   rr   z$weights_resident.<locals>.<listcomp>Ä   sƒ   ø€ ð  2jð  2jð  2jÉzÈtÐUYð  IMð  2jð  RV÷  Raò  Rað  bhñ  Riô  Rið  2j°$µs¸8±}´}ÀqÑ7HÐ7IÐ7IÔ2Jð  2jð  2jð  2jr   c              3   ó    •K  — | ]}|‰v V — Œ	d S r   r7   ©r9   rj   Ú	preloadeds     €r   rl   z#weights_resident.<locals>.<genexpr>Æ   s(   øè è € Ð4Ð4 Tˆt�yÐ Ð4Ð4Ð4Ð4Ð4Ð4r   )rI   Úactive_models_idsÚ_block_namesr   r    ÚidrO   rw   Úblocks_of_modules_sizesr;   Úpreloaded_blocks_per_modelÚall)	r   rd   r*   Únamesr,   rk   r+   rq   r�   s	   `     @@@r   Úweights_residentr‰   ²   s~  øøøø€ õ
 �6‰NŒN€EØ€}ØˆtØÑ€GˆXØ�wÔ0Ð0Ð0ØˆuÝ×Ò˜WÑ%Ô%€EØ€}Ø(*Ð*ˆ•˜WÑ%ØŒN˜8Ô$€EØ�YŠY˜¥" V¡*¤*Ð-Ñ.Ô.€FØ€~Ø˜C‘¨°5¨¨ 2 2½dÐB|ÐB|ÐB|ÐB|ÐW\×WjÒWjÑWlÔWlÐB|ÑB|ÔB|Ñ>|Ô>|ð  @Cñ  ?Cñ  Dˆð 2jð  2jð  2jð  2jð  2jÐ]dÔ]|÷  ^Cò  ^Cñ  ^Eô  ^Eð  2jñ  2jô  2jð  	jˆ�˜¥" V¡*¤*Ð-Ñ.ØÔ2°8Ô<€IÝÐ4Ð4Ð4Ð4¨VÐ4Ñ4Ô4Ñ4Ô4Ð4r   c                 óò  ‡‡‡‡‡— t          | ¦  «        }|€dt          ‰¦  «        dffS |\  ŠŠt                               ‰¦  «        }|�|d         t	          ‰¦  «        ‰fk    r�‰j        ‰         }t          ˆfd„|                     ¦   «         D ¦   «         ¦  «        dz   Šˆfd„t          t          ‰¦  «        ¦  «        D ¦   «         }t	          ‰¦  «        ‰fˆˆfd„|D ¦   «         fx}t          ‰<   |d         }‰‰j	        vrdt          ‰¦  «        d	ffS ‰j
        ‰         Šˆfd
„|D ¦   «         }‰j        €dn‰j        j                             ‰¦  «        }|�|r|j        |d         k    rd	|d<   g d}	}t          dt          |¦  «        dz   ¦  «        D ]O}
|
t          |¦  «        k    s||
         ||	         k    s||	         s |                     |	|
||	         f¦  «         |
}	ŒPt          |¦  «        S )a  The blocks of a tower of a managed model (a ModuleList of its blocks) as runs (start, stop, resident) that cover them in order:
    the blocks of a resident run are kept in VRAM now, the others are streamed when they run (all are resident while their model is
    loaded whole). The first block of a tower where an automatic preload starts its cycles is a run of its own, not resident, as are
    the blocks of a model not loaded yet. Query it at each pass: a dynamic preload changes the blocks kept between calls.Nr   Tc              3   ó*   •K  — | ]\  }}|‰u ¯	|V — Œd S r   r7   )r9   rj   Ú	submodulerk   s      €r   rl   z resident_runs.<locals>.<genexpr>Ù   s2   øè è € Ð_Ð_™˜t YÈ9ÐX^ÐK^ÐK^�dÐK^ÐK^ÐK^ÐK^Ð_Ð_r   rm   c                 ó4   •— g | ]}‰t          |¦  «        z   ‘ŒS r7   )Ústr)r9   rp   rq   s     €r   rr   z!resident_runs.<locals>.<listcomp>Ú   s$   ø€ ÐEÐEÐE¨��#˜e™*œ*Ñ$ÐEÐEÐEr   c                 óX   •— g | ]&}‰j                              ‰d z   |z   ¦  «        r|nd‘Œ'S ©ro   N)r…   r   )r9   rj   r*   r+   s     €€r   rr   z!resident_runs.<locals>.<listcomp>Û   s~   ø€ ð  Ffð  Ffð  Ffð  X\ÈgÔNm×NqÒNqÐrzð  ~Añ  sAð  DHñ  sHñ  OIô  OIð  GSÀdÀdð  OSð  Ffð  Ffð  Ffr   r   Fc                 ó    •— g | ]
}|d u p|‰v ‘ŒS r   r7   r€   s     €r   rr   z!resident_runs.<locals>.<listcomp>à   s'   ø€ ÐAÐAÐA°4ˆT�Tˆ\Ð.˜T YÐ.ÐAÐAÐAr   )rI   rv   Ú_tower_entriesr   r„   r    rO   rw   rx   r‚   r†   Úauto_preloadÚplansr/   ÚappendÚtuple)r   rk   rd   rs   r,   rˆ   ÚflagsÚplanÚrunsÚstartrp   r*   r+   rq   r�   s    `         @@@@r   Úresident_runsr›   Í   sW  øøøøø€ õ
 �6‰NŒN€EØ€}Ø•C˜‘K”K Ð&Ð(Ð(ØÑ€GˆXÝ× Ò  Ñ(Ô(€GØ€˜' !œ*­¨G©¬°hÐ(?Ò?Ð?Ø”˜xÔ(ˆÝÐ_Ð_Ð_Ð_°%×2EÒ2EÑ2GÔ2GÐ_Ñ_Ô_Ñ_Ô_ÐbeÑeˆØEÐEÐEÐEµ%½¸F¹¼Ñ2DÔ2DÐEÑEÔEˆÝ-/°©[¬[¸(Ð,Cð  Ffð  Ffð  Ffð  Ffð  Ffð  `eð  Ffñ  Ffô  Ffð  ,gð  	gˆ•. Ñ(Ø�AŒJ€EØ�wÔ0Ð0Ð0Ø•C˜‘K”K Ð'Ð)Ð)ØÔ2°8Ô<€IØAÐAÐAÐA¸5ÐAÑAÔA€EØÔ'Ð/ˆ4ˆ4°WÔ5IÔ5O×5SÒ5SÐT\Ñ5]Ô5]€DØÐ˜EÐ d¤j°E¸!´HÒ&<Ð&<Øˆˆa‰Ø�aˆ%€DÝ�q�#˜e™*œ* q™.Ñ)Ô)ð ð ˆØ•C˜‘J”JÒÐ %¨¤,°%¸´,Ò">Ð">ÀeÈEÄlÐ">Ø�KŠK˜  u¨U¤|Ð4Ñ5Ô5Ð5ØˆEøÝ�‰;Œ;Ðr   c                 ó–   — t          | ¦  «        }|€dS |\  }}|j                             |¦  «        }|du p|                     ¦   «         S )a™  Place a managed model's optional GPU expert copies now, outside graph recording (e.g. at the first step of a decoding loop replayed
    as one graph, which MMGP's hooks never see): as many as its budget or the dynamic preload allows, ordinary blocks first; never
    shrinks them. Returns False while its ordinary blocks are not all resident yet (call again at a later step). Models without
    experts: True.NT)rI   Úexpert_residencyr   Úplace)r   rd   r*   r+   Ú	residencys        r   Úplace_expertsr    ì   sS   € õ
 �6‰NŒN€EØ€}ØˆtØÑ€GˆXØÔ(×,Ò,¨XÑ6Ô6€IØ˜ÐÐ1 	§¢Ñ 1Ô 1Ð1r   c                 ó`   — t          | ¦  «        }|€dS |\  }}|j        duo||j        j        v S )zóWhether an automatic VRAM preload manages this model's blocks: it keeps as many as fit and releases some when another allocation
    needs VRAM (a co-tenant loaded beside it then takes only what it needs), keeping them again later as they run.NF)rI   r“   r”   rc   s       r   Údynamic_preloadr¢   ù   sA   € õ �6‰NŒN€EØ€}ØˆuØÑ€GˆXØÔ tÐ+ÐV°¸GÔ<PÔ<VÐ0VÐVr   c                 óÜ   ‡— t          | ¦  «        }|€dS |\  }Š‰|j        v rdS |j        �‰|j        j        v rdS t	          ˆfd„|j                             ¦   «         D ¦   «         ¦  «        S )aE  Whether this owner's weights may move during execution or include CPU experts.

    Whole-model external CUDA graphs need stable weight addresses. A dynamic
    preload remains reclaimable even when it currently happens to fit entirely.
    MMGP's own block graphs support these models and share their release lifecycle.
    NFTc              3   óR   •K  — | ]!\  }}|                      ‰d z   ¦  «        o|V — Œ"dS r�   )r}   )r9   rj   r~   r+   s      €r   rl   z)requires_layer_offload.<locals>.<genexpr>  s<   øè è € ÐrÐr¹J¸DÀ$ˆt�Š˜x¨#™~Ñ.Ô.Ð7°4ÐrÐrÐrÐrÐrÐrr   )rI   r�   r“   r”   Úanyr…   r;   rc   s      @r   Úrequires_layer_offloadr¦     s‡   ø€ õ �6‰NŒN€EØ€}ØˆuØÑ€GˆXØ�7Ô+Ð+Ð+ØˆtØÔÐ'¨H¸Ô8LÔ8RÐ,RÐ,RØˆtÝÐrÐrÐrÐrÈ'ÔJi×JoÒJoÑJqÔJqÐrÑrÔrÑrÔrÐrr   )rf   F)"Ú__doc__r#   Ú
contextlibr   Úcontextvarsr   r'   ÚWeakKeyDictionaryr=   r   r"   r   r   r   r   r0   r4   rA   rF   rI   rS   rW   rZ   r\   r`   re   ru   r‰   rƒ   r’   r›   r    r¢   r¦   r7   r   r   ú<module>r«      sø  ðà WÐ WØ €€€Ø %Ð %Ð %Ð %Ð %Ð %Ø "Ð "Ð "Ð "Ð "Ð "à €€€ð $ˆ'Ô
#Ñ
%Ô
%€Ø&ˆWÔ&Ñ(Ô(€
Ø€Ø"˜
Ð#>ÈÐMÑMÔMÐ ð ð+ð +ñ „ð+ðð ð ðAð Að Að	Oð 	Oð 	Oð
.ð 
.ð 
.ð
*ð 
*ð 
*ð ð  ð  ð<ð <ð <ðDð Dð Dð"!ð !ð !ð!ð !ð !ðð ð ð!ð !ð !ð	.ð 	.ð 	.ð(ð (ð (ð (ð&5ð 5ð 5ð. )ˆwÔ(Ñ*Ô*€Ø*�Ô*Ñ,Ô,€ðð ð ð>
2ð 
2ð 
2ðWð Wð Wðsð sð sð sð sr   