mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Significantly reduce clock_gettime syscalls on platforms with broken vdso (#81257)
This commit is contained in:
parent
8416cc1906
commit
1589c06203
@ -3,13 +3,13 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from collections.abc import Callable, Coroutine
|
from collections.abc import Callable, Coroutine
|
||||||
import logging
|
import logging
|
||||||
import time
|
|
||||||
from typing import Any, Generic, TypeVar
|
from typing import Any, Generic, TypeVar
|
||||||
|
|
||||||
from bleak import BleakError
|
from bleak import BleakError
|
||||||
|
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.debounce import Debouncer
|
from homeassistant.helpers.debounce import Debouncer
|
||||||
|
from homeassistant.util.dt import monotonic_time_coarse
|
||||||
|
|
||||||
from . import BluetoothChange, BluetoothScanningMode, BluetoothServiceInfoBleak
|
from . import BluetoothChange, BluetoothScanningMode, BluetoothServiceInfoBleak
|
||||||
from .passive_update_processor import PassiveBluetoothProcessorCoordinator
|
from .passive_update_processor import PassiveBluetoothProcessorCoordinator
|
||||||
@ -94,7 +94,7 @@ class ActiveBluetoothProcessorCoordinator(
|
|||||||
"""Return true if time to try and poll."""
|
"""Return true if time to try and poll."""
|
||||||
poll_age: float | None = None
|
poll_age: float | None = None
|
||||||
if self._last_poll:
|
if self._last_poll:
|
||||||
poll_age = time.monotonic() - self._last_poll
|
poll_age = monotonic_time_coarse() - self._last_poll
|
||||||
return self._needs_poll_method(service_info, poll_age)
|
return self._needs_poll_method(service_info, poll_age)
|
||||||
|
|
||||||
async def _async_poll_data(
|
async def _async_poll_data(
|
||||||
@ -124,7 +124,7 @@ class ActiveBluetoothProcessorCoordinator(
|
|||||||
self.last_poll_successful = False
|
self.last_poll_successful = False
|
||||||
return
|
return
|
||||||
finally:
|
finally:
|
||||||
self._last_poll = time.monotonic()
|
self._last_poll = monotonic_time_coarse()
|
||||||
|
|
||||||
if not self.last_poll_successful:
|
if not self.last_poll_successful:
|
||||||
self.logger.debug("%s: Polling recovered")
|
self.logger.debug("%s: Polling recovered")
|
||||||
|
@ -7,7 +7,6 @@ from dataclasses import replace
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
import time
|
|
||||||
from typing import TYPE_CHECKING, Any, Final
|
from typing import TYPE_CHECKING, Any, Final
|
||||||
|
|
||||||
from bleak.backends.scanner import AdvertisementDataCallback
|
from bleak.backends.scanner import AdvertisementDataCallback
|
||||||
@ -22,6 +21,7 @@ from homeassistant.core import (
|
|||||||
)
|
)
|
||||||
from homeassistant.helpers import discovery_flow
|
from homeassistant.helpers import discovery_flow
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
|
from homeassistant.util.dt import monotonic_time_coarse
|
||||||
|
|
||||||
from .advertisement_tracker import AdvertisementTracker
|
from .advertisement_tracker import AdvertisementTracker
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -69,7 +69,7 @@ APPLE_START_BYTES_WANTED: Final = {
|
|||||||
APPLE_DEVICE_ID_START_BYTE,
|
APPLE_DEVICE_ID_START_BYTE,
|
||||||
}
|
}
|
||||||
|
|
||||||
MONOTONIC_TIME: Final = time.monotonic
|
MONOTONIC_TIME: Final = monotonic_time_coarse
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ from collections.abc import Callable
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
import platform
|
import platform
|
||||||
import time
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import async_timeout
|
import async_timeout
|
||||||
@ -22,6 +21,7 @@ from dbus_fast import InvalidMessageError
|
|||||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback as hass_callback
|
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback as hass_callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
|
from homeassistant.util.dt import monotonic_time_coarse
|
||||||
from homeassistant.util.package import is_docker_env
|
from homeassistant.util.package import is_docker_env
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -35,7 +35,7 @@ from .models import BaseHaScanner, BluetoothScanningMode, BluetoothServiceInfoBl
|
|||||||
from .util import adapter_human_name, async_reset_adapter
|
from .util import adapter_human_name, async_reset_adapter
|
||||||
|
|
||||||
OriginalBleakScanner = bleak.BleakScanner
|
OriginalBleakScanner = bleak.BleakScanner
|
||||||
MONOTONIC_TIME = time.monotonic
|
MONOTONIC_TIME = monotonic_time_coarse
|
||||||
|
|
||||||
# or_patterns is a workaround for the fact that passive scanning
|
# or_patterns is a workaround for the fact that passive scanning
|
||||||
# needs at least one matcher to be set. The below matcher
|
# needs at least one matcher to be set. The below matcher
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import platform
|
import platform
|
||||||
import time
|
|
||||||
|
|
||||||
from bluetooth_auto_recovery import recover_adapter
|
from bluetooth_auto_recovery import recover_adapter
|
||||||
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.util.dt import monotonic_time_coarse
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DEFAULT_ADAPTER_BY_PLATFORM,
|
DEFAULT_ADAPTER_BY_PLATFORM,
|
||||||
@ -29,7 +29,7 @@ async def async_load_history_from_system() -> dict[str, BluetoothServiceInfoBlea
|
|||||||
|
|
||||||
bluez_dbus = BlueZDBusObjects()
|
bluez_dbus = BlueZDBusObjects()
|
||||||
await bluez_dbus.load()
|
await bluez_dbus.load()
|
||||||
now = time.monotonic()
|
now = monotonic_time_coarse()
|
||||||
return {
|
return {
|
||||||
address: BluetoothServiceInfoBleak(
|
address: BluetoothServiceInfoBleak(
|
||||||
name=history.advertisement_data.local_name
|
name=history.advertisement_data.local_name
|
||||||
|
@ -19,6 +19,7 @@ from homeassistant.components.bluetooth import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
|
from homeassistant.util.dt import monotonic_time_coarse
|
||||||
|
|
||||||
TWO_CHAR = re.compile("..")
|
TWO_CHAR = re.compile("..")
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ class ESPHomeScanner(BaseHaScanner):
|
|||||||
@callback
|
@callback
|
||||||
def async_on_advertisement(self, adv: BluetoothLEAdvertisement) -> None:
|
def async_on_advertisement(self, adv: BluetoothLEAdvertisement) -> None:
|
||||||
"""Call the registered callback."""
|
"""Call the registered callback."""
|
||||||
now = time.monotonic()
|
now = monotonic_time_coarse()
|
||||||
address = ":".join(TWO_CHAR.findall("%012X" % adv.address)) # must be upper
|
address = ":".join(TWO_CHAR.findall("%012X" % adv.address)) # must be upper
|
||||||
name = adv.name
|
name = adv.name
|
||||||
if prev_discovery := self._discovered_device_advertisement_datas.get(address):
|
if prev_discovery := self._discovered_device_advertisement_datas.get(address):
|
||||||
|
@ -4,7 +4,9 @@ from __future__ import annotations
|
|||||||
import bisect
|
import bisect
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
|
import platform
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
import zoneinfo
|
import zoneinfo
|
||||||
|
|
||||||
@ -13,6 +15,7 @@ import ciso8601
|
|||||||
DATE_STR_FORMAT = "%Y-%m-%d"
|
DATE_STR_FORMAT = "%Y-%m-%d"
|
||||||
UTC = dt.timezone.utc
|
UTC = dt.timezone.utc
|
||||||
DEFAULT_TIME_ZONE: dt.tzinfo = dt.timezone.utc
|
DEFAULT_TIME_ZONE: dt.tzinfo = dt.timezone.utc
|
||||||
|
CLOCK_MONOTONIC_COARSE = 6
|
||||||
|
|
||||||
# EPOCHORDINAL is not exposed as a constant
|
# EPOCHORDINAL is not exposed as a constant
|
||||||
# https://github.com/python/cpython/blob/3.10/Lib/zoneinfo/_zoneinfo.py#L12
|
# https://github.com/python/cpython/blob/3.10/Lib/zoneinfo/_zoneinfo.py#L12
|
||||||
@ -461,3 +464,26 @@ def _datetime_ambiguous(dattim: dt.datetime) -> bool:
|
|||||||
assert dattim.tzinfo is not None
|
assert dattim.tzinfo is not None
|
||||||
opposite_fold = dattim.replace(fold=not dattim.fold)
|
opposite_fold = dattim.replace(fold=not dattim.fold)
|
||||||
return _datetime_exists(dattim) and dattim.utcoffset() != opposite_fold.utcoffset()
|
return _datetime_exists(dattim) and dattim.utcoffset() != opposite_fold.utcoffset()
|
||||||
|
|
||||||
|
|
||||||
|
def __monotonic_time_coarse() -> float:
|
||||||
|
"""Return a monotonic time in seconds.
|
||||||
|
|
||||||
|
This is the coarse version of time_monotonic, which is faster but less accurate.
|
||||||
|
|
||||||
|
Since many arm64 and 32-bit platforms don't support VDSO with time.monotonic
|
||||||
|
because of errata, we can't rely on the kernel to provide a fast
|
||||||
|
monotonic time.
|
||||||
|
|
||||||
|
https://lore.kernel.org/lkml/20170404171826.25030-1-marc.zyngier@arm.com/
|
||||||
|
"""
|
||||||
|
return time.clock_gettime(CLOCK_MONOTONIC_COARSE)
|
||||||
|
|
||||||
|
|
||||||
|
monotonic_time_coarse = time.monotonic
|
||||||
|
with suppress(Exception):
|
||||||
|
if (
|
||||||
|
platform.system() == "Linux"
|
||||||
|
and abs(time.monotonic() - __monotonic_time_coarse()) < 1
|
||||||
|
):
|
||||||
|
monotonic_time_coarse = __monotonic_time_coarse
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
import time
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -719,3 +720,8 @@ def test_find_next_time_expression_tenth_second_pattern_does_not_drift_entering_
|
|||||||
assert (next_target - prev_target).total_seconds() == 60
|
assert (next_target - prev_target).total_seconds() == 60
|
||||||
assert next_target.second == 10
|
assert next_target.second == 10
|
||||||
prev_target = next_target
|
prev_target = next_target
|
||||||
|
|
||||||
|
|
||||||
|
def test_monotonic_time_coarse():
|
||||||
|
"""Test monotonic time coarse."""
|
||||||
|
assert abs(time.monotonic() - dt_util.monotonic_time_coarse()) < 1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user