U
    ;g;                     @   s~  d dl Z d dlZd dlm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Zd dlmZ d dlmZ d dlmZmZmZmZ d dlZd dlZdZdZe
eZe
  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d Z&dd Z'd6ddZ(dd Z)d7d!d"Z*dddd#Z+d8d$d%Z,d9d'd(Z-d)d* Z.d+d, Z/d-d. Z0d/d0 Z1d1d2 Z2d3d4 Z3ed5krze3  dS ):    N)literal_eval)defaultdict)ArgumentParserArgumentError	REMAINDERRawTextHelpFormatter)runrmcleanlistplotattachpeakaA  
Available commands:

    run      run a given command or python file
    attach   alias for 'run --attach': attach to an existing process by pid or name
    rm       remove a given file generated by mprof
    clean    clean the current directory from files created by mprof
    list     display existing profiles, with indices
    plot     plot memory consumption generated by mprof run
    peak     print the maximum memory used by an mprof run

Type mprof <command> --help for usage help on a specific command.
For example, mprof plot --help will list all plotting options.
c                   C   s$   t dttjd   t t d S )Nz)Usage: %s <command> <options> <arguments>r   )printospbasenamesysargvhelp_msg r   r   )/tmp/pip-unpacked-wheel-lmfbx10s/mprof.pyprint_usage'   s    r   c                   C   sH   t tjdkrt  td tjd tkr<t  td tjdS )z/Pop first argument, check it is a valid action.   )lenr   r   r   exitALL_ACTIONSpopr   r   r   r   
get_action-   s    

r   c              	   C   s<  t  d}|  | dkr&t|}ng }| D ]}|dkr<q.zt|}W n tk
r`   d}Y nX |dk	rz|| }W n  tk
r   td| Y nX ||kr|| q.t|r||kr|| q.t	|rtd| q.td| q.t
|D ]>}t|}|d d	 |d
  }t|r||kr|| q|S )a  Return list of profile filenames.

    Parameters
    ==========
    args (list)
        list of filename or integer. An integer is the index of the
        profile in the list of existing profiles. 0 is the oldest,
        -1 in the more recent.
        Non-existing files cause a ValueError exception to be thrown.

    Returns
    =======
    filenames (list)
        list of existing memory profile filenames. It is guaranteed
        that an given file name will not appear twice in this list.
    mprofile_??????????????.datall--Nz%Invalid index (non-existing file): %szPath %s is a directoryzFile %s not foundr   _tsr   )globsortcopyint
ValueError
IndexErrorappendr   isfileisdirreversedsplitext)argsprofiles	filenamesargindexfilenamepartsZtimestamp_filer   r   r   get_profile_filenames9   s>    




r4   c                  C   s   t dd} | jddtjd |  }td}t|D ]n\}}t|d 	dd	 }t
d
j|||dd |dd |dd |dd |dd |dd d q4dS )z(Display existing profiles, with indices.z*mprof list
This command takes no argument.usage	--versionversionactionr8   r   r   _z:{index} {filename} {hour}:{min}:{sec} {day}/{month}/{year}N         
         )r1   r2   yearmonthdayhourminsec)r   add_argumentmp__version__
parse_argsr4   	enumerater   r,   splitr   format)parserr-   r/   nr2   tsr   r   r   list_actions   s$     
 
 

 
 
rS   c                  C   s   t dd} | jddtjd | jdddd	d
d | jdddd |  }t|jdkrhtd t	d t
|j}|jrtd |D ]}t| qn|D ]}t| qdS )z)TODO: merge with clean_action (@pgervais)z'mprof rm [options] numbers_or_filenamesr5   r7   r8   r9   	--dry-rundry_runF
store_true2Show what will be done, without actually doing it.destdefaultr:   helpnumbers_or_filenames*znumbers or filenames removednargsr[   r   z9A profile to remove must be provided (number or filename)r   Files to be removed: N)r   rI   rJ   rK   rL   r   r\   r   r   r   r4   rU   osremoverP   r-   r/   r2   r   r   r   	rm_action   s(    



rd   c                  C   sz   t dd} | jddtjd | jdddd	d
d |  }td}|jrbtd |D ]}t| qRn|D ]}t	| qfdS )z/Remove every profile file in current directory.z+mprof clean
This command takes no argument.r5   r7   r8   r9   rT   rU   FrV   rW   rX   r   r`   N)
r   rI   rJ   rK   rL   r4   rU   r   ra   rb   rc   r   r   r   clean_action   s     
re   c                    s$   t d  fdd| D } d| S )z/Given a set or arguments, compute command-line.z 	c                    s&   g | ]}  |r|n
d | d  qS )')
isdisjoint).0sZblanksr   r   
<listcomp>   s     z get_cmd_line.<locals>.<listcomp> )setjoin)r-   r   rj   r   get_cmd_line   s    ro   c                 C   s(   t j D ]}| | kr
|  S q
d S )N)rJ   psutilZprocess_itername)rq   ir   r   r   find_first_process   s    
rs   c                  C   s0   t j} | d d dg | dd   t _t  d S )Nr   --attach)r   r   
run_action)r   r   r   r   attach_action   s     rv   c                  C   sj  dd l } dd l}tdtd}|jddtjd |jddd	d
d |jddd	dd |jddddtddd |jdddd	dd |jdddd	dd |jddd d	d!d |jd"d#d$d	d%d}|jd&d'd(dtd)d* |jd+d,d-d.| 	d/| 
  d0d1 |jd2d3d4d5d6d7d8gd4d9d: |jd;td<d= | }t|jdkrLtd> td? td@|jttjd  |j}|j}|jrtdA|d  |d  rt|d }t|}nRt|d }	|	d krt|dB|d |	j}z|	 }W n   t|}Y nX |j d krdC|_ ntdD |d !dErn|j"sn|j#rh|d $ds`|%dtj& dF|_'ndG|_'|j'rtdH |d $ds|%dtj& t|}dIdJdKd,|g}
|j(r|
)d |
|d?d?< |*|}nt|}|*|}t+|dL:}|,dM| tj-||j|j dG|j(|j#||j.dN W 5 Q R X |j/rf|j0dkrZt12dO|j0 t|j0 d S )PNr   zmprof run [options] program)r6   formatter_classr7   r8   r9   z--pythonpythonrV   znActivates extra features when the profiling executable is a Python program (currently: function timestamping.)rY   r:   r[   z
--nopythonnopythonzlDisables extra features when the profiled executable is a Python program (currently: function timestamping.)z
--intervalz-Tintervalz0.1storez-Sampling period (in seconds), defaults to 0.1rY   rZ   typer:   r[   z--include-childrenz-Cinclude_childrenz=Monitors forked processes as well (sum up all process memory)z--multiprocessz-Mmultiprocessz_Monitors forked processes creating individual plots for each child (disables --python features)z--exit-codez-E	exit_codezPropagate the exit codert   z-aattach_existingz8Attach to an existing process, by process name or by pidz	--timeout-ttimeoutzctimeout in seconds for the profiling, default new process has no timeout, attach existing is 1 hour)rY   r:   r~   r[   --output-or2   zmprofile_%s.datz%Y%m%d%H%M%SzFile to store results in, defaults to 'mprofile_<YYYYMMDDhhmmss>.dat' in the current directory,
(where <YYYYMMDDhhmmss> is the date-time of the program start).
This file contains the process memory consumption, in Mb (one value per line).rY   rZ   r[   	--backendbackendrp   Z
psutil_pssZ
psutil_ussposixtracemalloczoCurrent supported backends: 'psutil', 'psutil_pss', 'psutil_uss', 'posix', 'tracemalloc'. Defaults to 'psutil'.)rY   choicesrZ   r[   programam  Option 1: "<EXECUTABLE> <ARG1> <ARG2>..." - profile executable
Option 2: "<PYTHON_SCRIPT> <ARG1> <ARG2>..." - profile python script
Option 3: (--python flag present) "<PYTHON_EXECUTABLE> <PYTHON_SCRIPT> <ARG1> <ARG2>..." - profile python script with specified interpreter
Option 4: (--python flag present) "<PYTHON_MODULE> <ARG1> <ARG2>..." - profile python module
r^   z2A program to run must be provided. Use -h for helpr   z{1}: Sampling memory every {0}sz-attaching to existing process, using hint: {}z_
When attaching, program should be process name or pid.
Failed to find a process using hint: {}i  zrunning new processz.pyFTzrunning as a Python program...z-mmemory_profilerz--timestampazCMDLINE {0}
)procr{   r   
timestampsr   r   streamr   z.Program resulted with a non-zero exit code: %s)3time
subprocessr   r   rI   rJ   rK   floatr%   strftime	localtimer   rL   r   r   r   r   r   rO   r{   r   r   r   r2   r   isdigitr   ro   rs   r   pidZcmdliner   endswithrz   r   
startswithinsert
executablerx   r   r(   PopenopenwriteZmemory_usager   r   
returncodeloggererror)r   r   rP   Z
attach_argr-   Zmprofile_outputr   pcmd_liner   
extra_argsfr   r   r   ru      s    



 



  ru   rc              
   C   s  zddl }W n< tk
rH } ztd t| td W 5 d}~X Y nX d}| d | d  | }	| d | d  d|  }
||
dd|
g}||	|	|	 |	 g}|d dkrd| }|jdks|jd | d |   kr|jd kr*n n,|j|| d  | ||d  d	| d
|d |jdksf|jd | d |   krb|jd krn n,|j| | d  | ||d  d	| d
d dS )aG  Add two brackets on the memory line plot.

    This function uses the current figure.

    Parameters
    ==========
    xloc: tuple with 2 values
        brackets location (on horizontal axis).
    yloc: tuple with 2 values
        brackets location (on vertical axis)
    xshift: float
        value to subtract to xloc.
    r   N"matplotlib is needed for plotting.r   g      4@g      @r;   rl   -   )	linewidthlabel)r   )	pylabImportErrorr   r   r   ylimxlimasarrayr   )ZxlocZylocxshiftcolorr   optionspleZheight_ratioZvsizeZhsizeZ	bracket_xZ	bracket_yr   r   r   add_brackets%  s0     8  < r   c                 C   sv  i }g }g }t t}d}t| d}|D ]2}|dkr<td|dd\}}	|dkr|	d}
|t|
d  |t|
d  q&|d	kr|	d}
|
dd
 \}}}}}||g }t|t|t|t|g}t|
dkr|
d
 }|t	| || |||< q&|dkrL|	d}
|
d }|| t|
d t|
d f q&|dkr&|	}q&q&|
  |||| ||dS )a  Read an mprofile file and return its content.

    Returns
    =======
    content: dict
        Keys:

        - "mem_usage": (list) memory usage values, in MiB
        - "timestamp": (list) time instant for each memory usage value, in
            second
        - "func_timestamp": (dict) for each function, timestamps and memory
            usage upon entering and exiting.
        - 'cmd_line': (str) command-line ran for this profile.
    Nr   
zSampling time was too shortrl   r   ZMEMr   ZFUNC   r>   ZCHLDr   ZCMDLINE)	mem_usage	timestampfunc_timestampr2   r   children)r   r   r   r&   rN   r(   r   getr   r%   close)r2   Zfunc_tsr   r   r   r   r   lfieldvaluevaluesf_nameZ	mem_startstartZmem_endendrR   Z	to_appendZstack_levelZchldnumr   r   r   read_mprofile_fileT  sP    








  r   Tc           (      C   sp  zdd l }W n< tk
rH } ztd t| td W 5 d }~X Y nX dd l}t| }t|d dkrtd|d  td |d }	|d }
|d }|d	 }t|	dkr|		 D ]2}|D ](}|

|d d
  |
|d
d  qq||}||
}
|
 }|| }|
| }
t|
d }|
| }
| }| }d}d}|d k	odt|dod|jdk}tdt|dttt|d d  }d }|r||
|d}|d|d  }|j|
|d||t|   |d |r|j|
|
|d  |d  dddd | \}}|d7 }|d8 }t|dkr|rd}t| D ]\}\}}|dd |D | }|dd |D }d } d}!|r|||d} d| d }!|j||d||d t|   d ||!d |r|j||| d  | d  ddd!d | }"|"|d krN||  |"f}qN||d | d d | d d d"d ||d |  d d |  d d d"d t|	dkr"|r"d}#t!|	" }$|	 D ]f\}%}&|&D ]N}'t#|'d d
 |'d
d  |||#t|  |$|% d#|'d |'d    |d$ q|#d7 }#q|rl|j||  d d |  d d d"dd% |j|
| ||d"dd% |S )&Nr   r   r   r   ** No memory usage values have been found in the profile file.**
File path: {0}
File may be empty or invalid.
It can be deleted with "mprof rm {0}"r2   r   r   r   r   r=   )cygr   bkr   r   r   r   r   mslopeT %d / %m / %Y - start at %H:%M:%S.{0:03d}  z slope {0:.5f}+-r   r          ?z#00e3d8)r   r   MbP?r   r   c                 S   s   g | ]}|d  qS r   r   rh   itemr   r   r   rk     s     zplot_file.<locals>.<listcomp>c                 S   s   g | ]}|d  qS r   r   r   r   r   r   rk     s      z
child {}{}Zblackr   z %.3fs)r   r   r   r   colorsZ
linestyles)$r   r   r   r   r   numpyr   r   rO   r   extendr   argsortr   maxargmaxhasattrr   r   r   r   r%   roundmathmodfZpolyfitr   r   rM   itemsvlineshlinesr   function_labelskeysr   )(r2   r1   r   r   r   r   r   npmprofilerR   tmemchldr   vindglobal_startmax_memmax_mem_indZ
all_colorsmem_line_colorsZshow_trend_slopemem_line_labelZ	mem_trendbottomtopcmpointidxr   datactscmemZ
cmem_trendZchild_mem_trend_labelcmax_memfunc_numf_labelsr   exec_ts	executionr   r   r   	plot_file  s    


 $
$..
   r  )hovered_recthovered_textalphac           -         s  zdd l W n< tk
rH } ztd t| td W 5 d }~X Y nX dd l}t| }t|d dkrtd|d  td |d }|d }	|d }
|d	 }t|dkr|	 D ]2}|D ](}|	
|d d
  |

|d
d  qq||
}
||	}	|	 }|
| }
|	| }	|r<dtdd |	 D  ndfdd  fddtD }t|	d }|	| }	|
 }|
 }d}tdt|dttt|d d  }j|	|
d||t|   |d  \}}|d7 }|d8 } }|d | g  dd f d t|dkrJ|rJd}t|  D ]\}\}}|dd |D | }|dd |D }j||d||d t|   d|d | }||d kr`||  |f}q`!|d  d d  d d d d! "|d # d d # d d d d! fd"d#}fd$d%} t|dkrX|rXd}!t$|% }"i |  D ]\}#}$|$D ]r}%|%d d
 \}&}'|%d }(|(d })|&|8 }&|'|8 }'t&||( }*t'|&|'|(|)|#|*d&\}+},|#|,|+f|&|(|'|)f< q|!d7 }!qtd'k rF( j)*d(| ( j)*d)|  |rj"|# d d # d d d d!d* j!|	| ||d d!d* +| |S )+Nr   r   r   r   r   r2   r   r   r   r   r=   c                 s   s    | ]}|D ]}|d  V  q
qdS )r=   Nr   )rh   Z
executionsexr   r   r   	<genexpr>;  s       z flame_plotter.<locals>.<genexpr>c                    s   dd|     S )Nr         ?r   )level)
stack_sizer   r   level_to_saturation>  s    z*flame_plotter.<locals>.level_to_saturationc              
      sB   g | ]:}t jjd  |dfjjd |dfgqS )r   r   皙?)	itertoolscycle
matplotlibr   Z
hsv_to_rgb)rh   r  )r  r   r   r   rk   A  s
   z!flame_plotter.<locals>.<listcomp>r   r   r   r   r   r   r   TFr   c                 S   s   g | ]}|d  qS r   r   r   r   r   r   rk   i  s     c                 S   s   g | ]}|d  qS r   r   r   r   r   r   rk   j  s     r   zchild {}r   r    c                    sn  | j | j }}|d k	r|d k	r D ]\}\}}}|\}}}	}
||  k rX|	k r*n q*||  k rp|
k r*n q*td |kr d S td d k	rtd td  td d td d |td< |td< | td< td d td d td d     d S q*td d k	rjtd d td td  td d    d td< d td< d S )	Nr  r
  r	  r   r   r   r   r   皙?   )r   r   r   r   )	xdataydatar   FLAME_PLOTTER_VARS	set_alphaZ	set_colorZset_linewidthZ	get_alphadraw)eventxr   coordrq   textrectx0y0x1y1)r   
rectanglesr   r   mouse_motion_handlery  s4    0z+flame_plotter.<locals>.mouse_motion_handlerc           
         s   | j | j }}|d ks|d kr"d S  D ]\}}|\}}}}||  k rR|k r*n q*||  k rj|k r*n q*  jj}	|	  || |d  |	   	   d S q*d S )Nr   )
r  r  r   gcfcanvastoolbarZpush_currentZset_xlimset_ylimr  )
r  r  r   r  r;   r"  r#  r$  r%  r*  )r   r&  r  timestamp_axr   r   mouse_click_handler  s    0z*flame_plotter.<locals>.mouse_click_handler)r   d   Zmotion_notify_eventZbutton_release_eventr   ),r   r   r   r   r   r   r   r   rO   r   r   r   r   r   ranger   r   r   r   r   r%   r   r   r   r   r   ZgcagridZtwinxZ
set_yticksr+  rM   r   r   r   r   r   r   nextadd_timestamp_rectangler(  r)  Zmpl_connectZsca)-r2   r1   r   r   r   r   r   r   rR   r   r   r   r   r   r   r   r   r   r   r   r   r   r   axr   r   r   r   r   r  r  r'  r-  r  r  r   r  r  r"  r$  r#  r%  r   r!  r   r   )r  r   r&  r  r,  r   flame_plotter  s    





..    
   
r4  nonec           	      C   s8   | j ||f|||ddd}| j|||dddd}||fS )Nr   r   )r   r
  r   leftr   r  )ZhorizontalalignmentZverticalalignmentr   )Zfill_betweenxr   )	r3  r"  r$  r#  r%  	func_namer   r!  r   r   r   r   r2    s    
r2  c                    s   i   fdd}|| d  fdd D }|D ]0} | d } | d d } |= ||| q0t |dkrqrqtd	d
   D }|S )Nc                    sH   | D ]>}d |d| d  } |g |d}|d | qd S )N.)	functionsr  r9  )rn   rN   
setdefaultr(   )function_namesr  fnr   label_statestater   r   set_state_for  s    z&function_labels.<locals>.set_state_forr   c                    s$   g | ]}t  | d  dkr|qS )r9  r   )r   )rh   r   r>  r   r   rk     s      z#function_labels.<locals>.<listcomp>r9  r  r   c                 s   s"   | ]\}}|d  d |fV  qdS )r9  r   Nr   )rh   r   r=  r   r   r   r    s     z"function_labels.<locals>.<genexpr>)r   dictr   )Zdotted_function_namesr@  Zambiguous_labelsZambiguous_labelr;  Z	new_levelZfn_to_labelr   r>  r   r     s    
r   c               
   C   s  dd } d}t d|d}|jddtjd |jd	d
dd tddd |jdddddd |jdddd |jddd| dd |jddd dd!d |jd"d#d$dd%d |jd&d'd |jd(d)d*d+ | }z*|jd k	rd,d l}||j d,d l	}W n> t
k
r0 } ztd- t| td. W 5 d }~X Y nX |  t|}|jd/d0d1}|jsl|d2d2d3d4g}	n|d2d2d5d5g}	|jd k	r||jd, |jd.  t|d.ks|jrd6}
nd7}
t}|jrt}t|D ]\}}||||
|d8}q|d9 |d: |jd kr4t|d.kr4||d;  n|jd k	rL||j |jsx|	jd<d=d>}| d? |  |j r|!|j  n|"  d S )@Nc                 S   sN   zdd |  dD }W n   td|  Y nX t|dkrJtd|  |S )Nc                 S   s   g | ]}t |qS r   )r   )rh   r  r   r   r   rk     s     z2plot_action.<locals>.xlim_type.<locals>.<listcomp>,z;'%s' option must contain two numbers separated with a commar   )rN   r   r   )r   Znewvaluer   r   r   	xlim_type  s    zplot_action.<locals>.xlim_typezPlots using matplotlib the data file `file.dat` generated
using `mprof run`. If no .dat file is given, it will take the most recent
such file in the current directory.zmprof plot [options] [file.dat]r6   descriptionr7   r8   r9   z--titler   titler|   zString shown as plot titler}   z--no-function-tsz-nno_timestampsrV   z+Do not display function timestamps on plot.ry   r   r   z+Save plot to file instead of displaying it.)r[   z--windowz-wr   zXPlot a time-subset of the data. E.g. to plot between 0 and 20.5 seconds: --window 0,20.5)rY   r~   r[   z--flamez-f
flame_modezDPlot the timestamps as a flame-graph instead of the default bracketsz--slopez-sr   z)Plot a trend line and its numerical sloper   z%Specify the Matplotlib backend to user.   r]   profiles made by mprof runr^   r   r   r   )rB   r>   Z   )ZfigsizeZdpir  g333333?r  r  FT)r1   r   r   ztime (in seconds)zmemory used (in MiB)r   zcenter left)r   r   )locZbbox_to_anchorr   )#r   rI   rJ   rK   strrL   r   r  Zuser   r   r   r   r   Zioffget_profilesfigurerH  Zadd_axesr   r   rG  r  r4  rM   ZxlabelZylabelrF  ZlegendZ	get_framer  r0  outputZsavefigshow)rC  descrP   r-   r  r   r   r/   Zfigr3  r   ZplotterrQ   r2   r   Zlegr   r   r   plot_action  s    	 


rR  c                 C   s   |d kr| d S || d kr,t t|d | d | }g }t| d | d D ]<\}}|D ].}|d |  krz|d krZn qZ|| qZqN|S )Nr   r   z was not found.r   r   r   )r&   rL  zipr(   )proffuncZtime_rangesZfiltered_memoryZmibrR   rngr   r   r   %filter_mprofile_mem_usage_by_functionI  s     rW  c            
   	   C   s   d} t d| d}|jdddd |jdd	d d
d | }t|}|D ]}t|}zt||j}W n* tk
r   td	|d  Y qFY nX td	|d t
| |d  D ]*\}}t
dd |D }	td	||	 qqFd S )NzPrints the peak memory used in data file `file.dat` generated
using `mprof run`. If no .dat file is given, it will take the most recent
such file in the current directory.zmprof peak [options] [file.dat]rD  r.   r]   rI  r^   z--funcrU  zBShow the peak for this function. Does not support child processes.r   z
{}	NaN MiBr2   z{}	{:.3f} MiBr   c                 S   s   g | ]}|d  qS r   r   )rh   Zmem_tsr   r   r   rk   s  s     zpeak_action.<locals>.<listcomp>z  Child {}			{:.3f} MiB)r   rI   rL   rM  r   rW  rU  r&   r   rO   r   r   )
rQ  rP   r-   r/   r2   rT  r   childr   Z
child_peakr   r   r   peak_action]  s*    

rY  c              	   C   s   t  d}|  t| jdkrRt|dkr>td td td |d g}nvg }| jD ]j}t|r~||kr|	| q\z&t
|}|| |kr|	||  W q\ tk
r   td|  Y q\X q\t|std td |S )Nr   r   zhNo input file found. 
This program looks for mprofile_*.dat files, generated by the 'mprof run' command.r<   zUsing last profile data.zInput file not found: z No files found from given input.)r"   r#   r   r.   r   r   r   r   existsr(   r%   r&   )r-   r.   r/   rT  rQ   r   r   r   rM  w  s.    




rM  c                  C   s^   t d} ttjD ]$\}}| |rtj|d  q:qttt	t
tttd}|t    d S )Nz-[0-9]+r    )r	   r
   r   r   r   r   r   )recompilerM   r   r   matchr   rd   re   rS   ru   rv   rR  rY  r   )ZnegintrQ   r0   actionsr   r   r   main  s    

r_  __main__)r   r   NN)r   TTN)r   TTN)r5  )4r"   ra   os.pathpathr   r   r[  r$   r   r   loggingr  astr   collectionsr   argparser   r   r   r   	importlibr   rJ   r   r   	getLogger__name__r   basicConfigr   r   r4   rS   rd   re   ro   rs   rv   ru   r   r   r  r  r4  r2  r   rR  rW  rY  rM  r_  r   r   r   r   <module>   s^   
:d
/=
 
 9

V
