1 """Script to run benchmarks."""
3 from __future__
import annotations
7 from collections.abc
import Callable
8 from contextlib
import suppress
10 from timeit
import default_timer
as timer
12 from homeassistant
import core
16 async_track_state_change,
17 async_track_state_change_event,
24 BENCHMARKS: dict[str, Callable] = {}
28 """Handle benchmark commandline script."""
30 logging.getLogger(
"homeassistant.core").setLevel(logging.CRITICAL)
32 parser = argparse.ArgumentParser(description=
"Run a Home Assistant benchmark.")
33 parser.add_argument(
"name", choices=BENCHMARKS)
34 parser.add_argument(
"--script", choices=[
"benchmark"])
36 args = parser.parse_args()
38 bench = BENCHMARKS[args.name]
39 print(
"Using event loop:", asyncio.get_event_loop_policy().loop_name)
41 with suppress(KeyboardInterrupt):
47 """Run a benchmark."""
49 runtime = await bench(hass)
50 print(f
"Benchmark {bench.__name__} done in {runtime}s")
51 await hass.async_stop()
54 def benchmark[_CallableT: Callable](func: _CallableT) -> _CallableT:
55 """Decorate to mark a benchmark."""
56 BENCHMARKS[func.__name__] = func
62 """Fire a million events."""
64 event_name =
"benchmark_event"
65 events_to_fire = 10**6
73 hass.bus.async_listen(event_name, listener)
75 for _
in range(events_to_fire):
76 hass.bus.async_fire(event_name)
80 await hass.async_block_till_done()
82 assert count == events_to_fire
84 return timer() - start
89 """Fire a million events with a filter that rejects them."""
91 event_name =
"benchmark_event"
92 events_to_fire = 10**6
95 def event_filter(event_data):
105 hass.bus.async_listen(event_name, listener, event_filter=event_filter)
107 for _
in range(events_to_fire):
108 hass.bus.async_fire(event_name)
112 await hass.async_block_till_done()
116 return timer() - start
121 """Run a million events through state changed helper with 1000 entities."""
123 entity_id =
"light.kitchen"
124 event = asyncio.Event()
135 for idx
in range(1000):
138 "entity_id": f
"{entity_id}0",
143 for _
in range(10**6):
144 hass.bus.async_fire(EVENT_STATE_CHANGED, event_data)
150 return timer() - start
155 """Run a million events through state changed event helper with 1000 entities."""
157 entity_id =
"light.kitchen"
158 events_to_fire = 10**6
167 hass, [f
"{entity_id}{idx}" for idx
in range(1000)], listener
171 "entity_id": f
"{entity_id}0",
176 for _
in range(events_to_fire):
177 hass.bus.async_fire(EVENT_STATE_CHANGED, event_data)
181 await hass.async_block_till_done()
183 assert count == events_to_fire
185 return timer() - start
190 """Run a million events through state changed event helper.
192 With 1000 entities that all get filtered.
195 entity_id =
"light.kitchen"
196 events_to_fire = 10**6
205 hass, [f
"{entity_id}{idx}" for idx
in range(1000)], listener
209 "entity_id":
"switch.no_listeners",
214 for _
in range(events_to_fire):
215 hass.bus.async_fire(EVENT_STATE_CHANGED, event_data)
219 await hass.async_block_till_done()
223 return timer() - start
228 """Run a 100k state changes through entity filter."""
239 "binary_sensor.*_contact",
240 "binary_sensor.*_occupancy",
241 "binary_sensor.*_detected",
242 "binary_sensor.*_active",
244 "device_tracker.*_phone",
246 "binary_sensor.*_charging",
247 "binary_sensor.*_lock",
248 "binary_sensor.*_connected",
253 "binary_sensor.garage_door_open",
259 "domains": [
"input_number"],
260 "entity_globs": [
"media_player.google_*",
"group.all_*"],
266 "automation.home_arrival",
267 "script.shut_off_house",
268 "binary_sensor.garage_door_open",
269 "binary_sensor.front_door_lock",
270 "binary_sensor.kitchen_motion_sensor_occupancy",
273 "input_boolean.guest_staying_over",
274 "person.eleanor_fant",
275 "alert.issue_at_home",
276 "calendar.eleanor_fant_s_calendar",
281 size = len(entity_ids)
285 for i
in range(10**5):
286 entities_filter(entity_ids[i % size])
288 return timer() - start
293 """Run valid entity ID a million times."""
295 for _
in range(10**6):
296 core.valid_entity_id(
"light.kitchen")
297 return timer() - start
302 """Serialize million states with websocket default encoder."""
304 core.State(
"light.kitchen",
"on", {
"friendly_name":
"Kitchen Lights"})
305 for _
in range(10**6)
310 return timer() - start
EntityFilter convert_include_exclude_filter(dict[str, dict[str, list[str]]] config)
CALLBACK_TYPE async_track_state_change_event(HomeAssistant hass, str|Iterable[str] entity_ids, Callable[[Event[EventStateChangedData]], Any] action, HassJobType|None job_type=None)
CALLBACK_TYPE async_track_state_change(HomeAssistant hass, str|Iterable[str] entity_ids, Callable[[str, State|None, State|None], Coroutine[Any, Any, None]|None] action, str|Iterable[str]|None from_state=None, str|Iterable[str]|None to_state=None)
def state_changed_event_helper(hass)
def state_changed_helper(hass)
def json_serialize_states(hass)
def valid_entity_id(hass)
def filtering_entity_id(hass)
def state_changed_event_filter_helper(hass)
def fire_events_with_filter(hass)