
    -`i8Q                     `   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 d dl	m
Z
 d dlmZ d dlmZ d dlZd dlmZmZ d dlmZmZmZmZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dl m!Z! d dl"m#Z#  ee$          Z%ej&        dd         dk    p#ej&        dd         dk    oej&        d         dk    Z'd Z(d Z)d Z*	 d.dej+        de,de-de
ej+                 fdZ.de,de,de,de/e,e,f         fdZ0e j1         G d d                       Z2d!ed"e,d#e,d$edef
d%Z3d&e4d'e,d(e,d)e,d*e4defd+Z5d,eddfd-Z6dS )/    N)deque)Sequence)	timedelta)Any)ProcessGroupTCPStore)BackendPrefixStore_get_default_timeout_unregister_process_group)
rendezvous)init_logger)get_tcp_uri)suppress_stdout)is_torch_equal_or_newer   )r            )r   
      c                  f    t           rt          j                     d S t          j        d           d S )Nr   )USE_SCHED_YIELDossched_yieldtimesleep     j/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/vllm/distributed/utils.pyr   r   .   s/     

1r   c                 T    | |z  dk    sJ d                     | |                      dS )z6Ensure that numerator is divisible by the denominator.r   z{} is not divisible by {}N)format	numeratordenominators     r    ensure_divisibilityr&   5   s<    {"a''')D)K)K;* *'''''r   c                 ,    t          | |           | |z  S )zXEnsure that numerator is divisible by the denominator and return
    the division value.)r&   r#   s     r    divider(   <   s     	;///##r   Ftensornum_partitionscontiguous_split_chunksreturnc                     |                                  dz
  }t          |                                 |         |          }t          j        | ||          }|rt          d |D                       S |S )a5  Split a tensor along its last dimension.

    Arguments:
        tensor: input tensor.
        num_partitions: number of partitions to split the tensor
        contiguous_split_chunks: If True, make each chunk contiguous
                                 in memory.

    Returns:
        A list of Tensors
    r   )dimc              3   >   K   | ]}|                                 V  d S N)
contiguous).0chunks     r    	<genexpr>z.split_tensor_along_last_dim.<locals>.<genexpr>Z   s.      AAEU%%''AAAAAAr   )r.   r(   sizetorchsplittuple)r)   r*   r+   last_dimlast_dim_sizetensor_lists         r    split_tensor_along_last_dimr<   C   st    " zz||aH6;;==2NCCM+fmBBBK BAA[AAAAAAr   num_hidden_layerspp_rankpp_sizec                   
 t           j        }|	 d |                    d          D             }n5# t          $ r(}t          d                    |                    |d}~ww xY wt          |          |k    r#t          dt          |          d|d          t          |          | k    r#t          dt          |          d	| d          n| |z  

fd
t          |          D             }| |z  x}r_t          d|dz             D ]}|| xx         dz  cc<   t          	                    dd
                    d |D                                  t          |d|                   }|||         z   }	||	fS )a  Try to evenly distribute layers across partitions.

    If the number of layers is not divisible by the number of partitions,
    the remaining layers are evenly distributed across all but the last
    partition. The last partition is excluded because it often contains an
    additional norm layer and we are attempting to balance compute.

    If `pp_size > 2` and the number of remaining layers is
    `0 < x <= pp_size - 2` then the remaining layers are evenly distributed
    across the middle partitions. The first and last partitions are excluded
    because they contain the input and output embeddings respectively and we
    are attempting to reduce maximum memory consumption across partitions.
    Nc                 ,    g | ]}t          |          S r   )int)r2   layers     r    
<listcomp>z"get_pp_indices.<locals>.<listcomp>r   s    PPP#e**PPPr   ,zInvalid partition string: {}zlen(partitions)=z does not match pp_size=.zsum(partitions)=z" does not match num_hidden_layers=c                     g | ]}S r   r   )r2   _layers_per_partitions     r    rD   z"get_pp_indices.<locals>.<listcomp>}   s    CCCq*CCCr   r   r   zHidden layers were unevenly partitioned: [%s]. This can be manually overridden using the VLLM_PP_LAYER_PARTITION environment variablec              3   4   K   | ]}t          |          V  d S r0   )str)r2   ps     r    r4   z!get_pp_indices.<locals>.<genexpr>   s(      44AQ444444r   )envsVLLM_PP_LAYER_PARTITIONr7   
ValueErrorr"   lensumrangeloggerinfojoin)r=   r>   r?   partition_list_str
partitionserrremaining_layersistart_layer	end_layerrI   s             @r    get_pp_indicesr]   _   s     5%	PP2D2J2J32O2OPPPJJ 	 	 	.556HII 	 z??g%%MJMM'MMMNNNz??///WJWWBSWWWXXX 0  1G;CCCCE'NNCCC
07:: 	1.233 $ $A2!#KK? 4444444	   j'*++Kj11I##s   1 
A##AA#c                   ,   e Zd ZU dZeed<   eed<   ej        j        j	        ed<   e
j
        dz  ed<   dZeed<    ej        e	          Zeeef         ed
<    ej        e	          Zeeef         ed<   dZeed<    ej        e	          Zeeef         ed<    ej        e	          Zeeeef                  ed<   d ZdedefdZd ZdedefdZdedz  dedefdZdedee         fdZd"defdZ e!	 	 d#dededededed edd fd!            Z"dS )$StatelessProcessGroupzA dataclass to hold a metadata store, and the rank, world_size of the
    group. Only use it to communicate metadata between processes.
    For data-plane communication, create NCCL-related objects.
    rank
world_sizestoreNsocket  data_expiration_seconds)default_factorysend_dst_counterrecv_src_counterr   broadcast_send_counterbroadcast_recv_src_counterentriesc                     | j         | j        k     sJ d t          | j                  D             | _        d t          | j                  D             | _        d t          | j                  D             | _        d S )Nc                     i | ]}|d S r   r   r2   rZ   s     r    
<dictcomp>z7StatelessProcessGroup.__post_init__.<locals>.<dictcomp>        F F F!A F F Fr   c                     i | ]}|d S rn   r   ro   s     r    rp   z7StatelessProcessGroup.__post_init__.<locals>.<dictcomp>   rq   r   c                     i | ]}|d S rn   r   ro   s     r    rp   z7StatelessProcessGroup.__post_init__.<locals>.<dictcomp>   s    *P*P*PA1a*P*P*Pr   )r`   ra   rR   rg   rh   rj   )selfs    r    __post_init__z#StatelessProcessGroup.__post_init__   s}    y4?**** F FuT_/E/E F F F F FuT_/E/E F F F*P*Pt9O9O*P*P*P'''r   objdstc                 2   |                                   d| d| j        |          }| j                            |t	          j        |                     | j        |xx         dz  cc<   | j                            |t          j                    f           dS )z%Send an object to a destination rank.send_to//r   N)	expire_datarg   rb   setpickledumpsrk   appendr   )rt   rv   rw   keys       r    send_objzStatelessProcessGroup.send_obj   s    ;;;t4S9;;
sFL--...c"""a'"""S$)++./////r   c                     | j         rn| j         d         \  }}t          j                    |z
  | j        k    r4| j                            |           | j                                          ndS | j         ldS dS )zAExpire data that is older than `data_expiration_seconds` seconds.r   N)rk   r   re   rb   
delete_keypopleft)rt   r   	timestamps      r    r{   z!StatelessProcessGroup.expire_data   s    l 	!\!_NCy{{Y&)EEE
%%c***$$&&&& l 	 	 	 	 	r   srcr,   c           	          t          j        | j                            d| j         d| j        |                              }| j        |xx         dz  cc<   |S )z%Receive an object from a source rank.ry   rz   r   )r}   loadsrb   getr`   rh   )rt   r   rv   s      r    recv_objzStatelessProcessGroup.recv_obj   se    lJNNNdiNN$2G2LNNOO
 
 	c"""a'"""
r   c                    | j         |k    r|                                  d| d| j         }| j                            |t          j        |                     | xj        dz  c_        | j                            |t          j	                    f           |S d| d| j
        |          }t          j        | j                            |                    }| j
        |xx         dz  cc<   |S )zBroadcast an object from a source rank to all other ranks.
        It does not clean up after all ranks have received the object.
        Use it for limited times, e.g., for initialization.
        zbroadcast_from/rz   r   )r`   r{   ri   rb   r|   r}   r~   rk   r   r   rj   r   r   )rt   rv   r   r   r   s        r    broadcast_objz#StatelessProcessGroup.broadcast_obj   s    
 9GCGG$*EGGCJNN3S 1 1222''1,''Ldikk 2333JPCPP$*I#*NPPC|DJNN3$7$788H+C000A5000Or   c                 
   g }t          | j                  D ]k}|| j        k    r2|                    |           |                     || j                   ?|                     d|          }|                    |           l|S )z$All gather an object from all ranks.r   N)rR   ra   r`   r   r   )rt   rv   gathered_objsrZ   r   s        r    all_gather_objz$StatelessProcessGroup.all_gather_obj   s    t'' 	/ 	/ADI~~$$S)))""3DI"6666--d-::$$X....r         >@timeoutc           	         	 | j         dk    r.dt          j                     }|                     |d           n|                     dd          }n"# t          $ r}t          d          |d}~ww xY wd| d| j          }	 | j                            |d           n"# t          $ r}t          d	          |d}~ww xY wt          j                    }t                      }t          |          | j
        k     rt          j                    }||z
  |k    rt          d
|dd          t          | j
                  D ]}||v rd| d| }		 | j                            |	           |                    |           @# t          $ r Y Lt          $ r3}
t                              d|
           t#                       Y d}
~
d}
~
ww xY wt          |          | j
        k     rt#                       t          |          | j
        k     d| d| j          }	 | j                            |d           n"# t          $ r}t          d          |d}~ww xY w| j         dk    rdS t          j                    }t                      }t          |          | j
        k     rt          j                    |z
  |k    rt          d|dd          t          | j
                  D ]}||v rd| d| }		 | j                            |	           |                    |           @# t          $ r Y Lt          $ r3}
t                              d|
           t#                       Y d}
~
d}
~
ww xY wt          |          | j
        k     rt#                       t          |          | j
        k     t          | j
                  D ]}	 | j                            d| d|            n1# t          $ r$ t                              dd| d|            Y nw xY w	 | j                            d| d|            w# t          $ r$ t                              dd| d|            Y w xY wdS )aq  A robust barrier to synchronize all ranks.


        Uses a multi-phase approach to ensure all processes reach the barrier
        before proceeding:

        1. Each process signals it has reached the barrier

        2. Each process signals that it has confirmed the arrival of all other
        ranks.

        3. Rank 0 waits for all other ranks to signal their departure to ensure
        that all ranks have departed the barrier first.

        Args:
            timeout: Maximum time in seconds to wait for each phase (in seconds)


        Raises:
            RuntimeError: If coordination fails or times out
        r   barrier_r   NzFailed to broadcast barrier_idarrival_rH      1z Failed to signal barrier arrivalzBarrier timed out after z.2fz secondsz Error checking key existence: %s
departure_z"Failed to signal barrier departurez"Barrier departure timed out after zError deleting key: %s)r`   uuiduuid4r   	ExceptionRuntimeErrorrb   r|   r   rP   ra   rR   r   addKeyErrorrS   debugr   r   )rt   r   
barrier_idearrival_key
start_timeprocesses_arrivedcur_timerZ   r   check_edeparture_keyprocesses_departeds                r    barrierzStatelessProcessGroup.barrier   su   .	HyA~~6
66
"":1"5555!//!/<<
 	H 	H 	H?@@aG	H :99di99	JJNN;---- 	J 	J 	JABBI	J Y[[
&)ee#$$t66y{{H*$w.."#Sg#S#S#S#STTT 4?++ " ")))111a11
" JNN3'''%))!,,,,   D  " " "LL!CWMMMMMMMMMMM"
 $%%775 #$$t66F >Z==$)==	LJNN=$//// 	L 	L 	LCDD!K	L 9>>F Y[[
'*uu$%%77y{{Z''11"NNNNN  
 4?++ " "***3:3333
" JNN3'''&**1----   D  " " "LL!CWMMMMMMMMMMM"
 %&&887 $%%77< t'' 		V 		VAT
%%&A&A&Aa&A&ABBBB T T T57R*7R7Rq7R7RSSSSSTV
%%&C:&C&C&C&CDDDD V V V57TJ7T7TQR7T7TUUUUUV		V 		Vs   AA 
A2A--A2B 
B>)B99B>/E??
G	G)GGH3 3
I=II./L
M&*	M&3)M!!M&? O  +PP P33+Q! Q!,  hostportstore_timeoutc           	         |dk    }|rt          j         t           j        t           j                  }|                    t           j        t           j        d           |                    | |f           |                                 |                                }nd}d}t          | |||t          |          d|          }	t          |||	||          S )a  A replacement for `torch.distributed.init_process_group` that does not
        pollute the global state.

        If we have process A and process B called `torch.distributed.init_process_group`
        to form a group, and then we want to form another group with process A, B, C,
        D, it is not possible in PyTorch, because process A and process B have already
        formed a group, and process C and process D cannot join that group. This
        function is a workaround for this issue.

        `torch.distributed.init_process_group` is a global call, while this function
        is a stateless call. It will return a `StatelessProcessGroup` object that can be
        used for exchanging metadata. With this function, process A and process B
        can call `StatelessProcessGroup.create` to form a group, and then process A, B,
        C, and D can call `StatelessProcessGroup.create` to form another group.
        r   r   N)secondsF)	host_namer   ra   	is_masterr   	use_libuvmaster_listen_fd)r`   ra   rb   rc   re   )rc   AF_INETSOCK_STREAM
setsockopt
SOL_SOCKETSO_REUSEADDRbindlistenfilenor   r   r_   )
r   r   r`   ra   re   r   launch_serverlisten_socket	listen_fdrb   s
             r    createzStatelessProcessGroup.createn  s    0 	 		"M&.&:LMMM$$V%68KQOOOd|,,,  """%,,..II MI!#m444&
 
 
 %! $;
 
 
 	
r   )r   )rd   r   )#__name__
__module____qualname____doc__rB   __annotations__r6   _C_distributed_c10dStorerc   re   dataclassesfielddictrg   rh   ri   rj   r   rk   r8   rK   floatru   r   r   r{   r   r   listr   r   staticmethodr   r   r   r    r_   r_      s         
 IIIOOO8%++++ MD    #'S''' (9{'8'N'N'Nd38nNNN'8{'8'N'N'Nd38nNNN"#C###1B1BSW1X1X1XS#XXXX ):(9%(P(P(PGU5e$%PPPQ Q Q0C 0c 0 0 0 0	 	 	C C    t # #    $
# 
$s) 
 
 
 
DV DVu DV DV DV DVL  (, 3
 3
3
3
 3
 	3

 "%3
 3
 
!3
 3
 3
 \3
 3
 3
r   r_   prefix_store
group_rank
group_sizer   c                    t                      5  t          d          rt          | ||          }n't          j        d          }t          | |||          }ddlm}  || |||          }t          j        j        }t          j	        d          }	t          d          r|
                    |           |                                 |                    |	||           ddd           n# 1 swxY w Y   |S )	ze
    Stateless init ProcessGroup with gloo backend compatible with
    different torch versions.
    z2.6gloo)backendr   )ProcessGroupGloor   cpuN)r   r   r   Options"torch.distributed.distributed_c10dr   BackendTypeGLOOr6   device_set_default_backend_set_sequence_number_for_group_register_backend)
r   r   r   r   pgoptionsr   backend_classbackend_typer   s
             r    init_gloo_process_groupr     sv    
		 B B"5)) 	 BB #*6:::G	 B 	HGGGGG((*j'
 
 
 $/4e$$"5)) 	2##L11144666
V\=AAA7B B B B B B B B B B B B B B B8 Is   CC--C14C1r   r   r`   ra   r   c                    t          | |          }t          |          }t          |          }t          t	          ||||                    \  }}}|                    |           |}|}	t          ||          }
	 ddlm} |	                    ||
||	|          S # t          $ r t          |
||	|          cY S w xY w)a  
    A replacement for `torch.distributed.init_process_group` that does not
    pollute the global state. The created ProcessGroup object can be used for
    some operations such as `allreduce`, because it does not depend on the
    global rank. However, some operations such as `broadcast` cannot be used
    because it depends on the global rank.

    # TODO: ask for help from PyTorch team if we need the `broadcast` operation.

    This function is useful when we are not sure about the total number of
    processes in the process group. For example, we may have process
    1, 2, ..., 8 who want to communicate, and process 9 might be the same
    process as process 1, or it might be a different process; process 10
    might be the same process as process 5, or it might be a different process.
    In this case, how can we reliably form a communication channel within
    process 9 and 10, without affecting the communication channel within
    process 1, 2, ..., 8?

    One possible solution is to figure out if process 9 and 10 are the same
    as process 1 and 5 beforehand, and then form a communication channel
    based on the information, adjusting the ranks and world_size etc. However,
    figuring out the information is not always easy, and it will interfere
    with the main communication channel.

    Our solution is to always form a communication channel with process 1, 2,
    ..., 8, and then use this function to form another communication channel
    with process 9 and 10. This way, regardless of whether process 9 and 10
    are the same as process 1 and 5, the main communication channel is
    always formed with process 1, 2, ..., 8, and the additional communication
    channel is formed with process 9 and 10.
    r   r   )current_platform)r   r   r   r   r   )r   r   r   r   )r   r	   r   nextr   set_timeoutr
   vllm.platformsr   #stateless_init_device_torch_dist_pgNotImplementedErrorr   )r   r   r`   ra   r   init_methodr   rb   r   r   r   r   s               r    .stateless_init_torch_distributed_process_groupr     s   D dD))KgG"7++G";j'BBB E4 
gJJ {E22L
333333CC%!! D 
 
 	
  
 
 
 '%!!	
 
 
 	
 	
 	

s   =B B=<B=r   c                     t          d          r|                                  nddlm}  ||            t	          | j                   dS )zd
    Destroy ProcessGroup returned by
        stateless_init_torch_distributed_process_group().
    z2.7r   )_shutdown_backendN)r   shutdownr   r   r   
group_name)r   r   s     r    1stateless_destroy_torch_distributed_process_groupr     s_    
 u%% 
 	IHHHHH"bm,,,,,r   )F)7r   r   r}   rc   sysr   r   collectionsr   collections.abcr   datetimer   typingr   r6   torch.distributedr   r   r   r	   r
   r   r   torch.distributed.rendezvousr   	vllm.envsrM   vllm.loggerr   vllm.utils.network_utilsr   vllm.utils.system_utilsr   vllm.utils.torch_utilsr   r   rS   version_infor   r   r&   r(   TensorrB   boolr<   r8   r]   	dataclassr_   r   rK   r   r   r   r   r    <module>r     se       				   



         $ $ $ $ $ $              4 4 4 4 4 4 4 4            4 3 3 3 3 3       # # # # # # 0 0 0 0 0 0 3 3 3 3 3 3 : : : : : :	X		
 #BQB':5 RaRG#@(8(;q(@ 
    $ $ $ %* L " el	   8-$-$%(-$36-$
38_-$ -$ -$ -$` R
 R
 R
 R
 R
 R
 R
 R
j&&& & 	&
 & & & &RC

C
C
 #C
14C
?BC
C
 C
 C
 C
L-, -4 - - - - - -r   