o
    æe~  ã                   @   s¤  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlmZ d dl	m
Z
 d dl	mZ d dlm  mZ d dlm  mZ d dlZd dlZddlmZ d dlmZ defd	d
„Zdefdd„Zdd„ Zdefdd„Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Z dd„ Z!dd„ Z"d e#fd!d"„Z$d#d$„ Z%d%d&„ Z&d'd(„ Z'd)d*„ Z(d+d,„ Z)d-d.„ Z*d/d0„ Z+d1d2„ Z,d3d4„ Z-d5d6„ Z.d7d8„ Z/d9d:„ Z0h d;£h d<£h d=£d>œZ1d?d@„ Z2dS )Aé    N)Údefaultdict)ÚPopen)ÚSTDOUTé   )ÚModelConfig)ÚFASTDEPLOYSERVER_PATHÚcontentc                 C   ó   t  | tƒ ¡}t |¡}|S )zE
  Convert protocol messages in text format to json format string.
  )Útext_formatÚParser   Újson_formatZMessageToJson)r   ÚmessageZjson_string© r   ú[D:\Projects\ConvertPro\env\Lib\site-packages\visualdl/component/inference/fastdeploy_lib.pyÚ
pbtxt2json#   ó   
r   c                 C   r	   )zE
  Convert json format string to protocol messages in text format.
  )r   r   r   r
   ZMessageToString)r   r   Ú
text_protor   r   r   Ú
json2pbtxt,   r   r   c                 C   s&   i }|   ¡ D ]
\}}|r|||< q|S )a  
    Validate data in model config, we should check empty value recieved from front end.
    The easiest way to handle it is to drop empty value.
    Args:
        model_config: model config to be saved in config file
    Return:
        model config after filtering.
    )Úitems)Úmodel_configZmodel_config_filteredÚkeyÚvaluer   r   r   Úvalidate_data5   s   	€r   Úcur_dirc              	   C   s¬  i }i }t  | ¡ d¡\}}}|D ]º}t  t j ||¡¡ d¡\}}}t j |¡}	g }
|D ]}d|v r8|
 |¡ q-|
r}|
d }d|
v rQd}|
 |¡ |
 d|¡ nt	||ƒ d}|
 d|¡ t
 ttt j ||¡ƒ ¡ ƒ¡}|
d |d< |||	< |	|d< nq|D ]2}t d|¡r²|	|vri ||	< |||	 vrœg ||	 |< t  t j ||¡¡D ]}||	 |  |¡ q¦q€|	|vrËi ||	< t  t j |d¡¡ g ||	 d< q|sÒtd	ƒ‚||fS )
zh
  Analyse the model config in specified directory.
  Return a json object to describe configuration.
  Nú.pbtxtr   úconfig.pbtxtÚconfig_filenamesÚnameú\d+Ú1zPThe path you choose is not a valid model repository, please choose a valid path.)ÚosÚwalkÚsendÚpathÚjoinÚbasenameÚappendÚremoveÚinsertÚ"copy_config_file_to_default_configÚjsonÚloadsr   ÚopenÚreadÚreÚmatchÚlistdirÚmkdirÚ	Exception)r   Úall_model_configsÚall_model_versionsÚ
parent_dirZsub_dirsÚ	filenamesZmodel_dir_nameÚ	model_dirZmodel_sub_dirsÚ
model_namer   ÚfilenameZdefault_config_filenameÚjson_configÚmodel_sub_dirÚversion_resource_filer   r   r   Úanalyse_configE   s˜   

ÿÿÿÿ€
ÿ
ÿþÿÿÿÿÿÿþÿÿ€€ÿr=   c                 C   s>  g }g }i }d| v r| d }d| v r| d }|| }|D ]€}d|v r3|d }|d= i |d< ||d d< d|v r:|d= d|v rA|d= d|v r–|d dkr–d	|v r–|d	 }d
|vr[i |d
< ||d
 d	< |d	= g }|D ]#}	|	d dksv|	d dkr||  |	¡ qh|	d= |	d= |	d= |	d= |	d= qh|D ]}
| |
¡ qŽ|||d < q|S )z7
  Change config exchange format to original format.
  Ú	ensemblesÚmodelsÚoptimizationÚexecutionAcceleratorsÚversionsr   ÚplatformÚensembleÚstepÚensembleSchedulingÚ	modelNameÚfeedÚfetchÚ	modelTypeÚinputModelsÚoutputModelsÚ	inputVarsÚ
outputVarsr   )r&   r'   )Úexchange_formatr>   r?   Z
all_modelsZallsr   Zoptimization_configZstep_configsZremove_listÚmodel_config_in_stepZremove_itemr   r   r   Ú"exchange_format_to_original_formatŒ   sn   ÿÿ
ÿÿÿÿÿÿ
rQ   c                 C   s†   t  tttj | |¡ƒ ¡ ƒ¡}tj | ¡}||d< t	t  
|¡ƒ}ttj | d¡dƒ}| |¡ W d   ƒ d S 1 s<w   Y  d S )Nr   r   Úw)r*   r+   r   r,   r    r#   r$   r-   r%   r   ÚdumpsÚwrite)r7   Zconfig_namer:   r8   r   Úfr   r   r   r)   Â   s   ÿ"ÿr)   c              
   C   sÔ  i }g |d< g |d< |  ¡ D ]5\}}g }|  ¡ D ]&\}}i }||d< ||d< g |d< |D ]}	|d  |	|	dœ¡ q,| |¡ q|||< q|   ¡ D ]Ÿ\}}
t |
¡}d|
v rhd|
d v rh|
d d }|d= ||d< ||v rr|| |d	< d
|
v rÜ|
d
 dkrÜd|
v rÛd|
d v rÛ|d= |
d d |d< |d D ]}d|d< g |d< g |d< g |d< g |d< q•|d  ddg g g g dœ¡ |d  ddg g g g dœ¡ t|d |d |d ƒ |d  |¡ qHd|
v rç|d  |¡ qH|S )z7
  Change config original format to exchange format.
  r>   r?   Útitler   Úchildren)rV   r   r@   rA   rB   rC   rD   rF   rE   ÚnormalrJ   rK   rL   rM   rN   rH   Úvirtual)rG   rJ   rK   rL   rM   rN   rI   ÚinputÚoutputÚbackend)r   r&   ÚcopyÚdeepcopyÚanalyse_step_relationships)Zoriginal_formatÚversion_inforO   r8   Zversion_filenames_dictZversion_info_for_frontendZversion_namer6   Z#version_filenames_dict_for_frontendr9   r   Ztransformed_configZtransformed_optimization_configrP   r   r   r   Ú"original_format_to_exchange_formatÌ   sœ   
üÿ

ÿÿÿ
ÿÿÿÿ
úúþ€€ra   c                 C   sV  i }i }| D ]Ã}|||d < |d dkrq|D ]+}|d |vr6i ||d < t ƒ ||d  d< t ƒ ||d  d< ||d  d  d¡ q|D ]+}|d |vrdi ||d < t ƒ ||d  d< t ƒ ||d  d< ||d  d  d¡ qDq|d	  ¡ D ]%\}}||vr‘i ||< t ƒ || d< t ƒ || d< || d  |d ¡ qw|d
  ¡ D ]%\}}||vr½i ||< t ƒ || d< t ƒ || d< || d  |d ¡ q£q| ¡ D ]V\}}	|	d D ]#}
||
 d  |¡ |	d D ]}|||
 d vrø||
 d  |¡ qåqÖ|	d D ]%}|| d  |¡ |	d D ]}||| d vr!|| d  |¡ qqþqÎt|ƒ dS )a  
  Analyse model relationships in ensemble step. And fill      "inputModels", "outputModels", "inputVars", "outputVars" in step_config.
  step_config: step data in ensemble model config.
  inputs: inputs in ensemble model config.
  outputs: outputs in ensemble model config.
  rG   rJ   rY   r   Zfrom_modelsZ	to_modelsrH   rI   ZinputMapZ	outputMaprN   rL   rM   rK   N)ÚsetÚaddr   r&   Úcalculate_layout_for_frontend)Zstep_configZinputsZoutputsZmodels_dictZ	vars_dictrP   ÚvarZvar_placehold_nameÚvar_nameZrelationshipsZ
from_modelZvar_to_modelZto_modelZvar_from_modelr   r   r   r_     s|   ûÿ
ÿÿÿ
ÿÿúÿ€þ€þþr_   c                 C   s|   t  t j | |¡¡ d ¡\}}}g }g }|D ]}d|v r&d|vr&| |¡ qd|v r3d|v r3| |¡ qt|ƒt|ƒ }|S )Nr   Z	vdlbackup)r    r!   r#   r$   r"   r&   Úsorted)r   r   Ú_r6   r   Zbackup_config_filenamesr9   r   r   r   Ú"get_config_filenames_for_one_modelW  s"    ÿÿ€ÿri   c           
      C   sð   i }i }t j | ||¡}t tt|ƒ ¡ ƒ¡}||d< ||d< |||< i ||< t  t j | |¡¡D ]+}t	 
d|¡r\||| vrEg || |< t  t j | ||¡¡D ]}|| |  |¡ qPq1t||ƒ}	|	d rl|	d d S |	d rv|	d d S d S )Nr   r   r   r>   r   r?   )r    r#   r$   r*   r+   r   r,   r-   r0   r.   r/   r&   ra   )
r   r   Zconfig_filenamer3   r4   r9   r:   r;   r<   r   r   r   r   Úget_config_for_one_modeli  sF   ÿÿÿÿÿÿÿ€ÿÿrj   c                    s®   t tƒ‰‡ ‡‡fdd„‰ ˆ ˆd ƒ dd„ tˆ ¡ dd„ dD ƒ}d	}d
}|D ]-\}}||kr@|ˆ| d< |ˆ| d< |d7 }nd	}|ˆ| d< |ˆ| d< |d7 }|}q'dS )aŒ  
    Analyse model topology connections and prepare the positions for each model in layout.
    Dynamic program algorithm:
        depth(cur_node) = max([depth(prev_node) for prev_node in cur_node['inputModels']])
    Args:
        model_config_in_step(dict): model config in ensemble models' step, indexed by model name.
    Returns:
        None. Results calculated will be saved in place.
    c                    st   | d dkrdˆ| d < dS ˆ| d  dkrˆ| d  S t ‡ ‡fdd„ˆ| d  d D ƒƒd ˆ| d < ˆ| d  S )NrG   rH   r   c                    s   g | ]}ˆ ˆ| ƒ‘qS r   r   )Ú.0r8   )Údepth_recursiverP   r   r   Ú
<listcomp>˜  s    ÿzJcalculate_layout_for_frontend.<locals>.depth_recursive.<locals>.<listcomp>rK   r   )Úmax)Úmodel©rl   rP   Z
path_depthr   r   rl   ’  s   þýz6calculate_layout_for_frontend.<locals>.depth_recursiverI   c                 S   s   g | ]\}}||f‘qS r   r   )rk   ÚkÚvr   r   r   rm   Ÿ  s    ÿÿz1calculate_layout_for_frontend.<locals>.<listcomp>c                 S   s   | d S )Nr   r   )Úitemr   r   r   Ú<lambda>¡  s    z/calculate_layout_for_frontend.<locals>.<lambda>)r   r   éÿÿÿÿZpos_yZpos_xr   N)r   Úintrg   r   )rP   Zpath_depth_tupleZcur_xZ
last_depthr8   Údepthr   rp   r   rd   †  s&   
þ
rd   Úkwargsc                 C   sþ  dg}t j ¡ }i }|  ¡ D ]=\}}|dkr|||< q|dks#|dkr(|||< q|dkr7|r6||d< |||< q| d |¡¡ | d |¡¡ |||< q|d rb|d t  t¡v rbtd	 |d ¡ƒ‚t	|d
 ƒ\}}t
||ƒ}|d |d< d tdƒ¡}	t j t j t|	¡¡r™d tdƒ¡}	t j t j t|	¡¡s‡zt|tt j t|	¡dddtd|d}
W n ty¹   tdƒ‚w |d rÂ|d n|
j}tt j td |¡¡dƒ#}| |	d t|
jƒ d t |¡ d t |¡ ¡ W d  ƒ |
S 1 søw   Y  |
S )zB
  Launch a fastdeploy server according to specified arguments.
  ZfastdeployserverZdefault_model_namezserver-namezensemble-imgZgpusZCUDA_VISIBLE_DEVICESz--{}ú{}u^   Failed to launch serverï¼Œserver name {} has been usedï¼Œplease write a different server name.zmodel-repositoryz
logfile-{}é   rR   r   )Ú	bufferingT)ÚstdoutÚstderrÚuniversal_newlinesÚenvu^   Failed to launch fastdeployserverï¼Œplease check fastdeployserver is installed in environment.Ú
N)r    Úenvironr]   r   r&   Úformatr0   r   ÚRuntimeErrorr=   ra   Úget_random_stringr#   Úexistsr$   r   r,   r   r2   ÚpidrT   Ústrr*   rS   )rx   ÚcmdZ
launch_envZ
start_argsr   r   r3   r4   Zmodel_repo_configÚlogfilenameÚpÚserver_namerU   r   r   r   Úlaunch_process³  s”   

ÿ
þÿÿÿý
ø	ÿÿÿÿþÿÿÿ
ø
ö
rŒ   c                    s&   t j‰ d ‡ fdd„t| ƒD ƒ¡}|S )NÚ c                    s   g | ]}t  ˆ ¡‘qS r   )ÚrandomÚchoice)rk   Úi©Úlettersr   r   rm   ö  s    z%get_random_string.<locals>.<listcomp>)ÚstringÚascii_lowercaser$   Úrange)ÚlengthZ
result_strr   r‘   r   r„   ó  s   r„   c                 C   ó|   i }t j t j td | ¡¡¡r<tt j td | ¡¡dƒ}| ¡  d¡d }t	 
|¡}W d  ƒ |S 1 s7w   Y  |S )zÖ
    Get the start arguments for fastdeployserver process.
    Args:
        server_id(str): fastdeployserver process name
    Returns:
        args(dict): launch arguments when start fastdeployserver process.
    ry   Úrr€   é   N©r    r#   r…   r$   r   r‚   r,   r-   Úsplitr*   r+   )Ú	server_idÚargsrU   Zarguments_jsonr   r   r   Úget_start_argumentsú  ó   ÿþ
üûrž   c                 C   sv   d}t j t j td | ¡¡¡r9tt j td | ¡¡dƒ}t| ¡  	d¡d ƒ}W d  ƒ |S 1 s4w   Y  |S )z¥
    Get the process id for fastdeployserver process.
    Args:
        server_id(str): fastdeployserver process name
    Returns:
        pid(int): process id.
    Nry   r˜   r€   r   )
r    r#   r…   r$   r   r‚   r,   rv   r-   r›   )rœ   r†   rU   r   r   r   Úget_process_pid  s   ÿþ
ýür    c                 C   sr   d}t j t j td | ¡¡¡r7tt j td | ¡¡dƒ}| ¡  d¡d }W d  ƒ |S 1 s2w   Y  |S )zµ
    Get the process logfile name for fastdeployserver process.
    Args:
        server_id(str): fastdeployserver process name
    Returns:
        logfile(str): logfile name.
    Nry   r˜   r€   r   )	r    r#   r…   r$   r   r‚   r,   r-   r›   )rœ   r9   rU   r   r   r   Úget_process_logfile_name  s   ÿþ
ýür¡   c                 C   r—   )z×
    Get the model repository configuration for fastdeployserver process.
    Args:
        server_id(str): fastdeployserver process name
    Returns:
        configuration(dict): model repository configuration
    ry   r˜   r€   é   Nrš   )rœ   ÚconfrU   Z	conf_jsonr   r   r   Úget_process_model_configuration1  rŸ   r¤   c                 C   sœ   t j t j td | ¡¡¡rJt| ƒ}t j t j td |¡¡¡rLtt j td |¡¡dƒ}| |¡ | 	¡ }|W  d  ƒ S 1 sCw   Y  dS dS dS )z5
  Get the standard output of a opened subprocess.
  ry   r˜   N)
r    r#   r…   r$   r   r‚   r¡   r,   Úseekr-   )rœ   r–   r‰   rU   Údatar   r   r   Úget_process_outputD  s(   ÿÿÿþ
$ûúr§   c                 C   sÀ   t j t j td | ¡¡¡r^tt j td | ¡¡dƒ}| ¡  d¡}W d  ƒ n1 s-w   Y  d|d< tt j td | ¡¡dƒ}| 	d |¡¡ W d  ƒ dS 1 sWw   Y  dS dS )aä  
    Resource files for a dead server only deleted when user closes the server in frontend.
    When user close the server, pid recorded in logfile will be killed.
    In case a dead process id is reassigned for a new process, we should mark the pid recorded in logfile as outdated.
    Here, we choose to replace the pid to -1 in logfile to denote the zombie process         which has been polled and becomes dead.
    Args:
        server_id(str): fastdeployserver process name
    ry   r˜   r€   Nz-1r   rR   )
r    r#   r…   r$   r   r‚   r,   r-   r›   rT   )rœ   rU   Úcontentsr   r   r   Úmark_pid_for_dead_processV  s&   
ÿþýþ"ýùr©   c                 C   s|   t j t j td | ¡¡¡r<t| ƒ}t j t j td |¡¡¡r-t  t j td |¡¡¡ t  t j td | ¡¡¡ dS dS )zv
    Delete logfile for fastdeployserver process.
    Args:
        server_id(str): fastdeployserver process name
    ry   N)r    r#   r…   r$   r   r‚   r¡   r'   )rœ   r‰   r   r   r   Údelete_files_for_processm  s   ÿÿÿørª   c                 C   s~   t | ƒtkr%t| ƒ}|dkrdS z
t |tj¡ W dS  ty$   Y dS w | j}|  ¡  z|  	d¡ W dS  ty>   Y dS w )z
  Stop a opened subprocess.
  ru   Né
   )
Útyper‡   r    r    ÚkillÚsignalZSIGKILLr2   r†   Úwait)Úprocessr†   r   r   r   Úkill_process~  s    ÿÿr±   c                  C   sX   dd„ t  t¡D ƒ} g }| D ]}t|ƒdu rt|ƒ | |¡ q|D ]}|  |¡ q"| S )zœ
    Search server names in `FASTDEPLOYSERVER_PATH`, if process is dead and log still exists due to         some unexpectable reasons, delete log file.
    c                 S   s   g | ]}d |vr|‘qS )Zlogfiler   )rk   r   r   r   r   rm   ˜  s
    ÿz0get_alive_fastdeploy_servers.<locals>.<listcomp>F)r    r0   r   Úcheck_process_aliverª   r&   r'   )Zserver_namesZshould_delete_serversr‹   r   r   r   Úget_alive_fastdeploy_servers“  s   ÿ
€r³   c                 C   s   t | ƒ}|dkr
dS dS )zÛ
    Given a server id, check whether the process became zoombie and mark pid as -1.
    Args:
        server_id(str): fastdeployserver process name
    Return:
        status(bool): True if process became zoombie.
    ru   TF)r    ©rœ   r†   r   r   r   Úcheck_process_zombie¦  s   rµ   c                 C   s`   t | ƒ}|du r
dS |dkrdS zt |d¡ W n
 ty"   Y dS w dt |¡ ¡ vr.dS dS )zÉ
    Given a server id, check whether the process is alive or not.
    Args:
        server_id(str): fastdeployserver process name
    Return:
        status(bool): True if process is still alive.
    NFru   Tr   Zfastdeployserve)r    r    r­   ÚOSErrorÚpsutilÚProcessr   r´   r   r   r   r²   µ  s   ÿr²   >	   Znv_inference_request_successÚnv_inference_queue_duration_usÚ&nv_inference_compute_input_duration_usZnv_inference_exec_countZnv_inference_countZnv_inference_request_failureÚ&nv_inference_compute_infer_duration_usÚ nv_inference_request_duration_usÚ'nv_inference_compute_output_duration_us>   Únv_gpu_memory_total_bytesZnv_gpu_utilizationZnv_energy_consumptionÚnv_gpu_memory_used_bytesZnv_gpu_power_limitZnv_gpu_power_usage>   Znv_cpu_memory_total_bytesZnv_cpu_memory_used_bytesZnv_cpu_utilization)ÚModelÚGPUÚCPUc                 C   s„  i }i }zt  d | |¡¡}W n
 ty   Y d S w |j}| d¡D ]“}| d¡r*q"t d|¡}|s3q"| 	d¡}| 	d¡}| 	d¡}	i }
| d¡D ]}| d	¡\}}| 
d
¡}||
|< qI|dv rgt|	ƒd }	n|dv rut|	ƒd d d }	t ¡ D ];\}}||v r´|dkr˜|
d }||vr‘i ||< |	|| |< qy|dkr¯|
d }||vr¨i ||< |	|| |< qy|dkr´	 qyq"i }||d< ||d< |S )Nzhttp://{}:{}/metricsr€   ú#z(\w+){(.*)} (\w+)r   r™   r¢   ú,ú=ú")r¼   r¹   rº   r»   r½   iè  )r¾   r¿   i   rÀ   ro   rÁ   Zgpu_uuidrÂ   )ÚrequestsÚgetr‚   r2   Útextr›   Ú
startswithr.   r/   ÚgroupÚstripÚfloatÚ_metric_column_namer   )Zserver_addrZserver_portZmodel_tableZ	gpu_tableÚresZmetric_contentr   Zmetric_namero   r   ÚinfosÚinforq   rr   r   Zmetric_namesr8   Zgpu_nameÚresultsr   r   r   Úgenerate_metric_tableæ  sd   
ÿÿ
ÿ




€órÓ   )3r]   r*   r    rŽ   r.   r®   r“   Úcollectionsr   Ú
subprocessr   r   Zgoogle.protobuf.json_formatÚprotobufr   Zgoogle.protobuf.text_formatr
   r·   rÇ   Zproto.model_config_pb2r   Zvisualdl.utils.dirr   r‡   r   r   r   r=   rQ   r)   ra   r_   ri   rj   rd   ÚdictrŒ   r„   rž   r    r¡   r¤   r§   r©   rª   r±   r³   rµ   r²   rÎ   rÓ   r   r   r   r   Ú<module>   sZ   		G6
Q:-@ò