o
    
۾i*                     @   s  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
mZ d dlmZ d dlmZ d	d
lmZmZ d	dlmZ zd dlmZ d dlZd dlZW n eyh   eddZedZedZY nw deee f de!e fddZ"dddeee f de!e de#de$dB fddZ%deee f dedB de$dB fddZ&deee f dedB de$fddZ'deee f d ede$fd!d"Z(d#e!eee f  dedB dedB de)e!eee f  e*f fd$d%Z+d&d'd(d)d*ed+ed,e$dd)f
d-d.Z,d/e	d0e)e)eef d1f de	fd2d3Z-d/e	d4e)e)e)eef d1f e!eee f  f d5e!e d6e#fd7d8Z.d9e	dedB dedB d5e!e d6e#f
d:d;Z/eG d<d= d=Z0d>e0fd?d@Z1d>e j2fdAdBZ3e4dCkrpe j5e0j6dDZ7e08e7 e3e79  dS dS )E    N)ProcessPoolExecutor)	dataclass)partial)Path)ClassVar)full_groupby)PlaceholderModule   )DummyExecutor_json_load_bytes)sanitize_filename
matplotlibpyplotpandasseabornrun_datakeysc                 C   sF   |D ]}|| dd| ddhD ]}|| v r| |     S qqd S )N_-)replace)r   r   key	candidate r   U/home/ubuntu/.local/lib/python3.10/site-packages/vllm/benchmarks/sweep/plot_pareto.py_first_present   s   r   T
allow_zeror   returnc             
   C   sp   t | |}|d u rd S zt|}W n ttfy- } ztd| d|d| |d }~ww |s6|dkr6d S |S )Nz"Expected numeric value for one of z, but found z in run_data=r   )r   float	TypeError
ValueError)r   r   r   valuenumericexcr   r   r   _get_numeric#   s(   
r$   user_count_varc                 C   sD   |r|gng }| dg t| |dd}|d ur|S t| dgddS )Nrequest_rateFr   max_concurrent_requests)extendr$   )r   r%   
candidates
user_countr   r   r   _infer_user_count;   s   r+   gpu_count_varc                 C   sz   |r|gng }t | |dd}|r|S t | ddg}t | ddg}t | ddg}d	}|r/||9 }|r5||9 }|r;||9 }|S )
NFr   tensor_parallel_sizetppipeline_parallel_sizeppdata_parallel_sizedpg      ?)r$   )r   r,   direct_candidatesdirect_gpu_counttp_sizepp_sizedp_size
world_sizer   r   r   _infer_gpu_countI   s   r9   throughput_varc                 C   s0   t | |g}|d u rtd|dt|  |S )NzCannot find throughput metric z in run data. Available keys: )r$   r    sorted)r   r:   
throughputr   r   r   _get_throughput`   s   r=   all_datac             	   C   sv   g }d}| D ]0}t |d}t||}|d u r|d7 }qt||}|| }	|| }
|i ||	|
||d q||fS )Nr   output_throughputr	   )tokens_per_usertokens_per_gpuuser_count_estimate	gpu_count)r=   r+   r9   append)r>   r%   r,   preparedskipped_missing_usersrecordr<   r*   rC   r@   rA   r   r   r   _prepare_recordsn   s,   



rH   g&.>)epsilondfzpd.DataFramex_coly_colrI   c          
      C   sf   | j ||gddgd}g }tj }| D ]\}}|| }	|	|| kr-|| t||	}q| j| S )NF)	ascending)sort_valuesmathinfiterrowsrD   maxloc)
rJ   rK   rL   rI   	sorted_dffrontier_indicesbest_yidxrowy_valr   r   r   _pareto_frontier   s   


rZ   fig_dir	fig_group.c                 C   s8   dg}|r| dd |D  td|d }| | S )NPARETOc                 s   s"    | ]\}}| d | V  qdS )=Nr   ).0kvr   r   r   	<genexpr>   s     z _get_fig_path.<locals>.<genexpr>r   z.png)r(   r   join)r[   r\   partsfilenamer   r   r   _get_fig_path   s
   rf   fig_group_datalabel_bydry_runc             	   C   s  |\}}t | |}td tdt|  td|  |r%td d S tj|}|jddgd}|jr@td td d S t|dd}|	d}t
 \}	}
tj|ddd	d
|
dd tj|ddd|
dd |r| D ]-\}}g }|D ]}||v r|| d||   qv|r|
j|d |d d|dd qn|
d |
d |
jdddd
d |	  |	| t
|	 tdt| dt| d td d S )Nz[BEGIN FIGURE]zGroup: zOutput file: z[END FIGURE]r@   rA   )subsetz3No data points available after filtering; skipping.z0.5g333333?zAll runs)dataxycoloralphaaxlabelozPareto frontier)rk   rl   rm   markerrp   rq   r^   
   )fontsizezTokens/s/userzTokens/s/GPUTz--g      ?)	linestyle	linewidthro   zPlotted z points; Pareto frontier size: .)rf   printdictpd	DataFramefrom_recordsdropnaemptyrZ   rN   pltsubplotssnsscatterplotlineplotrQ   rD   textrc   
set_xlabel
set_ylabelgridtight_layoutsavefigcloselen)r[   rg   rh   ri   r\   fig_datafig_pathrJ   frontierfigrp   r   rX   label_partsr   r   r   r   	_plot_fig   sv   

		



r   
output_dirc             
   C   s   | d }dd |  dD }|std|  |jddd t|||d\}}|r1td	| d
 |s7tdt|dd d}	t|	dkrHt nt }
t	|

tt|||d|	 W d    d S 1 sew   Y  d S )Nparetoc                 S   s   g | ]}t |D ]}|qqS r   )r   )r_   pathr   r   r   r   
<listcomp>  s    zplot_pareto.<locals>.<listcomp>z**/summary.jsonz/Did not find any parameter sweep results under T)parentsexist_ok)r%   r,   zSkipped zL runs without a user count (`max_concurrency` or `max_concurrent_requests`).zUNo data points with both throughput and user count available to plot Pareto frontier.c                 S   s   t  S N)tuple)itemr   r   r   <lambda>!  s    zplot_pareto.<locals>.<lambda>)r   r	   )rh   ri   )rglobr    mkdirrH   rz   r   r   r
   r   allmapr   r   )r   r%   r,   rh   ri   r[   raw_dataprepared_datarF   
fig_groupsexecutorr   r   r   plot_pareto   sJ   

"r   c                   @   s   e Zd ZU eed< edB ed< edB ed< ee ed< eed< dZe	e ed< d	Z
e	e ed
< edejfddZedejfddZdS )SweepPlotParetoArgsr   Nr%   r,   rh   ri   r   parser_namezYPlot Pareto frontier between tokens/s/user and tokens/s/GPU from parameter sweep results.parser_helpargsc                 C   sN   t |j}| std| |jsg n|jd}| ||j|j||jdS )Nz!No parameter sweep results under ,r   r%   r,   rh   ri   )	r   
OUTPUT_DIRexistsr    rh   splitr%   r,   ri   )clsr   r   rh   r   r   r   from_cli_args@  s   
z!SweepPlotParetoArgs.from_cli_argsparserc                 C   s\   |j dtddd |j dtddd |j dtd d	d |j d
tddd |j dddd |S )Nr   resultsz3The directory containing the sweep results to plot.)typedefaulthelpz--user-count-varmax_concurrencyz_Result key that stores concurrent user count. Falls back to max_concurrent_requests if missing.z--gpu-count-varzResult key that stores GPU count. If not provided, falls back to num_gpus/gpu_count or tensor_parallel_size * pipeline_parallel_size.z
--label-byzmax_concurrency,gpu_countzEComma-separated list of fields to annotate on Pareto frontier points.z	--dry-run
store_truez8If set, prints the figures to plot without drawing them.)actionr   )add_argumentstr)r   r   r   r   r   add_cli_argsP  s<   z SweepPlotParetoArgs.add_cli_args)__name__
__module____qualname__r   __annotations__r   listboolr   r   r   classmethodargparse	Namespacer   ArgumentParserr   r   r   r   r   r   2  s   
 r   r   c                 C   s   t | j| j| j| j| jdS )Nr   )r   r   r%   r,   rh   ri   r   r   r   r   run_mainw  s   r   c                 C   s   t t|  d S r   )r   r   r   r   r   r   r   main  s   r   __main__)description):r   rO   concurrent.futuresr   dataclassesr   	functoolsr   pathlibr   typingr   vllm.utils.collection_utilsr   vllm.utils.import_utilsr   plotr
   r   utilsr   matplotlib.pyplotr   r   r   r|   r   r   ImportErrorplaceholder_attrr{   r   objectr   r   r   r   r$   r+   r9   r=   r   intrH   rZ   rf   r   r   r   r   r   r   r   r   r   r   r   
parse_argsr   r   r   r   <module>   s   








&

&
K
9D


