a
    ƹDf87                     @   s   d Z dadd Zdd ZG dd de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G dd deZdS )a  
This module contains functions for profiling in other threads and processes.

Functions for identifying a thread/process:
    process_id   - get the identifier (process id) for the current process
    thread_id    - get the identifier for the current thread

Functions for controlling profiling:
    enable_profiling - initialize a profiler in the current thread/process
    start_profiling  - begin profiling everything in the current thread/process
    stop_profiling   - stop profiling everything in the current thread/process
    disable_profiling - remove the profiler from the current thread/process

Functions that control profile statstics (pstats) output
    clear_stats  - clear stored pstats from the current thread/process
    get_stats    - get stored pstats for the current thread/process
    print_stats  - print stored pstats for the current thread/process
    dump_stats   - dump stored pstats for the current thread/process

Functions that add/remove profiling:
    profiled     - decorator to add profiling to a function
    not_profiled - decorator to remove profiling from a function
    profile     -  decorator for profiling a function (will enable_profiling)

Usage
=====

Typical calls to pathos profiling will roughly follow this example::

    >>> import time
    >>> import random
    >>> import pathos.profile as pr
    >>>
    >>> # build a worker function
    >>> def _work(i):
    ...     x = random.random()
    ...     time.sleep(x)
    ...     return (i,x)
    >>>
    >>> # generate a 'profiled' work function
    >>> config = dict(gen=pr.process_id)
    >>> work = pr.profiled(**config)(_work)
    >>> 
    >>> # enable profiling
    >>> pr.enable_profiling()
    >>> 
    >>> # profile the work (not the map internals) in the main process
    >>> for i in map(work, range(-10,0)):
    ...     print(i)
    ...
    >>> # profile the map in the main process, and work in the other process
    >>> from pathos.helpers import mp
    >>> pool = mp.Pool(10)
    >>> _uimap = pr.profiled(**config)(pool.imap_unordered)
    >>> for i in _uimap(work, range(-10,0)):
    ...     print(i)
    ...
    >>> # deactivate all profiling
    >>> pr.disable_profiling() # in the main process
    >>> tuple(_uimap(pr.disable_profiling, range(10))) # in the workers
    >>> for i in _uimap(work, range(-20,-10)):
    ...     print(i)
    ...
    >>> # re-activate profiling
    >>> pr.enable_profiling()
    >>> 
    >>> # print stats for profile of 'import math' in another process
    >>> def test_import(module):
    ...    __import__(module)
    ...
    >>> import pathos.pools as pp
    >>> pool = pp.ProcessPool(1)
    >>> pr.profile('cumulative', pipe=pool.pipe)(test_import, 'pox')
         10 function calls in 0.003 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.003    0.003 <stdin>:1(test_import)
        1    0.002    0.002    0.003    0.003 {__import__}
        1    0.001    0.001    0.001    0.001 __init__.py:8(<module>)
        1    0.000    0.000    0.000    0.000 shutils.py:11(<module>)
        1    0.000    0.000    0.000    0.000 _disk.py:15(<module>)
        1    0.000    0.000    0.000    0.000 {eval}
        1    0.000    0.000    0.000    0.000 utils.py:11(<module>)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 info.py:2(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


    >>> pool.close()
    >>> pool.join()
    >>> pool.clear()


Notes
=====

This module leverages the python's cProfile module, and is primarily a
high-level interface to that module that strives to make profiling in
a different thread or process easier.  The use of pathos.pools are suggested,
however are not required (as seen in the example above).

In many cases, profiling in another thread is not necessary, and either of
the following can be sufficient/better for timing and profiling::

    $ python -c "import time; s=time.time(); import pathos; print (time.time()-s)"
    $ python -c "import cProfile; p=cProfile.Profile(); p.enable(); import pathos; p.print_stats('cumulative')"

This module was inspired by: http://stackoverflow.com/a/32522579/4646678.
Nc                  C   s   ddl m}  |  jS )z7get the identifier (process id) for the current process    mp)Zpathos.helpersr   current_processpidr    r   [/nfs/NAS7/SABIOD/METHODE/ermites/ermites_venv/lib/python3.9/site-packages/pathos/profile.py
process_idz   s    r   c                  C   s   ddl } |  jS )z)get the identifier for the current threadr   N)	threadingcurrent_threadident)thr   r   r   	thread_id   s    r   c                   @   s"   e Zd ZdZd	ddZdd ZdS )
profiledzCdecorator for profiling a function (does not call enable profiling)Nid-.profc                 C   sV   || _ || _t|ttfv r:t|tu r,dn|| _t| _nd| _|du rLtn|| _dS )a  y=gen(), with y an indentifier (e.g. current_process().pid)

Important class members:
    prefix	- string prefix for pstats filename [default: 'id-']
    suffix      - string suffix for pstats filename [default: '.prof']
    pid         - function for obtaining id of current process/thread
    sort        - integer index of column in pstats output for sorting

Example:
    >>> import time
    >>> import random
    >>> import pathos.profile as pr
    >>>
    >>> config = dict(gen=pr.process_id)
    >>> @pr.profiled(**config)
    ... def work(i):
    ...     x = random.random()
    ...     time.sleep(x)
    ...     return (i,x)
    ...
    >>> pr.enable_profiling()
    >>> # profile the work (not the map internals); write to file for pstats
    >>> for i in map(work, range(-10,0)):
    ...     print(i)
    ...

NOTE: If gen is a bool or string, then sort=gen and pid is not used.
      Otherwise, pid=gen and sort is not used. Output can be ordered
      by setting gen to one of the following:
      'calls'      - call count
      'cumulative' - cumulative time
      'cumtime'    - cumulative time
      'file'       - file name
      'filename'   - file name
      'module'     - file name
      'ncalls'     - call count
      'pcalls'     - primitive call count
      'line'       - line number
      'name'       - function name
      'nfl'        - name/file/line
      'stdname'    - standard name
      'time'       - internal time
      'tottime'    - internal time
        N)prefixsuffixtypeboolstrsortr   r   )selfgenr   r   r   r   r   __init__   s    -zprofiled.__init__c                    s    fdd} |_ |S )Nc                     s   zt   d}W n* ty&   d}Y n ty:   d}Y n0  | i |}|rt   jtu rnt j nt 	dj
 jf  |S )NTF%s%s%s)profilerenableAttributeError	NameErrordisabler   r   print_statsr   
dump_statsr   r   )argskwdsZdoitresfr   r   r   	proactive   s    z$profiled.__call__.<locals>.proactive)__wrapped__)r   r'   r(   r   r&   r   __call__   s    zprofiled.__call__)Nr   r   __name__
__module____qualname____doc__r   r*   r   r   r   r   r      s   
6r   c                    s2   t | dddkrt | d|  n|   fdd}|S )zAdecorator to remove profiling (due to 'profiled') from a functionr,   Nr(   r)   c                     s    | i |S Nr   )r#   r$   _fr   r   wrapper   s    znot_profiled.<locals>.wrapper)getattr)r'   r3   r   r1   r   not_profiled   s
    r5   c                  G   s   ddl }| adS )z<initialize a profiler instance in the current thread/processr   N)cProfileZProfiler   )r#   r6   r   r   r   enable_profiling   s    r7   c                  G   sB   t du rt  zt   W n" ty,   Y n ty<   Y n0 dS )z8begin profiling everything in the current thread/processN)r   r7   r   r   r   r#   r   r   r   start_profiling   s
    r9   c                  G   s4   zt   W n" ty   Y n ty.   Y n0 dS )z7stop profiling everything in the current thread/processN)r   r    r   r   r8   r   r   r   stop_profiling   s    r:   c                  G   s$   t durt  t dd da dS )z<remove the profiler instance from the current thread/processNr   )r   r:   globalspopr8   r   r   r   disable_profiling   s    r=   c                  G   s4   zt   W n" ty   Y n ty.   Y n0 dS )zBclear all stored profiling results from the current thread/processN)r   clearr   r   r8   r   r   r   clear_stats   s    r?   c                  G   s4   zt  }W n" ty   Y n ty.   Y n0 |S )z?get all stored profiling results for the current thread/process)r   Zgetstatsr   r   )r#   r%   r   r   r   	get_stats   s    r@   c                  O   sB   | dd}zt| W n" ty,   Y n ty<   Y n0 dS )zAprint all stored profiling results for the current thread/processr   r   N)getr   r!   r   r   )r#   r$   r   r   r   r   r!     s
    r!   c                  O   s   t dddd}|| |d }|d }|d }|du r<tn|}d|| |f }zt| W n" typ   Y n ty   Y n0 dS )	zdump all stored profiling results for the current thread/process

Notes:
    see ``pathos.profile.profiled`` for settings for ``*args`` and ``**kwds``
    Nr   r   )r   r   r   r   r   r   r   )dictupdater   r   r"   r   r   )r#   r$   configr   r   r   filer   r   r   r"   
  s    
r"   c                   @   s"   e Zd ZdZdddZdd ZdS )profilez:decorator for profiling a function (will enable profiling)Nc                 K   s   | dd}t|ttdfvr0|t|d t|sBtddn|| _ddlm} |du rp| | _| jj	| _	n|| _	t
|d| | _| jjdkrtd	dS )
aa  sort is integer index of column in pstats output for sorting

Important class members:
    pipe        - pipe instance in which profiling is active

Example:
    >>> import time
    >>> import random
    >>> import pathos.profile as pr
    >>>
    ... def work():
    ...     x = random.random()
    ...     time.sleep(x)
    ...     return x
    ...
    >>> # profile the work; print pstats info
    >>> pr.profile()(work)
             4 function calls in 0.136 seconds

       Ordered by: standard name

       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
            1    0.000    0.000    0.136    0.136 <stdin>:1(work)
            1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
            1    0.000    0.000    0.000    0.000 {method 'random' of '_random.Random' objects}
            1    0.136    0.136    0.136    0.136 {time.sleep}

    0.1350568110491419
    >>>

NOTE: pipe provided should come from pool built with nodes=1. Other
      configuration keywords (config) are passed to 'pr.profiled'.
      Output can be ordered by setting sort to one of the following:
      'calls'      - call count
      'cumulative' - cumulative time
      'cumtime'    - cumulative time
      'file'       - file name
      'filename'   - file name
      'module'     - file name
      'ncalls'     - call count
      'pcalls'     - primitive call count
      'line'       - line number
      'name'       - function name
      'nfl'        - name/file/line
      'stdname'    - standard name
      'time'       - internal time
      'tottime'    - internal time
        pipeN)r   Fr   )
SerialPool__self__   z-pipe must draw from a pool with only one node)r<   r   r   rC   rB   rD   Zpathos.poolsrH   _poolrG   r4   nodes
ValueError)r   r   rD   rG   rH   r   r   r   r     s    1zprofile.__init__c                 O   sD   |  td  | j tf i | j|g|R i |}|  td  |S r0   )rG   r7   r   rD   r=   )r   functionr#   r$   resultr   r   r   r*   ]  s    (zprofile.__call__)Nr+   r   r   r   r   rF     s   
?rF   )r/   r   r   r   objectr   r5   r7   r9   r:   r=   r?   r@   r!   r"   rF   r   r   r   r   <module>   s   pH
I