mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Logbook speedup (#12566)
* Optimize logbook filtering * Avoid State construction during Events filtering * Move tuple creation out of loop * Add benchmark
This commit is contained in:
parent
8d0b7adf24
commit
f9ee29a5cd
@ -170,6 +170,8 @@ def humanify(events):
|
|||||||
- if 2+ sensor updates in GROUP_BY_MINUTES, show last
|
- if 2+ sensor updates in GROUP_BY_MINUTES, show last
|
||||||
- if home assistant stop and start happen in same minute call it restarted
|
- if home assistant stop and start happen in same minute call it restarted
|
||||||
"""
|
"""
|
||||||
|
domain_prefixes = tuple('{}.'.format(dom) for dom in CONTINUOUS_DOMAINS)
|
||||||
|
|
||||||
# Group events in batches of GROUP_BY_MINUTES
|
# Group events in batches of GROUP_BY_MINUTES
|
||||||
for _, g_events in groupby(
|
for _, g_events in groupby(
|
||||||
events,
|
events,
|
||||||
@ -189,11 +191,7 @@ def humanify(events):
|
|||||||
if event.event_type == EVENT_STATE_CHANGED:
|
if event.event_type == EVENT_STATE_CHANGED:
|
||||||
entity_id = event.data.get('entity_id')
|
entity_id = event.data.get('entity_id')
|
||||||
|
|
||||||
if entity_id is None:
|
if entity_id.startswith(domain_prefixes):
|
||||||
continue
|
|
||||||
|
|
||||||
if entity_id.startswith(tuple('{}.'.format(
|
|
||||||
domain) for domain in CONTINUOUS_DOMAINS)):
|
|
||||||
last_sensor_event[entity_id] = event
|
last_sensor_event[entity_id] = event
|
||||||
|
|
||||||
elif event.event_type == EVENT_HOMEASSISTANT_STOP:
|
elif event.event_type == EVENT_HOMEASSISTANT_STOP:
|
||||||
@ -214,14 +212,6 @@ def humanify(events):
|
|||||||
|
|
||||||
to_state = State.from_dict(event.data.get('new_state'))
|
to_state = State.from_dict(event.data.get('new_state'))
|
||||||
|
|
||||||
# If last_changed != last_updated only attributes have changed
|
|
||||||
# we do not report on that yet. Also filter auto groups.
|
|
||||||
if not to_state or \
|
|
||||||
to_state.last_changed != to_state.last_updated or \
|
|
||||||
to_state.domain == 'group' and \
|
|
||||||
to_state.attributes.get('auto', False):
|
|
||||||
continue
|
|
||||||
|
|
||||||
domain = to_state.domain
|
domain = to_state.domain
|
||||||
|
|
||||||
# Skip all but the last sensor state
|
# Skip all but the last sensor state
|
||||||
@ -290,7 +280,7 @@ def _get_events(hass, config, start_day, end_day):
|
|||||||
|
|
||||||
|
|
||||||
def _exclude_events(events, config):
|
def _exclude_events(events, config):
|
||||||
"""Get lists of excluded entities and platforms."""
|
"""Get list of filtered events."""
|
||||||
excluded_entities = []
|
excluded_entities = []
|
||||||
excluded_domains = []
|
excluded_domains = []
|
||||||
included_entities = []
|
included_entities = []
|
||||||
@ -309,23 +299,41 @@ def _exclude_events(events, config):
|
|||||||
domain, entity_id = None, None
|
domain, entity_id = None, None
|
||||||
|
|
||||||
if event.event_type == EVENT_STATE_CHANGED:
|
if event.event_type == EVENT_STATE_CHANGED:
|
||||||
to_state = State.from_dict(event.data.get('new_state'))
|
entity_id = event.data.get('entity_id')
|
||||||
|
|
||||||
|
if entity_id is None:
|
||||||
|
continue
|
||||||
|
|
||||||
# Do not report on new entities
|
# Do not report on new entities
|
||||||
if event.data.get('old_state') is None:
|
if event.data.get('old_state') is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
new_state = event.data.get('new_state')
|
||||||
|
|
||||||
# Do not report on entity removal
|
# Do not report on entity removal
|
||||||
if not to_state:
|
if not new_state:
|
||||||
|
continue
|
||||||
|
|
||||||
|
attributes = new_state.get('attributes', {})
|
||||||
|
|
||||||
|
# If last_changed != last_updated only attributes have changed
|
||||||
|
# we do not report on that yet.
|
||||||
|
last_changed = new_state.get('last_changed')
|
||||||
|
last_updated = new_state.get('last_updated')
|
||||||
|
if last_changed != last_updated:
|
||||||
|
continue
|
||||||
|
|
||||||
|
domain = split_entity_id(entity_id)[0]
|
||||||
|
|
||||||
|
# Also filter auto groups.
|
||||||
|
if domain == 'group' and attributes.get('auto', False):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# exclude entities which are customized hidden
|
# exclude entities which are customized hidden
|
||||||
hidden = to_state.attributes.get(ATTR_HIDDEN, False)
|
hidden = attributes.get(ATTR_HIDDEN, False)
|
||||||
if hidden:
|
if hidden:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
domain = to_state.domain
|
|
||||||
entity_id = to_state.entity_id
|
|
||||||
|
|
||||||
elif event.event_type == EVENT_LOGBOOK_ENTRY:
|
elif event.event_type == EVENT_LOGBOOK_ENTRY:
|
||||||
domain = event.data.get(ATTR_DOMAIN)
|
domain = event.data.get(ATTR_DOMAIN)
|
||||||
entity_id = event.data.get(ATTR_ENTITY_ID)
|
entity_id = event.data.get(ATTR_ENTITY_ID)
|
||||||
|
@ -144,3 +144,53 @@ def async_million_state_changed_helper(hass):
|
|||||||
yield from event.wait()
|
yield from event.wait()
|
||||||
|
|
||||||
return timer() - start
|
return timer() - start
|
||||||
|
|
||||||
|
|
||||||
|
@benchmark
|
||||||
|
@asyncio.coroutine
|
||||||
|
def logbook_filtering_state(hass):
|
||||||
|
"""Filter state changes."""
|
||||||
|
return _logbook_filtering(hass, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
|
@benchmark
|
||||||
|
@asyncio.coroutine
|
||||||
|
def logbook_filtering_attributes(hass):
|
||||||
|
"""Filter attribute changes."""
|
||||||
|
return _logbook_filtering(hass, 1, 2)
|
||||||
|
|
||||||
|
|
||||||
|
@benchmark
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _logbook_filtering(hass, last_changed, last_updated):
|
||||||
|
from homeassistant.components import logbook
|
||||||
|
|
||||||
|
entity_id = 'test.entity'
|
||||||
|
|
||||||
|
old_state = {
|
||||||
|
'entity_id': entity_id,
|
||||||
|
'state': 'off'
|
||||||
|
}
|
||||||
|
|
||||||
|
new_state = {
|
||||||
|
'entity_id': entity_id,
|
||||||
|
'state': 'on',
|
||||||
|
'last_updated': last_updated,
|
||||||
|
'last_changed': last_changed
|
||||||
|
}
|
||||||
|
|
||||||
|
event = core.Event(EVENT_STATE_CHANGED, {
|
||||||
|
'entity_id': entity_id,
|
||||||
|
'old_state': old_state,
|
||||||
|
'new_state': new_state
|
||||||
|
})
|
||||||
|
|
||||||
|
events = [event] * 10**5
|
||||||
|
|
||||||
|
start = timer()
|
||||||
|
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
events = logbook._exclude_events(events, {})
|
||||||
|
list(logbook.humanify(events))
|
||||||
|
|
||||||
|
return timer() - start
|
||||||
|
@ -372,7 +372,8 @@ class TestComponentLogbook(unittest.TestCase):
|
|||||||
eventB = self.create_state_changed_event(pointA, entity_id2, 20,
|
eventB = self.create_state_changed_event(pointA, entity_id2, 20,
|
||||||
{'auto': True})
|
{'auto': True})
|
||||||
|
|
||||||
entries = list(logbook.humanify((eventA, eventB)))
|
events = logbook._exclude_events((eventA, eventB), {})
|
||||||
|
entries = list(logbook.humanify(events))
|
||||||
|
|
||||||
self.assertEqual(1, len(entries))
|
self.assertEqual(1, len(entries))
|
||||||
self.assert_entry(entries[0], pointA, 'bla', domain='switch',
|
self.assert_entry(entries[0], pointA, 'bla', domain='switch',
|
||||||
@ -389,7 +390,8 @@ class TestComponentLogbook(unittest.TestCase):
|
|||||||
eventB = self.create_state_changed_event(
|
eventB = self.create_state_changed_event(
|
||||||
pointA, entity_id2, 20, last_changed=pointA, last_updated=pointB)
|
pointA, entity_id2, 20, last_changed=pointA, last_updated=pointB)
|
||||||
|
|
||||||
entries = list(logbook.humanify((eventA, eventB)))
|
events = logbook._exclude_events((eventA, eventB), {})
|
||||||
|
entries = list(logbook.humanify(events))
|
||||||
|
|
||||||
self.assertEqual(1, len(entries))
|
self.assertEqual(1, len(entries))
|
||||||
self.assert_entry(entries[0], pointA, 'bla', domain='switch',
|
self.assert_entry(entries[0], pointA, 'bla', domain='switch',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user