mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Decrease event loop latency by binding time.monotonic to loop.time directly (#98288)
* Decrease event loop latency by binding time.monotonic to loop.time directly This is a small improvment to decrease event loop latency. While the goal is is to reduce Bluetooth connection time latency, everything using asyncio is a bit more responsive as a result. * relo per comments * fix too fast by adding resolution, ensure monotonic time is patchable by freezegun * fix test that freezes time too late and has a race loop
This commit is contained in:
parent
07e20e1eab
commit
790c1bc251
@ -8,6 +8,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
|
from time import monotonic
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -114,6 +115,10 @@ class HassEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
|
|||||||
loop.set_default_executor = warn_use( # type: ignore[method-assign]
|
loop.set_default_executor = warn_use( # type: ignore[method-assign]
|
||||||
loop.set_default_executor, "sets default executor on the event loop"
|
loop.set_default_executor, "sets default executor on the event loop"
|
||||||
)
|
)
|
||||||
|
# bind the built-in time.monotonic directly as loop.time to avoid the
|
||||||
|
# overhead of the additional method call since its the most called loop
|
||||||
|
# method and its roughly 10%+ of all the call time in base_events.py
|
||||||
|
loop.time = monotonic # type: ignore[method-assign]
|
||||||
return loop
|
return loop
|
||||||
|
|
||||||
|
|
||||||
|
@ -420,6 +420,9 @@ def async_fire_time_changed(
|
|||||||
_async_fire_time_changed(hass, utc_datetime, fire_all)
|
_async_fire_time_changed(hass, utc_datetime, fire_all)
|
||||||
|
|
||||||
|
|
||||||
|
_MONOTONIC_RESOLUTION = time.get_clock_info("monotonic").resolution
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_fire_time_changed(
|
def _async_fire_time_changed(
|
||||||
hass: HomeAssistant, utc_datetime: datetime | None, fire_all: bool
|
hass: HomeAssistant, utc_datetime: datetime | None, fire_all: bool
|
||||||
@ -432,7 +435,7 @@ def _async_fire_time_changed(
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
mock_seconds_into_future = timestamp - time.time()
|
mock_seconds_into_future = timestamp - time.time()
|
||||||
future_seconds = task.when() - hass.loop.time()
|
future_seconds = task.when() - (hass.loop.time() + _MONOTONIC_RESOLUTION)
|
||||||
|
|
||||||
if fire_all or mock_seconds_into_future >= future_seconds:
|
if fire_all or mock_seconds_into_future >= future_seconds:
|
||||||
with patch(
|
with patch(
|
||||||
|
@ -8,6 +8,7 @@ from typing import Any
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant import config as hass_config
|
from homeassistant import config as hass_config
|
||||||
from homeassistant.components.recorder import Recorder
|
from homeassistant.components.recorder import Recorder
|
||||||
@ -1286,12 +1287,14 @@ async def test_initialize_from_database(
|
|||||||
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfTemperature.CELSIUS
|
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfTemperature.CELSIUS
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.freeze_time(
|
||||||
|
datetime(dt_util.utcnow().year + 1, 8, 2, 12, 23, 42, tzinfo=dt_util.UTC)
|
||||||
|
)
|
||||||
async def test_initialize_from_database_with_maxage(
|
async def test_initialize_from_database_with_maxage(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant
|
recorder_mock: Recorder, hass: HomeAssistant
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test initializing the statistics from the database."""
|
"""Test initializing the statistics from the database."""
|
||||||
now = dt_util.utcnow()
|
current_time = dt_util.utcnow()
|
||||||
current_time = datetime(now.year + 1, 8, 2, 12, 23, 42, tzinfo=dt_util.UTC)
|
|
||||||
|
|
||||||
# Testing correct retrieval from recorder, thus we do not
|
# Testing correct retrieval from recorder, thus we do not
|
||||||
# want purging to occur within the class itself.
|
# want purging to occur within the class itself.
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import time
|
||||||
|
|
||||||
from homeassistant import util
|
from homeassistant import runner, util
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
|
|
||||||
@ -12,5 +13,11 @@ def _utcnow() -> datetime.datetime:
|
|||||||
return datetime.datetime.now(datetime.UTC)
|
return datetime.datetime.now(datetime.UTC)
|
||||||
|
|
||||||
|
|
||||||
|
def _monotonic() -> float:
|
||||||
|
"""Make monotonic patchable by freezegun."""
|
||||||
|
return time.monotonic()
|
||||||
|
|
||||||
|
|
||||||
dt_util.utcnow = _utcnow # type: ignore[assignment]
|
dt_util.utcnow = _utcnow # type: ignore[assignment]
|
||||||
util.utcnow = _utcnow # type: ignore[assignment]
|
util.utcnow = _utcnow # type: ignore[assignment]
|
||||||
|
runner.monotonic = _monotonic # type: ignore[assignment]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user