B
     \                 @   s   d Z ddlmZmZmZ ddlZddlZddlmZ ddl	m	Z	 G dd de
ZG d	d
 d
e
ZG dd de
Ze ZejZdddZdd Zdd ZdS )a  
Expose each GPU devices directly.

This module implements a API that is like the "CUDA runtime" context manager
for managing CUDA context stack and clean up.  It relies on thread-local globals
to separate the context stack management of each thread. Contexts are also
sharable among threads.  Only the main thread can destroy Contexts.

Note:
- This module must be imported by the main-thread.

    )print_functionabsolute_importdivisionN)
servicelib   )driverc                   sH   e Zd Z fddZdd Zdd Zdd Zd	d
 Zedd Z	  Z
S )_DeviceListc                s<   |dkr,t  }dd t|D }|| _|S tt| |S )Nlstc             S   s   g | ]}t t|qS  )_DeviceContextManagerr   Z
get_device).0Zdevidr
   r
   9lib/python3.7/site-packages/numba/cuda/cudadrv/devices.py
<listcomp>   s   z+_DeviceList.__getattr__.<locals>.<listcomp>)r   Zget_device_countranger	   superr   __getattr__)selfattrZnumdevgpus)	__class__r
   r   r      s    z_DeviceList.__getattr__c             C   s
   | j | S )zB
        Returns the context manager for device *devnum*.
        )r	   )r   devnumr
   r
   r   __getitem__$   s    z_DeviceList.__getitem__c             C   s   d dd | jD S )Nz, c             S   s   g | ]}t |qS r
   )str)r   dr
   r
   r   r   +   s    z'_DeviceList.__str__.<locals>.<listcomp>)joinr	   )r   r
   r
   r   __str__*   s    z_DeviceList.__str__c             C   s
   t | jS )N)iterr	   )r   r
   r
   r   __iter__-   s    z_DeviceList.__iter__c             C   s
   t | jS )N)lenr	   )r   r
   r
   r   __len__0   s    z_DeviceList.__len__c             C   s   t jr| jt jjj S dS )zFReturns the active device or None if there's no active device
        N)_runtimecontext_stackr	   current_contextdeviceid)r   r
   r
   r   current3   s    z_DeviceList.current)__name__
__module____qualname__r   r   r   r   r   propertyr%   __classcell__r
   r
   )r   r   r      s   r   c               @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )r   aU  
    Provides a context manager for executing in the context of the chosen
    device. The normal use of instances of this type is from
    ``numba.cuda.gpus``. For example, to execute on device 2::

       with numba.cuda.gpus[2]:
           d_a = numba.cuda.to_device(a)

    to copy the array *a* onto device 2, referred to by *d_a*.
    c             C   s
   || _ d S )N)_device)r   r#   r
   r
   r   __init__G   s    z_DeviceContextManager.__init__c             C   s   t | j|S )N)getattrr+   )r   itemr
   r
   r   r   J   s    z!_DeviceContextManager.__getattr__c             C   s   t |  d S )N)r    push_context)r   r
   r
   r   	__enter__M   s    z_DeviceContextManager.__enter__c             C   s   t   d S )N)r    pop_context)r   exc_typeZexc_valZexc_tbr
   r
   r   __exit__P   s    z_DeviceContextManager.__exit__c             C   s   dj | dS )Nz<Managed Device {self.id}>)r   )format)r   r
   r
   r   r   S   s    z_DeviceContextManager.__str__N)	r&   r'   r(   __doc__r,   r   r0   r3   r   r
   r
   r
   r   r   ;   s   
r   c               @   sT   e Zd ZdZdd Zedd Zdd Zdd	 Zd
d Z	dd Z
dd Zdd ZdS )_RuntimezEmulate the CUDA runtime context management.

    It owns all Devices and Contexts.
    Keeps at most one Context per Device
    c             C   s*   t  | _t | _t | _t | _	d S )N)
r   r   r   ZTLStackr!   	threadingcurrent_thread_mainthreadRLock_lock)r   r
   r
   r   r,   ^   s    

z_Runtime.__init__c             C   s   | j jS )z&Return the active gpu context
        )r!   top)r   r
   r
   r   r"   k   s    z_Runtime.current_contextc          	   C   s&   | j  | }|  |S Q R X dS )zTry to use a already created context for the given gpu.  If none
        existed, create a new context.

        Returns the context
        N)r;   Zget_primary_contextpush)r   gpuctxr
   r
   r   _get_or_create_contextq   s    z_Runtime._get_or_create_contextc             C   s6   | j js| jj|kr | |}n| j}| j | |S )zlPush a context for the given GPU or create a new one if no context
        exist for the given GPU.
        )r!   Zis_emptyr"   r#   r@   r=   )r   r>   r?   r
   r
   r   r/   |   s
    z_Runtime.push_contextc             C   s4   | j }t| jdkr&|  | j  | js0tdS )zPop a context from the context stack if there is more than
        one context in the stack.

        Will not remove the last context in the stack.
        r   N)r"   r   r!   popAssertionError)r   r?   r
   r
   r   r1      s
    
z_Runtime.pop_contextc          	   C   s.   | j r| jS | j | | j| S Q R X dS )zoReturns the current context or push/create a context for the GPU
        with the given device number.
        N)r!   r"   r;   r/   r   )r   r   r
   r
   r   get_or_create_context   s    z_Runtime.get_or_create_contextc             C   s8   x| j r| j  }|  qW t | jkr4|   dS )zqClear all contexts in the thread.  Destroy the context if and only
        if we are in the main thread.
        N)r!   rA   r7   r8   r9   _destroy_all_contexts)r   r?   r
   r
   r   reset   s
    
z_Runtime.resetc             C   s   x| j D ]}|  qW d S )N)r   rE   )r   r>   r
   r
   r   rD      s    z_Runtime._destroy_all_contextsN)r&   r'   r(   r5   r,   r)   r"   r@   r/   r1   rC   rE   rD   r
   r
   r
   r   r6   W   s   
r6   c             C   s
   t | S )z^Get the current device or use a device by device number, and
    return the CUDA context.
    )r    rC   )r   r
   r
   r   get_context   s    rF   c                s   t   fdd}|S )z
    A decorator that ensures a CUDA context is available when *fn* is executed.

    Decorating *fn* is equivalent to writing::

       get_context()
       fn()

    at each call site.
    c                 s   t    | |S )N)rF   )argsZkws)fnr
   r   _require_cuda_context   s    z.require_context.<locals>._require_cuda_context)	functoolswraps)rH   rI   r
   )rH   r   require_context   s    rL   c               C   s   t   dS )zReset the CUDA subsystem for the current thread.

    In the main thread:
    This removes all CUDA contexts.  Only use this at shutdown or for
    cleaning up between tests.

    In non-main threads:
    This clear the CUDA context stack only.

    N)r    rE   r
   r
   r
   r   rE      s    rE   )r   )r5   Z
__future__r   r   r   rJ   r7   Znumbar   r   objectr   r   r6   r    r   rF   rL   rE   r
   r
   r
   r   <module>   s   '`
