




from multiprocessing import Lock, Pipe, Process

# lock used to ensure that two processes do not access a pipe at the same time
lowerCamelCase__			:       List[Any]         =							Lock()

def  UpperCAmelCase_							(				__UpperCAmelCase						:     Any      ,      __UpperCAmelCase						:     Tuple      ,      __UpperCAmelCase						:     int      ,      __UpperCAmelCase						:     Optional[int]      ,      __UpperCAmelCase						:     Any      ,      __UpperCAmelCase						:     str      ,      __UpperCAmelCase						:     Union[str, Any]							) ->			List[Any]:
      global process_lock

      # we perform n swaps since after n swaps we know we are sorted
      # we *could* stop early if we are sorted already, but it takes as long to
      # find out we are sorted as it does to sort the list with this algorithm
      for i in range(0      ,      10							):
            if (i + position) % 2 == 0 and r_send is not None:
                  # send your value to your right neighbor
                  process_lock.acquire()
                  r_send[1].send(__UpperCAmelCase							)
                  process_lock.release()

                  # receive your right neighbor's value
                  process_lock.acquire()
                  SCREAMING_SNAKE_CASE_ :    Any     						=      rr_cv[0].recv()
                  process_lock.release()

                  # take the lower value since you are on the left
                  SCREAMING_SNAKE_CASE_ :    Tuple     						=      min(__UpperCAmelCase      ,      __UpperCAmelCase							)
            elif (i + position) % 2 != 0 and l_send is not None:
                  # send your value to your left neighbor
                  process_lock.acquire()
                  l_send[1].send(__UpperCAmelCase							)
                  process_lock.release()

                  # receive your left neighbor's value
                  process_lock.acquire()
                  SCREAMING_SNAKE_CASE_ :    Dict     						=      lr_cv[0].recv()
                  process_lock.release()

                  # take the higher value since you are on the right
                  SCREAMING_SNAKE_CASE_ :    Any     						=      max(__UpperCAmelCase      ,      __UpperCAmelCase							)
    # after all swaps are performed, send the values back to main
      result_pipe[1].send(__UpperCAmelCase							)

def  UpperCAmelCase_							(				__UpperCAmelCase						:     List[str]							) ->			List[str]:
      SCREAMING_SNAKE_CASE_ :    int     						=      []
      SCREAMING_SNAKE_CASE_ :    Tuple     						=      []
      # initialize the list of pipes where the values will be retrieved
      for _ in arr:
            result_pipe.append(Pipe()							)
      # creates the processes
      # the first and last process only have one neighbor so they are made outside
      # of the loop
      SCREAMING_SNAKE_CASE_ :    Tuple     						=      Pipe()
      SCREAMING_SNAKE_CASE_ :    int     						=      Pipe()
      process_array_.append(
          Process(
              target=__UpperCAmelCase      ,      args=(0, arr[0], None, temp_rs, None, temp_rr, result_pipe[0])      ,      )							)
      SCREAMING_SNAKE_CASE_ :    Any     						=      temp_rs
      SCREAMING_SNAKE_CASE_ :    List[Any]     						=      temp_rr

      for i in range(1      ,      len(__UpperCAmelCase							) - 1							):
            SCREAMING_SNAKE_CASE_ :    Dict     						=      Pipe()
            SCREAMING_SNAKE_CASE_ :    Union[str, Any]     						=      Pipe()
            process_array_.append(
                Process(
                    target=__UpperCAmelCase      ,      args=(i, arr[i], temp_ls, temp_rs, temp_lr, temp_rr, result_pipe[i])      ,      )							)
            SCREAMING_SNAKE_CASE_ :    Any     						=      temp_rs
            SCREAMING_SNAKE_CASE_ :    List[str]     						=      temp_rr

      process_array_.append(
          Process(
              target=__UpperCAmelCase      ,      args=(
                  len(__UpperCAmelCase							) - 1,
                  arr[len(__UpperCAmelCase							) - 1],
                  temp_ls,
                  None,
                  temp_lr,
                  None,
                  result_pipe[len(__UpperCAmelCase							) - 1],
              )      ,      )							)

      # start the processes
      for p in process_array_:
            p.start()

      # wait for the processes to end and write their values to the list
      for p in range(0      ,      len(__UpperCAmelCase							)							):
            SCREAMING_SNAKE_CASE_ :    Any     						=      result_pipe[p][0].recv()
            process_array_[p].join()
      return arr

def  UpperCAmelCase_							(				) ->			Optional[Any]:
      SCREAMING_SNAKE_CASE_ :    Optional[Any]     						=      list(range(10      ,      0      ,      -1							)							)
      print('Initial List'							)
      print(*__UpperCAmelCase							)
      SCREAMING_SNAKE_CASE_ :    List[Any]     						=      odd_even_transposition(__UpperCAmelCase							)
      print('Sorted List\n'							)
      print(*__UpperCAmelCase							)


if __name__ == "__main__":
   main()





import gc
import threading
import time

import psutil
import torch





class 	lowerCamelCase_							:


 '''simple docstring'''







 def __init__(							self  :		Optional[Any]						):
       SCREAMING_SNAKE_CASE_     						=      psutil.Process()
       SCREAMING_SNAKE_CASE_     						=      False



 def 				lowerCAmelCase_  (							self  :		Dict						):
       SCREAMING_SNAKE_CASE_     						=      -1

       while True:
             SCREAMING_SNAKE_CASE_     						=      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 				lowerCAmelCase_  (							self  :		List[str]						):
       SCREAMING_SNAKE_CASE_     						=      True
       SCREAMING_SNAKE_CASE_     						=      threading.Thread(target=self.peak_monitor						)
       SCREAMING_SNAKE_CASE_     						=      True
       self.thread.start()




 def 				lowerCAmelCase_  (							self  :		List[str]						):
       SCREAMING_SNAKE_CASE_     						=      False
       self.thread.join()
       return self.cpu_memory_peak


lowerCamelCase__			:       List[str]         =							PeakCPUMemory()

def  UpperCAmelCase_							(				) ->			Tuple:
      # Time
      SCREAMING_SNAKE_CASE_     						=      {'time': time.time()}

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

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

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

      return measures

def  UpperCAmelCase_							(				__UpperCAmelCase						:     Optional[int]							) ->			Optional[Any]:
      # Time
      SCREAMING_SNAKE_CASE_     						=      {'time': time.time() - start_measures['time']}

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

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

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

      return measures





def  UpperCAmelCase_							(				__UpperCAmelCase						:     Optional[int]      ,      __UpperCAmelCase						:     Any							) ->			Optional[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(__UpperCAmelCase							)]:.2f}MiB"							)
            SCREAMING_SNAKE_CASE_     						=      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"							)