o
    vi7"                     @   s   d Z ddlZddlmZ ddlmZ ddlmZ ddlZddl	m
Z
 dedefd	d
ZddededB defddZdededefddZG dd deZdS )z>
Timer: helps measure CPU and CUDA times easily and reliably.
    N)ContextDecoratorwraps)Callable)logtime_usreturnc                 C   sD   | dkr| d }|ddS | dkr| d }|ddS | ddS )	z3
    Automatically format time in nanoseconds.
        .Aư>.2f s     @@MbP? ms us )r   time_stime_msr   r   O/data/cameron/vidgen/cosmos-policy/cosmos_policy/_src/imaginaire/utils/timer.py_autoformat_time_us   s   r   unitc                 C   sd   |du rt | S |dkr| ddS |dkr| d ddS |dkr*| d	 dd
S td| d)ze
    Automatically format time in nanoseconds either automatically or based on
    desired unit.
    Nusr   r   msr   r   sr
   r   
Time unit  is not supported.)r   NotImplementedErrorr   r   r   r   r   format_time_str-   s   r   c                 C   s<   |dkr| S |dkr| d S |dkr| d S t d| d)z;
    Format time in nanoseconds based on desired unit.
    r   r   r   r   r
   r   r   )r   r   r   r   r   format_timeA   s   r   c                   @   s   e Zd ZdZ					d)dedB dedededB d	ef
d
dZdefddZdd Zdd Z	de
de
fddZdd ZdefddZdefddZdefddZdefdd Zd!d" Zd*d#ejdB d$ejjdB fd%d&Zd'd( ZdS )+TimeraN  
    Reliable CPU and CUDA Timer.

    Args:
        tag (str | None): Optional tag used in logs/prints.

        measure_cpu (bool): Whether to measure CPU time (using `time`). Default: `True`.

        measure_cuda (bool): Whether to measure CUDA time (using CUDA events). Default: `True`.

        unit (str | None): Optional time unit. Must be either "s" (seconds), "ms" (microseconds),
            "us" (nanoseconds), or None (format automatically based on value).

        debug (bool): Whether to log results in debug mode instead of info. Default is False.

    Examples:
        ```python
        with Timer(measure_cpu=True, measure_cuda=True, unit="ms"):
            model(x)
        ```

        ```python
        @Timer(measure_cpu=True, measure_cuda=True, unit="ms")
        def func(x):
            return model(x)
        ```
    NTFtagmeasure_cpumeasure_cudar   debugc                 C   s   || _ || _d| _d| _d| _d| _d | _d | _d | _d | _	|d u r$dn|| _
|| _| jd ur=| jdvr=td| j d|| _d S )NFr   unknown)r   r   r   r   r   )r"   r#   measuredcpu_time_uscuda_time_usbusycpu_time_startcuda_start_eventcuda_end_eventcuda_streamr!   r   r   r$   )selfr!   r"   r#   r   r$   r   r   r   __init__o   s   
zTimer.__init__msgc                 C   s"   | j r
t | d S t| d S N)r$   r   info)r.   r0   r   r   r   _log   s   z
Timer._logc                 C   s   |    d S r1   )startr.   r   r   r   	__enter__   s   zTimer.__enter__c                 C   s   |    |   d S r1   )endreport)r.   exc_type	exc_value	tracebackr   r   r   __exit__   s   zTimer.__exit__funcr   c                    s   t   fdd}|S )Nc                     s*       | i |}    |S r1   )r4   r7   r8   )argskwargsresultr=   r.   r   r   wrapper   s
   zTimer.__call__.<locals>.wrapperr   )r.   r=   rB   r   rA   r   __call__   s   zTimer.__call__c              	   C   s   | j r| jr| d| j d|   d|    dS | j r.| d| j d|    dS | jrA| d| j d|    dS t )z'
        Reports measurements.
        zTime spent on z: CPU: z, CUDA: z: zCUDA time spent on N)r"   r#   r3   r!   get_cpu_time_strget_cuda_time_strr   r5   r   r   r   r8      s   *  zTimer.reportc                 C   V   | j std| j d| jstd| jdu rtd| jdus#J t| j| jdS )z/
        Returns CPU time measurement.
        (CPU timer is disabled (self.measure_cpu=).No measurements were made yet!Nz=No unit was specified. Please use get_cpu_time_str() instead.r   )r"   RuntimeErrorr&   r   r   r'   r5   r   r   r   get_cpu_time      
zTimer.get_cpu_timec                 C   rF   )z0
        Returns CUDA time measurement.
        *CUDA timer is disabled (self.measure_cuda=rH   rI   Nz>No unit was specified. Please use get_cuda_time_str() instead.rJ   )r#   rK   r&   r   r   r(   r5   r   r   r   get_cuda_time   rM   zTimer.get_cuda_timec                 C   6   | j std| j d| jstdt| j| jdS )z@
        Returns CPU time measurement in string format.
        rG   rH   rI   rJ   )r"   rK   r&   r   r'   r   r5   r   r   r   rD      
   zTimer.get_cpu_time_strc                 C   rP   )zA
        Returns CUDA time measurement in string format.
        rN   rH   rI   rJ   )r#   rK   r&   r   r(   r   r5   r   r   r   rE      rQ   zTimer.get_cuda_time_strc                 C   s   d| _ d| _d| _dS )z.
        Resets recorded measurements
        Fr   N)r&   r'   r(   r5   r   r   r   reset   s   
zTimer.resetcuda_devicer-   c                 C   s   | j rtdd| _ | jr|dur|ntj|| _| j  | jr't		 | _
| jrCtjjdd| _tjjdd| _| j| j dS dS )aY  
        Start time measurements.

        Args:
            cuda_device (torch.device | None): CUDA device. Will use default CUDA device if not indicated.

            cuda_stream (torch.cuda.Stream | None): CUDA stream to use for CUDA time measurement.
                Will use default stream for current CUDA device if not indicated.
        z"Already called Timer.start() once!TN)enable_timing)r)   rK   r#   torchcudacurrent_streamr-   synchronizer"   timer*   Eventr+   r,   record_event)r.   rS   r-   r   r   r   r4      s   


zTimer.startc                 C   sx   | j std| jr| j| j | j  | jr't | _	| j	| j
 d | _| jr4| j| jd | _d| _ d| _dS )zt
        Ends time measurements.

        NOTE: must be done on the same CUDA device and stream as start().
        z7Timer.start() must be called exactly once before end()!r	   r   FTN)r)   rK   r#   r-   r[   r,   rX   r"   rY   Zcpu_time_endr*   r'   r+   elapsed_timer(   r&   r5   r   r   r   r7     s   


z	Timer.end)NTTNF)NN)__name__
__module____qualname____doc__strboolr/   r3   r6   r<   r   rC   r8   floatrL   rO   rD   rE   rR   rU   devicerV   Streamr4   r7   r   r   r   r   r    R   s<    
"r    r1   )r`   rY   
contextlibr   	functoolsr   typingr   rU   #cosmos_policy._src.imaginaire.utilsr   rc   ra   r   r   r   r    r   r   r   r   <module>   s   