From a7a140fd14616779301b97800a65538a0c50d351 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 28 Jul 2024 18:15:59 +0200 Subject: [PATCH] `ultralytics 8.2.68` new HUB GCP region latency tests (#14753) Signed-off-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- docs/en/reference/hub/google/__init__.md | 16 +++ mkdocs.yml | 2 + ultralytics/__init__.py | 2 +- ultralytics/hub/google/__init__.py | 159 +++++++++++++++++++++++ 4 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 docs/en/reference/hub/google/__init__.md create mode 100644 ultralytics/hub/google/__init__.py diff --git a/docs/en/reference/hub/google/__init__.md b/docs/en/reference/hub/google/__init__.md new file mode 100644 index 0000000000..ac8c0441e0 --- /dev/null +++ b/docs/en/reference/hub/google/__init__.md @@ -0,0 +1,16 @@ +--- +description: Reference for the GCPRegions class in Ultralytics, which provides functionality for testing and analyzing latency across Google Cloud Platform regions. +keywords: Ultralytics, GCP, Google Cloud Platform, regions, latency testing, cloud computing, networking, performance analysis +--- + +# Reference for `ultralytics/hub/google/__init__.py` + +!!! Note + + This file is available at [https://github.com/ultralytics/ultralytics/blob/main/ultralytics/hub/google/\_\_init\_\_.py](https://github.com/ultralytics/ultralytics/blob/main/ultralytics/hub/google/__init__.py). If you spot a problem please help fix it by [contributing](https://docs.ultralytics.com/help/contributing/) a [Pull Request](https://github.com/ultralytics/ultralytics/edit/main/ultralytics/hub/google/__init__.py) 🛠️. Thank you 🙏! + +
+ +## ::: ultralytics.hub.google.GCPRegions + +

diff --git a/mkdocs.yml b/mkdocs.yml index ad11736fbc..82cc172d95 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -476,6 +476,8 @@ nav: - hub: - __init__: reference/hub/__init__.md - auth: reference/hub/auth.md + - google: + - __init__: reference/hub/google/__init__.md - session: reference/hub/session.md - utils: reference/hub/utils.md - models: diff --git a/ultralytics/__init__.py b/ultralytics/__init__.py index b140f3795c..b88be152da 100644 --- a/ultralytics/__init__.py +++ b/ultralytics/__init__.py @@ -1,6 +1,6 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license -__version__ = "8.2.67" +__version__ = "8.2.68" import os diff --git a/ultralytics/hub/google/__init__.py b/ultralytics/hub/google/__init__.py new file mode 100644 index 0000000000..1e8779ca00 --- /dev/null +++ b/ultralytics/hub/google/__init__.py @@ -0,0 +1,159 @@ +# Ultralytics YOLO 🚀, AGPL-3.0 license + +import concurrent.futures +import statistics +import time +from typing import List, Optional, Tuple + +import requests + + +class GCPRegions: + """ + A class for managing and analyzing Google Cloud Platform (GCP) regions. + + This class provides functionality to initialize, categorize, and analyze GCP regions based on their + geographical location, tier classification, and network latency. + + Attributes: + regions (Dict[str, Tuple[int, str, str]]): A dictionary of GCP regions with their tier, city, and country. + + Methods: + tier1: Returns a list of tier 1 GCP regions. + tier2: Returns a list of tier 2 GCP regions. + lowest_latency: Determines the GCP region(s) with the lowest network latency. + + Examples: + >>> from ultralytics.hub.google import GCPRegions + >>> regions = GCPRegions() + >>> lowest_latency_region = regions.lowest_latency(verbose=True, attempts=3) + >>> print(f"Lowest latency region: {lowest_latency_region[0][0]}") + """ + + def __init__(self): + """Initializes the GCPRegions class with predefined Google Cloud Platform regions and their details.""" + self.regions = { + "asia-east1": (1, "Taiwan", "China"), + "asia-east2": (2, "Hong Kong", "China"), + "asia-northeast1": (1, "Tokyo", "Japan"), + "asia-northeast2": (1, "Osaka", "Japan"), + "asia-northeast3": (2, "Seoul", "South Korea"), + "asia-south1": (2, "Mumbai", "India"), + "asia-south2": (2, "Delhi", "India"), + "asia-southeast1": (2, "Jurong West", "Singapore"), + "asia-southeast2": (2, "Jakarta", "Indonesia"), + "australia-southeast1": (2, "Sydney", "Australia"), + "australia-southeast2": (2, "Melbourne", "Australia"), + "europe-central2": (2, "Warsaw", "Poland"), + "europe-north1": (1, "Hamina", "Finland"), + "europe-southwest1": (1, "Madrid", "Spain"), + "europe-west1": (1, "St. Ghislain", "Belgium"), + "europe-west10": (2, "Berlin", "Germany"), + "europe-west12": (2, "Turin", "Italy"), + "europe-west2": (2, "London", "United Kingdom"), + "europe-west3": (2, "Frankfurt", "Germany"), + "europe-west4": (1, "Eemshaven", "Netherlands"), + "europe-west6": (2, "Zurich", "Switzerland"), + "europe-west8": (1, "Milan", "Italy"), + "europe-west9": (1, "Paris", "France"), + "me-central1": (2, "Doha", "Qatar"), + "me-west1": (1, "Tel Aviv", "Israel"), + "northamerica-northeast1": (2, "Montreal", "Canada"), + "northamerica-northeast2": (2, "Toronto", "Canada"), + "southamerica-east1": (2, "São Paulo", "Brazil"), + "southamerica-west1": (2, "Santiago", "Chile"), + "us-central1": (1, "Iowa", "United States"), + "us-east1": (1, "South Carolina", "United States"), + "us-east4": (1, "Northern Virginia", "United States"), + "us-east5": (1, "Columbus", "United States"), + "us-south1": (1, "Dallas", "United States"), + "us-west1": (1, "Oregon", "United States"), + "us-west2": (2, "Los Angeles", "United States"), + "us-west3": (2, "Salt Lake City", "United States"), + "us-west4": (2, "Las Vegas", "United States"), + } + + def tier1(self) -> List[str]: + """Returns a list of GCP regions classified as tier 1 based on predefined criteria.""" + return [region for region, info in self.regions.items() if info[0] == 1] + + def tier2(self) -> List[str]: + """Returns a list of GCP regions classified as tier 2 based on predefined criteria.""" + return [region for region, info in self.regions.items() if info[0] == 2] + + @staticmethod + def _ping_region(region: str, attempts: int = 1) -> Tuple[str, float, float, float, float]: + """Pings a specified GCP region and returns latency statistics: mean, min, max, and standard deviation.""" + url = f"https://{region}-docker.pkg.dev" + latencies = [] + for _ in range(attempts): + try: + start_time = time.time() + _ = requests.head(url, timeout=5) + latency = (time.time() - start_time) * 1000 # convert latency to milliseconds + if latency != float("inf"): + latencies.append(latency) + except requests.RequestException: + pass + if not latencies: + return region, float("inf"), float("inf"), float("inf"), float("inf") + + std_dev = statistics.stdev(latencies) if len(latencies) > 1 else 0 + return region, statistics.mean(latencies), std_dev, min(latencies), max(latencies) + + def lowest_latency( + self, + top: int = 1, + verbose: bool = False, + tier: Optional[int] = None, + attempts: int = 1, + ) -> List[Tuple[str, float, float, float, float]]: + """ + Determines the GCP regions with the lowest latency based on ping tests. + + Args: + top (int): Number of top regions to return. + verbose (bool): If True, prints detailed latency information for all tested regions. + tier (int | None): Filter regions by tier (1 or 2). If None, all regions are tested. + attempts (int): Number of ping attempts per region. + + Returns: + (List[Tuple[str, float, float, float, float]]): List of tuples containing region information and + latency statistics. Each tuple contains (region, mean_latency, std_dev, min_latency, max_latency). + + Examples: + >>> regions = GCPRegions() + >>> results = regions.lowest_latency(top=3, verbose=True, tier=1, attempts=2) + >>> print(results[0][0]) # Print the name of the lowest latency region + """ + if verbose: + print(f"Testing GCP regions for latency (with {attempts} {'retry' if attempts == 1 else 'attempts'})...") + + regions_to_test = [k for k, v in self.regions.items() if v[0] == tier] if tier else list(self.regions.keys()) + with concurrent.futures.ThreadPoolExecutor(max_workers=50) as executor: + results = list(executor.map(lambda r: self._ping_region(r, attempts), regions_to_test)) + + sorted_results = sorted(results, key=lambda x: x[1]) + + if verbose: + print(f"{'Region':<20} {'Location':<35} {'Tier':<5} {'Latency (ms)'}") + for region, mean, std, min_, max_ in sorted_results: + tier, city, country = self.regions[region] + location = f"{city}, {country}" + if mean == float("inf"): + print(f"{region:<20} {location:<35} {tier:<5} {'Timeout'}") + else: + print(f"{region:<20} {location:<35} {tier:<5} {mean:.0f} ± {std:.0f} ({min_:.0f} - {max_:.0f})") + print(f"\nLowest latency region{'s' if top > 1 else ''}:") + for region, mean, std, min_, max_ in sorted_results[:top]: + tier, city, country = self.regions[region] + location = f"{city}, {country}" + print(f"{region} ({location}, {mean:.0f} ± {std:.0f} ms ({min_:.0f} - {max_:.0f}))") + + return sorted_results[:top] + + +# Usage example +if __name__ == "__main__": + regions = GCPRegions() + top_3_latency_tier1 = regions.lowest_latency(top=3, verbose=True, tier=1, attempts=3)