docstr: A Timer class which implements TimerProtocol and stores timings in a dictionary `recorded_durations`.
  
  Args:
      cuda_sync: whether to call torch.cuda.synchronize() before and after timing. Defaults to True if CUDA is available.
      verbose: whether to enable verbose logging.
      size_bounds: defines the range of samples that should be kept in the timer. The lower bound should be smaller than
          the upper bound. When the number of samples reaches the upper bound, the oldest (upper-lower) bound samples will
          be removed. This range is applied per action.
  
  Note:
      Enabling cuda_sync will incur a performance hit, but will ensure accurate timings on GPUs.
  
  Raises:
      ValueError: If cuda_sync is set to True but CUDA is not available.
docstr_tok: ["A","Timer","class","which","implements","TimerProtocol","and","stores","timings","in","a","dictionary","`","recorded_durations","`",".","Args",":","cuda_sync",":","whether","to","call","torch.cuda.synchronize","(",")","before","and","after","timing",".","Defaults","to","True","if","CUDA","is","available",".","verbose",":","whether","to","enable","verbose","logging",".","size_bounds",":","defines","the","range","of","samples","that","should","be","kept","in","the","timer",".","The","lower","bound","should","be","smaller","than","the","upper","bound",".","When","the","number","of","samples","reaches","the","upper","bound",",","the","oldest","(","upper-lower",")","bound","samples","will","be","removed",".","This","range","is","applied","per","action",".","Note",":","Enabling","cuda_sync","will","incur","a","performance","hit",",","but","will","ensure","accurate","timings","on","GPUs",".","Raises",":","ValueError",":","If","cuda_sync","is","set","to","True","but","CUDA","is","not","available","."]
code: def __init__(
      self,
      *,
      cuda_sync: Optional[bool] = None,
      verbose: bool = False,
  ) -> None:
      """
      A Timer class which implements TimerProtocol and stores timings in a dictionary `recorded_durations`.
  
      Args:
          cuda_sync: whether to call torch.cuda.synchronize() before and after timing. Defaults to True if CUDA is available.
          verbose: whether to enable verbose logging.
          size_bounds: defines the range of samples that should be kept in the timer. The lower bound should be smaller than
              the upper bound. When the number of samples reaches the upper bound, the oldest (upper-lower) bound samples will
              be removed. This range is applied per action.
  
      Note:
          Enabling cuda_sync will incur a performance hit, but will ensure accurate timings on GPUs.
  
      Raises:
          ValueError: If cuda_sync is set to True but CUDA is not available.
  
      """
      if cuda_sync and not torch.cuda.is_available():
          raise ValueError(
              "CUDA must be available in order to enable CUDA synchronization."
          )
      self.cuda_sync: bool = (
          cuda_sync
          if cuda_sync is not None
          else torch.cuda.is_available()
      )
      self.verbose = verbose
      self.recorded_durations: Dict[str, List[float]] = defaultdict(
          list
      )
  
imports: import datetime
  import logging
  import os
  from collections import defaultdict
  from contextlib import contextmanager
  from time import perf_counter
  from typing import Any, Dict, Generator, List, Optional, Protocol, runtime_checkable, Sequence, Tuple, TypeVar
  import numpy
  import torch
  import torch.distributed
  from tabulate import tabulate
  from torchtnt.utils.distributed import PGWrapper
label_desc: Use image node_id 1 to create a new Timer object from inherited base classes: TimerProtocol with example: obj = Timer()