Ë
    f^(h“º  ã            
       óð  — d dl Z d dlmZ d dlmZ d dl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 d dlmZmZ d dlmZ d dlmZ  G d	„ d
«      Z G d„ d«      Z G d„ de«      Z	 d„ Zdededee   ddfd„Zdee   ddfd„Zdee   ddfd„Zdee   ddfd„Z dee   de!ee"f   fd„Z#dee   de!e"ef   fd„Z$dee   dee   de%e!eee   f   e!ee"f   ee   f   fd„Z&dee   dee   fd„Z'd„ Z( G d„ d«      Z)y) é    N)Údeque)Ú
NamedTuple)ÚDeviceÚget_extra_size_ofÚ get_latency_of_partitioned_graphÚ get_partition_to_latency_mappingÚNodeLatencyÚ	PartitionÚPartitionerConfigÚPartitionMode)ÚGraphModule)Úmap_argÚNode)Úget_size_of_all_nodes)Úsplit_modulec                   óN   — e Zd ZdZdedee   dee   dee   deddfd	„Zdefd
„Z	y)ÚDAGNodez€DAGNode class maintains useful information for a partition (submodule),
    and its input submodules and output submodules.
    Úsubmodule_nodeÚinput_nodesÚoutput_nodesÚlogical_device_idsÚ
size_bytesÚreturnNc                 óJ   — || _         || _        || _        || _        || _        y ©N)r   r   r   r   r   )Úselfr   r   r   r   r   s         úk/var/www/skyplay_api_hub/venv/lib/python3.12/site-packages/torch/fx/experimental/accelerator_partitioner.pyÚ__init__zDAGNode.__init__   s+   € ð %3ˆÔØ'2ˆÔØ(4ˆÔØ-?ˆÔØ$ˆ�ó    c                 ó,   — t        | j                  «      S r   )Ústrr   ©r   s    r   Ú__str__zDAGNode.__str__*   s   € Ü�4×&Ñ&Ó'Ð'r   )
Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   ÚlistÚintr   r!   r#   © r   r   r   r      s^   „ ñð%àð%ð ˜$‘Zð%ð ˜4‘jð	%ð
 ! ™Ið%ð ð%ð 
ó%ð(˜ô (r   r   c                   óJ   — e Zd ZdZdd„Zdedee   dee   dee   d	eddfd
„Zy)ÚDAGz$DAG class contains all the DAG nodesr   Nc                 ó   — g | _         y r   )Únodesr"   s    r   r   zDAG.__init__1   s	   € Ø$&ˆ�
r   r   r   r   Úlogical_devicesr   c                 óX   — t        |||||«      }| j                  j                  |«       y r   )r   r.   Úappend)r   r   r   r   r/   r   Únodes          r   Úcreate_nodezDAG.create_node4   s-   € ô Ø˜K¨°È
ó
ˆð 	�
‰
×Ñ˜$Õr   ©r   N)	r$   r%   r&   r'   r   r   r(   r)   r3   r*   r   r   r,   r,   .   sU   „ Ù.ó'ð àð ð ˜$‘Zð ð ˜4‘jð	 ð
 ˜c™ð ð ð ð 
ô r   r,   c                   ó&   — e Zd ZU dZeed<   eed<   y)ÚPartitionResultz4NameTuple used for returning DAG and a new fx moduleÚdagÚmodule_with_submodulesN)r$   r%   r&   r'   r,   Ú__annotations__r   r*   r   r   r6   r6   B   s   … Ù>à	ƒHØ'Ô'r   r6   c                 ó    — | D ]	  }g |_         Œ y r   )r   )Ú
partitionsÚ	partitions     r   Úreset_partition_devicer=   L   s   € Øò *ˆ	Ø')ˆ	Õ$ñ*r   Úpartition_0Úpartition_1r;   r   c                 ó  — t        t        |«      «      }| j                  j                  |j                  «      |_        |j	                  «        |j                  |«       |j                  | «       |j                  |«       t        |«       y)zÊGiven a list of partitions and its two partitions,
    combine these two partitions into a new one appending to the partitions
    and remove the previous two partitions from the list of partitions
    N)r
   Úlenr.   ÚunionÚrecalculate_mem_sizer1   ÚremoveÚreorganize_partitions)r>   r?   r;   r<   s       r   Úcombine_two_partitionsrF   Q   sq   € ô œ#˜j›/Ó*€IØ!×'Ñ'×-Ñ-¨k×.?Ñ.?Ó@€I„OØ×"Ñ"Ô$Ø×Ñ�iÔ Ø×Ñ�kÔ"Ø×Ñ�kÔ"Ü˜*Ô%Ø
r   c                 óf  — | D ]   }t        «       |_        t        «       |_        Œ" | D ]‡  }|j                  D ]v  }|j                  }|D ]c  }| D ]\  }||k7  sŒ	||j                  v sŒ||j                  vsŒ'|j                  j                  |«       |j                  j                  |«       Œ^ Œe Œx Œ‰ y)zHGiven a list of partitions, mark parents and children for each partitionN)ÚsetÚchildrenÚparentsr.   ÚusersÚadd)r;   r<   r2   rK   ÚnÚps         r   Úset_parents_and_childrenrO   b   s¹   € ð  ò "ˆ	Ü ›Uˆ	ÔÜ›Eˆ	Õð"ð  ò 1ˆ	Ø—O‘Oò 
	1ˆDà—J‘JˆEØò 1�ð $ò 1�AØ˜I“~¨!¨q¯w©wª,¸4ÀqÇwÁwÒ;NØ!×*Ñ*×.Ñ.¨qÔ1ØŸ	™	Ÿ™ iÕ0ñ1ñ	1ñ
	1ð1ð r   c                 óN   — t        | «      D ]  \  }}||_        Œ t        | «       y)zmGiven a list of partitions, reorganize partition id,
    its parents and its children for each partition
    N)Ú	enumerateÚpartition_idrO   )r;   Úir<   s      r   rE   rE   z   s/   € ô
 " *Ó-ò #‰ˆˆ9Ø!"ˆ	Õð#ä˜ZÔ(Ø
r   c                 ó”  — t        «       }t        «       }| D ],  }t        |j                  «      dk(  sŒ|j                  |«       Œ. t        «       }d}|ru|j	                  «       }||_        |j                  |«       |j                  }|D ]  }||vsŒ|j                  |«       Œ |s|j                  «       }t        «       }|dz  }|rŒuy)zJGiven a list of partitions,
    mark the bfs level for each partition
    r   é   N)rH   rA   rJ   rL   ÚpopÚ	bfs_levelrI   Úcopy)r;   Úcurrent_levelÚvisitedr<   Ú
next_levelÚlevelrI   Úchilds           r   Úget_bfs_level_partitionr^   …   sÎ   € ô %(£E€MÜ!›e€GØò )ˆ	äˆy× Ñ Ó! QÓ&Ø×Ñ˜iÕ(ð)ô "%£€JØ€Eá
Ø!×%Ñ%Ó'ˆ	Ø#ˆ	ÔØ�‰�IÔØ×%Ñ%ˆØò 	&ˆEØ˜JÒ&Ø—‘˜uÕ%ð	&ñ Ø&ŸO™OÓ-ˆMÜ›ˆJØ�Q‰JˆEò ð r   c                 óX   — i }| D ]"  }|j                   D ]  }|j                  ||<   Œ Œ$ |S )z;Given a list of partitions,return node to partition mapping)r.   rR   )r;   Únode_to_partitionr<   r2   s       r   Úget_node_to_partition_mappingra   ¡   sC   € à)+ÐØò =ˆ	Ø—O‘Oò 	=ˆDØ&/×&<Ñ&<Ð˜dÒ#ñ	=ð=ð Ðr   Údevicesc                 ó6   — i }| D ]  }|||j                   <   Œ |S )z6Get a mapping from device logical ID to Device object.)Ú
logical_id)rb   Úlogical_id_to_deviceÚds      r   Úget_logical_id_to_devicerg   ª   s,   € à.0ÐØò /ˆØ-.Ð˜QŸ\™\Ò*ð/àÐr   c                 ó6  — t        |«      }i }i }|D ]  }g ||<   |j                  ||<   Œ g }| D ]d  }|j                  g k7  rB|j                  D ]2  }||   }	||	   j                  |«       ||	xx   |j                  z  cc<   Œ4 ŒT|j                  |«       Œf |||fS )zãGiven a list of partitions and a list of devices, returns:
    1. A mapping from device to partitions on it;
    2. A mapping from device to its remaining memory size;
    3. A list of partitions that do not have a device.
    )rg   Úavailable_mem_bytesr   r1   Úused_mem_bytes)
r;   rb   re   Údevice_to_partitionsÚdevice_to_left_mem_bytesrf   Úno_device_partitionsr<   rd   Údevices
             r   Úget_device_partition_statsro   ²   sÚ   € ô 4°GÓ<Ðà:<Ðà24ÐØò <ˆØ"$Ð˜QÑØ&'×&;Ñ&;Ð  Ò#ð<ð ÐØò 3ˆ	Ø×'Ñ'¨2Ò-Ø'×:Ñ:ò M�
Ø-¨jÑ9�Ø$ VÑ,×3Ñ3°IÔ>Ø(¨Ó0°I×4LÑ4LÑLÔ0ñMð
 !×'Ñ'¨	Õ2ð3ð 	Ø Øðð r   c           	      ó  ‡‡‡— dt         dt        t            fd„Šdt         fˆˆˆfd„}t        | |«      \  ŠŠ}d}|D ]F  }t        t	        ‰j                  «       t        j                  d«      ¬«      «      Š ||«      }|rŒE |S  |S )z\Given a list of partitions and a list of devices,
    map each partition into a device.
    r<   r;   c                 ó  — t        «       }|D ]  }|j                  |j                  «      }Œ t        |«      dk(  r| j                  S |j                  | j                  «      }d}| j                  D ]  }|t        ||«      z  }Œ |S )Nr   )rH   rB   r.   rA   rj   r   )r<   r;   Ú	all_nodesrN   Úextra_size_neededr2   s         r   Ú$calculate_extra_mem_bytes_needed_forzNget_device_to_partitions_mapping.<locals>.calculate_extra_mem_bytes_needed_forÞ   sŠ   € ô  #›uˆ	Øò 	1ˆAØ!Ÿ™¨¯©Ó0‰Ið	1äˆy‹>˜QÒØ×+Ñ+Ð+Ø—O‘O I§O¡OÓ4ˆ	ØÐØ—O‘Oò 	DˆDØÔ!2°4¸Ó!CÑCÑð	Dà Ð r   c                 óÌ   •— ‰D ]^  } ‰| ‰|   «      }|‰|   k  sŒ‰|   j                  | «       | j                  j                  |j                  «       ‰|xx   |z  cc<    y y)a3  Given a partition, find a logical device for the partition
        The algorithm is to put the partition on the device
        that has just enough mem left for that partition.
        device_to_left_mem_bytes is a dictionary between device and its left mem size
        sorted by its left mem size
        TF)r1   r   rd   )r<   rf   rs   rt   rl   rk   s      €€€r   Úfind_device_forz9get_device_to_partitions_mapping.<locals>.find_device_forì   s~   ø€ ð *ò 	ˆAÙ DØÐ/°Ñ2ó!Ðð !Ð#;¸AÑ#>Ó>Ø$ QÑ'×.Ñ.¨yÔ9Ø×,Ñ,×3Ñ3°A·L±LÔAØ(¨Ó+Ð/@Ñ@Ó+Ùð	ð r   TrU   ©Úkey)r
   r(   ro   ÚdictÚsortedÚitemsÚoperatorÚ
itemgetter)	r;   rb   rv   rm   Úfound_devicer<   rt   rl   rk   s	         @@@r   Ú get_device_to_partitions_mappingr   ×   s¢   ú€ ð!Üð!Ü*.¬y©/ó!ð¤9÷ ô, 	# :¨wÓ7ñ	ØØ Øð €LØ)ò ˆ	Ü#'ÜÐ+×1Ñ1Ó3¼×9LÑ9LÈQÓ9OÔPó$
Ð ñ ' yÓ1ˆÚØØÐðð Ðr   c                 óÊ   — | h}t        | g«      }|rR|j                  «       }|j                  D ]0  }|| k(  r y||vsŒ|j                  |«       |j	                  |«       Œ2 |rŒRy)z^Given a partition,check if there is a circular dependency on
    this partition using bfs
    TF)r   ÚpopleftrI   rL   r1   )r<   rZ   ÚqueuerN   r]   s        r   Úcheck_dependencyrƒ     sm   € ð  )˜k€GÜ# Y KÓ0€EÙ
Ø�M‰M‹OˆØ—Z‘Zò 	(ˆEØ˜	Ò!Ùà Ò'Ø—K‘K Ô&Ø—L‘L Õ'ð	(ò ð r   c                   óü   — e Zd ZdZdd„Zdedej                  j                  de	de
fd„Z	 dd	eddfd
„Zdd„Zdd„Zdefd„Zdedefd„Zdefd„Zd„ Zdeddfd„Zdedeeef   ddfd„Zdedeeef   ddfd„Zd„ Zy)ÚPartitionera¯  A fx module may not fit into one device.
    Partitioner class helps partition one fx module into submodules (partitions),
    so that the submodules can be executed crossing different accelerators.
    The main function of this class is self.partition_graph.
    It partitions the fx module based on the scheme specified in partition_config
    A DAG structure is returned
    along with a new fx module with submodule nodes.
    r   Nc                 ó.   — g | _         i | _        g | _        y r   )r;   r`   rb   r"   s    r   r   zPartitioner.__init__,  s   € Ø+-ˆŒØ24ˆÔØ%'ˆ�r   Ú	fx_moduleÚtorch_moduleÚpartitioner_configc                 ó¤  ‡— || _         || _        |j                  | _        t        | j                  «      dk(  rt	        d«      ‚t        | j                   «       | j                   j                  j                  }t        d„ |D «       «      rt	        d«      ‚d}|D ],  }|j                  dk(  r n||j                  j                  z  }Œ. t        | j                  d„ ¬«      }|j                  t        j                  k(  r(| j!                  |j"                  |j$                  «       �na||j&                  k  r| j)                  ||j*                  ¬«       �n3|t-        d	„ | j                  D «       «      kD  rt	        d
«      ‚|j                  t        j.                  k(  rT| j                  d   j&                  Št        ˆfd„| j                  D «       «      st	        d«      ‚| j1                  ‰«       n˜|j                  t        j2                  k(  r'| j5                  |j6                  |j8                  «       nT|j                  t        j:                  k(  r'| j=                  |j6                  |j8                  «       n| j?                  «        |j@                  r| jA                  «        | jC                  «       }| jE                  |«      }	tG        |	|«      }
|
S )zÆGiven the fx module, torch module and partitioner_config,
        find the partitions, do the partitions,
        and then return a DAG and a new fx module with submodule nodes (partitions)
        r   z
No devicesc              3   ó8   K  — | ]  }|j                   d v –— Œ y­w)>   ÚoutputÚget_attrÚplaceholderN)Úop)Ú.0r2   s     r   ú	<genexpr>z.Partitioner.partition_graph.<locals>.<genexpr>D  s   è ø€ ÒRÀDˆt�w‰wÐ?Ô?ÑRùs   ‚z.No Partition since no operations in the modulerŒ   c                 ó   — | j                   S r   ©ri   ©rf   s    r   ú<lambda>z-Partitioner.partition_graph.<locals>.<lambda>M  s   € ¸a×>SÑ>S€ r   rw   )Úlogical_device_idc              3   ó4   K  — | ]  }|j                   –— Œ y ­wr   r“   )r�   rf   s     r   r‘   z.Partitioner.partition_graph.<locals>.<genexpr>Y  s   è ø€ Ò&SÀ q×'<Õ'<Ñ&Sùs   ‚z,Devices have no enough memory for the modulec              3   ó<   •K  — | ]  }|j                   ‰k(  –— Œ y ­wr   r“   )r�   rn   ri   s     €r   r‘   z.Partitioner.partition_graph.<locals>.<genexpr>_  s%   øè ø€ ò àð ×.Ñ.Ð2EÕEñùs   ƒz'All devices must have same memory size!)$Úgraph_modulerˆ   rb   rA   ÚRuntimeErrorr   Úgraphr.   Úallr�   r   Ú
total_sizeÚmaxÚmoder   Ú	aot_basedÚaot_based_partitionÚnode_to_partition_mappingÚ#partition_to_logical_device_mappingri   Úfind_single_partitionrd   ÚsumÚ	sparse_nnÚsparse_nn_partitionÚ
cost_awareÚcost_aware_partitionÚtransfer_rate_bytes_per_secÚnode_to_latency_mappingÚkl_basedÚkl_based_partitionÚsize_based_partitionÚsaturate_hostÚdo_partitionÚdump_dagr6   )r   r‡   rˆ   r‰   r.   Útotal_size_of_graphr2   Údevice_with_max_memr8   r7   Úretri   s              @r   Úpartition_graphzPartitioner.partition_graph1  sx  ø€ ð &ˆÔØ(ˆÔØ)×1Ñ1ˆŒÜˆt�|‰|Ó Ò!Ü˜|Ó,Ð,ä˜d×/Ñ/Ô0à×!Ñ!×'Ñ'×-Ñ-ˆÜÑRÈEÔRÔRÜÐOÓPÐPàÐØò 	>ˆDØ�w‰w˜(Ò"ÙØ 4§?¡?×#=Ñ#=Ñ=Ñð	>ô
 " $§,¡,Ñ4SÔTÐà×"Ñ"¤m×&=Ñ&=Ò=Ø×$Ñ$Ø"×<Ñ<Ø"×FÑFöð
 !Ð$7×$KÑ$KÒKØ×&Ñ&Ø#Ð7J×7UÑ7Uð 'ö ð !¤3Ñ&SÀdÇlÁlÔ&SÓ#SÒSÜÐMÓNÐNð "×&Ñ&¬-×*AÑ*AÒAØ&*§l¡l°1¡o×&IÑ&IÐ#Üó à"&§,¡,ôô ô 'Ð'PÓQÐQð ×(Ñ(Ð)<Õ=à#×(Ñ(¬M×,DÑ,DÒDØ×)Ñ)Ø&×BÑBØ&×>Ñ>õð
 $×(Ñ(¬M×,BÑ,BÒBØ×'Ñ'Ø&×BÑBØ&×>Ñ>õð
 ×)Ñ)Ô+ð ×+Ò+Ø×ÑÔ ð "&×!2Ñ!2Ó!4Ðð �m‰mÐ2Ó3ˆÜ˜cÐ#9Ó:ˆØˆ
r   r–   c                 ó  — | j                  «       }| j                  j                  j                  D ]-  }|j                  dk(  rŒ|j                  j                  |«       Œ/ ||_        |g|_        t        | j                  «      | _
        y)z'Fit the whole fx module into one devicerŒ   N)Úcreate_partitionr™   r›   r.   r�   rL   rj   r   ra   r;   r`   )r   r²   r–   r>   r2   s        r   r¤   z!Partitioner.find_single_partitionƒ  s�   € ð ×+Ñ+Ó-ˆØ×%Ñ%×+Ñ+×1Ñ1ò 	(ˆDØ�w‰w˜(Ò"ð Ø×Ñ×!Ñ! $Õ'ð	(ð &9ˆÔ"Ø*;Ð)<ˆÔ&ä!>¸t¿¹Ó!OˆÔØr   c                 ó\  ‡ ‡— dt         fˆˆ fd„}i }g Š‰ j                  «       }‰ j                  j                  j                  D �]‰  }|j
                  dv sŒt        ‰ j                  «      t        ‰ j                  «      k  �r:t        ||j                  «      }|j                  dk(  rN ||«      }‰j                  |«       |j                  ||<   |j                  j                  |j                  «       n§||   |k  rŸt        ‰ j                  «      t        ‰ j                  «      k(  r‰ j                  |«       Œ÷ ||«      }‰ j                  «       }t        ||j                  «      }|j                  ||<   |j                  j                  |j                  «       |j!                  |«       ||xx   |z  cc<   �Œy‰ j                  |«       �ŒŒ t#        ‰ j                  «       t%        ‰ j                  «      ‰ _        t)        ‰ j                  ‰ j                  «      }|st+        d«      ‚y)a™  This method is to partition the fx module based on memory size.
        It uses greedy approach. The result may not be the best.
        The basic idea is:
        Step 1:
        Find a device which has enough memory to fit the current node, create a empty partition
        with the size of that device.
        Then keep adding the following nodes into the partition until the partition is full.
        Step 2:
        Repeat Step 1 until no device left
        Step 3:
        If some nodes are left, create a partition for each left node (single node partition).
        and then try to map those partitions into logical devices with enough mem left.
        r   c                 ó
  •— t        | t        «       «      }t        ddd«      }‰j                  D ]  }|‰vsŒ|j                  |k\  sŒ|} n |j                  dk  rt        t        | «      dz   «      ‚‰j                  |«       |S )ziGiven a node, this function is to find a logical device
            that could fit the node.
            Ú éÿÿÿÿr   zis too large to fit any device)r   rH   r   rb   ri   rš   r!   r1   )r2   Úmem_size_neededrn   rf   Úoccupied_devicesr   s       €€r   Úfind_device_based_on_sizezCPartitioner.size_based_partition.<locals>.find_device_based_on_size£  s‹   ø€ ô 0°´c³eÓ<ˆOÜ˜B  BÓ'ˆFØ—\‘\ò �àÐ-Ò-Ø×-Ñ-°Ó@à�FÙðð ×)Ñ)¨AÒ-Ü"¤3 t£9Ð/OÑ#OÓPÐPØ×#Ñ# FÔ+ØˆMr   >   Úcall_methodÚcall_moduleÚcall_functionr   z6Cannot Get a Valid Partition to Logical Device MappingN)r   r·   r™   r›   r.   r�   rA   r;   rb   r   rj   r1   ri   r   rd   Úcreate_single_node_partitionÚadd_noderE   ra   r`   r   rš   )	r   r¾   Úpartition_to_left_mem_bytesr<   r2   Útotal_size_of_input_nodesrn   Ú!found_partition_to_device_mappingr½   s	   `       @r   r®   z Partitioner.size_based_partition”  sý  ù€ ð	¬vö 	ð& =?Ð#à)+ÐØ×)Ñ)Ó+ˆ	Ø×%Ñ%×+Ñ+×1Ñ1ó ,	<ˆDØ�w‰wÐIÒIä�t—‘Ó'¬3¨t¯|©|Ó+<Ó<Ü0AÀ$È	ÏÉÓ0XÐ-à ×/Ñ/°1Ò4á!:¸4Ó!@˜Ø(×/Ñ/°Ô7ð #×6Ñ6ð 4Ø%ñð "×4Ñ4×;Ñ;¸F×<MÑ<MÕNð
 8¸	ÑBØ7ò8ô  # 4§?¡?Ó3´s¸4¿<¹<Ó7HÒHð !%× AÑ AÀ$Ô GØ (ñ &?¸tÓ%D˜FØ(,×(=Ñ(=Ó(?˜IÜ8IØ $ i§o¡oó9Ð5ð
 !'× :Ñ :ð 8Ø )ñð &×8Ñ8×?Ñ?À×@QÑ@QÔRØ×&Ñ& tÔ,Ø/°	Ó:Ð>WÑWÕ:ð ×5Ñ5°dÖ;ðY,	<ôZ 	˜dŸo™oÔ.ä!>¸t¿¹Ó!OˆÔä,LØ�O‰O˜TŸ\™\ó-
Ð)ñ 1ÜÐWÓXÐXØr   c                 óî  — t        | j                  | j                  «      \  }}}t        |«      dk(  sJ dt        |«      › �«       ‚| j                  D �cg c]  }t        ||   «      dkD  sŒ|‘Œ }}i }t        |«      dz  t        |«      z   t        | j                  «      k  rÕd}| j                  D �cg c]  }||vr||vr|‘Œ }}i }	|D ]f  }
|D �cg c]#  }|j                  |
j                  ||
   z
  k\  r|‘Œ% }}t        |«      dk(  rd} n&t        |d„ ¬«      }|j                  |«       |
|	|<   Œh |snB|j                  |	«       t        |«      dz  t        |«      z   t        | j                  «      k  rŒÕ|j                  «       D ]6  \  }}|j                  }||   D ]  }|j                  j                  |«       Œ Œ8 | j                  D ]  }t        |j                  «       Œ yc c}w c c}w c c}w )	aá  Saturate host by assigning replicates to unused devices with enough memory.
        It uses a greedy approach to find a next available set of devices to place all split
        partitions: For each used device, it searches for an idle device with minimal memory
        size that can hold all the partition located on that device; If the search is successful
        for all used devices, it then assigns the new devices' logical ID to the corresponding
        partition.
        r   z2Expect no_device_partitions has 0 device, but get é   TFc                 ó   — | j                   S r   r“   r”   s    r   r•   z+Partitioner.saturate_host.<locals>.<lambda>$  s   € À!×BWÑBW€ r   rw   N)ro   r;   rb   rA   ri   ÚminrD   Úupdater{   rd   r   r1   Úprint)r   rk   rl   rm   rf   Úused_devicesÚ replicated_device_to_used_deviceÚsuccessÚidle_devicesÚtemp_replicate_mappingÚused_deviceÚavailable_devicesÚ
new_deviceÚreplicate_deviceÚoriginal_devicerd   r<   rN   s                     r   r¯   zPartitioner.saturate_hostò  s_  € ô ' t§¡¸¿¹ÓEñ		
Ø Ø$Ø ô Ð$Ó%¨Ò*ð	\à?ÄÐDXÓ@YÐ?ZÐ[ó	\Ø*ð $(§<¡<ÖT˜a´3Ð7KÈAÑ7NÓ3OÐRSÓ3SšÐTˆÐTàACÐ(ä�,Ó !Ñ#¤cÐ*JÓ&KÑKÌsØ�L‰LóP
ò 
ð ˆGð Ÿ™öàØ˜LÑ(¨QÐ6VÑ-Vò ðˆLð ð &(Ð"ð  ,ò A�ð *ö%àØ×,Ñ,Ø"×6Ñ6Ø.¨{Ñ;ñ<ò<ò ð%Ð!ð %ô Ð(Ó)¨QÒ.Ø#�GÙÜ Ð!2Ñ8WÔX�
Ø×#Ñ# JÔ/Ø5@Ð& zÒ2ðAñ  ØØ,×3Ñ3Ð4JÔKôC �,Ó !Ñ#¤cÐ*JÓ&KÑKÌsØ�L‰LóP
ó 
ðN .×3Ñ3Ó5ò	@ñ 
ØØà)×4Ñ4ˆJØ1°/ÑBò @�	Ø×,Ñ,×3Ñ3°JÕ?ñ@ð	@ð —‘ò 	(ˆAÜ�!×&Ñ&Õ'ñ	(ùò_ Uùòùò%s   ÁG(Á+G(Â3G-Ã(G2c                 óP   ‡ — t        ‰ j                  ‰ j                  ˆ fd„«      }|S )z9Return a new fx module with submodule nodes (partitions).c                 ó"   •— ‰j                   |    S r   )r`   )r2   r   s    €r   r•   z*Partitioner.do_partition.<locals>.<lambda><  s   ø€ ˜×/Ñ/°Ñ5€ r   )r   r™   rˆ   )r   r8   s   ` r   r°   zPartitioner.do_partition7  s+   ø€ ä!-Ø×ÑØ×ÑÛ5ó"
Ðð
 &Ð%r   r8   c                 ó¨  — t        «       }|j                  j                  D �]-  }|j                  dk(  r |S |j                  dv rŒ%|j                  t
        j                  k(  rŒCi }t        |j                  |j                  «       t        |j                  |j                  «       t        |j                  «      dkD  rt        |j                  «      }n|g}t        |j                  j!                  dd«      d   «      }| j"                  |   j$                  }| j"                  |   j&                  }|j)                  |t        |«      |||«       �Œ0 |S )z?Return the dag structure and the new fx module with submodules.rŒ   >   r�   rŽ   rU   Ú_r»   )r,   r›   r.   r�   Útargetr|   Ú__getitem__r   ÚargsÚ
setdefaultÚkwargsrA   rK   r(   r)   ÚnameÚrsplitr;   r   rj   r3   )	r   r8   r7   r2   r   r   rR   Ú
device_idsr   s	            r   r±   zPartitioner.dump_dag@  s   € ä‹eˆØ*×0Ñ0×6Ñ6ó 	ˆDØ�w‰w˜(Ò"Øð, ˆ
ð+ �w‰wÐ5Ñ5ØØ�{‰{œh×2Ñ2Ò2ØØ,.ˆKÜ�D—I‘I˜{×5Ñ5Ô6Ü�D—K‘K ×!7Ñ!7Ô8ô
 �4—:‘:‹ Ò"Ü# D§J¡JÓ/‘à $˜v�Ü˜tŸy™y×/Ñ/°°QÓ7¸Ñ;Ó<ˆLØŸ™¨Ñ6×IÑIˆJØŸ™¨Ñ6×EÑEˆJØ�O‰OØ”d˜;Ó'¨°zÀ:öð+	ð0 ˆ
r   c                 ó|   — t        | j                  «      }t        |«      }| j                  j                  |«       |S )z4Create a partition and append it to self.partitions.)rA   r;   r
   r1   )r   rR   r<   s      r   r·   zPartitioner.create_partition]  s2   € ä˜4Ÿ?™?Ó+ˆÜ˜lÓ+ˆ	Ø�‰×Ñ˜yÔ)ØÐr   c                 óF   — | j                  «       }|j                  |«       y)z$Create a partition for a single nodeN)r·   rÃ   )r   r2   r<   s      r   rÂ   z(Partitioner.create_single_node_partitiond  s!   € à×)Ñ)Ó+ˆ	Ø×Ñ˜4Ô Ør   ri   c                 ó¦  ‡ ‡‡‡‡‡‡— dt         t           dt        ddfˆˆ fd„}d„ Šdt         t           dt        dt         t           dt        t        t         t           f   fˆˆ fd„Šdˆˆˆˆˆ fd	„	}d
t
        dt        fˆ fd„}g Šg ŠdŠ‰ j                  «       }‰ j                  j                  j                  D ]ª  }|j                  dv sŒ ||«      ‰k7  r|j                  dk7  r ||«      }‰ Št        ||j                  «      }||j                  z   ‰kD  r; ||«      }t        ||j                  «      }|‰kD  rt        |j                  dz   «      ‚|j                  |«       Œ¬  ||d¬«       t!        ‰ j"                  «        |‰‰«        |‰‰«       d}‰D ]  }||j                  z  }Œ t%        ‰«      t%        ‰ j&                  «      kD  rGdt)        t%        ‰«      «      z   dz   t)        t%        ‰ j&                  «      «      z   dz   }	t        |	«      ‚g }
t+        ‰«      D ]‚  \  }}||j                  z   ‰kD  r$t        dt)        |j,                  «      z   dz   «      ‚‰ j&                  |   j.                  g|_        |
j3                  ‰ j&                  |   j.                  «       Œ„ ‰D ]	  }|
|_        Œ t5        ‰ j"                  «      ‰ _        y)a7  This method partition a sparse nn module.
        It is size based partition but different from size_based_partition,
        it only works when all the devices have same memory size (available_mem_bytes).
        In the future, devices with different mem sizes will be supported like size_based_partition.
        It first traverse all the nodes and do the partitions based on the same memory size.
        If the current partition has no enough memory left for a new op node
        (call_module, call_method, call_function), a new partition is created.
        When crossing the boundary between non-embedding nodes and embedding nodes,
        a new partition is created regardlessly.
        For example, if the current node is a non-embedding node but the next node is an
        embedding node, a new partition is created for the next node.
        After the partition, the partitions are combined as much as possible.
        The rule is that a non-embedding partition only
        combines with another non-embedding one.
        So as the embedding partitions.
        r;   ri   r   Nc                 ót   •— d}|r3t        | d„ ¬«      }t        ‰j                  «        ‰||| «      \  }} |rŒ3y)a§  Combining small partitions together to keep as less partitions as possible.
            Here is an example of the algorithm to do this:
            Assume some partitions, we first sort them based on partition used memory size.
            [(partition_4, 1), (partition_3, 1), (partition_2, 2), (partition_1, 7), (partition_0, 9)]
            The available memory is 10.
            step 1: self.find_partition_to_combine_based_on_size()
            First, mark bfs level for each partition
            Second, look the smallest partition, partition_4: 10 - 1 = 9
            It means any partition has a used memory equal or less than 9 could combine this partition
            We go from the largest and selection partition_0.
            Check the bfs level for two partitions, if the level difference is less than 2,
            it can be combined.
            step 2: repeat step 1 until no partitions can be combined
            Tc                 ó   — | j                   S r   )rj   )rN   s    r   r•   z[Partitioner.sparse_nn_partition.<locals>.combine_partitions_based_on_size.<locals>.<lambda>�  s   € ÀQ×EUÑEU€ r   rw   N)rz   r^   r;   )r;   ri   Úfind_combinationÚsorted_partitionsÚ'find_partition_to_combine_based_on_sizer   s       €€r   Ú combine_partitions_based_on_sizezIPartitioner.sparse_nn_partition.<locals>.combine_partitions_based_on_size|  sJ   ø€ ð"  $ÐÙ"ä$*¨:Ñ;UÔ$VÐ!ä'¨¯©Ô8Ù/VØ%Ð':¸Jó0Ñ,Ð  *ò #ð r   c                 ó€   — | j                   j                  |j                   «      }d}|D ]  }|t        ||«      z  }Œ |S )zuGiven two partitions, calculate how many mem bytes
            are needed if two partitions are combined
            r   )r.   rB   r   )Úp1Úp2r.   Úmem_bytes_neededr2   s        r   Úcalculate_mem_bytes_neededzCPartitioner.sparse_nn_partition.<locals>.calculate_mem_bytes_needed˜  sJ   € ð —H‘H—N‘N 2§8¡8Ó,ˆEØ ÐØò C�Ø Ô$5°d¸EÓ$BÑBÑ ðCà#Ð#r   ré   c                 óp  •— d}| j                  d«      }| ddd…   D ]”  }t        |j                  |j                  z
  «      dk  sŒ) ‰||«      }||k  sŒ8t        ||‰j                  «       |j                  |«       |j                  |«       |j                  ‰j                  d   «       d} ||fS  ||fS )z+step 1 in combine_partition_based_on_size()Fr   Nr»   rU   T)rV   ÚabsrW   rF   r;   rD   r1   )	ré   ri   r;   rè   Úsmallest_partitionrN   rï   rð   r   s	          €€r   rê   zPPartitioner.sparse_nn_partition.<locals>.find_partition_to_combine_based_on_size¢  sÎ   ø€ ð  %ÐØ!2×!6Ñ!6°qÓ!9ÐØ&¡t¨ tÑ,ò 
�ÜÐ)×3Ñ3°a·k±kÑAÓBÀaÓGá'AÀ!ÐEWÓ'XÐ$Ø'Ð+>Ó>Ü.¨qÐ2DÀdÇoÁoÔVØ"×)Ñ)Ð*<Ô=Ø"×)Ñ)¨!Ô,Ø"×)Ñ)¨$¯/©/¸"Ñ*=Ô>Ø+/Ð(ØØ# ZÐ/Ð/ð
ð $ ZÐ/Ð/r   c                 ó†   •— ‰r‰j                  | «       n‰j                  | «       |r‰j                  «       } ‰| _        | S y)zyIf crossing the boundary between non-embedding nodes and
            embedding nodes, create a new partition
            N)r1   r·   Úleft_mem_bytes)r<   Únew_partitionri   Úembedding_partitionsÚin_embedding_regionÚnon_embedding_partitionsr   s     €€€€€r   Úreset_partition_in_sparse_nnzEPartitioner.sparse_nn_partition.<locals>.reset_partition_in_sparse_nn·  sF   ø€ ñ #Ø$×+Ñ+¨IÕ6à(×/Ñ/°	Ô:ÙØ ×1Ñ1Ó3�	Ø+>�	Ô(Ø Ð Ør   r2   c                 óþ   •— | j                   dk(  rm‰j                  }t        | j                  «      j	                  d«      D ]:  }t        ||«      st        d|› d|› �«      ‚t        ||«      }dt        |«      v sŒ: y y)z$Check if a node is an embedding noderÀ   ú.zModule z has no attribute Ú	EmbeddingTF)r�   r™   r!   rÛ   ÚsplitÚhasattrrš   Úgetattr)r2   Ú	submoduleÚatomr   s      €r   Úis_embedding_nodez:Partitioner.sparse_nn_partition.<locals>.is_embedding_nodeÅ  s‡   ø€ à�w‰w˜-Ò'Ø ×-Ñ-�	Ü §¡Ó,×2Ñ2°3Ó7ò $�DÜ" 9¨dÔ3Ü*Ø% i [Ð0BÀ4À&ÐIóð ô !(¨	°4Ó 8�IØ"¤c¨)£nÒ4Ù#ð$ð r   F>   r¿   rÀ   rÁ   r   z!is too large to fit into a device)rö   zNeed z devices, but only z	 providedÚ
partition_zN(embedding partition) and non embedding partitions can not fit into one device)T)r(   r
   r)   ÚtupleÚboolr   r·   r™   r›   r.   r�   rj   r   rš   rÛ   rÃ   rO   r;   rA   rb   r!   rQ   rR   rd   r   r1   ra   r`   )r   ri   rë   rú   r  r<   r2   rÅ   Ú&total_size_of_non_embedding_partitionsÚmsgr½   rS   rð   r÷   rê   rø   rù   s   ``          @@@@@r   r§   zPartitioner.sparse_nn_partitionj  s  þ€ ð$	ÜœY™ð	Ü>Að	àö	ò8	$ð	0Ü#¤I™ð	0ä!$ð	0ô œY™ð	0ô ”4œœi™Ð(Ñ)ö		0÷*	ñ 	ð	¤Dð 	¬Tõ 	ð 13ÐØ46Ð à$)ÐØ×)Ñ)Ó+ˆ	Ø×%Ñ%×+Ñ+×1Ñ1ò 	)ˆDØ�w‰wÐIÒIá$ TÓ*Ð.AÒAð !×/Ñ/°1Ò4á$@ÀÓ$K˜	Ø.AÐ*AÐ'Ü,=¸dÀIÇOÁOÓ,TÐ)à-°	×0HÑ0HÑHØ)ò*ñ !=¸YÓ G�IÜ0AÀ$È	ÏÉÓ0XÐ-Ø0Ð3FÒFÜ*Ø ŸK™KÐ*MÑMóð ð ×"Ñ" 4Õ(ð+	)ñ, 	% Y¸eÕDä  §¡Ô1á(Ð)AÐCVÔWá(Ð)=Ð?RÔSØ12Ð.Ø1ò 	OˆIØ2°i×6NÑ6NÑNÑ2ð	Oô Ð#Ó$¤s¨4¯<©<Ó'8Ò8àÜ”cÐ.Ó/Ó0ñ1à'ñ(ô ”c˜$Ÿ,™,Ó'Ó(ñ)ð ñ	ð ô ˜sÓ#Ð#ØÐÜ%Ð&:Ó;ò 	D‰LˆAˆyð 7¸×9QÑ9QÑQØ%ò&ô #Ø Ü˜)×0Ñ0Ó1ñ2àfñgóð ð 15·±¸Q±×0JÑ0JÐ/K�	Ô,Ø ×'Ñ'¨¯©°Q©×(BÑ(BÕCð	Dð  2ò 	<ˆIØ+;ˆIÕ(ð	<ô "?¸t¿¹Ó!OˆÔØr   rª   r«   c                 óž  ‡ ‡‡‡— dt         fˆˆ ˆfd„Šdt        fˆ ˆfd„}‰ j                  j                  j                  D ]"  }|j
                  dvsŒ‰ j                  |«       Œ$ t        ‰ j                  «       t        ‰ j                  «       d}|r |‰‰«      }|rŒt        ‰ j                  «       t        ‰ j                  «      ‰ _        y)aG  This method is to partition the fx module based on the cost.
        The cost is the total latency of running the whole fx module.
        In partitioner_utils.py, the cost model is built.
        The cost aware partition algorithm is:
        #1. At every beginning, each node is a partition.
            Then we map all the partitions to the devices
            and calculate the cost
        #2. Then try to pre-combine any two of the partitions if the two
            partitions can be combined.
            (the bfs level is less than 2 or two partitions are connected and
            can find partition to device mapping)
            See if any partition pair could reduce the current cost.
            Choose the pair that shows the minimum cost and then combine them
        #3. Repeat #2 until the cost cannot be reduced.
        r   c                 ó�  •— ||    }||   }	 t        |j                  |j                  z
  «      dk  s||j                  v s||j                  v rot	        |||«       t        |d   «      rt        d«      S t        |«       t        |‰	j                  «      }|st        d«      S t        |‰«      }t        ||‰
«      }|S t        d«      S )zœGiven two partitions and a list of partitions, combine these two partitions
            and see what is the cost of the modified partition list
            rU   r»   Úinf)rò   rW   rJ   rI   rF   rƒ   Úfloatr=   r   rb   r   r   )Úp0_indexÚp1_indexr;   Úp0rí   Úfound_deivceÚpartition_to_latency_mappingÚcostr«   r   rª   s           €€€r   Útry_combining_partitionszBPartitioner.cost_aware_partition.<locals>.try_combining_partitions/  sÕ   ø€ ð ˜HÑ%ˆBØ˜HÑ%ˆBðô �R—\‘\ B§L¡LÑ0Ó1°QÒ6Ø˜"Ÿ*™*Ñ$Ø˜"Ÿ+™+Ñ&ä& r¨2¨zÔ:ä# J¨r¡NÔ3Ü  ›<Ð'ä& zÔ2Ü?Ø §¡ó �ñ $Ü  ›<Ð'ä/OØÐ 7ó0Ð,ô 8ØØ0Ø/ó�ð
 �ä˜“<Ðr   c           	      óÞ  •— t        ‰
j                  |«      }t        ‰
j                  || «      }t        ‰
j                  «      dk(  ryg }t	        t        ‰
j                  «      dz
  «      D ]`  }t	        |dz   t        ‰
j                  «      «      D ]9  } ‰||‰
j                  dd «      }||k  r||g}|}t        ‰
j                  «       Œ; Œb t        |«      dk7  r;‰
j                  |d      }‰
j                  |d      }	t        ||	‰
j                  «       t        ‰
j                  «       t        ‰
j                  «       t        ‰
j                  ‰
j                  «       t        |«      dk7  S )aÏ  Given transfer rate between partitions and each node's latency,
            find two partitions to combine so the cost of the partitions can
            be reduced.
            The algorithm is :
            1. Go through all the partition pairs and see
            if any pair of partitions can be combined.
            2. Calculate the cost after the combination.
            3. Select the minimum cost and combine its corresponding partition pair.
            rU   FNr   )r   r;   r   rA   ÚrangerE   rF   r^   r=   r   rb   )rª   r«   r  r  Úpartition_pairrS   ÚjÚnew_costr  rí   r   r  s             €€r   Úsearch_combinationz<Partitioner.cost_aware_partition.<locals>.search_combinationU  sN  ø€ ô ,LØ—‘Ð!8ó,Ð(ô 4Ø—‘Ø,Ø+óˆDô
 �4—?‘?Ó# qÒ(ØØ(*ˆNÜœ3˜tŸ™Ó/°!Ñ3Ó4ò ;�Ü˜q 1™u¤c¨$¯/©/Ó&:Ó;ò ;�Añ  8¸¸1¸d¿o¹oÉaÐ>PÓQ�HØ 4Ò'Ø*+¨Q¨˜Ø'˜Ü)¨$¯/©/Õ:ñ;ð;ô �>Ó" aÒ'Ø—_‘_ ^°AÑ%6Ñ7�Ø—_‘_ ^°AÑ%6Ñ7�Ü& r¨2¨t¯©Ô?Ü# D§O¡OÔ4Ü" 4§?¡?Ô3Ü,¨T¯_©_¸d¿l¹lÔKÜ�~Ó&¨!Ñ+Ð+r   >   rŒ   r�   rŽ   TN)r  r  r™   r›   r.   r�   rÂ   rO   r;   r^   rE   ra   r`   )r   rª   r«   r  r2   rè   r  s   ```   @r   r©   z Partitioner.cost_aware_partition  s¹   û€ ð*$	 Ì÷ $	 ðL(	,äö(	,ðT ×%Ñ%×+Ñ+×1Ñ1ò 	8ˆDØ�w‰wÐCÒCØ×1Ñ1°$Õ7ð	8ô 	! §¡Ô1ä §¡Ô0ØÐÙñ  2Ø+Ð-Dó Ðò ô 	˜dŸo™oÔ.ä!>¸t¿¹Ó!OˆÔØr   c           	      ó4  ‡ ‡‡‡— d„ Šˆ ˆˆfd„Šˆfd„}‰ j                  «        t        ‰ j                  |«      }t        ‰ j                  |‰«      }g }g }‰ j                  j
                  j                  D �cg c]  }|j                  dvr|‘Œ }	}|	D ]Ê  }
‰ j                  |
   }‰ j                  |   }t        ‰ j                  «      D ]7  \  }}||k7  sŒ‰ j                  |   } ||
|||‰«      \  }}||k  sŒ0|}|}||g}Œ9 t        |«      dk7  sŒ ‰|d   |d   |d   |d   «       t        ‰ j                  «       t        ‰ j                  ‰ j                  «       ŒÌ t        ‰ j                  «       t        ‰ j                  ‰ j                  «       yc c}w )aõ  This function is a cost aware partition based
        on Kernighan-Lin algorithm.
        First, the graph is partitioned using size_based_partition.
        Then, each node is swapped with any other node in a different
        partition, and at the same time, the cost is estimated after
        the swapping.
        For example, we have nodes n0, n1, n2, n3 and n4.
        Using size_based_partition, n0 and n1 are in Partition p0.
        n2, n3 and n4 in Partition p1. The current cost is estimated.
        We first tried using n0 to swap with n2 from the other partition.
        Then we see that swapping n0 and n2 shows a lower cost
        than the current cost and it is the minimum among other pairs like
        (n0, None)(This means moving n0 to Partition without swapping other nodes),
        (n0, n3) and (n0, n4). We swap n0 and n2 and set the new cost
        as the current cost.
        Then We repeat this process for all the other nodes until all swapping pairs
        are tried.
        c                 ó–   — | �"|j                  | «       |j                  | «       |�#|j                  |«       |j                  |«       y y r   )Úremove_noderÃ   )Ún0Ún1r  rí   s       r   Ú
swap_nodesz2Partitioner.kl_based_partition.<locals>.swap_nodes«  sA   € ð ˆ~Ø—‘˜rÔ"Ø—‘˜B”Øˆ~Ø—‘˜B”Ø—‘˜rÕ"ð r   c                 ó  •— t        d«      } ‰
| |||«       t        ‰	j                  «       t        |«      s{t        |«      spt	        ‰	j                  «       t        ‰	j                  |«      }t        ‰	j                  ‰	j                  «      }|st        d«      }nt        ‰	j                  |‰«      } ‰
|| ||«       t        ‰	j                  «       t	        ‰	j                  «       t        ‰	j                  ‰	j                  «       |S )Nr  )	r  rE   r;   rƒ   r=   r   r   rb   r   )r  r  r  rí   r«   Útransfer_rate_per_secr  r  r~   r   r  rª   s            €€€r   Útry_swap_nodesz6Partitioner.kl_based_partition.<locals>.try_swap_nodes¶  s×   ø€ ô ˜“<ˆDÙ�r˜2˜r 2Ô&ä! $§/¡/Ô2ä$ RÔ(Ô3CÀBÔ3GÜ& t§¡Ô7Ü/OØ—O‘OÐ%<ó0Ð,ô  @Ø—O‘O T§\¡\ó �ñ $Ü  ›<‘Dä;ØŸ™Ø4Ø3ó�Dñ �r˜2˜r 2Ô&Ü! $§/¡/Ô2Ü" 4§?¡?Ô3Ü,¨T¯_©_¸d¿l¹lÔKØˆKr   c           	      óº   •— t        |j                  «      dgz   }t        d«      }g }|D ],  }|�|j                  dv rŒ ‰
| |||||«      }	|	|k  sŒ'| |g}|	}Œ. 	|fS )zzThis function helps to swap one node from partition p0
            with all the nodes in another partition p1
            Nr  >   r�   rŽ   )r(   r.   r  r�   )r2   r  rí   r«   r!  Úp1_nodesÚmin_costÚ	node_pairr  r  r"  s             €r   Úswap_node_to_partitionz>Partitioner.kl_based_partition.<locals>.swap_node_to_partitionÖ  s†   ø€ ô ˜BŸH™H“~¨¨Ñ.ˆHÜ˜U“|ˆHØ$&ˆIØò 
$�à�> b§e¡eÐ/JÑ&JØá%Ø˜"˜b "Ð&=Ð?Tó�ð ˜(“?Ø!% r 
�IØ#‘Hð
$ð ˜�?Ð"r   >   rŒ   r�   rŽ   r   rU   N)r®   r   r;   r   r™   r›   r.   r�   r`   rQ   rA   rE   r   rb   )r   rª   r«   r'  r  r  r&  r  rM   Úop_nodesr2   r  r  r  rÚ   rí   r  Únew_node_pairr  r"  s   ``                @@r   r­   zPartitioner.kl_based_partition“  s³  û€ ò0		#ö	ô@	#ð. 	×!Ñ!Ô#Ü'GØ�O‰OÐ4ó(
Ð$ô 0Ø�O‰OÐ9Ð;Vó
ˆð !#ˆ	à*,ˆð ×&Ñ&×,Ñ,×2Ñ2ö
àØ�t‰tÐ@Ñ@ò ð
ˆð 
ð
 ò 	PˆDà×-Ñ-¨dÑ3ˆHØ—‘ Ñ*ˆBô  )¨¯©Ó9ò 2‘�˜!Ø˜xÓ'ØŸ™¨Ñ2�BÙ.DØØØØ/Ø3ó/Ñ+�H˜mð   $“Ø'˜Ø$1˜	Ø*,¨b¨™ð2ô" �9‹~ Ó"ÙØ˜a‘L )¨A¡,°¸qÑ0AÀ>ÐRSÑCTôô & d§o¡oÔ6Ü0°·±À$Ç,Á,ÕOð9	Pô: 	˜dŸo™oÔ.ä(¨¯©¸$¿,¹,ÔGØùòK
s   Á7Fc                 ó  — i }|| _         | j                   D ]n  }| j                   |   }||vr6t        |«      }| j                  j                  |«       |||<   ||   |_        n|| j                   |      }|j                  |«       Œp y)zqThis function helps to rebuild the partitions given the nodes and its
        corresponding partition id
        N)r`   r
   r;   r1   r   rÃ   )r   r¢   r£   Ú!partition_id_to_partition_mappingr2   rR   r<   s          r   r¡   zPartitioner.aot_based_partition!  s£   € ð CEÐ)Ø!:ˆÔØ×*Ñ*ò 	%ˆDØ×1Ñ1°$Ñ7ˆLàÐ#DÑDÜ% lÓ3�	Ø—‘×&Ñ& yÔ1ØBKÐ1°,Ñ?Ø/RØ ñ0�	Õ,ð >Ø×*Ñ*¨4Ñ0ñ�	ð ×Ñ˜tÕ$ñ	%r   r4   )r   )r$   r%   r&   r'   r   r   ÚtorchÚnnÚModuler   r6   rµ   r)   r¤   r®   r¯   r°   r,   r±   r
   r·   rÂ   r§   r  ry   r   r	   r©   r­   r¡   r*   r   r   r…   r…   "  s  „ ñó(ð
PàðPð —h‘h—o‘oðPð .ð	Pð
 
óPðf =>ñØ69ðà	óó"\ó|C(ðJ&˜kó &ð¨{ð ¸só ð: )ó òðn°sð n¸tó nð`wà%*ðwð "& d¨KÐ&7Ñ!8ðwð 
ó	wðrLà%*ðLð "& d¨KÐ&7Ñ!8ðLð 
ó	Ló\%r   r…   )*r|   Úcollectionsr   Útypingr   r,  Ú'torch.fx.experimental.partitioner_utilsr   r   r   r   r	   r
   r   r   Útorch.fx.graph_moduler   Útorch.fx.noder   r   Ú"torch.fx.passes.graph_manipulationr   Útorch.fx.passes.split_moduler   r   r,   r6   r=   r(   rF   rO   rE   r^   ry   r)   ra   rg   r  ro   r   rƒ   r…   r*   r   r   ú<module>r6     s‚  ðã Ý Ý ã ÷	÷ 	ó 	õ .ß 'Ý DÝ 5÷(ñ (÷. ñ  ô((�jô (ð Fò*ð
ØðØ)2ðØ@DÀYÁðà	óð"¨¨i©ð ¸Tó ð0 d¨9¡oð ¸$ó ð¨¨Y©ð ¸Dó ð8¨d°9©oð À$ÀtÈSÀyÁ/ó ð  d¨6¡lð  °t¸CÀ¸KÑ7Hó  ð"Ø�Y‘ð"Ø*.¨v©,ð"à
ˆ4�˜˜Y™Ð'Ñ(¨$¨v°s¨{Ñ*;¸TÀ)¹_ÐLÑMó"ðJ6Ø�Y‘ð6Ø*.¨v©,ó6òr÷$V%ò V%r   