U
    iâËd×£  ã                   @   sæ  d 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Zddl	Z	ddl
Z
ddlZddlmZmZmZmZ ddlmZmZmZmZmZmZ ddlZddlmZ ddlmZ ed Z z&ddl!m"Z" e"ƒ  dd	l#m$Z$ d
Z%W n e&k
rú   dZ%Y nX zddl#m'Z' d
Z(W n e&k
�r*   dZ(Y nX zddl)Z*d
Z+W n e&k
�rV   dZ+Y nX e
 ,e(d¡Z-e
 ,e%d¡Z.e(�o~e'j/dkZ0e
 ,e0d¡Z1ej2 3d¡Z4ej2 3d¡Z5ej6dkZ7e7Z8e4 Z9dd„ Z:e+�rÐdd„ Z;ndd„ Z;dd„ Z<dd„ Z=G dd„ de>ƒZ?G dd „ d e?ƒZ@G d!d"„ d"e>ƒZAG d#d$„ d$e?ƒZBG d%d&„ d&e?ƒZCG d'd(„ d(e?ƒZDd)d*„ ZEd+d,„ ZFe	jGZHG d-d.„ d.e>ƒZId/d0„ ZJeFeHejKƒZLeFeJd1ƒŽ ZMe4�s¬eFeJd2ƒŽ ZNeFeJd3ƒŽ ZOeFeJd4ƒŽ ZPG d5d6„ d6eƒZQejRd7kZSe
 ,eSd8¡G d9d:„ d:eQƒƒZTeT U¡  G d;d<„ d<e>ƒZVG d=d>„ d>eVeQƒZWeW U¡  G d?d@„ d@eƒZXeG dAdB„ dBeXƒƒZYeY U¡  eG dCdD„ dDeXƒƒZZeG dEdF„ dFeXƒƒZ[ee1G dGdH„ dHeXƒƒƒZ\ee.G dIdJ„ dJeXƒƒƒZ]eG dKdL„ dLeƒƒZ^ee-G dMdN„ dNeƒƒƒZ_e`dOk�râe
 a¡  dS )Pz
Tests the parallel backend
é    N)ÚjitÚ	vectorizeÚguvectorizeÚset_num_threads)Útemp_directoryÚoverride_configÚTestCaseÚtagÚskip_parfors_unsupportedÚ
linux_only)Ú_TIMEOUT)Úconfigg      N@)Ú_check_tbb_version_compatible)ÚtbbpoolTF)ÚomppoolzOpenMP threadpool requiredzTBB threadpool requiredÚGNUzGNU OpenMP only testsÚwinÚdarwinl        c                 C   s   t  | ¡| S ©N)ÚnpÚones©ÚnÚv© r   úZ/home/sam/Atlas/atlas_env/lib/python3.8/site-packages/numba/tests/test_parallel_backend.pyÚfooG   s    r   c                 C   s2   t  t  | | f¡t  | | f¡¡}|t  | ¡ | S r   )r   Údotr   Úarange)r   r   Úxr   r   r   ÚlinalgL   s     r    c                 C   s   t  | ¡| S r   )r   r   r   r   r   r   r    P   s    c                 C   s   | | S r   r   )ÚaÚbr   r   r   Ú	ufunc_fooU   s    r#   c                 C   s   | | |d< d S )Nr   r   )r!   r"   Úoutr   r   r   Ú
gufunc_fooY   s    r%   c                   @   s   e Zd Zdd„ ZdS )Úrunnablec                 K   s
   || _ d S r   )Ú_options)ÚselfÚoptionsr   r   r   Ú__init__^   s    zrunnable.__init__N)Ú__name__Ú
__module__Ú__qualname__r*   r   r   r   r   r&   ]   s   r&   c                   @   s   e Zd Zdd„ ZdS )Ú
jit_runnerc                 C   s>   t f | jŽtƒ}d}d}t||ƒ}|||ƒ}tj ||¡ d S ©Né   é
   )r   r'   r   r   ÚtestingÚassert_allclose©r(   Úcfuncr!   r"   ÚexpectedÚgotr   r   r   Ú__call__d   s    

zjit_runner.__call__N©r+   r,   r-   r8   r   r   r   r   r.   b   s   r.   c                   @   s   e Zd Zdd„ Zdd„ ZdS )Úmask_runnerc                 K   s   || _ || _d S r   )ÚrunnerÚmask)r(   r;   r<   r)   r   r   r   r*   n   s    zmask_runner.__init__c                 C   s   | j rt| j ƒ |  ¡  d S r   )r<   r   r;   )r(   r   r   r   r8   r   s    
zmask_runner.__call__N©r+   r,   r-   r*   r8   r   r   r   r   r:   m   s   r:   c                   @   s   e Zd Zdd„ ZdS )Úlinalg_runnerc                 C   s>   t f | jŽtƒ}d}d}t||ƒ}|||ƒ}tj ||¡ d S r/   )r   r'   r    r   r2   r3   r4   r   r   r   r8   |   s    

zlinalg_runner.__call__Nr9   r   r   r   r   r>   z   s   r>   c                   @   s   e Zd Zdd„ ZdS )Úvectorize_runnerc                 C   sR   t dgf| jŽtƒ}tj d¡ tj¡ }}t||ƒ}|||ƒ}tj ||¡ d S )Nz(f4, f4)r1   )	r   r'   r#   r   ÚrandomÚastypeÚfloat32r2   r3   r4   r   r   r   r8   ‡   s
    

zvectorize_runner.__call__Nr9   r   r   r   r   r?   …   s   r?   c                   @   s   e Zd Zdd„ ZdS )Úguvectorize_runnerc                 C   sX   dg}t |df| jŽtƒ}tj d¡ tj¡ }}t||ƒ}|||ƒ}tj 	||¡ d S )Nz(f4, f4, f4[:])z	(),()->()r1   )
r   r'   r%   r   r@   rA   rB   r#   r2   r3   )r(   Úsigr5   r!   r"   r6   r7   r   r   r   r8   ‘   s    

zguvectorize_runner.__call__Nr9   r   r   r   r   rC   �   s   rC   c              
   K   sr   |  d¡}z6t ¡  ttt| ƒd ƒƒD ]}t | ¡}|ƒ  q(W n, tk
rl } z| 	|¡ W 5 d }~X Y nX d S )NÚqueueg      ø?)
ÚgetÚfaulthandlerÚenableÚrangeÚintÚlenr@   ÚchoiceÚ	ExceptionÚput)ÚfnlistÚkwargsÚqÚ_ÚfnÚer   r   r   Úchooserš   s    

rU   c                    s   ‡ ‡fdd„}|S )Nc                    s–   ˆƒ }d|i‰‡ ‡‡fdd„t dƒD ƒ}|D ]}| ¡  q,|D ]}| ¡  q>| ¡ s’g }| ¡ sr| | d¡¡ qXd}t|d dd„ |D ƒ¡ ƒ‚d S )	NrE   c                    s   g | ]}ˆt ˆ fˆd �‘qS ))ÚtargetÚargsrP   )rU   )Ú.0Úi)rO   ÚkwsÚparallel_classr   r   Ú
<listcomp>©   s   ÿz8compile_factory.<locals>.run_compile.<locals>.<listcomp>r0   Fz)Error(s) occurred in delegated runner:
%sÚ
c                 S   s   g | ]}t |ƒ‘qS r   )Úrepr)rX   r   r   r   r   r\   ´   s     )rI   ÚstartÚjoinÚemptyÚappendrF   ÚRuntimeError)rO   rQ   ZthsÚthÚerrorsÚ_msg©r[   Ú
queue_impl)rO   rZ   r   Úrun_compile¦   s    ÿ

z$compile_factory.<locals>.run_compiler   )r[   rh   ri   r   rg   r   Úcompile_factory¥   s    rj   c                   @   s   e Zd Zdd„ Zdd„ ZdS )Ú_proc_class_implc                 C   s
   || _ d S r   )Ú_method)r(   Úmethodr   r   r   r*   ¾   s    z_proc_class_impl.__init__c                 O   s   t  | j¡}|j||ŽS r   )ÚmultiprocessingÚget_contextrl   ÚProcess)r(   rW   rP   Úctxr   r   r   r8   Á   s    z_proc_class_impl.__call__Nr=   r   r   r   r   rk   ¼   s   rk   c                 C   s,   | dkrd } t  | ¡}t| ƒ}|j}||fS )NÚdefault)rn   ro   rk   ÚQueue)rm   rq   ÚprocrE   r   r   r   Ú_get_mp_classesÆ   s    
ru   ÚspawnÚforkÚ
forkserverrr   c                   @   sj  e Zd ZdZedd�eddd�eddd�edd�eddd�edd�eddd�edddd�edd�eddd�edddd�gZe	s¸eddd	�edddd
�eddd	�edddd
�gZ
e e
¡ ejdk rÈg ZnddgZg ZeD ]ZeD ]Ze eeeƒ¡ qàqØddgZe d¡ e�r$e d¡ e d¡ ede	 d	�geddd�geddd�geedœZddhZddd„ZdS )ÚTestParallelBackendBasez6
    Base class for testing the parallel backends
    T)Únopython)rz   Úcache)rz   ZnogilÚparallel)rz   rV   )rz   rV   r{   )rz   r|   )rz   r|   r{   é   é   Ú	threadingr@   Úmultiprocessing_spawnÚmultiprocessing_forkÚmultiprocessing_forkserver)Zconcurrent_jitZconcurrent_vectorizeZconcurrent_guvectorizeZconcurrent_mix_useZconcurrent_mix_use_masksÚompÚtbbc              	   C   sÖ   t | jjƒ| _td| jƒ�² |dkr.t|ƒ nš|dkr@t|ƒ nˆ|dkrRt|ƒ nv|dkrdt|ƒ nd|dkrvt	|ƒ nR|dkr¼ttg}t
rž| t¡ | t¡ t |¡ |D ]}||ƒ q¬ntd| ƒ‚W 5 Q R X d S )	NZ	CACHE_DIRr   r�   r‚   r€   Zmultiprocessing_defaultr@   zUnknown parallelism supplied %s)r   Ú	__class__r+   Z
_cache_dirr   Úthread_implÚfork_proc_implÚforkserver_proc_implÚspawn_proc_implÚdefault_proc_implÚ_HAVE_OS_FORKrb   r@   ÚshuffleÚ
ValueError)r(   rO   ÚparallelismZpsÚimplr   r   r   ri     s.    







ÿz#TestParallelBackendBase.run_compileN)r   )r+   r,   r-   Ú__doc__r.   r>   r?   rC   Z	all_implsÚ_parfors_unsupportedZparfor_implsÚextendr   ÚNUMBA_NUM_THREADSÚmasksZ
mask_implsr�   r<   rb   r:   rŽ   r‹   ÚrunnersZsafe_backendsri   r   r   r   r   ry   Ú   sV   




õ

ü




ÿ
ÿ
ÿõry   )rƒ   r„   Ú	workqueuezThreading layer not explicitc                   @   s   e Zd ZdZedd„ ƒZdS )ÚTestParallelBackendav   These are like the numba.tests.test_threadsafety tests but designed
    instead to torture the parallel backend.
    If a suitable backend is supplied via NUMBA_THREADING_LAYER these tests
    can be run directly. This test class cannot be run using the multiprocessing
    option to the test runner (i.e. `./runtests -m`) as daemon processes cannot
    have children.
    c                 C   sX   | j D ]L}| j ¡ D ]<\}}d| d | }dd„ }|||ƒ}||_t| ||ƒ qqd S )NÚtest_rR   c                    s   ‡ ‡fdd„}|S )Nc                    s0   t  ¡ }|jrd}|  |¡ n| jˆ ˆd� d S )Nz)daemonized processes cannot have children)rŽ   )rn   Úcurrent_processÚdaemonÚskipTestri   )r(   Zselfprocrf   ©r�   Úpr   r   Útest_methodI  s
    zBTestParallelBackend.generate.<locals>.methgen.<locals>.test_methodr   )r�   r�   rž   r   rœ   r   ÚmethgenH  s    z-TestParallelBackend.generate.<locals>.methgen)rŽ   r•   Úitemsr+   Úsetattr)Úclsr�   Únamer�   ÚmethnamerŸ   rS   r   r   r   ÚgenerateB  s    


zTestParallelBackend.generateN)r+   r,   r-   r�   Úclassmethodr¥   r   r   r   r   r—   5  s   r—   c                   @   s0   e Zd Zeee dd¡dœZdd„ Zdd„ Z	dS )	ÚTestInSubprocessFÚ ©r„   rƒ   r–   c                 C   s|   t j|t jt j|d�}t t|j¡}zH| ¡  | 	¡ \}}|j
dkrZtd|j
| ¡ f ƒ‚| ¡ | ¡ fW ¢S | ¡  X dS )N©ÚstdoutÚstderrÚenvr   ú/process failed with code %s: stderr follows
%s
)NN©Ú
subprocessÚPopenÚPIPEr   ÚTimerÚ_TEST_TIMEOUTÚkillÚcancelr_   ÚcommunicateÚ
returncodeÚAssertionErrorÚdecode©r(   Úcmdliner­   ÚpopenÚtimeoutr$   Úerrr   r   r   Úrun_cmd_  s$    ý
ÿÿ
zTestInSubprocess.run_cmdc                 C   s0   t j ¡ }t|ƒ|d< tjdd|g}|  ||¡S )NÚNUMBA_THREADING_LAYERz-mznumba.runtests)ÚosÚenvironÚcopyÚstrÚsysÚ
executablerÀ   )r(   ÚtestZthreading_layerZenv_copyr¼   r   r   r   Úrun_test_in_separate_processr  s    
z-TestInSubprocess.run_test_in_separate_processN)
r+   r,   r-   Úskip_no_tbbÚskip_no_ompÚunittestÚskipIfÚbackendsrÀ   rÉ   r   r   r   r   r§   Z  s   
þr§   c                   @   s,   e Zd ZdZdZedd„ ƒZedd„ ƒZdS )ÚTestSpecificBackenda¦  
    This is quite contrived, for each test in the TestParallelBackend tests it
    generates a test that will run the TestParallelBackend test in a new python
    process with an environment modified to ensure a specific threadsafe backend
    is used. This is with view of testing the backends independently and in an
    isolated manner such that if they hang/crash/have issues, it doesn't kill
    the test suite.
    Fc           
         sb   | j }tj}d| d | }d|||f ‰‡ ‡fdd„}d||ˆ f }	t| |	tdƒ||ƒƒƒ d S )Nr˜   rR   z%s.%s.%sc                    sR   |   ˆˆ ¡\}}| jr&td||f ƒ |  d|¡ |  d|k¡ |  d|k¡ d S )Nzstdout:
 "%s"
 stderr:
 "%s"ÚOKÚFAILÚERROR)rÉ   Ú_DEBUGÚprintÚassertInÚ
assertTrue)r(   ÚorT   ©ÚbackendZinjected_methodr   r   Útest_template‹  s    z2TestSpecificBackend._inject.<locals>.test_templateztest_%s_%s_%sZlong_running)r,   r—   r+   r¡   r	   )
r¢   r�   r£   rÙ   Úbackend_guardZthemodZtheclsr¤   rÚ   Úinjected_testr   rØ   r   Ú_inject„  s    ÿzTestSpecificBackend._injectc              	   C   st   | j  ¡ D ]d\}}| jD ]T}| j ¡ D ]D}|dkrH|dkrHtj d¡rHq&|dkrZ|dkrZq&|  ||||¡ q&qq
d S )N)r�   r@   rƒ   Úlinux)r   r@   r–   )	rÎ   r    rŽ   r•   ÚkeysrÆ   ÚplatformÚ
startswithrÝ   )r¢   rÙ   rÛ   r�   r£   r   r   r   r¥   —  s    
ÿ
þÿzTestSpecificBackend.generateN)r+   r,   r-   r�   rÓ   r¦   rÝ   r¥   r   r   r   r   rÏ   y  s   
rÏ   c                   @   s6   e Zd ZdZdej e¡ Zddei Z	ddd„Z
dS )	ÚThreadLayerTestHelperzP
    Helper class for running an isolated piece of code based on a template
    z%raõ  if 1:
    import sys
    sys.path.insert(0, "%(here)r")
    import multiprocessing
    import numpy as np
    from numba import njit
    import numba
    try:
        import threading_backend_usecases
    except ImportError as e:
        print("DEBUG:", sys.path)
        raise e
    import os

    sigterm_handler = threading_backend_usecases.sigterm_handler
    busy_func = threading_backend_usecases.busy_func

    def the_test():
        %%s

    if __name__ == "__main__":
        the_test()
    ÚhereNc                 C   s–   |d krt j ¡ }tdƒ|d< tj|tjtj|d�}t t	|j
¡}z8| ¡  | ¡ \}}|jdkrxtd|j| ¡ f ƒ‚W 5 | ¡  X | ¡ | ¡ fS )Nrƒ   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À   Ï  s(    
ý
ÿÿ
zThreadLayerTestHelper.run_cmd)N)r+   r,   r-   r�   rÂ   ÚpathÚdirnameÚ__file__Z_hereÚtemplaterÀ   r   r   r   r   râ   ¯  s   êrâ   c                   @   s@   e Zd ZdZdZeee dd¡dœZ	e
dd„ ƒZe
dd„ ƒZd	S )
ÚTestThreadingLayerSelectionz@
    Checks that numba.threading_layer() reports correctly.
    Fr¨   r©   c                    s0   ‡ fdd„}dˆ  }t | |tdƒ||ƒƒƒ d S )Nc                    sZ   d}| j |ˆ   }tjd|g}tj ¡ }tˆ ƒ|d< | j||d�\}}| jrVt	||ƒ d S )Nz½if 1:
                X = np.arange(1000000.)
                Y = np.arange(1000000.)
                Z = busy_func(X, Y)
                assert numba.threading_layer() == '%s'
            ú-crÁ   ©r­   )
rç   rÆ   rÇ   rÂ   rÃ   rÄ   rÅ   rÀ   rÓ   rÔ   )r(   ÚbodyÚrunmer¼   r­   r$   r¿   ©rÙ   r   r   rÚ   ó  s    
z:TestThreadingLayerSelection._inject.<locals>.test_templatez test_threading_layer_selector_%sZ	important)r¡   r	   )r¢   rÙ   rÛ   rÚ   rÜ   r   rí   r   rÝ   ð  s
    ÿz#TestThreadingLayerSelection._injectc                 C   s$   | j  ¡ D ]\}}|  ||¡ q
d S r   )rÎ   r    rÝ   )r¢   rÙ   rÛ   r   r   r   r¥     s    z$TestThreadingLayerSelection.generateN)r+   r,   r-   r�   rÓ   rÊ   rË   rÌ   rÍ   rÎ   r¦   rÝ   r¥   r   r   r   r   rè   å  s   
þ
rè   c                   @   sZ   e Zd Zedœdd„Zeedd„ ƒƒZeedd„ ƒƒZedd	„ ƒZ	ed
d„ ƒZ
dd„ ZdS )ÚTestThreadingLayerPriority)Úenv_varc                 C   sJ   t j ¡ }d|d< ||d< d|› d�}tjdt |¡g}| j||d� dS )	zJTest setting priority via env var NUMBA_THREADING_LAYER_PRIORITY.
        rr   rÁ   ZNUMBA_THREADING_LAYER_PRIORITYa²  
                import numba

                # trigger threading layer decision
                # hence catching invalid THREADING_LAYER_PRIORITY
                @numba.jit(
                    'float64[::1](float64[::1], float64[::1])',
                    nopython=True,
                    parallel=True,
                )
                def plus(x, y):
                    return x + y

                captured_envvar = list("a	  ".split())
                assert numba.config.THREADING_LAYER_PRIORITY ==                     captured_envvar, "priority mismatch"
                assert numba.threading_layer() == captured_envvar[0],                    "selected backend mismatch"
                ré   rê   N)rÂ   rÃ   rÄ   rÆ   rÇ   ÚtextwrapÚdedentrÀ   )r(   rï   r­   ÚcodeÚcmdr   r   r   Úeach_env_var  s    
óýz'TestThreadingLayerPriority.each_env_varc                 C   s2   dddg}t  |¡D ]}d |¡}|  |¡ qd S )Nr„   rƒ   r–   ú )Ú	itertoolsÚpermutationsr`   rô   )r(   rr   r�   rï   r   r   r   Útest_valid_env_var2  s    

z-TestThreadingLayerPriority.test_valid_env_varc              	   C   sF   d}|   t¡�}|  |¡ W 5 Q R X dD ]}|  |› t|jƒ¡ q(d S )Nztbb omp workqueue notvalidhere)z!THREADING_LAYER_PRIORITY invalid:zIt must be a permutation of)ÚassertRaisesr¹   rô   rÕ   rÅ   Ú	exception)r(   rï   ZraisesÚmsgr   r   r   Útest_invalid_env_var:  s
    z/TestThreadingLayerPriority.test_invalid_env_varc                 C   s   dD ]}|   |¡ qd S )N)zomp tbb workqueuezomp workqueue tbb©rô   ©r(   rï   r   r   r   Útest_ompF  s    z#TestThreadingLayerPriority.test_ompc                 C   s   dD ]}|   |¡ qd S )N)ztbb omp workqueueztbb workqueue omprý   rþ   r   r   r   Útest_tbbK  s    z#TestThreadingLayerPriority.test_tbbc                 C   s   dD ]}|   |¡ qd S )N)zworkqueue tbb ompzworkqueue omp tbbrý   rþ   r   r   r   Útest_workqueueP  s    z)TestThreadingLayerPriority.test_workqueueN)r+   r,   r-   rÅ   rô   rË   rÊ   rø   rü   rÿ   r   r  r   r   r   r   rî     s   !


rî   c                   @   sH   e Zd ZdZdZedd„ ƒZedd„ ƒZdd„ Z	e
 ed	¡d
d„ ƒZdS )ÚTestMiscBackendIssueszL
    Checks fixes for the issues with threading backends implementation
    Fc                 C   s<   d}t jd|g}tj ¡ }d|d< d|d< | j||d� dS )	z8
        Tests that OMP does not overflow stack
        a‹  if 1:
            from numba import vectorize, threading_layer
            import numpy as np

            @vectorize(['f4(f4,f4,f4,f4,f4,f4,f4,f4)'], target='parallel')
            def foo(a, b, c, d, e, f, g, h):
                return a+b+c+d+e+f+g+h

            x = np.ones(2**20, np.float32)
            foo(*([x]*8))
            assert threading_layer() == "omp", "omp not found"
        ré   rƒ   rÁ   Z100KZOMP_STACKSIZErê   N©rÆ   rÇ   rÂ   rÃ   rÄ   rÀ   ©r(   rì   r¼   r­   r   r   r   Útest_omp_stack_overflow\  s    
z-TestMiscBackendIssues.test_omp_stack_overflowc                 C   s<   d}t jd|g}tj ¡ }d|d< d|d< | j||d� dS )	zq
        Tests that TBB works well with single thread
        https://github.com/numba/numba/issues/3440
        aM  if 1:
            from numba import njit, prange, threading_layer

            @njit(parallel=True)
            def foo(n):
                acc = 0
                for i in prange(n):
                    acc += i
                return acc

            foo(100)
            assert threading_layer() == "tbb", "tbb not found"
        ré   r„   rÁ   Ú1r“   rê   Nr  r  r   r   r   Útest_single_thread_tbbs  s    
z,TestMiscBackendIssues.test_single_thread_tbbc           	   
   C   sœ   d}t jd|g}tj ¡ }d|d< d|d< z| j||d�\}}W nV tk
r– } z8| jrbt||ƒ t	|ƒ}|  
d|¡ d	}|  
||¡ W 5 d
}~X Y nX d
S )zW
        Tests workqueue raises sigabrt if a nested parallel call is performed
        a¸  if 1:
            from numba import njit, prange
            import numpy as np

            @njit(parallel=True)
            def nested(x):
                for i in prange(len(x)):
                    x[i] += 1


            @njit(parallel=True)
            def main():
                Z = np.zeros((5, 10))
                for i in prange(Z.shape[0]):
                    nested(Z[i])
                return Z

            main()
        ré   r–   rÁ   Ú4r“   rê   zfailed with codezTNumba workqueue threading layer is terminating: Concurrent access has been detected.N)rÆ   rÇ   rÂ   rÃ   rÄ   rÀ   r¹   rÓ   rÔ   rÅ   rÕ   )	r(   rì   r¼   r­   r$   r¿   rT   Ze_msgr6   r   r   r   Ú+test_workqueue_aborts_on_nested_parallelismŒ  s    

zATestMiscBackendIssues.test_workqueue_aborts_on_nested_parallelismzTest needs fork(2)c                 C   s<   d}t jd|g}tj ¡ }d|d< d|d< | j||d� d S )NaÛ  if 1:
            from numba import njit, prange, threading_layer
            import numpy as np
            import multiprocessing

            if __name__ == "__main__":
                # Need for force fork context (OSX default is "spawn")
                multiprocessing.set_start_method('fork')

                @njit(parallel=True)
                def func(x):
                    return 10. * x

                arr = np.arange(2.)

                # run in single process to start Numba's thread pool
                np.testing.assert_allclose(func(arr), func.py_func(arr))

                # now run in a multiprocessing pool to get a fork from a
                # non-main thread
                with multiprocessing.Pool(10) as p:
                    result = p.map(func, [arr])
                np.testing.assert_allclose(result,
                                           func.py_func(np.expand_dims(arr, 0)))

                assert threading_layer() == "workqueue"
        ré   r–   rÁ   r  r“   rê   r  r  r   r   r   Ú0test_workqueue_handles_fork_from_non_main_threadµ  s    
zFTestMiscBackendIssues.test_workqueue_handles_fork_from_non_main_threadN)r+   r,   r-   r�   rÓ   rË   r  rÊ   r  r	  rÌ   Ú
skipUnlessr‹   r
  r   r   r   r   r  U  s   

)
r  c                   @   sT   e Zd ZdZdZdd„ Zdd„ Zdd„ Zed	d
„ ƒZ	dd„ Z
dd„ Zedd„ ƒZdS )ÚTestForkSafetyIssueszV
    Checks Numba's behaviour in various situations involving GNU OpenMP and fork
    Fc                 C   s"   d}t jd|g}|  |¡\}}d S )Nzsif 1:
            from numba.np.ufunc import omppool
            assert omppool.openmp_vendor == 'GNU'
            ré   )rÆ   rÇ   rÀ   )r(   rì   r¼   r$   r¿   r   r   r   Ú!test_check_threading_layer_is_gnuè  s    z6TestForkSafetyIssues.test_check_threading_layer_is_gnuc              
   C   sd   d}| j | }tjd|g}z|  |¡\}}W n2 tk
r^ } z|  dt|ƒ¡ W 5 d}~X Y nX dS )z~
        Whilst normally valid, this actually isn't for Numba invariant of OpenMP
        Checks SIGABRT is received.
        züif 1:
            X = np.arange(1000000.)
            Y = np.arange(1000000.)
            Z = busy_func(X, Y)
            pid = os.fork()
            if pid  == 0:
                Z = busy_func(X, Y)
            else:
                os.wait()
        ré   zfailed with code -6N)rç   rÆ   rÇ   rÀ   r¹   rÕ   rÅ   )r(   rë   rì   r¼   r$   r¿   rT   r   r   r   Ú!test_par_parent_os_fork_par_childð  s    

z6TestForkSafetyIssues.test_par_parent_os_fork_par_childc                 C   s<   d}| j | }tjd|g}|  |¡\}}| jr8t||ƒ dS )au  
        Implicit use of multiprocessing fork context.
        Does this:
        1. Start with OpenMP
        2. Fork to processes using OpenMP (this is invalid)
        3. Joins fork
        4. Check the exception pushed onto the queue that is a result of
           catching SIGTERM coming from the C++ aborting on illegal fork
           pattern for GNU OpenMP
        aí  if 1:
            mp = multiprocessing.get_context('fork')
            X = np.arange(1000000.)
            Y = np.arange(1000000.)
            q = mp.Queue()

            # Start OpenMP runtime on parent via parallel function
            Z = busy_func(X, Y, q)

            # fork() underneath with no exec, will abort
            proc = mp.Process(target = busy_func, args=(X, Y, q))
            proc.start()

            err = q.get()
            assert "Caught SIGTERM" in str(err)
        ré   N©rç   rÆ   rÇ   rÀ   rÓ   rÔ   ©r(   rë   rì   r¼   r$   r¿   r   r   r   Ú*test_par_parent_implicit_mp_fork_par_child  s    
z?TestForkSafetyIssues.test_par_parent_implicit_mp_fork_par_childc                 C   s<   d}| j | }tjd|g}|  |¡\}}| jr8t||ƒ dS )au  
        Explicit use of multiprocessing fork context.
        Does this:
        1. Start with OpenMP
        2. Fork to processes using OpenMP (this is invalid)
        3. Joins fork
        4. Check the exception pushed onto the queue that is a result of
           catching SIGTERM coming from the C++ aborting on illegal fork
           pattern for GNU OpenMP
        a  if 1:
            X = np.arange(1000000.)
            Y = np.arange(1000000.)
            q = multiprocessing.Queue()

            # Start OpenMP runtime on parent via parallel function
            Z = busy_func(X, Y, q)

            # fork() underneath with no exec, will abort
            ctx = multiprocessing.get_context('fork')
            proc = ctx.Process(target = busy_func, args=(X, Y, q))
            proc.start()
            proc.join()

            err = q.get()
            assert "Caught SIGTERM" in str(err)
        ré   Nr  r  r   r   r   Ú*test_par_parent_explicit_mp_fork_par_child'  s    
z?TestForkSafetyIssues.test_par_parent_explicit_mp_fork_par_childc                 C   s<   d}| j | }tjd|g}|  |¡\}}| jr8t||ƒ dS )zØ
        Explicit use of multiprocessing spawn, this is safe.
        Does this:
        1. Start with OpenMP
        2. Spawn to processes using OpenMP
        3. Join spawns
        4. Run some more OpenMP
        aÈ  if 1:
            X = np.arange(1000000.)
            Y = np.arange(1000000.)
            q = multiprocessing.Queue()

            # Start OpenMP runtime and run on parent via parallel function
            Z = busy_func(X, Y, q)
            procs = []
            ctx = multiprocessing.get_context('spawn')
            for x in range(20): # start a lot to try and get overlap
                ## fork() + exec() to run some OpenMP on children
                proc = ctx.Process(target = busy_func, args=(X, Y, q))
                procs.append(proc)
                sys.stdout.flush()
                sys.stderr.flush()
                proc.start()

            [p.join() for p in procs]

            try:
                q.get(False)
            except multiprocessing.queues.Empty:
                pass
            else:
                raise RuntimeError("Queue was not empty")

            # Run some more OpenMP on parent
            Z = busy_func(X, Y, q)
        ré   Nr  r  r   r   r   Ú-test_par_parent_mp_spawn_par_child_par_parentJ  s    	
zBTestForkSafetyIssues.test_par_parent_mp_spawn_par_child_par_parentc                 C   s<   d}| j | }tjd|g}|  |¡\}}| jr8t||ƒ dS )a  
        Implicit use of multiprocessing (will be fork, but cannot declare that
        in Py2.7 as there's no process launch context).
        Does this:
        1. Start with no OpenMP
        2. Fork to processes using OpenMP
        3. Join forks
        4. Run some OpenMP
        a,  if 1:
            X = np.arange(1000000.)
            Y = np.arange(1000000.)
            q = multiprocessing.Queue()

            # this is ok
            procs = []
            for x in range(10):
                # fork() underneath with but no OpenMP in parent, this is ok
                proc = multiprocessing.Process(target = busy_func,
                                               args=(X, Y, q))
                procs.append(proc)
                proc.start()

            [p.join() for p in procs]

            # and this is still ok as the OpenMP happened in forks
            Z = busy_func(X, Y, q)
            try:
                q.get(False)
            except multiprocessing.queues.Empty:
                pass
            else:
                raise RuntimeError("Queue was not empty")
        ré   Nr  r  r   r   r   Ú=test_serial_parent_implicit_mp_fork_par_child_then_par_parentv  s    

zRTestForkSafetyIssues.test_serial_parent_implicit_mp_fork_par_child_then_par_parentc                 C   s<   d}| j | }tjd|g}|  |¡\}}| jr8t||ƒ dS )zÇ
        Explicit use of multiprocessing 'fork'.
        Does this:
        1. Start with no OpenMP
        2. Fork to processes using OpenMP
        3. Join forks
        4. Run some OpenMP
        a'  if 1:
            X = np.arange(1000000.)
            Y = np.arange(1000000.)
            q = multiprocessing.Queue()

            # this is ok
            procs = []
            ctx = multiprocessing.get_context('fork')
            for x in range(10):
                # fork() underneath with but no OpenMP in parent, this is ok
                proc = ctx.Process(target = busy_func, args=(X, Y, q))
                procs.append(proc)
                proc.start()

            [p.join() for p in procs]

            # and this is still ok as the OpenMP happened in forks
            Z = busy_func(X, Y, q)
            try:
                q.get(False)
            except multiprocessing.queues.Empty:
                pass
            else:
                raise RuntimeError("Queue was not empty")
        ré   Nr  r  r   r   r   Ú=test_serial_parent_explicit_mp_fork_par_child_then_par_parentŸ  s    

zRTestForkSafetyIssues.test_serial_parent_explicit_mp_fork_par_child_then_par_parentN)r+   r,   r-   r�   rÓ   r  r  r  r   r  r  r  r  r   r   r   r   r  à  s   !
",)r  c                   @   s(   e Zd ZdZedd„ ƒZedd„ ƒZdS )ÚTestTBBSpecificIssuesFc                 C   sL   d}t jd|g}|  |¡\}}d}|  ||¡ | jrHtd|ƒ td|ƒ d S )Na%  if 1:
            import threading
            import numba
            numba.config.THREADING_LAYER='tbb'
            from numba import njit, prange, objmode
            from numba.core.serialize import PickleCallableByPath
            import os

            e_running = threading.Event()
            e_proceed = threading.Event()

            def indirect_core():
                e_running.set()
                # wait for forker() to have forked
                while not e_proceed.isSet():
                    pass

            indirect = PickleCallableByPath(indirect_core)

            @njit
            def obj_mode_func():
                with objmode():
                    indirect()

            @njit(parallel=True, nogil=True)
            def work():
                acc = 0
                for x in prange(10):
                    acc += x
                obj_mode_func()
                return acc

            def runner():
                work()

            def forker():
                # wait for the jit function to say it's running
                while not e_running.isSet():
                    pass
                # then fork
                os.fork()
                # now fork is done signal the runner to proceed to exit
                e_proceed.set()

            numba_runner = threading.Thread(target=runner,)
            fork_runner =  threading.Thread(target=forker,)

            threads = (numba_runner, fork_runner)
            for t in threads:
                t.start()
            for t in threads:
                t.join()
        ré   z9Attempted to fork from a non-main thread, the TBB libraryúOUT:úERR:)rÆ   rÇ   rÀ   rÕ   rÓ   rÔ   )r(   rì   r¼   r$   r¿   Zmsg_headr   r   r   Útest_fork_from_non_main_threadÏ  s    6
z4TestTBBSpecificIssues.test_fork_from_non_main_threadc                 C   s†   |   ¡  d}d d|¡}tjd|g}tj ¡ }d|d< | j||d�\}}||kr\|  d¡ n|  	d	|¡ | j
r‚td
|ƒ td|ƒ d S )NzSKIP: COMPILATION FAILEDax  if 1:
            import ctypes
            import sys
            import multiprocessing as mp
            from tempfile import TemporaryDirectory, NamedTemporaryFile
            from numba.pycc.platform import Toolchain, external_compiler_works
            from numba import njit, prange, threading_layer
            import faulthandler
            faulthandler.enable()
            if not external_compiler_works():
                raise AssertionError('External compilers are not found.')
            with TemporaryDirectory() as tmpdir:
                with NamedTemporaryFile(dir=tmpdir) as tmpfile:
                    try:
                        src = """
                        #define TBB_PREVIEW_WAITING_FOR_WORKERS 1
                        #include <tbb/tbb.h>
                        static tbb::task_scheduler_handle tsh;
                        extern "C"
                        {
                        void launch(void)
                        {
                            tsh = tbb::task_scheduler_handle::get();
                        }
                        }
                        """
                        cxxfile = f"{tmpfile.name}.cxx"
                        with open(cxxfile, 'wt') as f:
                            f.write(src)
                        tc = Toolchain()
                        object_files = tc.compile_objects([cxxfile,],
                                                           output_dir=tmpdir)
                        dso_name = f"{tmpfile.name}.so"
                        tc.link_shared(dso_name, object_files,
                                       libraries=['tbb',],
                                       export_symbols=['launch'])
                        # Load into the process, it doesn't matter whether the
                        # DSO exists on disk once it's loaded in.
                        DLL = ctypes.CDLL(dso_name)
                    except Exception as e:
                        # Something is broken in compilation, could be one of
                        # many things including, but not limited to: missing tbb
                        # headers, incorrect permissions, compilers that don't
                        # work for the above
                        print(e)
                        print('BROKEN_COMPILERS')
                        sys.exit(0)

                    # Do the test, launch this library and also execute a
                    # function with the TBB threading layer.

                    DLL.launch()

                    @njit(parallel=True)
                    def foo(n):
                        acc = 0
                        for i in prange(n):
                            acc += i
                        return acc

                    foo(1)

            # Check the threading layer used was TBB
            assert threading_layer() == 'tbb'

            # Use mp context for a controlled version of fork, this triggers the
            # reported bug.

            ctx = mp.get_context('fork')
            def nowork():
                pass
            p = ctx.Process(target=nowork)
            p.start()
            p.join(10)
            print("SUCCESS")
            ÚBROKEN_COMPILERSré   r„   rÁ   rê   z3Compilation of DSO failed. Check output for detailsÚSUCCESSr  r  )Zskip_if_no_external_compilerÚreplacerÆ   rÇ   rÂ   rÃ   rÄ   rÀ   r›   rÕ   rÓ   rÔ   )r(   r  rì   r¼   r­   r$   r¿   r   r   r   Ú&test_lifetime_of_task_scheduler_handle*  s     K µM

z<TestTBBSpecificIssues.test_lifetime_of_task_scheduler_handleN)r+   r,   r-   rÓ   r   r  r  r   r   r   r   r  É  s
   
Zr  c                   @   s,   e Zd ZdZdd„ Zedd„ ƒZdd„ ZdS )	ÚTestInitSafetyIssuesFc                 C   sv   t j|t jt jd�}t t|j¡}z8| ¡  | 	¡ \}}|j
dkrXtd|j
| ¡ f ƒ‚W 5 | ¡  X | ¡ | ¡ fS )N)r«   r¬   r   r®   r¯   )r(   r¼   r½   r¾   r$   r¿   r   r   r   rÀ   ’  s     þ
ÿÿ
zTestInitSafetyIssues.run_cmdc                 C   sX   t j t j t¡d¡}tj|g}|  |¡\}}|  d|¡ | j	rTt
d|ƒ t
d|ƒ d S )Nzorphaned_semaphore_usecase.pyzleaked semaphorer  r  )rÂ   rä   r`   rå   ræ   rÆ   rÇ   rÀ   ZassertNotInrÓ   rÔ   )r(   Z	test_filer¼   r$   r¿   r   r   r   Útest_orphaned_semaphore£  s    ÿ

z,TestInitSafetyIssues.test_orphaned_semaphorec              	   C   s€   dD ]v}zt  |¡ W n tk
r.   Y qY nX d}tjd| |¡g}|  |¡\}}| jrntd|ƒ td|ƒ |  	||¡ qd S )N)rw   rv   rx   zƒimport numba; import multiprocessing;multiprocessing.set_start_method('{}');print(multiprocessing.get_context().get_start_method())ré   r  r  )
rn   ro   r�   rÆ   rÇ   ÚformatrÀ   rÓ   rÔ   rÕ   )r(   Úmethró   r¼   r$   r¿   r   r   r   Útest_lazy_lock_init´  s    


z(TestInitSafetyIssues.test_lazy_lock_initN)r+   r,   r-   rÓ   rÀ   r   r  r"  r   r   r   r   r  �  s
   
r  c                   @   s   e Zd Zdd„ ZdS )ÚTestOpenMPVendorsc                 C   sN   t ƒ }d|d< d|d< d|d< | ¡ D ]"}tj |¡r&|  || tj¡ q&dS )z>
        Checks the OpenMP vendor strings are correct
        ZMSÚwin32ZIntelr   r   rÞ   N)Údictrß   rÆ   rà   rá   ÚassertEqualr   Úopenmp_vendor)r(   r6   Úkr   r   r   Útest_vendorsÎ  s    zTestOpenMPVendors.test_vendorsN)r+   r,   r-   r)  r   r   r   r   r#  Ê  s   r#  Ú__main__)br�   rG   rö   rn   rÂ   r@   r°   rÆ   rð   r   rÌ   Únumpyr   Znumbar   r   r   r   Znumba.tests.supportr   r   r   r	   r
   r   rE   Zt_queueZnumba.testing.mainr   Z_RUNNER_TIMEOUTZ
numba.corer   r´   Znumba.np.ufunc.parallelr   Znumba.np.ufuncr   Z_HAVE_TBB_POOLÚImportErrorr   Z_HAVE_OMP_POOLZscipy.linalg.cython_lapackZscipyZ_HAVE_LAPACKr  rË   rÊ   r'  Z_gnuompZskip_unless_gnu_omprà   rá   Ú_windowsZ_osxÚmaxsizeZ_32bitr‘   r‹   r   r    r#   r%   Úobjectr&   r.   r:   r>   r?   rC   rU   rj   ÚThreadZ_thread_classrk   ru   rs   r†   r‰   r‡   rˆ   rŠ   ry   ZTHREADING_LAYERZ_specific_backendsr—   r¥   r§   rÏ   râ   rè   rî   r  r  r  r  r#  r+   Úmainr   r   r   r   Ú<module>   sÄ    






	X

!36%F  h C<
