3
dX/                 @   s   d Z ddlZddlZddlZddlmZ yddlZW n& ek
rZ Z z
dZW Y ddZ[X nX ddl	m
Z
mZ ejdZe
jZdZG dd	 d	ZG d
d dejZdd Zdd ZdddZdd ZdddZdd Zdd ZdS )z(
Utilities to keep track of performance
    N)time   )configloggingznipype.utilsg      @c               @   s6   e Zd ZdZedd ZdddZd	d
 Zdd ZdS )ResourceMonitorMockz1A mock class to use when the monitor is disabled.c             C   s   dS )zGet/set the internal filenameN )selfr   r   7/tmp/pip-build-7vycvbft/nipype/nipype/utils/profiler.pyfname   s    zResourceMonitorMock.fname   NTc             C   s   d S )Nr   )r   pidfreqr
   pythonr   r   r	   __init__#   s    zResourceMonitorMock.__init__c             C   s   d S )Nr   )r   r   r   r	   start&   s    zResourceMonitorMock.startc             C   s   i S )Nr   )r   r   r   r	   stop)   s    zResourceMonitorMock.stop)r   NT)	__name__
__module____qualname____doc__propertyr
   r   r   r   r   r   r   r	   r      s
   
r   c               @   s@   e Zd ZdZdddZedd Zd	d
 ZdddZdd Z	dS )ResourceMonitorzW
    A ``Thread`` to monitor a specific PID with a certain frequence
    to a file
    r   NTc             C   s   dd l }|dk rtd| |d kr4d|t |f }tjj|| _t| jd| _|| _	|| _
|j|| _| jdd tjj|  tj | _d S )Nr   g?z,Frequency (%0.2fs) cannot be lower than 0.2sz.proc-%d_time-%s_freq-%0.2fw)cpu_interval)psutilRuntimeErrorr   ospathabspath_fnameopen_logfile_freqZ_pythonProcess_process_sample	threadingThreadr   Event_event)r   r   r   r
   r   r   r   r   r	   r   3   s    zResourceMonitor.__init__c             C   s   | j S )zGet/set the internal filename)r   )r   r   r   r	   r
   I   s    zResourceMonitor.fnamec             C   s   | j j s8| j j  | j  | j  | jj  | jj  ddd}tj	| j
dd}|jrtj|}|dddf j d |d< |dddf j |d	< |ddd
f j |dddf j |dddf d j |dddf d j d|d< |S )zStop monitoring.N)mem_peak_gbcpu_percent,)	delimiterr   i   r*      r+   r      )r   ZcpusZrss_GiBZvms_GiBZ	prof_dict)r)   is_setsetjoinr%   r!   flushclosenpZloadtxtr   sizeZ
atleast_2dmaxtolist)r   retvalvalsr   r   r	   r   N   s$    




 zResourceMonitor.stopc          %   C   s4  d}d}d}yJ| j j 6 || j j|d7 }| j j }||j7 }||j7 }W d Q R X W n tjk
rl   Y nX y| j jdd}W n tjk
r   g }Y nX xd|D ]\}y@|j . ||j 7 }|j }||j7 }||j7 }W d Q R X W q tjk
r   Y qX qW t	dt
 ||t |t f | jd | jj  d S )Ng        )intervalT)	recursivez%f,%f,%f,%f)file)r$   Zoneshotr+   memory_inforssvmsr   NoSuchProcesschildrenprintr   _MBr!   r3   )r   r   cpur?   r@   Zmem_inforB   childr   r   r	   r%   j   s4    






$zResourceMonitor._samplec             C   sH   t  }|}x8| jj sB| j  || j7 }| jjtd|t    qW dS )z+Core monitoring function, called by start()r   N)r   r)   r0   r%   r"   waitr7   )r   
start_timeZwait_tilr   r   r	   run   s    
zResourceMonitor.run)r   NT)N)
r   r   r   r   r   r   r
   r   r%   rI   r   r   r   r	   r   -   s   

 r   c          
   C   s   |dkrdS ddl }ddl}| j| jt| jjdt| jjdt| jjdt| jjddt| jjd	d| j| jd
	}|d dks|d dkrd|d< |j	dj
|j| dS )a  Function to record node run statistics to a log file as json
    dictionaries

    Parameters
    ----------
    node : nipype.pipeline.engine.Node
        the node being logged
    status : string
        acceptable values are 'start', 'end'; otherwise it is
        considered and error

    Returns
    -------
    None
        this function does not return any values, it logs the node
        status info to the callback logger
    endNr   Z	startTimeZendTimedurationr+   zN/Ar*   )	nameidr   finishrK   Zruntime_threadsZruntime_memory_gbZestimated_memory_gbnum_threadsr   rN   Terrorcallback)r   jsonrL   _idgetattrresultZruntimemem_gbn_procs	getLoggerdebugdumps)nodestatusr   rR   Zstatus_dictr   r   r	   log_nodes_cb   s     
r]   c        	   
   C   s   ddl } ddl}d|jkrdtdd8}|j }dd |D d }t|j d }|d }W dQ R X n@d|jkr| jdj j	 jdd }t|d }nd}t
||S )zC
    Function to get the total RAM of the running system in GB
    r   Nlinuxz/proc/meminforc             S   s   g | ]}d |kr|qS )ZMemTotalr   ).0liner   r   r	   
<listcomp>   s    z.get_system_total_memory_gb.<locals>.<listcomp>r.   g      @r   darwinzsysctl hw.memsize r/   z$System platform: %s is not supportedg      0Ag      A)r   sysplatformr    	readlinesfloatsplitpopenreadstrip	Exception)	r   rf   Zf_inZmeminfo_linesZmem_total_line	mem_totalZ	memory_gbZmem_strerr_msgr   r   r	   get_system_total_memory_gb   s    

rq   Fc             C   sh   t stdy$t|t| |d}t|t| }W n. tk
r^ } ztjd| W Y dd}~X nX ||fS )a  
    Function to get the RAM and threads utilized by a given process

    Parameters
    ----------
    pid : integer
        the process ID of process to profile
    mem_mb : float
        the high memory watermark so far during process execution (in MB)
    num_threads: int
        the high thread watermark so far during process execution

    Returns
    -------
    mem_mb : float
        the new high memory watermark of process (MB)
    num_threads : float
        the new high thread watermark of process
    zHAttempted to measure resources with option "monitoring.enabled" set off.)pyfuncz+Could not get resources used by process.
%sN)resource_monitorr   r7   _get_ram_mb_get_num_threadsrn   
profloggerinfo)r   mem_mbrO   rr   excr   r   r	   get_max_resources_used   s    rz   c             C   s
  yt j| }|j t jkr$|j }n:|j dkrZdd |j D }dd |D }t|}nd}d}x~|jddD ]n}t|j dkrp|j t jkr|j }n:|j dkrdd |j D }d	d |D }t|}nd}||7 }qpW W n t jk
r   d
S X t	||}|S )a  
    Function to get the number of threads a process is using

    Parameters
    ----------
    pid : integer
        the process ID of process to profile

    Returns
    -------
    num_threads : int
        the number of threads that the process is using

    r.   c             S   s   g | ]}t j|jqS r   )r   r#   rM   )r`   thrr   r   r	   rb     s    z$_get_num_threads.<locals>.<listcomp>c             S   s   g | ]}|j  tjkr|qS r   )r\   r   STATUS_RUNNING)r`   tprocr   r   r	   rb     s    r   T)r<   c             S   s   g | ]}t j|jqS r   )r   r#   rM   )r`   r{   r   r   r	   rb   -  s    c             S   s   g | ]}|j  tjkr|qS r   )r\   r   r|   )r`   r}   r   r   r	   rb   /  s   N)
r   r#   r\   r|   rO   threadslenrB   rA   r7   )r   procrO   ZtprocsZalive_tprocsZchild_threadsrF   Z	child_thrr   r   r	   ru     s2    





ru   c             C   st   yXt j| }|j j}|t }x6|jddD ]&}|j j}|rF||8 }||t 7 }q,W W n t jk
rn   dS X |S )a  
    Function to get the RAM usage of a process and its children
    Reference: http://ftp.dev411.com/t/python/python-list/095thexx8g/multiprocessing-forking-memory-usage

    Parameters
    ----------
    pid : integer
        the PID of the process to get RAM usage of
    pyfunc : boolean (optional); default=False
        a flag to indicate if the process is a python function;
        when Pythons are multithreaded via multiprocess or threading,
        children functions include their own memory + parents. if this
        is set, the parent memory will removed from children memories


    Returns
    -------
    mem_mb : float
        the memory RAM in MB utilized by the process PID

    T)r<   N)r   r#   r>   r?   rD   rB   rA   )r   rr   parentZ
parent_memrx   rF   Z	child_memr   r   r	   rt   D  s    


rt   c             C   s&   d}x|dk r |d7 }| |   qW d S )Nr   g    cAr.   r   )xZctrr   r   r	   _use_cpun  s    
r   c                s   ddl }ddlddl}ddlm} ddlm} ddlm} |j	d}j
dj
d j
d	 d fdd}|j|j }	|	j j }
|||
 }|d |	j j }~|jd|j |
| | dkr|| }|j|t|  dS )zG
    Function to execute multiple use_gb_ram functions in parallel
    r   N)Pool)r   )r   znipype.interfacez  rd    g      @r/   c                s2   t |  }d|    }j||ks.t|S )z+A test function to consume mem_gb GB of RAMrd   )int	getsizeofAssertionError)rV   	num_bytesZgb_str)BOFFSETBSIZE_GBrf   r   r	   _use_gb_ram  s    z#_use_resources.<locals>._use_gb_ramr   z)[%d] Memory offset %0.2fGB, total %0.2fGBr.   Tg      A)r   rf   r   multiprocessingr   Znipyper   Znipype.utils.profilerr   rX   r   r#   getpidr>   r?   rw   maprange)rW   rV   r   r   r   r   r   Zifloggerr   pZ
mem_offsetZbig_strro   poolr   )r   r   r   rf   r	   _use_resourcesv  s.    

	r   g      0A)F)F)r   r   numpyr5   r&   r   r   ImportErrorry   r   r   r   rX   rv   rs   rD   r   r'   r   r]   rq   rz   ru   rt   r   r   r   r   r   r	   <module>   s*   
h.
%@
*