
    ȅigN                     $   S SK r S SKJrJr  S SKJrJr  S SKrS SK	J
r
  S SKJr  S SKJrJr  SSKJrJrJr  / S	Qr\
" S
S9S 5       r\
" S
S9S 5       r\
" S
S9\ " S S5      5       5       r\
" S
S9S
S
\R0                  R2                  4S\R0                  R2                  S\\   S\S\S\\R0                  R2                     S\\R0                  R2                  \\R0                  R2                  \\\4   4   4   4S jj5       r \
" S
S9SS j5       r!g)    N)	dataclassfield)OptionalUnion)compatibility)map_arg)HolderModulelift_subgraph_as_module   )CALLABLE_NODE_OPSis_node_output_tensorNodeList)getattr_recursivesetattr_recursive	Componentsplit_by_tags!move_non_tensor_nodes_on_boundaryF)is_backward_compatiblec                 (   UR                  S5       H|  n[        U [        R                  R                  5      (       a3  [        U S5      (       a   X R                  ;   a  U R                  U   n M]    g [        X5      (       a  [        X5      n M|    g    U $ )N._modules)split
isinstancetorchnn
ModuleListhasattrr   getattr)objnamelayers      U/home/james-whalen/.local/lib/python3.13/site-packages/torch/fx/passes/split_utils.pyr   r      sq    Cc588..//sJ''E\\,All5)S  #%C ! J    c                     SU;  a  [        XU5        g UR                  S5      n[        [        XS   5      SR	                  USS  5      U5        g )Nr   r   r   )setattrr   r   r   join)r   attrvaluer!   s       r"   r   r   &   sD    
$5!

3'#Qx0#((592EuMr#   c                   j   \ rS rSr% Sr\R                  R                  \S'   \	\S'   \
\S'   \" \S9r\\S'   \" \S9r\\S'   \" \S9r\\S	'   \" \S9r\\R                  R$                  \R                  R$                  4   \S
'   \" \S9r\\
   \S'   Sr\\R                  R,                     \S'   Srg)r   /   zP
A component serves as a container for a subgraph we want to create afterwards.
graphorderr    )default_factoryinput_placeholdersorig_inputsorig_outputsgetattr_mapsconstructor_argsNgm )__name__
__module____qualname____firstlineno____doc__r   fxGraph__annotations__intstrr   listr.   r/   r0   dictr1   Noder2   r3   r   GraphModule__static_attributes__r4   r#   r"   r   r   /   s     88>>J
I  %T:: d3K3 t4L$4 8=T7RL$uxx}}ehhmm34R"'"=d3i=)-B%%&-r#   r   r3   tagsreturn_fqn_mappingreturn_tupleGraphModuleClsreturnc           
      
  ^^^^ S[         R                  R                  R                  S[        4S jn0 m0 m0 n/ n0 m[         R                  R                  5       n0 n	Sn
U HK  n[        [         R                  R                  5       [        U5      U 5      mUR                  T5        TXk'   MM     U R                  R                   GH  nUR                  S:X  a  U
b  [        S5      eUn
M&  UR                  S:X  aO  UR                  UR                  UR                  S9X'   [         R                   " UR"                  5      X   l        M  UR                  S	:X  a  M  [%        US
5      (       d   SUR'                  5        35       eU" UR(                  5      U" UR*                  5      -    Vs/ s H  nUR                  S;  d  M  TU   PM     nnXlR,                     mTTU'   [/        S U 5       SS9nTR0                  U:  d$   STR                   STR0                   SU 35       eUUUU4S jnTR                  R3                  UU5      nUR,                  Ul        UTU'   TTU'   GM     U
c  [        S5      eU" U
R(                  S   5       H@  nUR                  S	:X  a(  UR5                  UR                  UR                  S9X'   M;  STU'   MB     T H3  nUR                  S:w  d  M  TU   R6                  R                  U5        M5     0 nU GHr  m[9        [;        TR<                  TR6                  5      5      nU(       a  TR                  R?                  U5        O/TR                  R?                  [        U5      S:X  a  US   OU5        [A        U TR                  TR                  S9u  Tl!        nURE                  U5        URG                  TR                  [9        [;        U	R<                  TRH                  5      5      SS9n[        U5      S:X  a  U(       d  UU	TR6                  S   '   GM$  [K        TR6                  5       H5  u  nn[         R                  RM                  U5      U   R                  U	U'   M7     GMu     UR?                  [O        U
R(                  S   U	R<                  5      5        [Q        U Vs0 s H  nUR                  URB                  _M     sn5      nU R                  RR                  Ul)        U" U
R(                  S   5       H?  nUR                  S	:X  d  M  [U        UUR                  [W        XRX                  5      5        MA     U" UU5      nU(       a  UU4$ U$ s  snf s  snf )a  
Splits a GraphModule using tags on its graph nodes. We honor the order of
tags. For example, we have tags = ["a", "b", "c"], the function will create
the initial submodules in the order of "a", "b", "c".

To set a tag:
gm.graph.nodes[idx].tag = "mytag"

This will result in all nodes with the same tag being extracted and placed in their
own submodule. For placeholder, output and get_attr node, the tag is ignored. placeholder
and output nodes are created when needed while get_attr nodes get copied to submodules
where they are used.

Given the following module def:

class SimpleModule(torch.nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.linear1 = torch.nn.Linear(...)
        self.linear2 = torch.nn.Linear(...)
        self.linear3 = torch.nn.Linear(...)

    def forward(self, in1, in2):
        r1 = self.linear1(in1)
        r2 = self.linear2(in2)
        r3 = torch.cat([r1, r2])
        return self.linear3(r3)

Marking the node corresponding to in1 with the tag sc.REQUEST_ONLY.lower() results in the following split:

ro:
def forward(self, in1):
    self = self.root
    linear1 = self.linear1(in1)
    return linear1

main:
def forward(self, in2, linear1):
    self = self.root
    linear2 = self.linear2(in2)
    cat_1 = torch.cat([linear1, linear2])
    linear3 = self.linear3(cat_1)
    return linear3

main:
def forward(self, in1, in2):
    self = self.root
    ro_0 = self.ro_0(in1)
    main_1 = self.main_1(in2, ro_0)
    return main_1

Returns:
    split_gm: torch fx graph after split
    orig_to_split_fqn_mapping: a map between the original fqn and the fqn
        after split for call_module and get_attr.
xrH   c                 4    / n[        XR                  5        U$ )z3
Stores nodes in x to a list and returns the list.
)r   append)rJ   rs     r"   flattensplit_by_tags.<locals>.flatten   s     88r#   NoutputzMultiple output nodes in graph!placeholder	type_exprget_attrtagzNode does not have tag: >   rT   rQ   c              3   8   #    U  H  oR                   v   M     g 7fN)r,   ).0cs     r"   	<genexpr> split_by_tags.<locals>.<genexpr>   s     7#6a''#6s   r   )defaultz
Component z8 order must be >= max of its upstream components, order=z	 and max=c                   > U R                   S:X  a  U TR                  ;  am  TR                  R                  U R                  U R
                  S9TR                  U '   [        R                  " U R                  5      TR                  U    l        TR                  U    $ U R                   S:w  a  TU    T:X  a  TU    $ U TR                  ;  a  TR                  R                  U 5        TR                  R                  U R                  U R
                  S9n[        R                  " U R                  5      Ul        TR                  R                  U5        S TU '   TR                  TR                  R                  U 5         $ )NrT   rR   rQ   )opr1   r+   rT   targettypecopymetar/   rL   rQ   r    r.   index)rJ   rQ   compnode_remappingnode_to_componentused_in_mains     r"   
remap_func!split_by_tags.<locals>.remap_func   sB    ttz!D---+/::+>+>AFF ,? ,D%%a( 15		!&&0AD%%a(-((++
 tt}$):1)=)E%a(( (((  ''*"jj44QVVqvv4N#'99QVV#4 ''..{;"&Q**4+;+;+A+A!+DEEr#   zGraph had no output node!r   )subgraph	comp_name)argskwargs)-r   r:   nodeArgumentr   r;   r   lenrL   r+   nodesr^   RuntimeErrorrQ   r    r`   ra   rb   r   format_noderl   rm   rU   maxr,   	node_copyrT   r0   tuplemap__getitem__rP   r
   r3   updatecall_moduler/   	enumerateProxyr   r	   _codegenr%   r   r_   )r3   rD   rE   rF   rG   rN   tag_to_componentall_componentsmain_gmain_remappingoutput_noderU   rn   rJ   upstream_componentsmxrh   norig_to_split_fqn_mappingoutscomp_orig_to_split_fqn_mapping	main_nodeiord   	main_root	result_gmre   rf   rg   s                           `  @@@r"   r   r   I   s	   B588==)) h  :<N 9; .0 ')N /1L XX^^F :<N ,0K )3~+>3%Id# $  77h&"#DEEK 77m##)#5#5dii499#5#UN (,		$))(<N % 77j  tU##T'?@P@P@R?S%TT# TYY''$++*>>
>tt66 !a > 	 
  )"&$ 7#67C zzR 	
#[\`\f\f[ggpqsptu	

	F 	F8 JJ  z2 t#!O R 677[%%a()44: !'!&& IN #LO * 44= a --44Q7 
 13S33T5F5FGHJJd# JJTad1gTB2Ityy3
// 	"(()GH &&IIs>55t7G7GHI ' 
	 t9>,3<N4,,Q/0!$"3"341$)HHNN9$=a$@$E$Eq! 57 > MM'+**1-~/I/IJK^L^Tdii0^LMIhh''FO [%%a()44:Iqvv'8XX'FG * y&1I333m
R Ms   .U5	U5!U:c                 p  ^^ 0 m[        U 5       H  u  pUR                   H  nUTU'   M
     M     S[        R                  R                  S[
        [        R                  R                     4U4S jjmS[        R                  R                  S[
        [        R                  R                     4U4S jjnS[        R                  R                  S[        S[        4UU4S jjnS[        R                  R                  S[        S[        S[        [        [        [        R                  R                     4   4UU4S	 jjn[        U 5       GHd  u  prUR                  (       d  M  / n[        5       n	UR                   H5  n[        U5      (       a  M  U" X75      (       d  M$  UR                  U5        M7     U(       d  Ms  UR                  S
5      n
X;   a  M!  U	R                  U
5        U
T;  d	  TU
   U:w  a  MC  T" U
5      n[        U5      S
:  d   S5       e[        5       nU H   nTU   nX:w  d  M  UR                  U5        M"     [        U5      S:w  a  [!        SU
R"                   S35        M  UR                  5       nU" XU5      u  nnU(       Ga  U H  nUR                  R%                  U5        X   R                  R                  U5        UTU'   [!        SU
R"                   SUR"                   SUR                  (       a  SOS SU SX   R                  (       a  SOS SU 35        M     U" U
5      nU Hd  n[        U5      (       a  M  UU	;  d  M  UT;   d  M%  TU   U:X  d  M0  U" UU5      (       d   SUR"                   S35       eUR                  U5        Mf     U(       a  GM  GMg     g)a  
Move non-tensor nodes on the boundary between subgraphs.

For each subgraph:

1. Find nodes whose type is not tensor and any of its children is in another
   subgraph, put them in a queue for next step

2. Do a BFS on those nodes in the queue,  and run a DFS for each node, let's say node X and it is in subgraph A:

   a. if it is in to_subgraph, return (continue DFS)
   b. if it is in from_subgraph, collect the nodes to nodes_to_move, and continue DFS
   c. otherwise, this means it cannot be moved
   d. also check if node X's parent should be put into the queue. (The queue may
      have duplicated nodes, just process the node once)

Args:
    subgraphs: List of subgraphs containing nodes to be processed
rn   rH   c                    > U R                    Vs/ s H#  nUR                  [        ;   d  M  UT;   d  M!  UPM%     sn$ s  snf )z@Get children nodes that are in callable ops and in some subgraph)usersr^   r   )rn   usernode_to_subgraphs     r"   get_children_in_graph@move_non_tensor_nodes_on_boundary.<locals>.get_children_in_graph\  sI     


"ww++ 048H0H "
 	
 
   ===c                    > U R                    Vs/ s H#  nUR                  [        ;   d  M  UT;   d  M!  UPM%     sn$ s  snf )z>Get parent nodes that are in callable ops and in some subgraph)all_input_nodesr^   r   )rn   argr   s     r"   get_parents_in_graph?move_non_tensor_nodes_on_boundary.<locals>.get_parents_in_graphd  sK     ++
+vv** /26F/F +
 	
 
r   current_subgraph_idxc                 B   >^ T" U 5      n[        UU4S jU 5       5      $ )z
Check if the node has any children in a subgraph different from current_subgraph_idx.
This is the requirement used in both step 1 and step d.
c              3   4   >#    U  H  nTU   T:g  v   M     g 7frW   r4   )rX   childr   r   s     r"   rZ   \move_non_tensor_nodes_on_boundary.<locals>.has_children_in_other_subgraph.<locals>.<genexpr>t  s       
IQU#';;s   )any)rn   r   childrenr   r   s    ` r"   has_children_in_other_subgraphImove_non_tensor_nodes_on_boundary.<locals>.has_children_in_other_subgraphl  s)     ). 
IQ
 
 	
r#   from_subgraphto_subgraphc                 n   >^^^^^^ [        5       m[        5       mSmUUUUUUUU4S jmT" U 5        TT4$ )a]  
Check if node and its dependencies can be moved from from_subgraph to to_subgraph.
Returns (can_move, nodes_to_move)

For node X, do a DFS on its descendants, for each node:
- if it is in to_subgraph, return (continue DFS)
- if it is in from_subgraph, collect the nodes to nodes_to_move, and continue DFS
- otherwise, this means it cannot be moved
Tc                    > U T;   a  g TR                  U 5        U T;  a  g TU    nUT
:X  a  g UT:X  a  T	R                  U 5        OSmg T" U 5      nU H  nT(       d  M  T" U5        M     g )NF)add)current_nodecurrent_subgraphr   r   can_movedfsr   r   r   nodes_to_mover   visiteds       r"   r   Vmove_non_tensor_nodes_on_boundary.<locals>.can_move_node_and_dependencies.<locals>.dfs  s     w&KK% #33/=;.!]2!!,/ ! -\:H!8J "r#   )set)	rn   r   r   r   r   r   r   r   r   s	    ``@@@@r"   can_move_node_and_dependenciesImove_non_tensor_nodes_on_boundary.<locals>.can_move_node_and_dependenciesx  s6     %	 	> 	D	&&r#   r   z:Only node that has children in other subgraph can be movedr   zCannot move non-tensor node z: on boundary because it has children in multiple subgraphsz"In order move the non-tensor node z on boundary, moved node z from accgpu_z to zParent z) should have children in another subgraphN)r{   rq   r   r:   rA   r?   r=   boolrv   r   is_accr   rL   popr   rp   printr    remove)	subgraphsr   rj   rn   r   r   r   subgraph_idxqueue	processedr   r   target_subgraph_candidatesr   child_subgraphtarget_subgraphr   r   node_to_moveparentsparentr   r   s                        @@r"   r   r   A  s}   , 24 +NND%&T" # ,
EHHMM 
d588==6I 

588== 
T%((--5H 


hhmm

36

	

 

1'hhmm1',/1'>A1'	tS''	(1' 1'h #,I"6%'(+	NND$T** .dAAT" # e 99Q<L (MM,' $44#L1\A,\:Hx=1$ L$
 *-&!!1%!8!1.22>B "
 -.!32<3D3D2EE  A 8<<>O 'EO'#Hm $1LNN)),7.44;;LI5D$\2<\=N=N<O P&&2&7&7%8u]b>ccdeqdr s'0'A'H'HeeTTUVeUfh %2 /|<%F1&99")3"&66,V4D  >flSS %fkk]2[\S V, &u e% #7r#   )rH   N)"ra   dataclassesr   r   typingr   r   torch.fxr   torch.fx._compatibilityr   torch.fx.graphr   torch.fx.passes.utilsr	   r
   tools_commonr   r   r   __all__r   r   r   r:   rB   r?   r>   r   r`   rv   r@   r   r   r4   r#   r"   <module>r      sX    ( "  1 " G L L e, - e,N -N e,
. .  -.0 e,  %161E1Ett
s)t t 	t
 --.t 588uxx';';T#s(^'K!LLMt -tn e,A- -A-r#   