server: Stop making lists out of everything
As a demonstration of the cost of this pattern:
$ python -m timeit "for i in list(range(0, 1000000)): pass"
10 loops, best of 3: 31.4 msec per loop
vs:
$ python -m timeit "for i in range(0, 1000000): pass"
10 loops, best of 3: 23.5 msec per loop
Avoiding the list represents a 33% improvement in execution speed.
In a couple of cases this strategy is taken a bit further and generators
are introduced to avoid explicitly creating lists.
Change-Id: I28b3d90dd227f5a2661cd86c0941c54531ad5413
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/obmc/mapper/server.py b/obmc/mapper/server.py
index 5e51d65..1d13c5a 100644
--- a/obmc/mapper/server.py
+++ b/obmc/mapper/server.py
@@ -30,6 +30,7 @@
import obmc.dbuslib.enums
import sys
import traceback
+from itertools import chain
class MapperBusyException(dbus.exceptions.DBusException):
@@ -65,7 +66,7 @@
@staticmethod
def _to_path_elements(path):
- return list(filter(bool, path.split('/')))
+ return filter(bool, path.split('/'))
def __call__(self, path):
try:
@@ -101,10 +102,9 @@
def _gmo_callback(self, path, objs):
try:
self.gmo_pending.remove(path)
- for k, v in list(objs.items()):
- ifaces = {iface: properties for iface, properties in list(
- filter(lambda x: iface_match(x[0]), v.items()))}
- self.results[k] = ifaces
+ for k, v in objs.items():
+ self.results[k] = dict(x for x in v.items()
+ if iface_match(x[0]))
except Exception as e:
error_callback(service, path, e)
return None
@@ -120,9 +120,9 @@
try:
path_elements = self._to_path_elements(path)
root = ET.fromstring(data)
- ifaces = list(filter(
- self._match,
- [x.attrib.get('name') for x in root.findall('interface')]))
+ all_ifaces = root.findall('interface')
+ ifaces = filter(self._match,
+ [x.attrib.get('name') for x in all_ifaces])
ifaces = {x: {} for x in ifaces}
self.results[path] = ifaces
@@ -149,12 +149,12 @@
error_handler=lambda e: error_callback(
service, path, e))
else:
- children = list(filter(
+ children = filter(
bool,
- [x.attrib.get('name') for x in root.findall('node')]))
+ [x.attrib.get('name') for x in root.findall('node')])
children = [
- self._to_path(
- path_elements + self._to_path_elements(x))
+ self._to_path(chain(path_elements,
+ self._to_path_elements(x)))
for x in sorted(children)]
for child in filter(subtree_match, children):
if child not in self.results:
@@ -166,8 +166,7 @@
self.check_done()
def _find_interfaces(self, path):
- path_elements = self._to_path_elements(path)
- path = self._to_path(path_elements)
+ path = self._to_path(self._to_path_elements(path))
obj = conn.get_object(service, path, introspect=False)
iface = dbus.Interface(obj, dbus.INTROSPECTABLE_IFACE)
self.introspect_pending.append(path)
@@ -303,7 +302,7 @@
# make sure its in our cache, and add it if not.
cache_entry = self.cache_get(path)
old = self.interfaces_get(cache_entry, owner)
- new = list(set(old).union([dbus.BUS_DAEMON_IFACE + '.ObjectManager']))
+ new = set(old).union([dbus.BUS_DAEMON_IFACE + '.ObjectManager'])
self.update_interfaces(path, owner, old, new)
def defer_signal(self, owner, callback):
@@ -314,7 +313,7 @@
owner = self.bus_normalize(str(kw['sender']))
if not owner:
return
- interfaces = self.filter_signal_interfaces(iter(list(iprops.keys())))
+ interfaces = self.filter_signal_interfaces(iprops.keys())
if not interfaces:
return
@@ -322,7 +321,7 @@
self.add_new_objmgr(str(kw['sender_path']), owner)
cache_entry = self.cache_get(path)
old = self.interfaces_get(cache_entry, owner)
- new = list(set(interfaces).union(old))
+ new = set(interfaces).union(old)
new = {x: iprops.get(x, {}) for x in new}
self.update_interfaces(path, owner, old, new)
else:
@@ -344,7 +343,7 @@
self.add_new_objmgr(str(kw['sender_path']), owner)
cache_entry = self.cache_get(path)
old = self.interfaces_get(cache_entry, owner)
- new = list(set(old).difference(interfaces))
+ new = set(old).difference(interfaces)
self.update_interfaces(path, owner, old, new)
else:
self.defer_signal(
@@ -415,20 +414,20 @@
# __xx -> intf list
# xx -> intf dict
if isinstance(old, dict):
- __old = list(old.keys())
+ __old = old.keys()
else:
__old = old
old = {x: {} for x in old}
if isinstance(new, dict):
- __new = list(new.keys())
+ __new = new.keys()
else:
__new = new
new = {x: {} for x in new}
cache_entry = self.cache.setdefault(path, {})
created = [] if self.has_interfaces(cache_entry) else [path]
- added = list(set(__new).difference(__old))
- removed = list(set(__old).difference(__new))
+ added = set(__new).difference(__old)
+ removed = set(__old).difference(__new)
self.interfaces_append(cache_entry, owner, added)
self.interfaces_remove(cache_entry, owner, removed, path)
destroyed = [] if self.has_interfaces(cache_entry) else [path]
@@ -445,7 +444,7 @@
path, owner, old_assoc, new_assoc, created, destroyed)
def add_items(self, owner, bus_items):
- for path, items in list(bus_items.items()):
+ for path, items in bus_items.items():
self.update_interfaces(path, str(owner), old=[], new=items)
def path_match(self, path):
@@ -492,11 +491,9 @@
traceback.print_exception(*sys.exc_info())
if not owners:
- owned_names = [
- x for x in self.bus.list_names()
- if not obmc.dbuslib.bindings.is_unique(x)]
- owners = list(
- filter(bool, [get_owner(name) for name in owned_names]))
+ owned_names = [x for x in self.bus.list_names()
+ if not obmc.dbuslib.bindings.is_unique(x)]
+ owners = filter(bool, (get_owner(name) for name in owned_names))
for owned_name, o in owners:
if not self.bus_normalize(owned_name):
continue
@@ -565,18 +562,14 @@
# Remove interfaces from a service that
# aren't in a filter.
- svc_map = lambda svc: (
- svc[0],
- list(set(ifaces).intersection(svc[1])))
+ svc_map = lambda svc: (svc[0], set(ifaces).intersection(svc[1]))
# Remove services where no interfaces remain after mapping.
svc_filter = lambda svc: svc[1]
- obj_map = lambda o: (
- tuple(*list(filter(svc_filter, list(map(svc_map, [o]))))))
+ obj_map = lambda o: tuple(*filter(svc_filter, map(svc_map, [o])))
- return dict(
- [x for x in map(obj_map, iter(list(item.items()))) if x])
+ return dict(x for x in map(obj_map, item.items()) if x)
# Called with a list of path/object tuples.
if not ifaces:
@@ -618,10 +611,7 @@
@staticmethod
def has_interfaces(item):
- for owner in list(item.keys()):
- if ObjectMapper.interfaces_get(item, owner):
- return True
- return False
+ return any(item.values())
@staticmethod
def is_association(interfaces):
@@ -659,7 +649,7 @@
associations = []
if not owners:
index = self.index.get(forward, {})
- owners = list(index.get(path, {}).keys())
+ owners = index.get(path, {}).keys()
# f: forward
# r: reverse
@@ -681,9 +671,8 @@
iface = obmc.dbuslib.enums.OBMC_ASSOC_IFACE
assoc = self.manager.get(path, None)
- old_endpoints = assoc.Get(iface, 'endpoints') if assoc else []
- new_endpoints = list(
- set(old_endpoints).union(added).difference(removed))
+ old_endpoints = set(assoc.Get(iface, 'endpoints') if assoc else [])
+ new_endpoints = old_endpoints.union(added).difference(removed)
if old_endpoints == new_endpoints:
return
@@ -693,11 +682,11 @@
if create:
self.manager.add(
- path, Association(self.bus, path, new_endpoints))
+ path, Association(self.bus, path, list(new_endpoints)))
elif delete:
self.manager.remove(path)
else:
- assoc.Set(iface, 'endpoints', new_endpoints)
+ assoc.Set(iface, 'endpoints', list(new_endpoints))
if create != delete:
self.update_interfaces(
@@ -705,8 +694,8 @@
def update_associations(
self, path, owner, old, new, created=[], destroyed=[]):
- added = list(set(new).difference(old))
- removed = list(set(old).difference(new))
+ added = set(new).difference(old)
+ removed = set(old).difference(new)
for forward, reverse, endpoint in added:
if not endpoint:
# skip associations without an endpoint
@@ -764,22 +753,22 @@
if not self.cache_get(path):
raise MapperNotFoundException(path)
- elements = list(filter(bool, path.split('/')))
- paths = []
objs = {}
- while elements:
- elements.pop()
- paths.append('/' + '/'.join(elements))
- if path != '/':
- paths.append('/')
- for path in paths:
- obj = self.cache_get(path)
+ def parents(path):
+ yield "/"
+ parent = ""
+ for elem in (x for x in list(filter(bool, path.split('/')))[:-1]):
+ parent += "/" + elem
+ yield parent
+
+ for parent in parents(path):
+ obj = self.cache_get(parent)
if not obj:
continue
- objs[path] = obj
+ objs[parent] = obj
- return self.filter_interfaces(list(objs.items()), interfaces)
+ return self.filter_interfaces(objs.items(), interfaces)
@dbus.service.signal(obmc.mapper.MAPPER_IFACE + '.Private', 's')
def IntrospectionComplete(self, name):