import gc
import threading
import time

import psutil
import torch

class       snake_case					:




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




       """simple docstring"""
       SCREAMING_SNAKE_CASE__				:				List[str]			=		psutil.Process()
       SCREAMING_SNAKE_CASE__				:				Optional[Any]			=		False




  def 	__lowercase(      self     :	Dict				)->       Optional[Any]:




       """simple docstring"""
       SCREAMING_SNAKE_CASE__				:				str			=		-1

       while True:
            SCREAMING_SNAKE_CASE__				:				Optional[int]			=		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 	__lowercase(      self     :	Any				)->       Tuple:




       """simple docstring"""
       SCREAMING_SNAKE_CASE__				:				str			=		True
       SCREAMING_SNAKE_CASE__				:				Optional[int]			=		threading.Thread(target=self.peak_monitor				)
       SCREAMING_SNAKE_CASE__				:				Union[str, Any]			=		True
       self.thread.start()




  def 	__lowercase(      self     :	Tuple				)->       List[str]:




       """simple docstring"""
       SCREAMING_SNAKE_CASE__				:				Optional[Any]			=		False
       self.thread.join()
       return self.cpu_memory_peak




SCREAMING_SNAKE_CASE__		:					Union[str, Any]						=					PeakCPUMemory()







def     _a				(      ):







     '''simple docstring'''


     SCREAMING_SNAKE_CASE__				:				Dict			=		{'time': time.time()}

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

     # CPU mem
     SCREAMING_SNAKE_CASE__				:				Tuple			=		psutil.Process().memory_info().rss
     cpu_peak_tracker.start()

     # GPU mem
     for i in range(torch.cuda.device_count() ):
          SCREAMING_SNAKE_CASE__				:				Dict			=		torch.cuda.memory_allocated(lowercase__ )
     torch.cuda.reset_peak_memory_stats()

     return measures







def     _a				(      lowercase__  :			Tuple ):







     '''simple docstring'''


     SCREAMING_SNAKE_CASE__				:				Tuple			=		{'time': time.time() - start_measures['time']}

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

     # CPU mem
     SCREAMING_SNAKE_CASE__				:				Union[str, Any]			=		(psutil.Process().memory_info().rss - start_measures['cpu']) / 2**20
     SCREAMING_SNAKE_CASE__				:				int			=		(cpu_peak_tracker.stop() - start_measures['cpu']) / 2**20

     # GPU mem
     for i in range(torch.cuda.device_count() ):
          SCREAMING_SNAKE_CASE__				:				Dict			=		(torch.cuda.memory_allocated(lowercase__ ) - start_measures[str(lowercase__ )]) / 2**20
          SCREAMING_SNAKE_CASE__				:				List[Any]			=		(torch.cuda.max_memory_allocated(lowercase__ ) - start_measures[str(lowercase__ )]) / 2**20

     return measures







def     _a				(      lowercase__  :			Dict     ,  lowercase__  :			Optional[Any] ):







     '''simple docstring'''


     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(lowercase__ )]:.2f}MiB''' )
          SCREAMING_SNAKE_CASE__				:				Any			=		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''' )




def     _a				(      lowercase__  :			int     ,  lowercase__  :			int ):







     '''simple docstring'''


     return int((input_a, input_a).count(0 ) != 0 )







def     _a				(      ):







     '''simple docstring'''


     assert nand_gate(0     ,  0 ) == 1
     assert nand_gate(0     ,  1 ) == 1
     assert nand_gate(1     ,  0 ) == 1
     assert nand_gate(1     ,  1 ) == 0


if __name__ == "__main__":
      print(nand_gate(0, 0))
      print(nand_gate(0, 1))
      print(nand_gate(1, 0))
      print(nand_gate(1, 1))



