U
    .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mZ ddl	m
Z
mZ ddlmZ ddlmZ dZdd	d
gZejdd ejdkrejnejZejdkrejnejZG dd dejZz
ejZW n ek
r   ejZY nX ddddddddddddddddddddZ e!e"dd  e # D Z$d!d" e # D Z%e!e"d#d  e # D Z&d$d" e # D Z'e!e d% d& Z(d'd( Z)ed)d*d+d, Z*e)e!e$e%d-d.d	 Z+G d/d0 d0Z,G d1d2 d2e,eZ-e)d3.d4d  e$D d3.e'd3.e(d5G d6d de,Z/e)d3.d7d  e&D d3.d8d  e$D d3.e'd3.e(d9G d:d
 d
Z0e)d3.d;d  e$D d3.d<d  e%D d-G d=d> d>e
Z1G d?d@ d@e1Z2G dAdB dBe1Z3G dCdD dDe1Z4G dEd% d%e1Z5dFdG Z6e7dHkre6  dS )Izthreadpoolctl

This module provides utilities to introspect native libraries that relies on
thread pools (notably BLAS and OpenMP implementations) and dynamically set the
maximal number of threads they can use.
    N)find_library)ABCabstractmethod)	lru_cache)ContextDecoratorz3.1.0threadpool_limitsthreadpool_infoThreadpoolControllerZKMP_DUPLICATE_LIB_OKTruel        c                   @   s,   e Zd ZdefdejfdejfdefgZdS )_dl_phdr_infoZ	dlpi_addr	dlpi_nameZ	dlpi_phdrZ
dlpi_phnumN)	__name__
__module____qualname___SYSTEM_UINTctypesc_char_pc_void_p_SYSTEM_UINT_HALF_fields_ r   r   1/tmp/pip-unpacked-wheel-hgipyrju/threadpoolctl.pyr   /   s
   r   openmp)libiompZlibgomplibompZvcomp)user_apiinternal_apifilename_prefixesblasopenblas)Zlibopenblaslibblas)openblas_get_num_threadsopenblas_get_num_threads64_)r   r   r   check_symbolsZmkl)Z	libmkl_rtZmkl_rtr    )MKL_Get_Max_ThreadsZblis)Zlibblisr    )bli_thread_get_num_threads)OpenMPControllerOpenBLASControllerMKLControllerBLISControllerc                 c   s   | ]}|d  V  qdS )r   Nr   .0libr   r   r   	<genexpr>`   s     r-   c                 C   s   g | ]}|d  qS )r   r   r*   r   r   r   
<listcomp>a   s     r.   c                 c   s    | ]}|d  D ]
}|V  qqdS )r   Nr   )r+   r,   prefixr   r   r   r-   c   s   
 c                 C   s    g | ]}|d  dkr|d qS )r   r   r   r   r*   r   r   r   r.   i   s   r&   r   c                     s    fdd}|S )Nc                    s   | j d k	r| j j | _ | S N)__doc__format)oargskwargsr   r   	decoratort   s    
z$_format_docstring.<locals>.decoratorr   )r5   r6   r7   r   r4   r   _format_docstrings   s    r8   i'  )maxsizec                 C   s   t j| S )zCSmall caching wrapper around os.path.realpath to limit system calls)ospathrealpath)filepathr   r   r   	_realpath|   s    r>   )	USER_APISZINTERNAL_APISc                   C   s
   t   S )a  Return the maximal number of threads for each detected library.

    Return a list with all the supported libraries that have been found. Each
    library is represented by a dict with the following information:

      - "user_api" : user API. Possible values are {USER_APIS}.
      - "internal_api": internal API. Possible values are {INTERNAL_APIS}.
      - "prefix" : filename prefix of the specific implementation.
      - "filepath": path to the loaded library.
      - "version": version of the library (if available).
      - "num_threads": the current thread limit.

    In addition, each library may contain internal_api specific entries.
    )r	   infor   r   r   r   r      s    c                   @   sh   e Zd ZdZdddddZdd Zdd	 Zedddd
dZdd Z	e	Z
dd Zdd Zdd ZdS )_ThreadpoolLimitera  The guts of ThreadpoolController.limit

    Refer to the docstring of ThreadpoolController.limit for more details.

    It will only act on the library controllers held by the provided `controller`.
    Using the default constructor sets the limits right away such that it can be used as
    a callable. Setting the limits can be delayed by using the `wrap` class method such
    that it can be used as a decorator.
    Nlimitsr   c                C   s6   || _ | ||\| _| _| _| j  | _|   d S r0   )_controller_check_params_limits	_user_api	_prefixesr@   _original_info_set_threadpool_limitsself
controllerrC   r   r   r   r   __init__   s     z_ThreadpoolLimiter.__init__c                 C   s   | S r0   r   rL   r   r   r   	__enter__   s    z_ThreadpoolLimiter.__enter__c                 C   s   |    d S r0   )restore_original_limits)rL   typevalue	tracebackr   r   r   __exit__   s    z_ThreadpoolLimiter.__exit__c                C   s   t |||dS )z@Return an instance of this class that can be used as a decorator)rM   rC   r   )_ThreadpoolLimiterDecorator)clsrM   rC   r   r   r   r   wrap   s
      z_ThreadpoolLimiter.wrapc                 C   s,   t | jj| jD ]\}}||d  qdS )z,Set the limits back to their original valuesnum_threadsN)ziprD   lib_controllersrI   set_num_threads)rL   lib_controllerZoriginal_infor   r   r   rQ      s
     z*_ThreadpoolLimiter.restore_original_limitsc                    s   i }g }| j D ]b  fdd| jD }t|}t|}|dkrH| }n |dkrVd}nt|}|  || < q|rtdd	| d  |S )	zuOriginal num_threads from before calling threadpool_limits

        Return a dict `{user_api: num_threads}`.
        c                    s    g | ]}|d   kr|d qS )r   rY   r   r+   Zlib_infor   r   r   r.      s   z?_ThreadpoolLimiter.get_original_num_threads.<locals>.<listcomp>   r   Nz1Multiple value possible for following user apis: , z. Returning the minimum.)
rG   rI   setlenpopminappendwarningswarnjoin)rL   rY   Zwarning_apisrC   Zn_limitslimitr   r_   r   get_original_num_threads   s0    




z+_ThreadpoolLimiter.get_original_num_threadsc                    s  t  tr$ dkr$| j  \ } dks6t  tr|dkrDt}n&|tkrT|g}ntdt d| d dk	r fdd|D  g }nnt  trdd  D  nt  t	rd	d  j
D  t  tstd
t  ddd  D }dd  D } ||fS )zCSuitable values for the _limits, _user_api and _prefixes attributesZsequential_blas_under_openmpNzuser_api must be either in z or None. Got z	 instead.c                    s   i | ]
}| qS r   r   r+   apirC   r   r   
<dictcomp>   s      z4_ThreadpoolLimiter._check_params.<locals>.<dictcomp>c                 S   s   i | ]}|d  |d qS r/   rY   r   r^   r   r   r   ro      s     c                 S   s   i | ]}|j |jqS r   rp   r+   r]   r   r   r   ro     s    zUlimits must either be an int, a list, a dict, or 'sequential_blas_under_openmp'. Got z insteadc                 S   s   g | ]}|t kr|qS r   )_ALL_PREFIXESr+   r/   r   r   r   r.     s      z4_ThreadpoolLimiter._check_params.<locals>.<listcomp>c                 S   s   g | ]}|t kr|qS r   )_ALL_USER_APISrl   r   r   r   r.     s      )
isinstancestrrD   ,_get_params_for_sequential_blas_under_openmpvaluesintrt   
ValueErrorlistr	   r[   dict	TypeErrorrR   )rL   rC   r   prefixesr   rn   r   rE      s>    


z _ThreadpoolLimiter._check_paramsc                 C   sh   | j dkrdS | jjD ]L}|j| j kr4| j |j }n|j| j kr| j |j }nq|dk	r|| qdS )zChange the maximal number of threads in selected thread pools.

        Return a list with all the supported libraries that have been found
        matching `self._prefixes` and `self._user_api`.
        N)rF   rD   r[   r/   r   r\   )rL   r]   rY   r   r   r   rJ     s    
z)_ThreadpoolLimiter._set_threadpool_limits)r   r   r   r1   rN   rP   rU   classmethodrX   rQ   
unregisterrk   rE   rJ   r   r   r   r   rA      s   
$3rA   c                   @   s(   e Zd ZdZdddddZdd ZdS )rV   z8Same as _ThreadpoolLimiter but to be used as a decoratorNrB   c                C   s"   |  ||\| _| _| _|| _d S r0   )rE   rF   rG   rH   rD   rK   r   r   r   rN   1  s
     z$_ThreadpoolLimiterDecorator.__init__c                 C   s   | j  | _|   | S r0   )rD   r@   rI   rJ   rO   r   r   r   rP   7  s    z%_ThreadpoolLimiterDecorator.__enter__)r   r   r   r1   rN   rP   r   r   r   r   rV   .  s   rV   ra   c                 c   s   | ]}d | d V  qdS "Nr   rl   r   r   r   r-   A  s     r?   	BLAS_LIBSOPENMP_LIBSc                       s4   e Zd ZdZd fdd	Zed fdd	Z  ZS )	r   ag  Change the maximal number of threads that can be used in thread pools.

    This object can be used either as a callable (the construction of this object
    limits the number of threads), as a context manager in a `with` block to
    automatically restore the original state of the controlled libraries when exiting
    the block, or as a decorator through its `wrap` method.

    Set the maximal number of threads that can be used in thread pools used in
    the supported libraries to `limit`. This function works for libraries that
    are already loaded in the interpreter and can be changed dynamically.

    This effect is global and impacts the whole Python process. There is no thread level
    isolation as these libraries do not offer thread-local APIs to configure the number
    of threads to use in nested parallel calls.

    Parameters
    ----------
    limits : int, dict, 'sequential_blas_under_openmp' or None (default=None)
        The maximal number of threads that can be used in thread pools

        - If int, sets the maximum number of threads to `limits` for each
          library selected by `user_api`.

        - If it is a dictionary `{{key: max_threads}}`, this function sets a
          custom maximum number of threads for each `key` which can be either a
          `user_api` or a `prefix` for a specific library.

        - If 'sequential_blas_under_openmp', it will chose the appropriate `limits`
          and `user_api` parameters for the specific use case of sequential BLAS
          calls within an OpenMP parallel region. The `user_api` parameter is
          ignored.

        - If None, this function does not do anything.

    user_api : {USER_APIS} or None (default=None)
        APIs of libraries to limit. Used only if `limits` is an int.

        - If "blas", it will only limit BLAS supported libraries ({BLAS_LIBS}).

        - If "openmp", it will only limit OpenMP supported libraries
          ({OPENMP_LIBS}). Note that it can affect the number of threads used
          by the BLAS libraries if they rely on OpenMP.

        - If None, this function will apply to all supported libraries.
    Nc                    s   t  jt ||d d S NrB   )superrN   r	   rL   rC   r   	__class__r   r   rN   t  s    zthreadpool_limits.__init__c                    s   t  jt ||dS r   )r   rX   r	   )rW   rC   r   r   r   r   rX   w  s    zthreadpool_limits.wrap)NN)NN)r   r   r   r1   rN   r   rX   __classcell__r   r   r   r   r   @  s   .c                 c   s   | ]}d | d V  qdS r   r   rs   r   r   r   r-   }  s     c                 c   s   | ]}d | d V  qdS r   r   rl   r   r   r   r-   ~  s     )PREFIXESr?   r   r   c                   @   s  e Zd ZdZe Zdd Zedd Zdd Z	dd	 Z
d
d Zeddd eD dededdddddZeddd eD dededddd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ed'd( Zed)d* ZdS )+r	   zCollection of LibController objects for all loaded supported libraries

    Attributes
    ----------
    lib_controllers : list of `LibController` objects
        The list of library controllers of all loaded supported libraries.
    c                 C   s   g | _ |   |   d S r0   )r[   _load_libraries_warn_if_incompatible_openmprO   r   r   r   rN     s    zThreadpoolController.__init__c                 C   s   |  | }||_|S r0   )__new__r[   )rW   r[   Znew_controllerr   r   r   _from_controllers  s    
z&ThreadpoolController._from_controllersc                 C   s   dd | j D S )z.Return lib_controllers info as a list of dictsc                 S   s   g | ]}|  qS r   )r@   rq   r   r   r   r.     s     z-ThreadpoolController.info.<locals>.<listcomp>)r[   rO   r   r   r   r@     s    zThreadpoolController.infoc                    sH      D ] \}}t|ts |gn| |< q fdd| jD }t|S )a>  Return a ThreadpoolController containing a subset of its current
        library controllers

        It will select all libraries matching at least one pair (key, value) from kwargs
        where key is an entry of the library info dict (like "user_api", "internal_api",
        "prefix", ...) and value is the value or a list of acceptable values for that
        entry.

        For instance, `ThreadpoolController().select(internal_api=["blis", "openblas"])`
        will select all library controllers whose internal_api is either "blis" or
        "openblas".
        c                    s*   g | ]" t  fd d D r qS )c                 3   s"   | ]\}}t  |d |kV  qd S r0   )getattr)r+   keyvalsr]   r   r   r-     s   z9ThreadpoolController.select.<locals>.<listcomp>.<genexpr>)anyitems)r+   r6   r   r   r.     s
   z/ThreadpoolController.select.<locals>.<listcomp>)r   ru   r{   r[   r	   r   )rL   r6   r   r   r[   r   r   r   select  s    
	zThreadpoolController.selectc                 C   s$   | j dddjrdddS dddS )zReturn appropriate params to use for a sequential BLAS call in an OpenMP loop

        This function takes into account the unexpected behavior of OpenBLAS with the
        OpenMP threading layer.
        r   r   )r   threading_layerNrB   r`   r   )r   r[   rO   r   r   r   rw     s     
zAThreadpoolController._get_params_for_sequential_blas_under_openmpra   c                 c   s   | ]}d  |V  qdS z"{}"Nr2   rl   r   r   r   r-     s     zThreadpoolController.<genexpr>r   NrB   c                C   s   t | ||dS )a  Change the maximal number of threads that can be used in thread pools.

        This function returns an object that can be used either as a callable (the
        construction of this object limits the number of threads) or as a context
        manager, in a `with` block to automatically restore the original state of the
        controlled libraries when exiting the block.

        Set the maximal number of threads that can be used in thread pools used in
        the supported libraries to `limits`. This function works for libraries that
        are already loaded in the interpreter and can be changed dynamically.

        This effect is global and impacts the whole Python process. There is no thread
        level isolation as these libraries do not offer thread-local APIs to configure
        the number of threads to use in nested parallel calls.

        Parameters
        ----------
        limits : int, dict, 'sequential_blas_under_openmp' or None (default=None)
            The maximal number of threads that can be used in thread pools

            - If int, sets the maximum number of threads to `limits` for each
              library selected by `user_api`.

            - If it is a dictionary `{{key: max_threads}}`, this function sets a
              custom maximum number of threads for each `key` which can be either a
              `user_api` or a `prefix` for a specific library.

            - If 'sequential_blas_under_openmp', it will chose the appropriate `limits`
              and `user_api` parameters for the specific use case of sequential BLAS
              calls within an OpenMP parallel region. The `user_api` parameter is
              ignored.

            - If None, this function does not do anything.

        user_api : {USER_APIS} or None (default=None)
            APIs of libraries to limit. Used only if `limits` is an int.

            - If "blas", it will only limit BLAS supported libraries ({BLAS_LIBS}).

            - If "openmp", it will only limit OpenMP supported libraries
              ({OPENMP_LIBS}). Note that it can affect the number of threads used
              by the BLAS libraries if they rely on OpenMP.

            - If None, this function will apply to all supported libraries.
        rB   )rA   r   r   r   r   rj     s    3zThreadpoolController.limitc                 c   s   | ]}d  |V  qdS r   r   rl   r   r   r   r-     s     c                C   s   t j| ||dS )a  Change the maximal number of threads that can be used in thread pools.

        This function returns an object that can be used as a decorator.

        Set the maximal number of threads that can be used in thread pools used in
        the supported libraries to `limits`. This function works for libraries that
        are already loaded in the interpreter and can be changed dynamically.

        Parameters
        ----------
        limits : int, dict or None (default=None)
            The maximal number of threads that can be used in thread pools

            - If int, sets the maximum number of threads to `limits` for each
              library selected by `user_api`.

            - If it is a dictionary `{{key: max_threads}}`, this function sets a
              custom maximum number of threads for each `key` which can be either a
              `user_api` or a `prefix` for a specific library.

            - If None, this function does not do anything.

        user_api : {USER_APIS} or None (default=None)
            APIs of libraries to limit. Used only if `limits` is an int.

            - If "blas", it will only limit BLAS supported libraries ({BLAS_LIBS}).

            - If "openmp", it will only limit OpenMP supported libraries
              ({OPENMP_LIBS}). Note that it can affect the number of threads used
              by the BLAS libraries if they rely on OpenMP.

            - If None, this function will apply to all supported libraries.
        rB   )rA   rX   r   r   r   r   rX     s    'zThreadpoolController.wrapc                 C   s
   t | jS r0   )rc   r[   rO   r   r   r   __len__%  s    zThreadpoolController.__len__c                 C   s4   t jdkr|   nt jdkr(|   n|   dS )zALoop through loaded shared libraries and store the supported onesdarwinwin32N)sysplatform_find_libraries_with_dyld+_find_libraries_with_enum_process_module_ex$_find_libraries_with_dl_iterate_phdrrO   r   r   r   r   (  s
    



z$ThreadpoolController._load_librariesc                    s`      }t|dsg S  fdd}ttjtttjtj}||}td}|	|| dS )an  Loop through loaded libraries and return binders on supported ones

        This function is expected to work on POSIX system only.
        This code is adapted from code by Intel developer @anton-malakhov
        available at https://github.com/IntelPython/smp

        Copyright (c) 2017, Intel Corporation published under the BSD 3-Clause
        license
        dl_iterate_phdrc                    s$   | j j}|r |d} | dS )Nutf-8r   )contentsr   decode_make_controller_from_path)r@   sizedatar=   rO   r   r   match_library_callbackA  s
    

zYThreadpoolController._find_libraries_with_dl_iterate_phdr.<locals>.match_library_callback    N)
	_get_libchasattrr   	CFUNCTYPEc_intPOINTERr   c_size_tr   r   )rL   libcr   Zc_func_signatureZc_match_library_callbackr   r   rO   r   r   1  s    



z9ThreadpoolController._find_libraries_with_dl_iterate_phdrc                 C   s^   |   }t|dsg S | }tj|j_t|D ](}t||}|	d}| 
| q0dS )zLoop through loaded libraries and return binders on supported ones

        This function is expected to work on OSX system only
        _dyld_image_countr   N)r   r   r   r   r   Z_dyld_get_image_namerestyperange	string_atr   r   )rL   r   Zn_dyldir=   r   r   r   r   V  s    


z.ThreadpoolController._find_libraries_with_dyldc              	   C   sF  ddl m}m}m} d}d}d}| d}| d}|||B dt }	|	s`td	t  zd
}
| }||
  }t
|}||	t
||t
||std||jkrq|j||
  }
ql|j||
  }t||d| }t
|}| }|D ]:}||	|t
|t
|s td|j}| | qW 5 |	|	 X dS )a  Loop through loaded libraries and return binders on supported ones

        This function is expected to work on windows system only.
        This code is adapted from code by Philipp Hagemeister @phihag available
        at https://stackoverflow.com/questions/17474574
        r   )DWORDHMODULEMAX_PATHi         ZPsapikernel32FzCould not open PID    zEnumProcessModulesEx failedNzGetModuleFileNameEx failed)Zctypes.wintypesr   r   r   _get_windllZOpenProcessr:   getpidOSErrorZCloseHandler   sizeofZEnumProcessModulesExbyrefrS   mapcreate_unicode_bufferZGetModuleFileNameExWr   )rL   r   r   r   ZPROCESS_QUERY_INFORMATIONZPROCESS_VM_READZLIST_LIBRARIES_ALLZps_apiZ	kernel_32Z	h_processZ	buf_countneededbufbuf_sizecountZ	h_modulesZn_sizeZh_moduler=   r   r   r   r   i  sX    

  



   z@ThreadpoolController._find_libraries_with_enum_process_module_exc           
         s   t |}tj| }t D ]\}}| ||d }|dkrBq |dkr|dr t	
|t t fdd|d D sq nq |d }|d	 }t | }|||||d
}	| j|	 q dS )z:Store a library controller if it is supported and selectedr   Nr    .dllc                 3   s   | ]}t  |V  qd S r0   )r   )r+   funcr    r   r   r-     s   zBThreadpoolController._make_controller_from_path.<locals>.<genexpr>r#   r   r   r=   r/   r   r   )r>   r:   r;   basenamelower_SUPPORTED_LIBRARIESr   _check_prefixendswithr   CDLL_RTLD_NOLOADr   globalsr[   rf   )
rL   r=   filenamecontroller_classZcandidate_libr/   r   r   Zlib_controller_classr]   r   r   r   r     s0    

z/ThreadpoolController._make_controller_from_pathc                 C   s    |D ]}| |r|  S qdS )z]Return the prefix library_basename starts with

        Return None if none matches.
        N
startswith)rL   Zlibrary_basenamer   r/   r   r   r   r     s    

z"ThreadpoolController._check_prefixc                 C   sH   t jdkrdS dd | jD }td}d|krDd|krDt|t dS )z?Raise a warning if llvm-OpenMP and intel-OpenMP are both loadedlinuxNc                 S   s   g | ]
}|j qS r   )r/   rq   r   r   r   r.     s     zEThreadpoolController._warn_if_incompatible_openmp.<locals>.<listcomp>a  
            Found Intel OpenMP ('libiomp') and LLVM OpenMP ('libomp') loaded at
            the same time. Both libraries are known to be incompatible and this
            can cause random crashes or deadlocks on Linux when loaded in the
            same Python program.
            Using threadpoolctl may cause crashes or deadlocks. For more
            information and possible workarounds, please see
                https://github.com/joblib/threadpoolctl/blob/master/multiple_openmp.md
            r   r   )r   r   r[   textwrapdedentrg   rh   RuntimeWarning)rL   r~   msgr   r   r   r     s    
z1ThreadpoolController._warn_if_incompatible_openmpc                 C   sD   | j d}|dkr@td}|dkr(dS tj|td}|| j d< |S )z Load the lib-C for unix systems.r   Ncmode)_system_librariesgetr   r   r   r   )rW   r   Z	libc_namer   r   r   r     s    
zThreadpoolController._get_libcc                 C   s2   | j |}|dkr.t| d}|| j |< |S )zLoad a windows DLLNr   )r   r   r   ZWinDLL)rW   Zdll_namedllr   r   r   r     s
    
z ThreadpoolController._get_windll)r   r   r   r1   r|   r   rN   r   r   r@   r   rw   r8   ri   rt   _ALL_BLAS_LIBRARIES_ALL_OPENMP_LIBRARIESrj   rX   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r	   |  s@   
0$	%?5

c                 c   s   | ]}d  |V  qdS r   r   rl   r   r   r   r-     s     c                 c   s   | ]}d  |V  qdS r   r   rl   r   r   r   r-     s     c                   @   s\   e Zd ZdZdddddddZdd Zedd	 Zed
d Z	edd Z
edd ZdS )LibControlleraA  Abstract base class for the individual library controllers

    A library controller is represented by the following information:
      - "user_api" : user API. Possible values are {USER_APIS}.
      - "internal_api" : internal API. Possible values are {INTERNAL_APIS}.
      - "prefix" : prefix of the shared library's name.
      - "filepath" : path to the loaded library.
      - "version" : version of the library (if available).
      - "num_threads" : the current thread limit.

    In addition, each library controller may contain internal_api specific
    entries.
    Nr   c                C   s6   || _ || _|| _|| _tj|td| _|  | _	d S )Nr   )
r   r   r/   r=   r   r   r   _dynlibget_versionversion)rL   r=   r/   r   r   r   r   r   rN   %  s    zLibController.__init__c                 C   s(   t t| fd| ji}dd | D S )z&Return relevant info wrapped in a dictrY   c                 S   s    i | ]\}}| d s||qS )_r   )r+   kvr   r   r   ro   0  s     
  z&LibController.info.<locals>.<dictcomp>)r|   varsrY   r   )rL   Z	all_attrsr   r   r   r@   -  s    zLibController.infoc                 C   s   |   S r0   )get_num_threadsrO   r   r   r   rY   2  s    zLibController.num_threadsc                 C   s   dS )z5Return the maximum number of threads available to useNr   rO   r   r   r   r   6  s    zLibController.get_num_threadsc                 C   s   dS )z(Set the maximum number of threads to useNr   )rL   rY   r   r   r   r\   ;  s    zLibController.set_num_threadsc                 C   s   dS )z(Return the version of the shared libraryNr   rO   r   r   r   r   @  s    zLibController.get_version)r   r   r   r1   rN   r@   propertyrY   r   r   r\   r   r   r   r   r   r     s   


r   c                       sH   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Zdd Z	  Z
S )r'   zController class for OpenBLASc                    s&   t  jf | |  | _|  | _d S r0   r   rN   _get_threading_layerr   _get_architecturearchitecturerL   r6   r   r   r   rN   I  s    
zOpenBLASController.__init__c                 C   s"   t | jdt | jddd }| S )Nr!   r"   c                   S   s   d S r0   r   r   r   r   r   <lambda>S  r   z4OpenBLASController.get_num_threads.<locals>.<lambda>r   r   rL   get_funcr   r   r   r   N  s    z"OpenBLASController.get_num_threadsc                 C   s$   t | jdt | jddd }||S )NZopenblas_set_num_threadsZopenblas_set_num_threads64_c                 S   s   d S r0   r   rY   r   r   r   r   ^  r   z4OpenBLASController.set_num_threads.<locals>.<lambda>r   rL   rY   Zset_funcr   r   r   r\   X  s      z"OpenBLASController.set_num_threadsc                 C   sT   t | jdt | jdd }|d kr$d S tj|_|  }|d dkrP|d dS d S )NZopenblas_get_configZopenblas_get_config64_r   s   OpenBLASr`   r   )r   r   r   r   r   splitr   )rL   Z
get_configconfigr   r   r   r   c  s    
zOpenBLASController.get_versionc                 C   sF   t | jdt | jdd}|dkr$dS | }|dkr6dS |dkrBdS d	S )
z&Return the threading layer of OpenBLASopenblas_get_parallelZopenblas_get_parallel64_Nunknown   r   r`   pthreadsdisabledr   )rL   r   r   r   r   r   r   t  s    z'OpenBLASController._get_threading_layerc                 C   s8   t | jdt | jdd}|dkr$dS tj|_| dS )z,Return the architecture detected by OpenBLASZopenblas_get_corenameZopenblas_get_corename64_Nr   r   r   r   r   r   r   )rL   Zget_corenamer   r   r   r     s    z$OpenBLASController._get_architecturer   r   r   r1   rN   r   r\   r   r   r   r   r   r   r   r   r'   F  s   
r'   c                       sH   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Zdd Z	  Z
S )r)   zController class for BLISc                    s&   t  jf | |  | _|  | _d S r0   r   r   r   r   r   rN     s    
zBLISController.__init__c                 C   s(   t | jddd }| }|dkr$dS |S )Nr%   c                   S   s   d S r0   r   r   r   r   r   r     r   z0BLISController.get_num_threads.<locals>.<lambda>r`   r   )rL   r   rY   r   r   r   r     s    zBLISController.get_num_threadsc                 C   s   t | jddd }||S )NZbli_thread_set_num_threadsc                 S   s   d S r0   r   r   r   r   r   r     r   z0BLISController.set_num_threads.<locals>.<lambda>r   r   r   r   r   r\     s      zBLISController.set_num_threadsc                 C   s.   t | jdd }|d krd S tj|_| dS )NZbli_info_get_version_strr   r  )rL   Zget_version_r   r   r   r     s
    zBLISController.get_versionc                 C   s    | j  rdS | j  rdS dS )z"Return the threading layer of BLISr   r  r  )r   Zbli_info_get_enable_openmpZbli_info_get_enable_pthreadsrO   r   r   r   r     s
    

z#BLISController._get_threading_layerc                 C   sP   t | jdd}t | jdd}|dks,|dkr0dS tj|_tj|_|| dS )z(Return the architecture detected by BLISbli_arch_query_idNbli_arch_stringr   )r   r   r   r   r   r   r   )rL   r  r  r   r   r   r     s    z BLISController._get_architecturer  r   r   r   r   r)     s   r)   c                       s@   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Z  Z	S )r(   zController class for MKLc                    s   t  jf | |  | _d S r0   )r   rN   r   r   r   r   r   r   rN     s    zMKLController.__init__c                 C   s   t | jddd }| S )Nr$   c                   S   s   d S r0   r   r   r   r   r   r     r   z/MKLController.get_num_threads.<locals>.<lambda>r   r   r   r   r   r     s    zMKLController.get_num_threadsc                 C   s   t | jddd }||S )NZMKL_Set_Num_Threadsc                 S   s   d S r0   r   r   r   r   r   r     r   z/MKLController.set_num_threads.<locals>.<lambda>r   r   r   r   r   r\     s      zMKLController.set_num_threadsc                 C   s\   t | jdsd S td}| j|d |jd}td|}|d k	rT|	 d }|
 S )NMKL_Get_Version_String   r   zVersion ([^ ]+) r   )r   r   r   create_string_bufferr	  rS   r   researchgroupsstrip)rL   resr   groupr   r   r   r     s    
zMKLController.get_versionc                 C   s0   t | jddd }dddddd	d
}||d S )z!Return the threading layer of MKLZMKL_Set_Threading_Layerc                 S   s   dS )Nr  r   )Zlayerr   r   r   r     r   z4MKLController._get_threading_layer.<locals>.<lambda>intel
sequentialZpgiZgnuZtbbznot specified)r   r`   r  r      r  r  r   )rL   Zset_threading_layerZ	layer_mapr   r   r   r     s      z"MKLController._get_threading_layer)
r   r   r   r1   rN   r   r\   r   r   r   r   r   r   r   r(     s   r(   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	r&   zController class for OpenMPc                 C   s   t | jddd }| S )NZomp_get_max_threadsc                   S   s   d S r0   r   r   r   r   r   r     r   z2OpenMPController.get_num_threads.<locals>.<lambda>r   r   r   r   r   r     s    z OpenMPController.get_num_threadsc                 C   s   t | jddd }||S )NZomp_set_num_threadsc                 S   s   d S r0   r   r   r   r   r   r     r   z2OpenMPController.set_num_threads.<locals>.<lambda>r   r   r   r   r   r\     s      z OpenMPController.set_num_threadsc                 C   s   d S r0   r   rO   r   r   r   r     s    zOpenMPController.get_versionN)r   r   r   r1   r   r\   r   r   r   r   r   r&     s   c               	   C   s   ddl } ddl}ddl}ddl}| jddd}|jdddd	d
dd |jdddd ||jdd }|jD ]<}z|j	|dd W qn t
k
r   td||jd Y qnX qn|jrt|j t|jt dd dS )zBCommandline interface to display thread-pool information and exit.r   Nz5python -m threadpoolctl -i numpy scipy.linalg xgboostz)Display thread-pool information and exit.)usagedescriptionz-iz--importmodules*r   z;Python modules to import before introspecting thread-pools.)destnargsdefaulthelpz-cz	--commandz@a Python statement to execute before introspecting thread-pools.)r  r`   )packagezWARNING: could not import)filer  )indent)argparse	importlibjsonr   ArgumentParseradd_argument
parse_argsargvr  import_moduleImportErrorprintstderrcommandexecdumpsr   )r   r!  r"  r   parseroptionsmoduler   r   r   _main  s<    

r1  __main__)8r1   r:   r  r   r   r   rg   Zctypes.utilr   abcr   r   	functoolsr   
contextlibr   __version____all__environ
setdefaultr9   c_uint64c_uint32r   c_uint16r   	Structurer   RTLD_NOLOADr   AttributeErrorDEFAULT_MODEr   r{   rb   rx   rt   Z_ALL_INTERNAL_APISrr   r   r   r8   r>   r   rA   rV   ri   r   r	   r   r'   r)   r(   r&   r1  r   r   r   r   r   <module>   s   



	

 7   0L31&
