42 lines
1.4 KiB
Python
42 lines
1.4 KiB
Python
from asyncio import sleep
|
|
from time import monotonic, process_time
|
|
|
|
SLEEP_GRANULARITY: float = 1 / 50
|
|
SLEEP_IDLE: float = SLEEP_GRANULARITY / 20.0
|
|
|
|
|
|
async def wait_for_idle(
|
|
min_sleep: float = SLEEP_GRANULARITY, max_sleep: float = 1
|
|
) -> None:
|
|
"""Wait until the process isn't working very hard.
|
|
|
|
This will compare wall clock time with process time. If the process time
|
|
is not advancing at the same rate as wall clock time it means the process is
|
|
idle (i.e. sleeping or waiting for input).
|
|
|
|
When the process is idle it suggests that input has been processed and the state
|
|
is predictable enough to test.
|
|
|
|
Args:
|
|
min_sleep: Minimum time to wait.
|
|
max_sleep: Maximum time to wait.
|
|
"""
|
|
start_time = monotonic()
|
|
|
|
while True:
|
|
cpu_time = process_time()
|
|
# Sleep for a predetermined amount of time
|
|
await sleep(SLEEP_GRANULARITY)
|
|
# Calculate the wall clock elapsed time and the process elapsed time
|
|
cpu_elapsed = process_time() - cpu_time
|
|
elapsed_time = monotonic() - start_time
|
|
|
|
# If we have slept the maximum, we can break
|
|
if elapsed_time >= max_sleep:
|
|
break
|
|
|
|
# If we have slept at least the minimum and the cpu elapsed is significantly less
|
|
# than wall clock, then we can assume the process has finished working for now
|
|
if elapsed_time > min_sleep and cpu_elapsed < SLEEP_IDLE:
|
|
break
|