Advertisement
kopyl

Untitled

Dec 11th, 2023
642
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.38 KB | None | 0 0
  1. from tqdm import tqdm
  2. import os
  3. import sys
  4. import requests
  5. import time
  6. import argparse
  7.  
  8.  
  9. parser = argparse.ArgumentParser()
  10. parser.add_argument(
  11.     "--min-gpu-count",
  12.     type=int,
  13.     default=6,
  14.     help="Minimum number of GPUs to rent",
  15. )
  16. parser.add_argument(
  17.     "--max-gpu-count",
  18.     type=int,
  19.     default=8,
  20.     help="Maximum number of GPUs to rent",
  21. )
  22.  
  23.  
  24. sys.setrecursionlimit(100_000_000)
  25. p = print
  26.  
  27.  
  28. WAIT_TIME = 1
  29. NAME = 'icons-train'
  30. MIN_GPU_COUNT = 6
  31. MAX_GPU_COUNT = 8
  32.  
  33. IMAGE_NAME = f'runpod/pytorch:2.1.0-py3.10-cuda11.8.0-devel-ubuntu22.04'
  34. GPU_TYPE_ID = 'NVIDIA A100 80GB PCIe'
  35. OS_DISK_SIZE_GB = 100
  36. PERSISTENT_DISK_SIZE_GB = 0
  37. CLOUD_TYPE = 'SECURE'
  38. MIN_DOWNLOAD_SPEED = 700
  39. DATA_CENTER_ID = 'EU-RO-1'
  40. NETWORK_VOLUME_ID = '54epb6rtc4'
  41. TEMPLATE_ID = 'ue50iblx66'
  42. CUDA_VERSION = '12.2'
  43.  
  44.  
  45. class CurrentDatetime:
  46.  
  47.     date = time.strftime('%d %b %Y')
  48.     time = time.strftime('%H:%M:%S')
  49.  
  50.     def __str__(self):
  51.         return f"{self.date} {self.time}"
  52.  
  53.  
  54. def get_caught_error(additional_message=""):  # import sys, os
  55.     exc_type, exc_obj, exc_tb = sys.exc_info()
  56.     fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
  57.     message = (
  58.         f"Now {CurrentDatetime()}\n"
  59.         f"\"{fname}\" caught an error "
  60.         f"{exc_type.__name__} "
  61.         f"on line {exc_tb.tb_lineno}:\n"
  62.         f"\"{exc_obj}\""
  63.         f"\n\n{additional_message}"
  64.     )
  65.     return message
  66.  
  67.  
  68. def retry_request_till_success(
  69.     request: requests.models.Request
  70. ) -> requests.models.Response:
  71.  
  72.     def wrapper(*args, **kwargs):
  73.         retry_time_count = 1
  74.         while True:
  75.             retry_in_seconds = 1
  76.             try:
  77.                 if ( response := request(*args, **kwargs) ) == None:  # doc.id#13
  78.                     p("There is no request to retry")
  79.                     break
  80.                 while True:
  81.                     retry_in_seconds = 1
  82.                     if (r := response.status_code) in [200, 404]:
  83.                         break
  84.                     else:
  85.                         if (
  86.                             response
  87.                         ).status_code not in [200, 404]:
  88.                             p(
  89.                                 f"URL: {response.url} "
  90.                                 f"Request in {request.__name__} failed. "
  91.                                 f"Status_code – {response.status_code} "
  92.                                 f"Will retry again in {retry_in_seconds} seconds"
  93.                             )
  94.                             time.sleep(retry_in_seconds)
  95.                             retry_time_count += 1
  96.                         else:
  97.                             break
  98.                 return response
  99.             except (
  100.                 requests.ConnectTimeout,
  101.                 requests.exceptions.ReadTimeout
  102.             ) as e:
  103.                 error = get_caught_error()
  104.                 p(
  105.                     f"Request in {request.__name__} failed. "
  106.                     f"Timed out with error {error}"
  107.                     f"Will retry again in {retry_in_seconds} seconds"
  108.                 )
  109.                 time.sleep(retry_in_seconds)
  110.                 retry_time_count += 1
  111.             except requests.exceptions.ConnectionError as e:
  112.                 sleep_time = 0.1
  113.                 p(
  114.                     f"Request in {request.__name__} failed @"
  115.                     f"{CurrentDatetime()}. "
  116.                     "No connection to internet... "
  117.                     f"Will retry again in {sleep_time} seconds"
  118.                 )
  119.                 time.sleep(sleep_time)
  120.     return wrapper
  121.  
  122. @retry_request_till_success
  123. def request_with_retries(url, json):
  124.     return requests.post(url, json=json)
  125.  
  126.  
  127. class API(object):
  128.     def __init__(self, api_key):
  129.         self.API_KEY = api_key
  130.  
  131.     def _run_query(self, payload, auth_required=False):
  132.         url = 'https://api.runpod.io/graphql'
  133.  
  134.         if auth_required:
  135.             url += f'?api_key={self.API_KEY}'
  136.  
  137.         response = request_with_retries(url, payload)
  138.  
  139.         return response
  140.  
  141.     # https://docs.runpod.io/docs/create-pod
  142.     def create_on_demand_pod(self, pod_config):
  143.         return self._run_query({
  144.             "query": """
  145.                mutation {{
  146.                    podFindAndDeployOnDemand(input: {{ {pod_config} }}) {{
  147.                        containerDiskInGb
  148.                        apiKey
  149.                        costPerHr
  150.                        desiredStatus
  151.                        dockerArgs
  152.                        dockerId
  153.                        gpuCount
  154.                        id
  155.                        imageName
  156.                        machineId
  157.                        memoryInGb
  158.                        name
  159.                        podType
  160.                        ports
  161.                        templateId
  162.                        uptimeSeconds
  163.                        vcpuCount
  164.                        version
  165.                        volumeEncrypted
  166.                        volumeInGb
  167.                        volumeKey
  168.                        volumeMountPath
  169.                        runtime {{
  170.                            uptimeInSeconds
  171.                            ports {{
  172.                                ip
  173.                                isIpPublic
  174.                                privatePort
  175.                                publicPort
  176.                                type
  177.                            }}
  178.                            gpus {{
  179.                                id
  180.                                gpuUtilPercent
  181.                                memoryUtilPercent
  182.                            }}
  183.                            container {{
  184.                                cpuPercent
  185.                                memoryPercent
  186.                            }}
  187.                        }}
  188.                        machine {{
  189.                            podHostId
  190.                        }}
  191.                    }}
  192.                }}
  193.            """.format(pod_config=pod_config)
  194.         }, True)
  195.  
  196.  
  197. ERRORS = {
  198.     "specs": (
  199.         "There are no longer any instances available with "
  200.         "the requested specifications. Please refresh and try again."
  201.     ),
  202.     "disk": (
  203.         "There are no longer any instances available with "
  204.         "enough disk space."
  205.     )
  206. }
  207.  
  208.  
  209. def calculate_gpu(min_gpu_count, max_gpu_count):
  210.     while True:
  211.         for gpu_count in range(max_gpu_count, min_gpu_count - 1, -1):
  212.             yield gpu_count
  213.  
  214.  
  215.  
  216. def create_pod(api, bar, gpu_count_generator):
  217.     gpu_count = next(gpu_count_generator)
  218.    
  219.     bar.set_description(f"{gpu_count} GPU")
  220.     bar.update(1)
  221.     pod_config = f"""
  222.        cudaVersion: "{CUDA_VERSION}",
  223.        templateId: "{TEMPLATE_ID}",
  224.        networkVolumeId: "{NETWORK_VOLUME_ID}",
  225.        dataCenterId: "{DATA_CENTER_ID}",
  226.        minDownload: {MIN_DOWNLOAD_SPEED},
  227.        gpuCount: {gpu_count},
  228.        volumeInGb: {PERSISTENT_DISK_SIZE_GB},
  229.        containerDiskInGb: {OS_DISK_SIZE_GB},
  230.        gpuTypeId: "{GPU_TYPE_ID}",
  231.        cloudType: {CLOUD_TYPE},
  232.        supportPublicIp: true,
  233.        name: "{NAME}",
  234.        dockerArgs: "",
  235.        volumeMountPath: "/workspace",
  236.        imageName: "{IMAGE_NAME}",
  237.        startJupyter: true,
  238.        startSsh: true,
  239.    """
  240.  
  241.     response = api.create_on_demand_pod(pod_config)
  242.     resp_json = response.json()
  243.  
  244.     if response.status_code == 200:
  245.         if 'errors' in resp_json:
  246.  
  247.             for error in resp_json['errors']:
  248.                 if error['message'] == ERRORS['specs']:
  249.                     create_pod(api, bar, gpu_count_generator)
  250.                 elif error['message'] == ERRORS['disk']:
  251.                     print(error)
  252.                     print('No instances with enough disk space available, sleeping for 5 seconds')
  253.                     create_pod(api, bar, gpu_count_generator)
  254.                 else:
  255.                     print('ERROR: ' + error['message'])
  256.         else:
  257.             return resp_json
  258.  
  259.  
  260. def get_pod_and_sound_alarm(api, min_gpu_count=MIN_GPU_COUNT, max_gpu_count=MAX_GPU_COUNT):
  261.     bar = tqdm(desc=f"8 GPU", total=1)
  262.     gpu_count_generator = calculate_gpu(min_gpu_count, max_gpu_count)
  263.     create_pod(api, bar, gpu_count_generator)
  264.     os.system('afplay alarm.mov')
  265.  
  266.  
  267. if __name__ == '__main__':
  268.     args = parser.parse_args()
  269.     api = API("XXX")
  270.     get_pod_and_sound_alarm(api, args.min_gpu_count, args.max_gpu_count)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement