a
    d5                     @   sj  d dl Z d dlZd dlmZ d dl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 d dlmZmZ G dd	 d	eZd&ee
e dddZe
e dddZee	dddZededddZedddZee
e e
e f dddZedddZee
e  dddZ e
e e
e e
e ddd Z!edd!d"Z"ej#dd#d$d%Z$dS )'    N)contextmanager)	lru_cache)castDict	GeneratorListOptionalUnion)rank_zero_info)Accelerator)_TORCH_GREATER_EQUAL_1_12_TORCH_GREATER_EQUAL_2_0c                   @   s   e Zd ZdZejddddZddddZee	e
eee
 f eee
  d	d
dZeee
 eej d	ddZee
dddZeedddZeeddddZdS )CUDAAcceleratorz$Accelerator for NVIDIA CUDA devices.Ndevicereturnc                 C   s2   |j dkrtd| dt| tj| dS )zm
        Raises:
            ValueError:
                If the selected device is not of type CUDA.
        cudazDevice should be CUDA, got z	 instead.N)type
ValueError_check_cuda_matmul_precisiontorchr   Z
set_device)selfr    r   k/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/lightning_fabric/accelerators/cuda.pysetup_device   s    
zCUDAAccelerator.setup_devicer   c                 C   s   t j  d S )N)r   r   Zempty_cache)r   r   r   r   teardown)   s    zCUDAAccelerator.teardown)devicesr   c                 C   s   ddl m} || ddS )z!Accelerator device parsing logic.r   )_parse_gpu_idsT)Zinclude_cuda)Z(lightning_fabric.utilities.device_parserr   )r   r   r   r   r   parse_devices-   s    zCUDAAccelerator.parse_devicesc                 C   s   dd | D S )z*Gets parallel devices for the Accelerator.c                 S   s   g | ]}t d |qS )r   )r   r   ).0ir   r   r   
<listcomp>7       z8CUDAAccelerator.get_parallel_devices.<locals>.<listcomp>r   )r   r   r   r   get_parallel_devices4   s    z$CUDAAccelerator.get_parallel_devicesc                   C   s   t  S )z!Get the devices when set to auto.num_cuda_devicesr   r   r   r   auto_device_count9   s    z!CUDAAccelerator.auto_device_countc                   C   s
   t  dkS )Nr   r%   r   r   r   r   is_available>   s    zCUDAAccelerator.is_available)accelerator_registryr   c                 C   s   |j d| | jjd d S )Nr   )description)register	__class____name__)clsr)   r   r   r   register_acceleratorsB   s
    z%CUDAAccelerator.register_accelerators)r-   
__module____qualname____doc__r   r   r   r   staticmethodr	   intstrr   r   r   r$   r'   boolr(   classmethodr   r/   r   r   r   r   r      s   (r   )num_devicesr   c              	   C   s   t  }|std|  d| t|kr@td|  dt| dg }g }|D ]Z}ztjdtd|d W n  ty   || Y qLY n0 || t|| krL qqL| dkrt|| krtd|  d	t| d
| d|S )a  Returns a list of all available and usable CUDA GPU devices.

    A GPU is considered usable if we can successfully move a tensor to the device, and this is what this function
    tests for each GPU on the system until the target number of usable devices is found.

    A subset of GPUs on the system might be used by other processes, and if the GPU is configured to operate in
    'exclusive' mode (configurable by the admin), then only one process is allowed to occupy it.

    Args:
        num_devices: The number of devices you want to request. By default, this function will return as many as there
            are usable CUDA GPU devices available.

    Warning:
        If multiple processes call this function at the same time, there can be race conditions in the case where
        both processes determine that the device is unoccupied, leading into one of them crashing later on.
    zYou requested to find z? devices but there are no visible CUDA devices on this machine.z# devices but this machine only has z GPUs.r   r   )r   r8   z devices but only z& are currently available. The devices zA are occupied by other processes and can't be used at the moment.)_get_all_visible_cuda_devicesr   lenr   Ztensorr   RuntimeErrorappend)r9   visible_devicesZavailable_devicesZunavailable_devicesZgpu_idxr   r   r   find_usable_cuda_devicesK   s6    



r?   r   c                   C   s   t tt S )a  Returns a list of all visible CUDA GPU devices.

    Devices masked by the environment variabale ``CUDA_VISIBLE_DEVICES`` won't be returned here. For example, assume you
    have 8 physical GPUs. If ``CUDA_VISIBLE_DEVICES="1,3,6"``, then this function will return the list ``[0, 1, 2]``
    because these are the three visible GPUs after applying the mask ``CUDA_VISIBLE_DEVICES``.
    )listranger&   r   r   r   r   r:   }   s    r:   c                  c   sT   t tjdrJt dkrJtsJtjj} ttj_zdV  W | tj_qP| tj_0 ndV  dS )zpContext manager that safely patches :func:`torch.cuda.is_available` with its NVML-based version if
    possible.Z_cuda_getDeviceCountr   N)hasattrr   Z_C_device_count_nvmlr   r   r(   is_cuda_available)Z
orig_checkr   r   r   _patch_cuda_is_available   s    rE      c                  C   s*   t rtj S t } | dk r&tj S | S )zReturns the number of available CUDA devices.

    Unlike :func:`torch.cuda.device_count`, this function does its best not to create a CUDA context for fork support,
    if the platform allows it.
    r   )r   r   r   Zdevice_countrC   )Z
nvml_countr   r   r   r&      s    
r&   c                   C   s   t rtj S t dkS )zReturns a bool indicating if CUDA is currently available.

    Unlike :func:`torch.cuda.is_available`, this function does its best not to create a CUDA context for fork support,
    if the platform allows it.
    r   )r   r   r   r(   r&   r   r   r   r   rD      s    rD   c                  C   s   t d} | du rttdS ttddd}tttt ddd	}| d
rX|| d
S | drl|| dS g }| dD ]@}||	 }||v rt
tt g   S |dk r q|| qz|S )z0Parse CUDA_VISIBLE_DEVICES environment variable.ZCUDA_VISIBLE_DEVICESN@   )sr   c                 S   sj   | sdS t | D ]<\}}| s4|dkr0|dv s4 qN|d t| kr|d7 }q|dkrft| d| S dS )z:Return -1 or positive integer sequence string starts with,r8   r   z+-rF   N)	enumerateisdigitr;   r4   )rH   idxcr   r   r   _strtoul   s    
z(_parse_visible_devices.<locals>._strtoul)lstprefixr   c                 S   sJ   g }|  dD ]6}||v r,ttt g   S ||s: qF|| q|S )N,)splitr   r   r5   
startswithr=   )rN   rO   rcselemr   r   r   parse_list_with_prefix   s    
z6_parse_visible_devices.<locals>.parse_list_with_prefixzGPU-MIG-rP   r   )osgetenvr@   rA   r5   r4   r   rR   rQ   stripr   r=   )varrM   rU   rcrT   xr   r   r   _parse_visible_devices   s$    




r]   c                  C   sn   ddl m} m}m} |d}| }|dkr:td dS |d}|| |}|dkrftd dS ~|jS )zgReturn number of devices as reported by NVML or negative value if NVML discovery/initialization failed.r   )byrefc_intCDLLlibnvidia-ml.so.1Can't initialize NVMLr8   Can't get nvml device count)	ctypesr^   r_   r`   nvmlInitwarningswarnnvmlDeviceGetCount_v2value)r^   r_   r`   nvml_hr[   	dev_countr   r   r   _raw_device_count_nvml   s    

rl   c                  C   s   ddl m} m}m}m}m} |d}| }|dkrBtd dS |d}|	| |}|dkrntd dS g }t
|jD ]|}	| }
||	| |
}|dkrtd  dS d	}||}||
||}|dkrtd
  dS ||jdd q|~|S )z^Return list of device UUID as reported by NVML or None if NVM discovery/initialization failed.r   )r^   r_   c_void_pr`   create_string_bufferra   rb   Nr8   rc   zCan't get device handle`   zCan't get device UUIDascii )rd   r^   r_   rm   r`   rn   re   rf   rg   rh   rA   ri   ZnvmlDeviceGetHandleByIndex_v2ZnvmlDeviceGetUUIDr=   rawdecoderY   )r^   r_   rm   r`   rn   rj   r[   rk   uuidsrK   Zdev_idZbuf_lenbufr   r   r   _raw_device_uuid_nvml   s6    



rv   )
candidatesrt   r   c                 C   sb   t tt  tddd}g }| D ]>}|||}|dk r8 q^||v rRttt g   S || q|S )zuGiven the set of partial uuids and list of known uuids builds a set of ordinals excluding ambiguous partials
    IDs.)	candidatert   r   c                 S   s8   d}t |D ]&\}}|| s q|dkr. dS |}q|S )Nr8   )rI   rR   )rx   rt   
best_matchrK   uuidr   r   r   uuid_to_orinal  s    
z3_transform_uuid_to_ordinals.<locals>.uuid_to_orinalr   )r5   r   r4   r   r=   )rw   rt   r{   r[   rx   rK   r   r   r   _transform_uuid_to_ordinals  s    
r|   c                  C   s   t  } | sdS zt| d tu r^| d dr4W dS t }|du rHW dS tttt | |} n>t }|dkrr|W S t	| D ] \}}tt
||krz|  W S qzW n& ty   Y dS  ty   Y dS 0 t| S )zReturn number of devices as reported by NVML taking CUDA_VISIBLE_DEVICES into account.

    Negative value is returned if NVML discovery or initialization has failed.
    r   rV   r8   N)r]   r   r5   rR   rv   r|   r   r   rl   rI   r4   OSErrorAttributeErrorr;   )r>   rt   Zraw_cntrK   valr   r   r   rC   6  s,    rC   r   c                 C   sP   t sd S tj| \}}|dk}|s(d S t dkrLtdtj| d d S )N   ZhighestzYou are using a CUDA device (a5  ) that has Tensor Cores. To properly utilize them, you should set `torch.set_float32_matmul_precision('medium' | 'high')` which will trade-off precision for performance. For more details, read https://pytorch.org/docs/stable/generated/torch.set_float32_matmul_precision.html#torch.set_float32_matmul_precision)r   r   r   Zget_device_capabilityZget_float32_matmul_precisionr
   Zget_device_name)r   major_Zampere_or_laterr   r   r   r   V  s    r   )r8   )%rW   rf   
contextlibr   	functoolsr   typingr   r   r   r   r   r	   r   Z"lightning_utilities.core.rank_zeror
   Z)lightning_fabric.accelerators.acceleratorr   Z"lightning_fabric.utilities.importsr   r   r   r4   r?   r:   rE   r&   r6   rD   r5   r]   rl   rv   r|   rC   r   r   r   r   r   r   <module>   s,    021! 