import itertools
from pathlib import Path
import sys
import time
from typing import Generator, List, Optional, cast
from ymmsl.v0_2 import Reference
[docs]
def instance_to_kernel(instance: Reference) -> Reference:
"""Extracts the name of the kernel from an instance name.
Args:
instance: The name of a kernel instance.
Returns:
The name of its kernel.
"""
i = len(instance)
while isinstance(instance[i - 1], int):
i -= 1
return instance[:i]
[docs]
def instance_indices(instance: Reference) -> List[int]:
"""Extracts the indices from an instance name.
Args:
instance: The name of a kernel instance.
Returns:
The name of its kernel.
"""
i = len(instance)
while isinstance(instance[i - 1], int):
i -= 1
# Note that the slice operator on References returns a Reference,
# which we don't want here.
return [cast(int, instance[j]) for j in range(i, len(instance))]
[docs]
def generate_indices(dims: List[int]) -> Generator[List[int], None, None]:
"""Generates all indices in a block of the given dimensions.
Args:
dims: The dimensions of the block.
Yields:
Lists of indices, one for each point in the block.
"""
for index in itertools.product(*map(range, dims)):
yield list(index)
_DEFAULT_BASE_DELAY = 0.5
_DEFAULT_TIMEOUT = 30.0
_FACTOR = 2.0 ** (1.0 / 3.0)
[docs]
class Retrier:
"""Helper class for retrying things with a delay and timeout.
This backs off exponentially, immediately retrying on the first attempt, then
waiting 2**tries * base_delay seconds between tries.
"""
def __init__(
self, timeout: float = _DEFAULT_TIMEOUT,
base_delay: float = _DEFAULT_BASE_DELAY
) -> None:
"""Create a Retrier.
Args:
timeout: Timeout in seconds after which to give up
base_delay: Base delay in seconds between retries
"""
self._base_delay = base_delay
self._factor = _FACTOR
self._timeout = timeout
self._tries = 0
self._start = 0.0
[docs]
def sleep(self) -> None:
"""Sleep until it's time for the next retry."""
if self._tries == 0:
delay = 0.0
else:
delay = self._base_delay * self._factor ** (self._tries - 1)
time.sleep(delay)
self._tries += 1
[docs]
def should_give_up(self) -> bool:
"""Return whether to give up or retry."""
if self._tries == 0:
self._start = time.monotonic()
elapsed = time.monotonic() - self._start
return elapsed >= self._timeout