|
import time |
|
from abc import ABCMeta, abstractmethod |
|
from typing import Union |
|
|
|
from ..lock_helper import LockContext, LockContextType |
|
|
|
|
|
class BaseTime(metaclass=ABCMeta): |
|
""" |
|
Overview: |
|
Abstract time interface |
|
Interfaces: |
|
``time`` |
|
""" |
|
|
|
@abstractmethod |
|
def time(self) -> Union[int, float]: |
|
""" |
|
Overview: |
|
Get time information |
|
|
|
Returns: |
|
- time(:obj:`float, int`): time information |
|
""" |
|
raise NotImplementedError |
|
|
|
|
|
class NaturalTime(BaseTime): |
|
""" |
|
Overview: |
|
Natural time object |
|
Interfaces: |
|
``__init__``, ``time`` |
|
Example: |
|
>>> from ding.utils.autolog.time_ctl import NaturalTime |
|
>>> time_ = NaturalTime() |
|
""" |
|
|
|
def __init__(self): |
|
self.__last_time = None |
|
|
|
def time(self) -> float: |
|
""" |
|
Overview: |
|
Get current natural time (float format, unix timestamp) |
|
|
|
Returns: |
|
- time(:obj:`float`): unix timestamp |
|
|
|
Example: |
|
>>> from ding.utils.autolog.time_ctl import NaturalTime |
|
>>> time_ = NaturalTime() |
|
>>> time_.time() |
|
1603896383.8811457 |
|
""" |
|
_current_time = time.time() |
|
if self.__last_time is not None: |
|
_current_time = max(_current_time, self.__last_time) |
|
|
|
self.__last_time = _current_time |
|
return _current_time |
|
|
|
|
|
class TickTime(BaseTime): |
|
""" |
|
Overview: |
|
Tick time object |
|
Interfaces: |
|
``__init__``, ``step``, ``time`` |
|
Example: |
|
>>> from ding.utils.autolog.time_ctl import TickTime |
|
>>> time_ = TickTime() |
|
""" |
|
|
|
def __init__(self, init: int = 0): |
|
""" |
|
Overview: |
|
Constructor of TickTime |
|
|
|
Arguments: |
|
- init (:obj:`int`): initial time, default is 0 |
|
""" |
|
self.__tick_time = init |
|
|
|
def step(self, delta: int = 1) -> int: |
|
""" |
|
Overview |
|
Step the time forward for this TickTime |
|
|
|
Arguments: |
|
- delta (:obj:`int`): steps to step forward, default is 1 |
|
|
|
Returns: |
|
- time (:obj:`int`): new time after stepping |
|
|
|
Example: |
|
>>> from ding.utils.autolog.time_ctl import TickTime |
|
>>> time_ = TickTime(0) |
|
>>> time_.step() |
|
1 |
|
>>> time_.step(2) |
|
3 |
|
""" |
|
if not isinstance(delta, int): |
|
raise TypeError("Delta should be positive int, but {actual} found.".format(actual=type(delta).__name__)) |
|
elif delta < 1: |
|
raise ValueError("Delta should be no less than 1, but {actual} found.".format(actual=repr(delta))) |
|
else: |
|
self.__tick_time += delta |
|
return self.__tick_time |
|
|
|
def time(self) -> int: |
|
""" |
|
Overview |
|
Get current tick time |
|
|
|
Returns: |
|
int: current tick time |
|
|
|
Example: |
|
>>> from ding.utils.autolog.time_ctl import TickTime |
|
>>> time_ = TickTime(0) |
|
>>> time_.step() |
|
>>> time_.time() |
|
1 |
|
""" |
|
return self.__tick_time |
|
|
|
|
|
class TimeProxy(BaseTime): |
|
""" |
|
Overview: |
|
Proxy of time object, it can freeze time, sometimes useful when reproducing. |
|
This object is thread-safe, and also freeze and unfreeze operation is strictly ordered. |
|
Interfaces: |
|
``__init__``, ``freeze``, ``unfreeze``, ``time``, ``current_time`` |
|
Example: |
|
>>> from ding.utils.autolog.time_ctl import TickTime, TimeProxy |
|
>>> tick_time_ = TickTime() |
|
>>> time_ = TimeProxy(tick_time_) |
|
>>> tick_time_.step() |
|
>>> print(tick_time_.time(), time_.time(), time_.current_time()) |
|
1 1 1 |
|
>>> time_.freeze() |
|
>>> tick_time_.step() |
|
>>> print(tick_time_.time(), time_.time(), time_.current_time()) |
|
2 1 2 |
|
>>> time_.unfreeze() |
|
>>> print(tick_time_.time(), time_.time(), time_.current_time()) |
|
2 2 2 |
|
""" |
|
|
|
def __init__(self, time_: BaseTime, frozen: bool = False, lock_type: LockContextType = LockContextType.THREAD_LOCK): |
|
""" |
|
Overview: |
|
Constructor for Time proxy |
|
|
|
Arguments: |
|
- time_ (:obj:`BaseTime`): another time object it based on |
|
- frozen (:obj:`bool`): this object will be frozen immediately if true, otherwise not, default is False |
|
- lock_type (:obj:`LockContextType`): type of the lock, default is THREAD_LOCK |
|
""" |
|
self.__time = time_ |
|
self.__current_time = self.__time.time() |
|
|
|
self.__frozen = frozen |
|
self.__lock = LockContext(lock_type) |
|
self.__frozen_lock = LockContext(lock_type) |
|
if self.__frozen: |
|
self.__frozen_lock.acquire() |
|
|
|
@property |
|
def is_frozen(self) -> bool: |
|
""" |
|
Overview: |
|
Get if this time proxy object is frozen |
|
|
|
Returns: |
|
bool: true if it is frozen, otherwise false |
|
""" |
|
with self.__lock: |
|
return self.__frozen |
|
|
|
def freeze(self): |
|
""" |
|
Overview: |
|
Freeze this time proxy |
|
""" |
|
with self.__lock: |
|
self.__frozen_lock.acquire() |
|
self.__frozen = True |
|
self.__current_time = self.__time.time() |
|
|
|
def unfreeze(self): |
|
""" |
|
Overview: |
|
Unfreeze this time proxy |
|
""" |
|
with self.__lock: |
|
self.__frozen = False |
|
self.__frozen_lock.release() |
|
|
|
def time(self) -> Union[int, float]: |
|
""" |
|
Overview: |
|
Get time (may be frozen time) |
|
|
|
Returns: |
|
int or float: the time |
|
""" |
|
with self.__lock: |
|
if self.__frozen: |
|
return self.__current_time |
|
else: |
|
return self.__time.time() |
|
|
|
def current_time(self) -> Union[int, float]: |
|
""" |
|
Overview: |
|
Get current time (will not be frozen time) |
|
|
|
Returns: |
|
int or float: current time |
|
""" |
|
return self.__time.time() |
|
|