

import gc
import threading
import time

import psutil
import torch


class    A__ :



    def __init__(   self    )  -> List[Any]:





           '''simple docstring'''
           A_		   = psutil.Process()
           A_		   = False



    def    snake_case_     (   self    )  -> List[Any]:





           '''simple docstring'''
           A_		   = -1

           while True:
                  A_		   = max(self.process.memory_info().rss						,			self.cpu_memory_peak    )

                  # can't sleep or will not catch the peak right (this comment is here on purpose)
                  if not self.peak_monitoring:
                         break



    def    snake_case_     (   self    )  -> Union[str, Any]:





           '''simple docstring'''
           A_		   = True
           A_		   = threading.Thread(target=self.peak_monitor    )
           A_		   = True
           self.thread.start()







    def    snake_case_     (   self    )  -> List[str]:





           '''simple docstring'''
           A_		   = False
           self.thread.join()
           return self.cpu_memory_peak

__lowerCamelCase						    =      PeakCPUMemory()
def  UpperCAmelCase__      ( )     ->     List[Any]:
       # Time
       A_		   = {"time": time.time()}

       gc.collect()
       torch.cuda.empty_cache()

       # CPU mem
       A_		   = psutil.Process().memory_info().rss
       cpu_peak_tracker.start()

       # GPU mem
       for i in range(torch.cuda.device_count()			):
              A_		   = torch.cuda.memory_allocated(_lowerCAmelCase			)
       torch.cuda.reset_peak_memory_stats()

       return measures
def  UpperCAmelCase__      ( UpperCAmelCase__			)     ->     int:
       # Time
       A_		   = {"time": time.time() - start_measures["time"]}

       gc.collect()
       torch.cuda.empty_cache()

       # CPU mem
       A_		   = (psutil.Process().memory_info().rss - start_measures["cpu"]) / 2**20
       A_		   = (cpu_peak_tracker.stop() - start_measures["cpu"]) / 2**20

       # GPU mem
       for i in range(torch.cuda.device_count()			):
              A_		   = (torch.cuda.memory_allocated(_lowerCAmelCase			) - start_measures[str(_lowerCAmelCase			)]) / 2**20
              A_		   = (torch.cuda.max_memory_allocated(_lowerCAmelCase			) - start_measures[str(_lowerCAmelCase			)]) / 2**20

       return measures







def  UpperCAmelCase__      ( UpperCAmelCase__,    UpperCAmelCase__			)     ->     Any:
       print(F'''{description}:'''			)
       print(F'''- Time: {measures["time"]:.2f}s'''			)
       for i in range(torch.cuda.device_count()			):
              print(F'''- GPU {i} allocated: {measures[str(_lowerCAmelCase			)]:.2f}MiB'''			)
              A_		   = measures[F'''{i}-peak''']
              print(F'''- GPU {i} peak: {peak:.2f}MiB'''			)
       print(F'''- CPU RAM allocated: {measures["cpu"]:.2f}MiB'''			)
       print(F'''- CPU RAM peak: {measures["cpu-peak"]:.2f}MiB'''			)



'''simple docstring'''







from functools import lru_cache
@lru_cache
def  UpperCAmelCase__      ( UpperCAmelCase__			)     ->     int:
       if num < 0:
              raise ValueError("""Number should not be negative."""			)

       return 1 if num in (0, 1) else num * factorial(num - 1			)


if __name__ == "__main__":
      import doctest

      doctest.testmod()
