U
    ªÊ¹jŽü  ã                   @   sæ  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlm	Z	m
Z
mZmZ d dlZd dlZd dlmZ ddlmZmZmZmZ ddlmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z% ddl&m'Z' e (e)¡Z*dd„ Z+G dd„ dƒZ,dddœdd„Z-ej.j/j0ej.j/j1ej.j/j2ej.j/j3dœZ4G dd„ dƒZ5G dd„ de5ƒZ6G dd„ de5ƒZ7G dd„ de5ƒZ8G dd„ de5ƒZ9G dd„ de9ƒZ:d)d!d"„Z;ej<G d#d$„ d$ƒƒZ=G d%d&„ d&ƒZ>G d'd(„ d(ƒZ?dS )*é    N)ÚDictÚListÚOptionalÚSet)Údynamo_timedé   )ÚconfigÚdependenciesÚirÚmetrics)Úget_scheduling_for_device)ÚStarDepÚWeakDep)ÚComputedBuffer)ÚSimplifyIndexing)Úcache_on_selfÚcmpÚfree_symbol_hasÚget_device_tflopsÚget_dtype_sizeÚget_gpu_dram_gbpsÚ
has_tritonÚsympy_product)ÚVc                 C   sB   t | tƒrt| td�} tj| dd�}d|kr>dt |d¡› �S |S )N©Úkeyé   )ÚindentÚ
ú    )Ú
isinstanceÚsetÚsortedÚstrÚpprintÚpformatÚtextwrapr   )ÚobjÚresult© r)   úX/var/www/html/bwave/python/venv/lib/python3.8/site-packages/torch/_inductor/scheduler.pyr%   %   s    
r%   c                   @   s0   e Zd Zdd„ Zdd„ Zdd„ Zdd„ ZeZd	S )
Ú
OutputNodec                 C   s   |h| _ g | _d S ©N)Úunmet_dependenciesÚinverse_users©ÚselfÚdepr)   r)   r*   Ú__init__0   s    zOutputNode.__init__c                 C   s   dS ©NFr)   ©r0   r)   r)   r*   Úis_reduction4   s    zOutputNode.is_reductionc                 C   s   dS )Nr)   r)   r4   r)   r)   r*   Úget_alias_names7   s    zOutputNode.get_alias_namesc                 C   s   dS )NZOUTPUTr)   r4   r)   r)   r*   Úget_name:   s    zOutputNode.get_nameN)Ú__name__Ú
__module__Ú__qualname__r2   r5   r6   r7   Ú__repr__r)   r)   r)   r*   r+   /   s
   r+   ÚBaseSchedulerNode©Únode1Únode2c                 C   s,   |   ¡ s|  ¡ rt | |¡S t | |¡S d S r,   )Ú
is_foreachÚForeachKernelSchedulerNodeÚfuseÚFusedSchedulerNoder=   r)   r)   r*   rB   @   s    rB   )zextern_kernels.convolutionzextern_kernels.mmzextern_kernels.bmmzextern_kernels.addmmc                   @   s¸  e Zd Zdejdœdd„Zdd„ Zedœdd	„Zedœd
d„Z	dd„ Z
eeef dœdd„Zdd„ Zed dœdd„Zee eeef dœdd„Zdd„ Zdd„ Zdd„ Zejd œd!d"„Zd#d$„ Zee dœd%d&„Zee dœd'd(„Zd)d*„ Zd+d,„ Zd-d.„ Zedœd/d0„Zedœd1d2„Zee dœd3d4„Z ed  dœd5d6„Z!d7d8„ Z"d9d:„ Z#d;d<„ Z$d=d>„ Z%d?d@„ Z&ej'dAœdBdC„Z(dDdE„ Z)dFdG„ Z*dHdI„ Z+dRdKdL„Z,e-dœdMdN„Z.e/dœdOdP„Z0dQS )Sr<   Ú	Scheduler©Ú	schedulerÚnodec                 C   sH   || _ || _d | _g | _|  | ¡ ¡ d | _d | _d | _d | _	d| _
d S r3   )rF   rG   Úusersr.   Úset_read_writesZget_read_writesÚrecursive_predecessorsÚ	min_orderÚ	max_orderÚ
last_usageÚwritten)r0   rF   rG   r)   r)   r*   r2   Q   s    zBaseSchedulerNode.__init__c                 C   s   t | ƒj› d|  ¡ ›d�S )Nz(name=ú)©Útyper8   r7   r4   r)   r)   r*   r;   ]   s    zBaseSchedulerNode.__repr__©Úreturnc                 C   sÀ   |   ¡ }|› dt| ƒj› dt| jƒj› d�|› dt| jjƒ› �|› dt| jƒ› �|› dt| jj| j ƒ› �|› d| j	› �g}z||  
¡ g7 }W n" tk
r°   tjdd	d
� Y nX d |¡ ¡ S )z#Longer form printout for trace logsz: ú(rO   z
.writes = z.unmet_dependencies = z.met_dependencies = z	.users = zIgnoring error in debug_str()T)Úexc_infor   )r7   rQ   r8   rG   r%   Úread_writesÚwritesr-   ÚreadsrH   Údebug_str_extraÚ	ExceptionÚlogÚwarningÚjoinÚrstrip©r0   ÚnameÚlinesr)   r)   r*   Ú	debug_str`   s    "ûÿ
zBaseSchedulerNode.debug_strc                 C   s   dS )NÚ r)   r4   r)   r)   r*   rY   s   s    z!BaseSchedulerNode.debug_str_extrac                 C   s   t  d| | j| jj¡ d S )Nz(%s: unmet_dependencies = %s, writes = %s)r[   Úinfor-   rV   rW   r4   r)   r)   r*   Úlog_detailsv   s    üzBaseSchedulerNode.log_details©Úrenamesc                 C   s   |   | j |¡¡ d S r,   )rI   rV   Úrename©r0   rg   r)   r)   r*   Úupdate_mutated_names~   s    z&BaseSchedulerNode.update_mutated_namesc                 C   s   |   | j |¡¡ d S r,   )rI   rV   Z	with_readr/   r)   r)   r*   Úadd_mutation_dep�   s    z"BaseSchedulerNode.add_mutation_depÚNodeUser©rH   c                 C   s\   i }|D ]@}t |jƒ|kr:| |t |jƒ ¡|t |jƒ< q||t |jƒ< qt| ¡ ƒ| _d S r,   )ÚidrG   ÚmergeÚlistÚvaluesrH   )r0   rH   r(   Úuser)   r)   r*   Ú	set_users„   s     zBaseSchedulerNode.set_users©Úfuture_used_buffersÚmutation_real_namec                    s(   |   ¡ }‡ fdd„|D ƒ}|| | _d S )Nc                    s   h | ]}ˆ   ||¡’qS r)   )Úget)Ú.0Úk©rv   r)   r*   Ú	<setcomp>’   s     z3BaseSchedulerNode.set_last_usage.<locals>.<setcomp>)Úused_or_aliased_buffer_namesrM   )r0   ru   rv   Zused_buffersr)   rz   r*   Úset_last_usageŽ   s    z BaseSchedulerNode.set_last_usagec                 C   s
   | j  ¡ S r,   )rG   r6   r4   r)   r)   r*   Úget_aliases•   s    zBaseSchedulerNode.get_aliasesc                 C   s
   | j  ¡ S r,   )rG   Úget_mutation_namesr4   r)   r)   r*   Úget_mutations˜   s    zBaseSchedulerNode.get_mutationsc                 C   s   t |  ¡ p|  ¡ ƒS r,   )Úboolr~   r€   r4   r)   r)   r*   Úhas_aliasing_or_mutation›   s    z*BaseSchedulerNode.has_aliasing_or_mutation)Úrwc                 C   s   || _ | j j| _|  ¡  d S r,   )rV   rX   r-   Ú
prune_deps)r0   rƒ   r)   r)   r*   rI   ž   s    
z!BaseSchedulerNode.set_read_writesc                 C   s   | j jS r,   )rV   Ú	op_countsr4   r)   r)   r*   r…   £   s    zBaseSchedulerNode.op_countsc                 C   s   dd„ t  | jj| jj¡D ƒS )Nc                 S   s   h | ]
}|j ’qS r)   ©r`   ©rx   r1   r)   r)   r*   r{   §   s   ÿz6BaseSchedulerNode.used_buffer_names.<locals>.<setcomp>)Ú	itertoolsÚchainrV   rX   rW   r4   r)   r)   r*   Úused_buffer_names¦   s    þz#BaseSchedulerNode.used_buffer_namesc                 C   sp   t ƒ }t | jj| jj¡D ]P}| |j¡ tj	j
 |j¡rtj	j
|j  ¡ }t|tjƒr| |jj ¡ ¡ q|S r,   )r!   rˆ   r‰   rV   rX   rW   Úaddr`   r   ÚgraphÚname_to_bufferrw   Ú
get_layoutr    r
   ÚAliasedLayoutÚviewÚdatar7   )r0   Z
used_namesr1   Úlayoutr)   r)   r*   r|   ¬   s    z.BaseSchedulerNode.used_or_aliased_buffer_namesc                    s   ‡ fdd„ˆ j D ƒˆ _ d S )Nc                    s   h | ]}|j ˆ jjkr|’qS r)   )r`   rF   Úavailable_buffer_namesr‡   r4   r)   r*   r{   ¹   s   þz/BaseSchedulerNode.prune_deps.<locals>.<setcomp>©r-   r4   r)   r4   r*   r„   ¸   s    
þzBaseSchedulerNode.prune_depsc                    s4   dd„ ‰ ‡ fdd„| j jD ƒ}|  | j  |¡¡ d S )Nc                 S   s   t | tƒo| jtjjkS r,   )r    r   r`   r   rŒ   Úremoved_buffers)r1   r)   r)   r*   Úshould_pruneÁ   s    z7BaseSchedulerNode.prune_weak_deps.<locals>.should_prunec                    s   h | ]}ˆ |ƒr|’qS r)   r)   r‡   ©r–   r)   r*   r{   Ä   s      z4BaseSchedulerNode.prune_weak_deps.<locals>.<setcomp>)rV   rX   rI   Úremove_reads)r0   Z	to_remover)   r—   r*   Úprune_weak_deps¿   s    z!BaseSchedulerNode.prune_weak_depsc                    s~   t  ¡ ‰ ˆjD ](}t|tƒsˆ ˆ|j  ¡   d7  < q‡ ‡‡fdd„‰‡fdd„ˆjD ƒ}ˆj| ˆ_ˆ ˆj 	|¡¡ dS )aŽ  
        Prunes stardeps intended for mutation ordering
        on an upstream fused node if after fusion there is another dependency
        on the fused upstream node, making the stardep redundant

        In essence this enforces an ordering on fusions. As fusions occur, prunable stardeps will
        be incrementally removed, enabling other fusions, ensuring they are fused in order.
        r   c                    s>   t | tƒr6ˆ ˆ| j  ¡  dk}ˆ| j ˆk}|p4|S dS d S )Nr   F)r    r   r`   r7   )r1   Zis_redundantZis_self_dep)Úname_to_dep_countÚname_to_fused_noder0   r)   r*   r–   Ö   s    
ÿz<BaseSchedulerNode.prune_redundant_deps.<locals>.should_prunec                    s   h | ]}ˆ |ƒr|’qS r)   r)   r‡   r—   r)   r*   r{   ã   s      z9BaseSchedulerNode.prune_redundant_deps.<locals>.<setcomp>N)
ÚcollectionsÚCounterr-   r    r   r`   r7   rI   rV   r˜   )r0   r›   r1   Zdeps_to_pruner)   )rš   r›   r0   r–   r*   Úprune_redundant_depsÇ   s    	

z&BaseSchedulerNode.prune_redundant_depsc                 C   s
   | j  ¡ S r,   ©rG   r7   r4   r)   r)   r*   r7   ç   s    zBaseSchedulerNode.get_namec                 C   s   |   ¡ S r,   ©r7   r4   r)   r)   r*   Úget_first_nameê   s    z BaseSchedulerNode.get_first_namec                 C   s
   |   ¡ hS r,   r    r4   r)   r)   r*   Ú	get_namesí   s    zBaseSchedulerNode.get_namesc                 C   s   | gS r,   r)   r4   r)   r)   r*   Ú	get_nodesð   s    zBaseSchedulerNode.get_nodesc                 C   s
   | j  ¡ S r,   )rG   Ú
get_devicer4   r)   r)   r*   r¤   ó   s    zBaseSchedulerNode.get_devicec                 C   s   dS r3   r)   r4   r)   r)   r*   r5   ö   s    zBaseSchedulerNode.is_reductionc                 C   s   dS r3   r)   r4   r)   r)   r*   Úis_templateù   s    zBaseSchedulerNode.is_templatec                 C   s   dS r3   r)   r4   r)   r)   r*   Ú	is_externü   s    zBaseSchedulerNode.is_externc                 C   s   dS r3   r)   r4   r)   r)   r*   r@   ÿ   s    zBaseSchedulerNode.is_foreach©Úread_depc                 C   s   dS r3   r)   ©r0   r¨   r)   r)   r*   Úcan_inplace  s    zBaseSchedulerNode.can_inplacec                 C   s   dS r3   r)   r4   r)   r)   r*   Úhas_side_effects  s    z"BaseSchedulerNode.has_side_effectsc                    sö  ˆ j  ¡ sd S tˆ tfƒrBˆ j  ¡ s.ˆ j  ¡ rBtjj 	ˆ j ¡ d S tˆ tfƒsptˆ t
ƒ�râtˆ j tjtjfƒ�râtj�râttjtjjjjƒr ttjdd ƒd k	�râddlm} tˆ jjdd„ d�}|D �]}ˆ jj |j¡}|rÄtjj  |ˆ ¡rÄ‡ fdd„|j!D ƒ}t"|ƒdkrÄ|d	 j#rÄ|d	 j ˆ krÄt|j  $¡ tj%tj&tj'fƒsÄ||j ƒ|ˆ j ƒkrÄtjj (|j ˆ j ¡ t)tjd
ƒ�rÚtjj* +| ,¡ ˆ  ,¡ ¡ ttjtjjjjƒ�rÊtjj- .| ,¡ ¡ tjj- .ˆ  ,¡ ¡ ˆ j/ 0| ,¡ ¡  d S qÄtjj 	ˆ j ¡ d S )NÚ	mutationsr   )Úbuffer_reuse_keyc                 S   s   | j S r,   r†   ©Úxr)   r)   r*   Ú<lambda>#  ó    z,BaseSchedulerNode.allocate.<locals>.<lambda>r   c                    s"   g | ]}|j  ¡ ˆ jjkr|‘qS r)   )rG   r7   rF   r“   ©rx   r¯   r4   r)   r*   Ú
<listcomp>*  s
   ÿþz.BaseSchedulerNode.allocate.<locals>.<listcomp>r   Úargs)1rG   Zshould_allocater    ÚSchedulerNoder6   r   r   rŒ   Úwrapper_codeZcodegen_allocationÚExternKernelSchedulerNoder
   Ú	AllReduceÚInPlaceHintr   Úinplace_buffersÚkernelÚtorchÚ	_inductorÚcodegenÚtritonZTritonKernelÚgetattrZcodegen.wrapperr­   r"   rV   rX   rF   Úname_to_noderw   r`   Z	can_reuserH   Úlenrª   rŽ   ZMultiOutputLayoutZMutationLayoutr�   Zcodegen_inplace_reuseÚhasattrr´   Zmake_inplacer7   r¬   r‹   rM   Údiscard)r0   r­   Zordered_readsÚreadZ
input_nodeZremaining_usesr)   r4   r*   Úallocate  s†    
ÿÿ
þûú	÷õô
ÿ
þ
ÿþýýþüÿô ÿ ÿ 
ÿzBaseSchedulerNode.allocatec                 C   s"   | j D ]}t|jtƒr dS qdS )NFT)rH   r    rG   r+   )r0   rr   r)   r)   r*   Úcan_freeW  s    
zBaseSchedulerNode.can_freeTc           	      C   s  t js
d S |r| jrd S | jj}g }|D ]¾}|jdkr8q(| d¡ | d¡ d|j› d|j› �}d|jkr~|d|jd › � }| |¡ d|jkr(|jd › }| 	d	¡d
 }| d| 
dd¡ 
dd¡ 
dd¡ ¡ | d¡ | d¡ q(t|ƒdkrød S | |¡ d| _d S )NÚoutputrc   z#pragma CMT ORIGIN:z#pragma CMT ú Zseq_nrz seq_nr:Ústack_traceú|éÿÿÿÿÚ{z{{Ú}z}}r   ú\z#pragma CMT END ORIGINr   T)r   Zcomment_originrN   rG   ÚoriginsÚopÚappendÚtargetÚmetaÚsplitÚreplacerÂ   Ú
writelines)	r0   ÚbufferZ	only_oncerÐ   Z	out_linesÚoZop_info_strrÊ   Zstack_trace_last_liner)   r)   r*   Úcodegen_originating_info]  sF    






 ÿ þÿÿ

z*BaseSchedulerNode.codegen_originating_infoc                    sÜ   t ˆtƒrdS dd„ ˆjjD ƒ}dd„ ˆjjD ƒ}‡fdd„‰ t ˆtƒrj‡ fdd„|D ƒ}|| }|| }d}||B D ]`}|tjjkr”tjj| }n|tjj	krvtjj	| }nqv|tjj
 t| ¡ ƒ¡t| ¡ ƒ 7 }qv|S )Nr   c                 S   s   h | ]
}|j ’qS r)   r†   r‡   r)   r)   r*   r{   ‰  s     zABaseSchedulerNode.get_read_write_buffers_sizes.<locals>.<setcomp>c                 S   s   h | ]
}|j ’qS r)   r†   r‡   r)   r)   r*   r{   Š  s     c                    s.   dd„ ˆ j j|  jD ƒ}t|tˆ jƒ ƒdkS )Nc                 S   s   h | ]
}|j ’qS r)   )rG   )rx   Úuserr)   r)   r*   r{   �  s     zZBaseSchedulerNode.get_read_write_buffers_sizes.<locals>.is_materialized.<locals>.<setcomp>r   )rF   rÁ   rH   rÂ   r!   Úsnodes)ÚbufZbuf_usesr4   r)   r*   Úis_materializedŒ  s    zGBaseSchedulerNode.get_read_write_buffers_sizes.<locals>.is_materializedc                    s   h | ]}ˆ |ƒs|’qS r)   r)   r‡   )rÞ   r)   r*   r{   ‘  s      )r    ÚNopKernelSchedulerNoderV   rX   rW   rC   r   rŒ   r�   Úgraph_inputsÚsizevarsZ	size_hintr   Úget_sizer   Ú	get_dtype)r0   rX   rW   r•   Z
node_bytesrÝ   r)   )rÞ   r0   r*   Úget_read_write_buffers_sizes†  s,    



ÿ
þz.BaseSchedulerNode.get_read_write_buffers_sizesc                    s�  d }d }| j s:| jst‚| jd j  ¡ }| jd j  ¡ }n| j  ¡ }| j  ¡ }d|jjkr^dS ztƒ }t|ƒd }W n t	k
rŠ   Y dS X t
| tƒ�rft t| j ddƒd ¡}|d k	�rŒddlm} ddlm} |ƒ �ˆ |dd	��r}d
dlm‰  ‡ fdd„| j jD ƒ}	| j j}
|
j|f|	ž| j jŽ d}| ¡ }|| | W  5 Q R £ W  5 Q R £ S Q R X W 5 Q R X n&t
| tƒ�s€t
| j tƒ�rŒ|  ¡ | S dS )Nr   Úcudal    J)£r»   rc   )ÚFakeTensorMode)ÚFlopCounterModeF)Údisplayr   ©Úir_node_to_tensorc                    s   g | ]}ˆ |ƒ‘qS r)   r)   )rx   Úinputré   r)   r*   r³   Ä  s    z;BaseSchedulerNode.get_estimated_runtime.<locals>.<listcomp>g      à?)rG   rÜ   ÚAssertionErrorrŽ   rã   ÚdevicerQ   r   r   rZ   r    r·   Úkernel_name_to_oprw   rÀ   Ztorch._subclasses.fake_tensorræ   Ztorch.utils.flop_counterrç   r
   rê   ÚinputsÚ	__class__Zprocess_kernelÚkwargsZget_total_flopsrC   r   rä   )r0   r’   ZdtypeZgpu_memory_bandwidthZ	gpu_flopsrÑ   ræ   rç   Zflop_counter_modeZfake_inputsÚclsÚfactorZcounted_flopsr)   ré   r*   Úget_estimated_runtime¢  sN    




ÿ
ÿ6 ÿz'BaseSchedulerNode.get_estimated_runtimeN)T)1r8   r9   r:   r
   ÚBufferr2   r;   r#   rb   rY   re   r   rj   rk   r   rs   r   r}   r~   r€   r‚   r	   Ú
ReadWritesrI   r…   rŠ   r|   r„   r™   rž   r7   r¡   r¢   r£   r¤   r5   r¥   r¦   r@   Ú	MemoryDeprª   r«   rÆ   rÇ   rÚ   Úinträ   Úfloatrô   r)   r)   r)   r*   r<   P   sJ    
ÿ O
)c                   @   s:   e Zd Zedœdd„Zdd„ Zdd„ Zejdœd	d
„Z	dS )r·   rR   c                 C   s   |   ¡ › dt| jdd ƒ› �S )Nz.node.kernel = r»   )r7   rÀ   rG   r4   r)   r)   r*   rY   Ú  s    z)ExternKernelSchedulerNode.debug_str_extrac                 C   s   dS ©NTr)   r4   r)   r)   r*   r¦   Ý  s    z#ExternKernelSchedulerNode.is_externc                 C   s   t | jdƒo| j ¡ S )Nr«   )rÃ   rG   r«   r4   r)   r)   r*   r«   à  s    z*ExternKernelSchedulerNode.has_side_effectsr§   c                 C   sz   |   ¡ s|  ¡ rdS |j| jjkr&dS t| jtjj	j
tjj	jfƒsFdS t| jjƒdkrvtt| jjƒƒ}| ¡ | ¡ kS dS ©NFr   )r~   r¥   r`   rF   rÁ   r    rG   r¼   r½   r
   r¸   r¹   rÂ   rV   rW   ÚnextÚiterÚnumbytes_hint©r0   r¨   Ú	write_depr)   r)   r*   rª   ã  s     ÿz%ExternKernelSchedulerNode.can_inplaceN)
r8   r9   r:   r#   rY   r¦   r«   r	   r÷   rª   r)   r)   r)   r*   r·   Ù  s   r·   c                   @   s   e Zd ZdS )rß   N)r8   r9   r:   r)   r)   r)   r*   rß   ù  s   rß   c                       s„   e Zd Zdejdœ‡ fdd„Zedœdd„Zdd	„ Zd
d„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zejdœdd„Z‡  ZS )rµ   rD   rE   c                    sn   t ƒ  ||¡ | ¡ \| _| _| ¡ || jƒf| _|  ¡ rJ|  | 	¡ ¡ n |  t
j| jf| jžddiŽ¡ d S )NÚ	normalizeT)Úsuperr2   Zsimplify_and_reorderÚ_sizesÚ_bodyr¤   Úgroupr¥   rI   Znormalized_read_writesr	   Úextract_read_writes)r0   rF   rG   Úgroup_fn©rð   r)   r*   r2   þ  s"    ýÿÿÿÿzSchedulerNode.__init__rR   c                 C   sÈ   |   ¡ }|› d| jd › �|› d| jd › �|› d| j› �g}|  ¡ rb| |› dt|  ¡ ƒ› �¡ |  ¡ r†| |› dt|  ¡ ƒ› �¡ t| jt	j
ƒr¾| d|› d	�¡ | t | j ¡ d
¡¡ d |¡S )Nz.group.device = r   z.group.iteration = r   z	.sizes = z.aliases = z.mutations = zclass z_loop_body:r   r   )r7   r  r  r~   rÒ   r%   r€   r    r  r
   ZLoopBodyr&   r   rb   r]   r_   r)   r)   r*   rY     s    ýzSchedulerNode.debug_str_extrac                 C   s   | j S r,   )r  r4   r)   r)   r*   Ú
get_ranges   s    zSchedulerNode.get_rangesc                 C   s   t | j ¡ ƒS r,   )r�   rG   Zget_reduction_typer4   r)   r)   r*   r5   #  s    zSchedulerNode.is_reductionc                 C   s   t | jtjƒS r,   )r    rG   r
   ÚTemplateBufferr4   r)   r)   r*   r¥   &  s    zSchedulerNode.is_templatec                 G   s   |   ¡  |  |¡ d S r,   )Úmark_runr¾   )r0   Ú
index_varsr)   r)   r*   Úrun)  s    zSchedulerNode.runc                 C   s   |   ¡  d S r,   )rÆ   r4   r)   r)   r*   r  -  s    zSchedulerNode.mark_runc                 C   sH   | j }ttt|ƒƒttt|ƒƒks&t‚tttj 	|¡tj 	|¡ƒƒ}|S r,   )
r  ÚsumÚmaprÂ   rì   ÚdictÚziprˆ   r‰   Úfrom_iterable)r0   r  ÚsizesÚ
var_rangesr)   r)   r*   Úranges_from_index_vars0  s     

þÿz$SchedulerNode.ranges_from_index_varsc              
   C   sz   |   |¡}zFt tt ¡ |ƒ¡�( tj | ¡� | j|Ž  W 5 Q R X W 5 Q R X W n$ tk
rt   t	 
d| j¡ ‚ Y nX d S )NzError in codegen for %s)r  r   Zset_ops_handlerr   Zget_ops_handlerr»   Zset_current_noder  rZ   r[   ÚfatalrG   )r0   r  r  r)   r)   r*   r¾   ;  s    
ÿ
þ"zSchedulerNode.codegenc                    s$   ˆj \}‰ ‡ ‡fdd„}t ||¡S )zH
        Get the memory dependencies in the non-reduction axis.
        c                    s   ˆ  | dd„ ˆ D ƒ¡S )Nc                 S   s   g | ]}t  d ¡‘qS )r   )ÚsympyÚInteger)rx   Ú_r)   r)   r*   r³   M  s     zCSchedulerNode.pointwise_read_writes.<locals>.fn.<locals>.<listcomp>)r  )Úindex©Zreduction_sizesr0   r)   r*   ÚfnL  s    z/SchedulerNode.pointwise_read_writes.<locals>.fn)r  r	   r  )r0   r  r  r)   r  r*   Úpointwise_read_writesF  s    
z#SchedulerNode.pointwise_read_writesr§   c                 C   s\   |   ¡ s|  ¡ rdS t| jjƒdkrXt|tjƒrXtt	| jjƒƒ}|j
|j
koV|j|jkS dS rû   )r~   r¥   rÂ   rV   rW   r    r	   r÷   rü   rý   r  Úsizerÿ   r)   r)   r*   rª   Q  s     ÿzSchedulerNode.can_inplace)r8   r9   r:   r
   r   r2   r#   rY   r	  r5   r¥   r  r  r  r¾   r  r	   r÷   rª   Ú__classcell__r)   r)   r  r*   rµ   ý  s   rµ   c                       s†  e Zd ZdZeeedœdd„ƒZdee dœdd„Z	e
ed	œd
d„ƒZed	œdd„Ze
ee d	œdd„ƒZed	œdd„Zee eeef dœ‡ fdd„Ze
ee d	œdd„ƒZe
ee d	œdd„ƒZee d	œdd„Zdd„ Ze
dd„ ƒZe
dd „ ƒZd!d"„ Zd#d$„ Ze
d%d&„ ƒZe
d'd(„ ƒZeeef d)œd*d+„Zd,d-„ Zed. d/œd0d1„Zd2d3„ Z d4d5„ Z!e"j#d6œd7d8„Z$d9d:„ Z%d;d<„ Z&‡  Z'S )=rC   zæ
    This is a "fake" scheduler node that represents a group of scheduler nodes
    that are meant to be fused together. The way it does this is by maintaining
    its unmet dependencies as the union of its constituent nodes.
    r=   c                 C   s(   |j |j kst‚| |j | ¡ | ¡  ƒS r,   )rF   rì   r£   )rò   r>   r?   r)   r)   r*   rB   c  s    zFusedSchedulerNode.fuserD   )rF   rÜ   c                    sÀ   |ˆ _ |ˆ _d ˆ _d ˆ _g ˆ _t|dd„ d�jˆ _tjdd„ |D ƒŽ ˆ _	ˆ  
tj dd„ |D ƒ¡¡ ‡ fdd„tjd	d„ |D ƒŽ D ƒˆ jj ˆ _td
d„ ˆ j D ƒƒˆ _tdd„ ˆ j D ƒƒˆ _d S )Nc                 S   s   t |  ¡ ƒS r,   )rø   r5   r®   r)   r)   r*   r°   o  r±   z-FusedSchedulerNode.__init__.<locals>.<lambda>r   c                 S   s   g | ]
}|j ‘qS r)   )rJ   r²   r)   r)   r*   r³   q  s     z/FusedSchedulerNode.__init__.<locals>.<listcomp>c                 S   s   g | ]
}|j ‘qS r)   )rV   r²   r)   r)   r*   r³   u  s     c                    s   h | ]}|j ˆ  ¡ kr|’qS r)   ©r`   r¢   r‡   r4   r)   r*   r{   x  s   þz.FusedSchedulerNode.__init__.<locals>.<setcomp>c                 S   s   g | ]
}|j ‘qS r)   r”   r²   r)   r)   r*   r³   z  s     c                 S   s   g | ]
}|j ‘qS r)   ©rK   r²   r)   r)   r*   r³   }  s     c                 S   s   g | ]
}|j ‘qS r)   )rL   r²   r)   r)   r*   r³   ~  s     )rÜ   rF   rG   rH   r.   Úmaxr  r!   ÚunionrJ   rI   r	   rö   Ú
merge_listrV   rW   r-   ÚminrK   rL   )r0   rF   rÜ   r)   r4   r*   r2   h  s&    ÿÿ
þüzFusedSchedulerNode.__init__rR   c                 C   s   d  dd„ | jD ƒ¡S )Nr  c                 S   s   g | ]}|  ¡ ‘qS r)   r    r²   r)   r)   r*   r³   ‚  s     z/FusedSchedulerNode.get_name.<locals>.<listcomp>)r]   rÜ   r4   r)   r)   r*   r7   €  s    zFusedSchedulerNode.get_namec                 C   s   | j d  ¡ S ©Nr   )rÜ   r7   r4   r)   r)   r*   r¡   „  s    z!FusedSchedulerNode.get_first_namec                 C   s   t jdd„ | jD ƒŽ S )Nc                 S   s   g | ]}|  ¡ ‘qS r)   )r¢   r²   r)   r)   r*   r³   ‰  s     z0FusedSchedulerNode.get_names.<locals>.<listcomp>©r!   r#  rÜ   r4   r)   r)   r*   r¢   ‡  s    zFusedSchedulerNode.get_namesc                    s.   ‡ fdd„t ˆ jƒD ƒ}t d |¡ ¡ d¡S )Nc                    s,   g | ]$\}}ˆ   ¡ › d |› d| ¡ › �‘qS )z.snodes[z] =
)r7   rb   )rx   ÚirG   r4   r)   r*   r³   Œ  s   ÿz6FusedSchedulerNode.debug_str_extra.<locals>.<listcomp>r   r   )Ú	enumeraterÜ   r&   r   r]   r^   )r0   ra   r)   r4   r*   rY   ‹  s    
þz"FusedSchedulerNode.debug_str_extrart   c                    s@   t ƒ  ||¡ tƒ }t| jƒD ]}| ||¡ | |j¡ qd S r,   )r  r}   r!   ÚreversedrÜ   ÚupdaterM   )r0   ru   rv   rG   r  r)   r*   r}   ’  s
    z!FusedSchedulerNode.set_last_usagec                 C   s   t jdd„ | jD ƒŽ S )Nc                 S   s   g | ]}|  ¡ ‘qS r)   )rŠ   r²   r)   r)   r*   r³   ¡  s     z8FusedSchedulerNode.used_buffer_names.<locals>.<listcomp>r'  r4   r)   r)   r*   rŠ   Ÿ  s    z$FusedSchedulerNode.used_buffer_namesc                 C   s   t jdd„ | jD ƒŽ S )Nc                 S   s   g | ]}|  ¡ ‘qS r)   )r|   r²   r)   r)   r*   r³   ¥  s     zCFusedSchedulerNode.used_or_aliased_buffer_names.<locals>.<listcomp>r'  r4   r)   r)   r*   r|   £  s    z/FusedSchedulerNode.used_or_aliased_buffer_namesc                 C   s   | j S r,   )rÜ   r4   r)   r)   r*   r£   §  s    zFusedSchedulerNode.get_nodesc                 C   s   t | ƒj› d|  ¡ › d�S )Nz(nodes=rO   rP   r4   r)   r)   r*   r;   ª  s    zFusedSchedulerNode.__repr__c                 C   s   t dd„ | jD ƒƒS )Nc                 s   s   | ]}|  ¡ V  qd S r,   )r5   r²   r)   r)   r*   Ú	<genexpr>¯  s     z2FusedSchedulerNode.is_reduction.<locals>.<genexpr>©ÚanyrÜ   r4   r)   r)   r*   r5   ­  s    zFusedSchedulerNode.is_reductionc                 C   s   t dd„ | jD ƒƒS )Nc                 s   s   | ]}|  ¡ V  qd S r,   )r¥   r²   r)   r)   r*   r,  ³  s     z1FusedSchedulerNode.is_template.<locals>.<genexpr>r-  r4   r)   r)   r*   r¥   ±  s    zFusedSchedulerNode.is_templatec                 C   s   dS r3   r)   r4   r)   r)   r*   r@   µ  s    zFusedSchedulerNode.is_foreachc                 C   s
   | j d S r&  )r  r4   r)   r)   r*   r¤   ¸  s    zFusedSchedulerNode.get_devicec                 C   s   t dd„ | jD ƒƒS )Nc                 s   s   | ]}|  ¡ V  qd S r,   )r‚   r²   r)   r)   r*   r,  ½  s     z>FusedSchedulerNode.has_aliasing_or_mutation.<locals>.<genexpr>r-  r4   r)   r)   r*   r‚   »  s    z+FusedSchedulerNode.has_aliasing_or_mutationc                 C   s&   t  ¡ }| jD ]}| | ¡ ¡ q|S r,   )rœ   r�   rÜ   r+  r…   )r0   r…   rG   r)   r)   r*   r…   ¿  s    
zFusedSchedulerNode.op_countsrf   c                 C   s   t ‚d S r,   ©ÚNotImplementedErrorri   r)   r)   r*   rj   È  s    z'FusedSchedulerNode.update_mutated_namesc                 C   s   t ‚d S r,   r/  ©r0   r`   r)   r)   r*   rk   Ë  s    z#FusedSchedulerNode.add_mutation_deprl   rm   c                 C   s   t ‚d S r,   r/  )r0   rH   r)   r)   r*   rs   Î  s    zFusedSchedulerNode.set_usersc                 C   s   t ‚d S r,   r/  r4   r)   r)   r*   r~   Ñ  s    zFusedSchedulerNode.get_aliasesc                 C   s   t ‚d S r,   r/  r4   r)   r)   r*   r€   Ô  s    z FusedSchedulerNode.get_mutationsr§   c                 C   s   t ‚d S r,   r/  r©   r)   r)   r*   rª   ×  s    zFusedSchedulerNode.can_inplacec                 C   s   t ‚d S r,   r/  r4   r)   r)   r*   rÆ   Ú  s    zFusedSchedulerNode.allocatec                 C   s   t ‚d S r,   r/  r4   r)   r)   r*   rÇ   Ý  s    zFusedSchedulerNode.can_free)(r8   r9   r:   Ú__doc__Úclassmethodr<   rB   r   rµ   r2   r   r#   r7   r¡   r   r¢   rY   r   r}   rŠ   r|   r£   r;   r5   r¥   r@   r¤   r‚   r…   rj   rk   rs   r~   r€   r	   r÷   rª   rÆ   rÇ   r  r)   r)   r  r*   rC   \  sJ    
ÿ



rC   c                       sŽ   e Zd ZdZdd„ Zdd„ Zedd„ ƒZedd	„ ƒZdde	e
 dœ‡ fdd„Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Z‡  ZS )rA   z{Scheduler node which consists of a list of scheduler nodes that each operate on a
    distinct tensor in a list of tensors.c                 C   s    |  ¡ | jkr| j|  ¡  S d S r,   )r7   Úread_to_node)r0   Úproducerr)   r)   r*   Úget_consumer_subnode_forå  s    z3ForeachKernelSchedulerNode.get_consumer_subnode_forc                 C   s.   |j jD ] }|j| jkr| j|j   S qd S r,   )rV   rX   r`   rÁ   )r0   ÚconsumerÚrdr)   r)   r*   Úget_producer_subnode_forë  s    z3ForeachKernelSchedulerNode.get_producer_subnode_forc                    s¨   ˆ   ¡ rD|  ¡ rDtˆ jƒt|jƒkoBt‡ fdd„tˆ j|jƒD ƒƒS |  ¡ rp| ˆ ¡}|d k	rl|j ˆ |¡S dS ˆ   ¡ rœˆ  |¡}|d k	r˜ˆ j ||¡S dS t	dƒ‚d S )Nc                 3   s    | ]\}}ˆ j  ||¡V  qd S r,   )rF   Úcan_fuse©rx   ÚlÚr©r5  r)   r*   r,  õ  s   ÿz6ForeachKernelSchedulerNode.can_fuse.<locals>.<genexpr>FzXAt least one node passed to ForeachKernelSchedulerNode.can_fuse should be a foreach node)
r@   rÂ   rÜ   Úallr  r6  rF   r:  r9  rì   )rò   r5  r7  Úconsumer_subnodeÚproducer_subnoder)   r>  r*   r:  ò  s"     þ

ÿz#ForeachKernelSchedulerNode.can_fusec           
      C   s  |  ¡ s|  ¡ st‚d }d }|  ¡ rF|  ¡ rFdd„ t|j|jƒD ƒ}n²|  ¡ r | |¡}g }|}d }|jD ]2}||kr’t ||¡}|}| |¡ qj| |¡ qjnX|  ¡ rø| |¡}	g }|}d }|jD ]2}||	krìt ||¡}|}| |¡ qÄ| |¡ qÄ| |j	|||ƒS )Nc                 S   s   g | ]\}}t  ||¡‘qS r)   )rC   rB   r;  r)   r)   r*   r³     s   ÿz3ForeachKernelSchedulerNode.fuse.<locals>.<listcomp>)
r@   rì   r  rÜ   r9  rC   rB   rÒ   r6  rF   )
rò   r5  r7  Úprev_node_1Úprev_node_2Úfused_nodesrA  rG   Únew_noder@  r)   r)   r*   rB     s<    þ



zForeachKernelSchedulerNode.fuseNrD   )rF   Únodesc           
         sP  i ˆ _ i ˆ _|d ks|d krhtƒ  ||¡ |D ]6}|jjD ]}|ˆ j |j< q:| ¡ D ]}|ˆ j|< qTq.nÊ|ˆ _|ˆ _	ˆ  
tj |j|jg¡¡ ‡ fdd„t |j|j¡D ƒˆ jj ˆ _t|j|jgƒˆ _t|j|jgƒˆ _| ¡ ræ|n|}| ¡ rö|n|}	|jˆ _ˆ j |	j¡ |jˆ _|	 ¡ D ]}|	ˆ j|< �q |d  ¡ dfˆ _tƒ ˆ _d S )Nc                    s   h | ]}|j ˆ  ¡ kr|’qS r)   r   r‡   r4   r)   r*   r{   O  s   üz6ForeachKernelSchedulerNode.__init__.<locals>.<setcomp>r   )r4  rÁ   r  r2   rV   rX   r`   r¢   rF   rÜ   rI   r	   rö   r$  r!   r#  r-   rW   r%  rK   r"  rL   r@   rJ   r+  r¤   r  rÐ   )
r0   rF   rF  rB  rC  rG   rÅ   r`   Zforeach_nodeÚ
other_noder  r4   r*   r2   2  sF    
ÿÿ
 ÿþúz#ForeachKernelSchedulerNode.__init__c                 C   s   t ‚d S r,   r/  r4   r)   r)   r*   r  h  s    z#ForeachKernelSchedulerNode.mark_runc                 C   s   | j  ¡ | j  ¡ ƒ ƒ d S r,   )rG   Zget_store_functionZmake_loaderr4   r)   r)   r*   r¾   k  s    z"ForeachKernelSchedulerNode.codegenc                 C   s   t S r,   r/  r4   r)   r)   r*   rÇ   n  s    z#ForeachKernelSchedulerNode.can_freec                 C   s   dS rú   r)   r4   r)   r)   r*   r@   q  s    z%ForeachKernelSchedulerNode.is_foreachc                 C   s
   t | jƒS )zŸReturns a list of nodes which comprise the foreach kernel, operating on corresponding elements of our input lists.
        These nodes may be vertically fused.)rp   rÜ   r4   r)   r)   r*   Úget_subkernel_nodest  s    z.ForeachKernelSchedulerNode.get_subkernel_nodesc                 C   s   t tjdd„ | jD ƒŽ ƒS )ziReturns all nodes contained in this kernel, unpacking fused nodes into their constituent scheduler nodes.c                 S   s   g | ]}|  ¡ ‘qS r)   )r£   r²   r)   r)   r*   r³   {  s     z8ForeachKernelSchedulerNode.get_nodes.<locals>.<listcomp>)rp   rˆ   r‰   rÜ   r4   r)   r)   r*   r£   y  s    z$ForeachKernelSchedulerNode.get_nodesc                 C   s   | j d  ¡ S r&  )rÜ   r¡   r4   r)   r)   r*   r¡   }  s    z)ForeachKernelSchedulerNode.get_first_name)NN)r8   r9   r:   r2  r6  r9  r3  r:  rB   r   rµ   r2   r  r¾   rÇ   r@   rH  r£   r¡   r  r)   r)   r  r*   rA   á  s(   

*  ûý6rA   r)   c                    s`   t j‡ ‡fdd„ƒ}ttttˆd ƒƒƒƒ}t|ƒdkrJ‡fdd„|D ƒ‰tjr\|j|d� |S )z�
    A heuristic to decide loop iteration orders.  This has not been well
    tuned and may be something we should autotune.
    c                    s¨   ˆˆ  dksˆˆ dkr2t ˆˆ  dkˆˆ dkƒS ‡ fdd„ˆD ƒ}‡fdd„ˆD ƒ}tdd„ t||ƒD ƒƒ}tdd„ t||ƒD ƒƒ}||kr’dS ||krždS t ˆˆ ƒS )	Nr   c                    s   g | ]}|ˆ  ‘qS r)   r)   ©rx   Úsl)Úar)   r*   r³   �  s     z6pick_loop_order.<locals>.index_cmp.<locals>.<listcomp>c                    s   g | ]}|ˆ  ‘qS r)   r)   rI  )Úbr)   r*   r³   Ž  s     c                 s   s"   | ]\}}|d kp||k V  qdS ©r   Nr)   ©rx   Zsl_aZsl_br)   r)   r*   r,  ’  s    z5pick_loop_order.<locals>.index_cmp.<locals>.<genexpr>c                 s   s"   | ]\}}|d kp||k V  qdS rM  r)   rN  r)   r)   r*   r,  •  s    rÌ   )r   r  r  )rK  rL  Zstride_len_aZstride_len_bZa_firstZb_first©r  Ústride_lengths)rK  rL  r*   Ú	index_cmp‡  s    ÿÿz"pick_loop_order.<locals>.index_cmpr   c                    s   g | ]}ˆ | ‘qS r)   r)   )rx   Úpi)rP  r)   r*   r³   £  s     z#pick_loop_order.<locals>.<listcomp>r   )	Ú	functoolsÚ
cmp_to_keyrp   r*  ÚrangerÂ   r   Zpick_loop_ordersÚsort)rP  r  Zpriority_idxrQ  Úorderr)   rO  r*   Úpick_loop_order�  s    rX  c                   @   sF   e Zd ZU eed< dZeed< dZeed< dd„ Zd d dœdd	„Z	d
S )rl   rG   Frª   Úis_weakc                 C   s
   | j  ¡ S r,   rŸ   r4   r)   r)   r*   r7   ²  s    zNodeUser.get_name)ÚotherrS   c                 C   s.   | j |j kst‚t| j | jo |j| jo*|jƒS r,   )rG   rì   rl   rª   rY  )r0   rZ  r)   r)   r*   ro   µ  s    

ýzNodeUser.mergeN)
r8   r9   r:   r<   Ú__annotations__rª   r�   rY  r7   ro   r)   r)   r)   r*   rl   ©  s
   
rl   c                       sB  e Zd Ze‡ fdd„ƒZdd„ Zdd„ Zdd„ Zd	d
„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zeedœdd„Zeedœd d!„Zd"d#„ Zeedœd$d%„Zd&d'„ Zd(d)„ Zd*d+„ Zd,d-„ Zd.d/„ Zd0d1„ Zd2d3„ Zd4d5„ Zed6œd7d8„Z e!j"d9œd:d;„Z#e!j"d9œd<d=„Z$d>d?„ Z%ed@dA„ ƒZ&‡  Z'S )BrD   c                    sl  t ƒ  ¡  i ˆ _i ˆ _g ˆ _tjj ¡ tjj	 ¡ ™ˆ _
‡ fdd„|D ƒˆ _ˆ j
 tjj	 ¡ ¡ ˆ jD ]}| ¡  qddd„ ˆ jD ƒˆ _d ˆ _i ˆ _i ˆ _ˆ  ¡  ˆ  ¡  ˆ  ¡  ˆ  ¡  t jtˆ jƒ7  _tj ˆ j¡ tˆ jƒˆ _dd„ ˆ jD ƒˆ _ˆ  ¡  ˆ  ¡  ˆ  ¡  ˆ  ¡  tj ˆ j¡ tj ˆ j¡ ˆ   ¡  d ˆ _!t"ƒ ˆ _#t"ƒ ˆ _$i ˆ _%t& 'dtˆ jƒ¡ d S )Nc                    s   g | ]}ˆ   |¡‘qS r)   )Úcreate_scheduler_node©rx   Únr4   r)   r*   r³   Ë  s     z&Scheduler.__init__.<locals>.<listcomp>c                 S   s   i | ]}|  ¡ |“qS r)   r    r]  r)   r)   r*   Ú
<dictcomp>Ò  s      z&Scheduler.__init__.<locals>.<dictcomp>c                 S   s   i | ]}|  ¡ |“qS r)   r    r]  r)   r)   r*   r_  å  s      z)Number of scheduler nodes after fusion %d)(r  r2   ÚbackendsZ
fuse_cacherF  r   rŒ   rà   ÚkeysÚ	constantsr“   r+  r„   rÁ   r›   rv   Úmutation_renamesÚcompute_dependenciesÚtopological_sort_scheduleÚdead_node_eliminationÚcompute_predecessorsr   Zir_nodes_pre_fusionrÂ   ÚdebugZir_pre_fusionZnum_orig_nodesÚcreate_foreach_nodesÚ
fuse_nodesÚcompute_last_usageZir_post_fusionZgraph_diagramÚdebug_draw_graphÚcurrent_devicer!   Úbuffer_names_to_freeÚbuffer_names_no_longer_neededÚorigin_to_indexr[   rd   )r0   rF  rG   r  r4   r*   r2   ¿  sF    


þ

zScheduler.__init__c                 C   s0   t j dd¡dkr,ddlm} || jdd� dS )z,Generate an image of the graph for debuggingZINDUCTOR_WRITE_SCHEDULER_GRAPHNÚ1r   )Údraw_buffersT)Zprint_graph)ÚosÚenvironrw   rh  rr  rF  )r0   rr  r)   r)   r*   rl  ù  s    zScheduler.debug_draw_graphc                 C   s0   t  tj¡r,t  d|¡ | jD ]}| ¡  qd S )Nz%s:)r[   ÚisEnabledForÚloggingÚINFOrd   rF  re   )r0   ÚlabelrG   r)   r)   r*   Údebug_print_nodes   s    
zScheduler.debug_print_nodesc                 C   st   |j d k	stdƒ‚| ¡ r$t| |ƒS t|tjtjfƒrR|  | 	¡ ¡j
}t| ||ƒS t|tjƒrht| |ƒS t|ƒ‚d S )Nz2All nodes passed to scheduling must have an origin)rÐ   rì   Zis_no_oprß   r    r
   r   r
  Úget_backendr¤   r  rµ   ZExternKernelr·   r0  )r0   rG   r  r)   r)   r*   r\    s    ÿþ

zScheduler.create_scheduler_nodec                    s    t ƒ ‰g }ˆj ¡ ‰ tjj ¡ D ]`}ˆ |¡ ‡ fdd„|D ƒ}|sFq ‡fdd„|D ƒ}tˆ|ƒ}| 	|¡ |D ]}|ˆj|< qpq ‡fdd„ˆj
D ƒ| ˆ_
d S )Nc                    s   g | ]}|ˆ kr|‘qS r)   r)   ©rx   r`   )Úkept_node_namesr)   r*   r³     s      z2Scheduler.create_foreach_nodes.<locals>.<listcomp>c                    s   g | ]}ˆ j | ‘qS r)   )rÁ   r{  r4   r)   r*   r³   !  s     c                    s   g | ]}|  ¡ ˆ kr|‘qS r)   r    )rx   rG   )Úremoved_node_namesr)   r*   r³   )  s     )r!   r›   ra  r   rŒ   Úlistsrq   r+  rA   rÒ   rF  )r0   Zfe_nodesÚnamesrÜ   Zfe_noder`   r)   )r|  r}  r0   r*   ri    s$    




ÿþzScheduler.create_foreach_nodesc                    sÂ  t  t¡‰ˆjD ]”}| ¡ }| ¡ D ]~}|ˆkr€|ˆkr€ˆ| }ˆ| }|| }ˆ ¡ D ]$}ˆ| |kstˆ| |krX|ˆ|< qXq$|ˆkr–ˆ| ˆ|< q$ˆ| ˆ|< q$q‡‡fdd„‰‡ ‡fdd„‰ d‡‡fdd„	}ˆjD �]}	|	 ¡ D ]r}
ˆ|
ƒ}
||
|	ƒ |	 t	|
ƒ¡ ˆ|
 D ]D}ˆ| ¡ ƒ}ˆ |	 ¡ ƒ}||k�r|	 t
|ƒ¡ |||	dd	� �qqæ|	jjD ]&}t|t
ƒ}||j|	|	 |¡|ƒ �qb|	 ˆj¡ |	 ¡ D ]>}
|	 ¡ ˆjˆ|
ƒ< |	 ¡ ˆj|
< ˆj |
|
¡ˆj|	 ¡ < �qžqØtj ¡ D ]}||tt	|ƒƒƒ �qêˆjD ]4}|tjjk�r
||tt	|ƒƒƒ tjj |¡ �q
d
d„ ttjj ¡ ƒD ƒ‰‡fdd„tjjD ƒtj_ˆjD ]}	|	 ˆ|	 ¡  ¡ �qzˆjD ]"}	|	jD ]}|jj  !|	¡ �q¤�qšdS )zi
        Create dependency edges between nodes, handling aliasing and
        mutation properly.
        c                    s   | ˆj krˆ ˆj |  ƒS | S r,   )rc  ©r^  )rh   r0   r)   r*   rh   G  s    
z.Scheduler.compute_dependencies.<locals>.renamec                    s~   | h}ˆj |  }t|jjƒd }|jjD ]P}|jˆj kr(t|tjƒr(t|tjƒr(|j	|j	kr(|j
|j
kr(| ˆ |jƒ¡ q(|S r&  )rÁ   rp   rV   rW   rX   r`   r    r	   r÷   r  r  r+  )Ú	node_nameZreachable_namesrG   r   r¨   )Údep_closurer0   r)   r*   r‚  L  s     

ÿ
þ
ý
ü
ûz3Scheduler.compute_dependencies.<locals>.dep_closureFc                    s   ˆ ˆ| ƒ   t|||ƒ¡ d S r,   )rÒ   rl   )Zused_by_nameZ	user_noderª   rY  )Úname_to_usersrh   r)   r*   Úadd_user[  s    
ÿz0Scheduler.compute_dependencies.<locals>.add_userT)rY  c                 S   s   i | ]\}}||“qS r)   r)   )rx   r  r`   r)   r)   r*   r_  Š  s     z2Scheduler.compute_dependencies.<locals>.<dictcomp>c                    s   g | ]}ˆ | ‘qS r)   r)   r{  )Ú	inp_namesr)   r*   r³   �  s    z2Scheduler.compute_dependencies.<locals>.<listcomp>N)FF)"rœ   Údefaultdictrp   rF  r7   r~   ra  r€   rk   r   r   rV   rX   r    r`   rª   rj   rc  rv   rw   r   rŒ   Úget_output_namesr+   rà   Zmutated_inputsr‹   r)  Zmutated_input_idxsrs   rH   rG   r.   rÒ   )r0   r>   Z
node1_nameZ
node2_nameZlist1Zlist2Úcombinedr   r„  rG   Zalt_namerG  Z
other_nameZknown_dep_node_namesrÅ   rY  r�  r`   rÛ   r)   )r‚  r…  rƒ  rh   r0   r*   rd  -  sp    




 ÿ
ÿ
ÿ



zScheduler.compute_dependenciesc                    s¬   d}|r”g }| j D ]f}tdœdd„‰ | ¡  oDt‡ fdd„|jD ƒƒ}|sV| |¡ qt d| ¡ ¡ t	j
j | ¡ ¡ qt| j ƒt|ƒk}|| _ q| j D ]}| ¡  qšdS )	z0
        Remove any nodes without users
        T©rÛ   c                 S   s   | j p|  ¡ tjjkS r,   )rY  r7   r   rŒ   r•   r‰  r)   r)   r*   Úcan_eliminate_user£  s    z;Scheduler.dead_node_elimination.<locals>.can_eliminate_userc                 3   s   | ]}ˆ |ƒV  qd S r,   r)   )rx   Úu©rŠ  r)   r*   r,  ¦  s    z2Scheduler.dead_node_elimination.<locals>.<genexpr>zremoved dead node: %sN)rF  rl   r«   r?  rH   rÒ   r[   rh  r7   r   rŒ   r•   r‹   rÂ   r™   )r0   ZagainZupdated_nodesrG   Zcan_eliminater)   rŒ  r*   rf  š  s     
ÿ
zScheduler.dead_node_eliminationc                    sb   t ƒ ‰tƒ ‰ g ‰‡ ‡‡‡fdd„‰| jD ]}| ¡ D ]}|ˆ |< q4q(| jD ]}ˆ|ƒ qJˆ| _dS )zD
        Ensure self.nodes is in topologically sorted order
        c                    sF   | ˆkrBˆ  | ¡ t| jdd„ d�D ]}ˆˆ |j ƒ q$ˆ | ¡ d S )Nc                 S   s   | j S r,   r†   )Údr)   r)   r*   r°   Ã  r±   zDScheduler.topological_sort_schedule.<locals>.visit.<locals>.<lambda>r   )r‹   r"   r-   r`   rÒ   )r^  r1   ©rÁ   r(   ÚseenÚvisitr)   r*   r�  À  s
    
z2Scheduler.topological_sort_schedule.<locals>.visitN)r!   r  rF  r¢   )r0   rG   r`   r)   rŽ  r*   re  ¸  s    


z#Scheduler.topological_sort_schedulec                 C   sr   i }| j D ]B}tƒ }|jD ]}| |j¡ |||j O }q||| ¡ < ||_q
t| j ƒD ]\}}||_||_	qXdS )z;
        Populate each node.recursive_predecessors
        N)
rF  r!   r-   r‹   r`   r7   rJ   r)  rK   rL   )r0   Zname_to_predecessorsrG   rJ   r1   rW  r)   r)   r*   rg  Î  s    

zScheduler.compute_predecessorsc                 C   s6   t dƒD ](}t| jƒ}|  ¡  t| jƒ|kr q2qdS )zO
        Mutates self.nodes to combine nodes into FusedSchedulerNodes.
        é
   N)rU  rÂ   rF  Úfuse_nodes_once)r0   r  Zold_lenr)   r)   r*   rj  à  s
    
zScheduler.fuse_nodesc                    s¼   t | jƒ}|  ¡ D ]‚\}}| j| ¡  }| j| ¡  }|  ||¡r|  ||¡st||ƒ‰ | |¡ | |¡ | 	ˆ ¡ | j 
‡ fdd„ˆ  ¡ D ƒ¡ qt|dd„ d�| _|  ¡  |  ¡  dS )a  
        Mutates self.nodes to combine nodes into FusedSchedulerNodes.

        This relies on two key functions to control the logic:
            - self.can_fuses(): checks if a fusion is legal
            - self.score_fusion(): assigns priority to a given fusion
        c                    s   i | ]}|  ¡ ˆ “qS r)   r    r]  ©Znode3r)   r*   r_  þ  s      z-Scheduler.fuse_nodes_once.<locals>.<dictcomp>c                 S   s   | j S r,   r!  r®   r)   r)   r*   r°      r±   z+Scheduler.fuse_nodes_once.<locals>.<lambda>r   N)r!   rF  Úget_possible_fusionsr›   r¡   r:  Úwill_fusion_create_cyclerB   Úremover‹   r+  r£   r"   re  rž   )r0   rD  r>   r?   r)   r“  r*   r’  ê  s$    
 ÿ



ÿzScheduler.fuse_nodes_oncec                 C   s   | j D ]}| | j¡ qd S r,   )rF  rž   r›   )r0   rG   r)   r)   r*   rž     s    
zScheduler.prune_redundant_depsc                    sÂ   g ‰ t ƒ ‰‡ ‡‡fdd„}t t¡}ˆjD ] }| ¡ D ]}||  |¡ q6q*| ¡ D ]}||ƒ qTtj	r²t t¡}ˆjD ]"}t
|ddƒ}|rx||  |¡ qx| ¡ D ]}||ƒ q¤tˆ ˆjdd�S )z^
        Helper to find all legal fusion opportunities, sorted by self.score_fusion()
        c                    sŠ   t | ƒD ]|\}}| |d d … D ]b}||f}|ˆkr6q ˆ |¡ ˆ ||¡rXˆ  |¡ q | ¡ sh| ¡ r ˆ ||¡r ˆ  ||f¡ q qd S )Nr   )r)  r‹   r:  rÒ   r¥   r@   )rF  Znode1_indexr>   r?   r   ©Zpossible_fusionsr�  r0   r)   r*   Úcheck_all_pairs  s    
 ÿz7Scheduler.get_possible_fusions.<locals>.check_all_pairsr  NT)r   Úreverse)r!   rœ   r†  rp   rF  rŠ   rÒ   rq   r   Úaggressive_fusionrÀ   r"   Úscore_fusion_key)r0   r˜  Zbuffer_names_groupingrG   rÝ   Znode_groupingZgroup_groupingr  r)   r—  r*   r”    s$    





zScheduler.get_possible_fusionsc                    sR   ‡ ‡‡‡‡fdd„‰ t ƒ ‰| ¡ | ¡ B ‰|j|jB ˆ ‰t‡ ‡fdd„ˆD ƒƒS )zHFinds whether there's a path from src to dst caused indirectly by fusionc                    sn   t | tƒrj| ˆkrjˆ | ¡ tˆ| j@ ƒ}|r2|S |  ¡ }| ˆ¡}|rL|S t‡ ‡fdd„| jˆ D ƒƒS dS )Nc                 3   s   | ]}ˆ ˆj | ƒV  qd S r,   ©r›   r]  ©Úcheckr0   r)   r*   r,  B  s   ÿzDScheduler.will_fusion_create_cycle.<locals>.check.<locals>.<genexpr>F)r    rC   r‹   r�   rJ   r¢   Úissubsetr.  )rG   Zcond0r  Zshortcut©rž  Zcombined_namesZcombined_predecessorsr0   Úvisitedr)   r*   rž  4  s    

þz1Scheduler.will_fusion_create_cycle.<locals>.checkc                 3   s   | ]}ˆ ˆj | ƒV  qd S r,   rœ  r]  r�  r)   r*   r,  M  s     z5Scheduler.will_fusion_create_cycle.<locals>.<genexpr>)r!   r¢   rJ   r.  ©r0   r>   r?   r)   r   r*   r•  1  s    
þz"Scheduler.will_fusion_create_cycler=   c                 C   s*   t t|j|j ƒt|j|j ƒƒ}|dkS )aA  
        This function prevents fusion for nodes that can increase memory
        footprint. This problem is more common in horizontal fusion, where nodes
        that are far apart in the original order get fused, lengthening the live
        intervals of tensors. This is very evident in models with activation
        checkpointing, where the recomputed nodes from different checkpointed
        regions get fused and significantly increase the memory footprint.

        The current attempt is a quick, possibly hacky, heuristic to prevent the
        fusion of nodes that are far away in the original order.

        A better but difficult to implement heursitic would be to use live
        intervals of the buffers, find region of peak pressure in the original
        program and prevent fusion that crosses that peak region. We might need
        special care or good approximation in this implementation, as fusion of
        node changes live intervals, and re-computing live intervals and peak
        memory after each fusion can introduce large compilation overhead.
        é@   )r"  ÚabsrK   rL   )r0   r>   r?   Úproximity_scorer)   r)   r*   Úcan_fusion_increase_peak_memoryO  s
    þz)Scheduler.can_fusion_increase_peak_memoryc                 C   sv  ||krdS t |ttfƒr&| ¡ s&dS t |ttfƒr@| ¡ s@dS | ¡ sP| ¡ r\t ||¡S | ¡ |j@ rndS | ¡ rzdS | ¡ rœ| 	¡ s˜| 
¡ s˜tjsœdS | ¡ }|| ¡ kr´dS |  ||¡dk}|râtjrÞ| 
¡ sÞ| 
¡ râdS | ¡ �s| ¡ �st| ¡ ƒt| ¡ ƒ tjk�rdS | ¡ |j@ �rN|  ||¡�s<dS |  |¡ ||¡S |  ||¡�r`dS |  |¡ ||¡S dS )zj
        Determine if it is possible to combine node1 and node2 into a
        single fused node.
        Fr   N)r    r·   rß   r¥   r@   rA   r:  r¢   rJ   r‚   r5   r   Zepilogue_fusionr¤   Úscore_fusion_memoryrš  rÂ   r£   Zmax_fusion_sizeÚcan_fuse_verticalrz  r¦  Úcan_fuse_horizontal)r0   r>   r?   rí   Zno_shared_datar)   r)   r*   r:  j  sh    ÿþÿþÿþýÿÿÿÿþýzScheduler.can_fusec           	      C   sä   |  ¡ }tƒ }|jD ]Š}|jjD ]|}|j|jkr t|ƒt|ƒkr t|jdƒs t|jdƒs |j|jkr t	|j
ƒt	|j
ƒkr |j
dt	|j
ƒ… |j
kr | |¡ q qdd„ |j| D ƒ}||@ rÀdS |D ]}|| j| j@ rÄ dS qÄdS )a  
        Check if it is legal to fuse a consumer (node2) into a producer (node1).

        We can fuse them if all the reads of node2 either match
        corresponding writes in node1, or are written by nodes that can
        be scheduled before the fusion of node1 and node2.
        ÚtmpNc                 S   s   h | ]
}|j ’qS r)   r†   r‡   r)   r)   r*   r{   Ã  s     z.Scheduler.can_fuse_vertical.<locals>.<setcomp>FT)r¢   r!   r-   rV   rW   r`   rQ   r   r  rÂ   r  r‹   r›   rJ   )	r0   r>   r?   Znode1_namesZcomputed_depsr8  ÚcdZremaining_depsr`   r)   r)   r*   r¨  §  s4    

ÿþ
ý
ü
ûúù	zScheduler.can_fuse_verticalc                 C   sb   |   ||¡}tt|j|j ƒt|j|j ƒƒ }| ¡ tjkoD|dk| ¡ | ¡ koZ|dk||fS )a\  
        Assign a score (higher comes first) to the fusion of node1
        and node2.  When different fusions conflict with each other,
        this is the way we decide what order to run them in.

        Our current score is based on:
        - Estimate of the saved memory operations
        - Fusions closer together in original order
        r   )	r§  r"  r¤  rK   rL   r¥   r   Zepilogue_fusion_firstr5   )r0   r>   r?   Zmemory_scorer¥  r)   r)   r*   Úscore_fusionÏ  s    
þüzScheduler.score_fusionc                 C   s2   |j j|j jB |j j|j jB @ }tdd„ |D ƒƒS )zf
        The first term in our fusion score that estimates number of saved memory operations.
        c                 s   s   | ]}|  ¡ V  qd S r,   )rþ   r‡   r)   r)   r*   r,  ì  s     z0Scheduler.score_fusion_memory.<locals>.<genexpr>)rV   rX   rW   r  )r0   r>   r?   Zcommon_memory_depsr)   r)   r*   r§  å  s    ÿzScheduler.score_fusion_memoryc                 C   s   |\}}|   ||¡S )z-
        Shim for list.sort(key=...)
        )r¬  )r0   rF  r>   r?   r)   r)   r*   r›  î  s    zScheduler.score_fusion_keyc                 C   sN   t ƒ }tj ¡ D ]}| |¡ qt| jƒD ]}| || j¡ | 	|j
¡ q*dS )zg
        Populate node.last_usage recursively (also for the nodes within a FusedSchedulerNode)
        N)r!   r   rŒ   r‡  r‹   r*  rF  r}   rv   r+  rM   )r0   ru   r�  rG   r)   r)   r*   rk  õ  s    zScheduler.compute_last_usagec                 C   s”   t | jtjj tjjj ƒD ]h}|| jkrN| j| }| ¡ r„tjj 	|j
¡ q|tjjkrtjj| j}| ¡ stt‚tjj 	|j¡ q| j ¡  dS )z*Free any buffers that are no longer neededN)r"   rn  r   rŒ   r•   r¶   ZfreedrÁ   rÇ   Zcodegen_freerG   rà   r‘   Zis_input_bufferrì   Úclear)r0   r`   rG   Zstorager)   r)   r*   Úfree_buffers  s     ÿþÿ

zScheduler.free_buffersc                    s¨   t jjˆj@ ‰ ‡fdd„}tt|ˆ ƒƒ‰ ˆ D ]v}|t jjjkr˜t jjj| }t|t	ƒrb| 
d¡rbq,t‡ fdd„|jD ƒƒ}|rˆˆ |¡ t jj |¡ q,ˆ |¡ q,dS )zr
        Any buffers that are both created and have a last use in the
        same kernel can be removed.
        c                    s.   | t jjko,| t jjjko,| ˆ jko,| ˆ jkS r,   )r   r»   Zmust_keep_buffersr´   Zinput_buffersrc  rv   r€  r4   r)   r*   Úremove_filter  s    ÿþüz<Scheduler.remove_kernel_local_buffers.<locals>.remove_filterÚREMOVEDc                 3   s   | ]}|ˆ kV  qd S r,   r)   r]  )Únames_to_remover)   r*   r,  -  s     z8Scheduler.remove_kernel_local_buffers.<locals>.<genexpr>N)r   r»   Zstore_buffer_namesro  rp   Úfilterr´   rº   r    r#   Ú
startswithr?  Zother_namesÚremove_inplace_bufferrŒ   Zinplaced_to_remover‹   Úremove_buffer)r0   r¯  r`   rÝ   r–  r)   )r±  r0   r*   Úremove_kernel_local_buffers  s    ÿ
z%Scheduler.remove_kernel_local_buffersc                 C   s,   t  d|¡ dtjjj|< tjj |¡ d S )Nzremove_buffer(%r)r°  )	r[   rh  r   r»   r´   Zoutput_buffersrŒ   r•   r‹   r1  r)   r)   r*   rµ  4  s    zScheduler.remove_bufferc                 C   sD   t  d|¡ tjjj| j}| dd¡tjjj|< tjj	 
|¡ d S )Nzremoving_inplace_buffer(%r)Z
in_out_ptrr°  )r[   rh  r   r»   r´   rº   Ú
inner_namerÖ   rŒ   r•   r‹   )r0   r`   r·  r)   r)   r*   r´  <  s     ÿzScheduler.remove_inplace_bufferc                 C   s$   | j  ¡ D ]}| ¡  q
|  ¡  d S r,   )r`  rq   Úflushr®  )r0   Úbackendr)   r)   r*   r¸  D  s    
zScheduler.flush)Úscheduler_nodec                 C   s6   t |tƒst‚| ¡  |j}| tjj¡ |  	¡  d S r,   )
r    r·   rì   rÆ   rG   r¾   r   rŒ   r¶   r®  )r0   rº  rG   r)   r)   r*   Úcodegen_extern_callI  s
    zScheduler.codegen_extern_call)rí   c                 C   sº   |j dks"|jd k	s"t|› d�ƒ‚tjj |j ¡ tj |j¡ t|j ƒ}|d krbt	d|j › �ƒ‚|j dkr²t
ƒ s²tj |¡}|jdk rªt	d|j› d|j› d|j› �ƒ‚nt	dƒ‚|| ƒS )	Nrå   z( should have been normalized in loweringzUnsupported device type: é   zFound zº which is too old to be supported by the triton GPU compiler, which is used as the backend. Triton only supports devices of CUDA Capability >= 7.0, but your device is of CUDA capability Ú.z�Cannot find a working triton installation. More information on installing Triton can be found at https://github.com/openai/triton)rQ   r  rì   r   rŒ   Zdevice_typesr‹   Zadd_device_idxr   ÚRuntimeErrorr   r¼   rå   Zget_device_propertiesÚmajorr`   Úminor)r0   rí   Zdevice_schedulingZdevice_propsr)   r)   r*   Úcreate_backendP  s*    ÿÿþ

ÿÿzScheduler.create_backendc                 C   s$   || j kr|  |¡| j |< | j | S r,   )r`  rÁ  )r0   rí   r)   r)   r*   rz  h  s    
zScheduler.get_backendc                    sD   ‡fdd„‰ ‡ fdd„|  ¡ D ƒ}|r@t|ƒ\}}tjj |¡ d S )Nc                    s2   | ˆ j kr(ˆ j  dd„ t| jjƒD ƒ¡ ˆ j |  S )Nc                 S   s   i | ]\}}||“qS r)   r)   )rx   r(  r^  r)   r)   r*   r_  p  s      z>Scheduler.enter_context.<locals>.get_order.<locals>.<dictcomp>)rp  r+  r)  rŒ   rF  r€  r4   r)   r*   Ú	get_ordern  s    
z*Scheduler.enter_context.<locals>.get_orderc                    s&   g | ]}|j jD ]}ˆ |ƒ|f‘qqS r)   )rG   rÐ   )rx   r^  Úe)rÂ  r)   r*   r³   s  s     
  z+Scheduler.enter_context.<locals>.<listcomp>)r£   r"  r   rŒ   r¶   Úenter_context)r0   rG   rÐ   r  Úlastr)   )rÂ  r0   r*   rÄ  m  s
    zScheduler.enter_contextc                 C   s°  | j D �]š}|  |¡ | j |j¡ t|tƒsÒ| ¡ }|| jksP| 	¡ sP| 
¡ rX|  ¡  || jkrÒ|jdkr®| jrŠ| jjdkrŠtjj ¡  |jd k	sœtdƒ‚tjj |j¡ n| jrÌ| jjdkrÌtjj ¡  || _| j |j¡ | 
¡ �r
| ¡ ^}}|  |¡ ||¡ np| 	¡ �r |  |¡ nZ| ¡ �r<|  |¡ |¡ n>t|ttfƒ�rb|  |¡ | ¡ ¡ nt|tƒ�srt‚| ¡  tj j!�r’|  |¡ "¡  | j# | $¡ ¡ q|  ¡  d S )Nrå   zdevice should have an index)%rF  rÄ  ro  r+  rM   r    rß   r¤   rm  r¦   r¥   r¸  rQ   r   rŒ   r¶   Zcodegen_device_guard_exitr  rì   Zcodegen_device_guard_enterrn  r£   rz  Úcodegen_templater»  r@   Zcodegen_foreachrC   rµ   Úcodegen_nodesrÆ   r   r¿   Zdebug_sync_kernelÚcodegen_syncr“   r¢   )r0   rG   rí   Úepiloguer)   r)   r*   r¾   x  sJ    

ÿþý





zScheduler.codegen)(r8   r9   r:   r   r2   rl  ry  r\  ri  rd  rf  re  rg  rj  r’  rž   r”  r•  r<   r¦  r:  r¨  r¬  r§  r›  rk  r®  r¶  rµ  r´  r¸  r·   r»  r¼   rí   rÁ  rz  rÄ  r¾   r  r)   r)   r  r*   rD   ¾  sF   9m
) ÿ=(	 rD   c                   @   sj   e Zd Zeedœdd„Zeedœdd„Zdd„ Zeee dœd	d
„Zee dœdd„Z	dd„ Z
dd„ ZdS )ÚBaseSchedulingr=   c                 C   s
   t ƒ ‚dS )zO
        Check whether node1 and node2 can be vertically fused or not.
        Nr/  r¢  r)   r)   r*   r¨  ¨  s    z BaseScheduling.can_fuse_verticalc                 C   s
   t ƒ ‚dS )zQ
        Check whether node1 and node2 can be horizontally fused or not.
        Nr/  r¢  r)   r)   r*   r©  ®  s    z"BaseScheduling.can_fuse_horizontalc                 C   s
   t ƒ ‚dS )z[
        Process the iteration sizes in case a transformation needs to be applied.
        Nr/  )r0   r  r)   r)   r*   r  ´  s    zBaseScheduling.group_fn)Útemplate_nodeÚepilogue_nodesc                 C   s
   t ƒ ‚dS )zã
        Given a template node, generate a kernel.

        This function is only available for triton now. If the third-party backend behaves as a sub-class
        of TritonScheduling, it can override it or reuse it.
        Nr/  )r0   rË  rÌ  r)   r)   r*   rÆ  º  s    	zBaseScheduling.codegen_template)rF  c                 C   s
   t ƒ ‚dS )zD
        Generate a kernel given a list of pre-fused nodes.
        Nr/  )r0   rF  r)   r)   r*   rÇ  Å  s    zBaseScheduling.codegen_nodesc                 C   s
   t ƒ ‚dS )zt
        Generate synchronization code for the kernel. This method depends on the hardware characteristics.
        Nr/  r4   r)   r)   r*   rÈ  Ë  s    zBaseScheduling.codegen_syncc                 C   s
   t ƒ ‚dS )z]
        Flush the generated kernel and python wrapper code to the source code file.
        Nr/  r4   r)   r)   r*   r¸  Ñ  s    zBaseScheduling.flushN)r8   r9   r:   r<   r¨  r©  r  r   rÆ  rÇ  rÈ  r¸  r)   r)   r)   r*   rÊ  §  s    ÿrÊ  )r)   )@rœ   ÚdataclassesrS  rˆ   rv  rs  r$   r&   Útypingr   r   r   r   r  r¼   Ztorch._dynamo.utilsr   rc   r   r	   r
   r   Zcodegen.commonr   r   r   r   rá   r   Úutilsr   r   r   r   r   r   r   r   Zvirtualizedr   Ú	getLoggerr8   r[   r%   r+   rB   ZopsZatenZconvolutionÚmmZbmmZaddmmrî   r<   r·   rß   rµ   rC   rA   rX  Ú	dataclassrl   rD   rÊ  r)   r)   r)   r*   Ú<module>   s`   (


	ü    _  !
(     n