Benjamin Schubert pushed to branch bschubert/optimize-sort at BuildStream / buildstream
Commits:
-
897ae570
by Benjamin Schubert at 2019-01-30T17:38:27Z
4 changed files:
- buildstream/_loader/loadelement.py
- buildstream/_loader/loader.py
- buildstream/_loader/types.py
- buildstream/_profile.py
Changes:
... | ... | @@ -81,42 +81,6 @@ class LoadElement(): |
81 | 81 |
# Extract the Dependencies
|
82 | 82 |
self.deps = _extract_depends_from_node(self.node, loader=self._loader)
|
83 | 83 |
|
84 |
- # depends():
|
|
85 |
- #
|
|
86 |
- # Checks if this element depends on another element, directly
|
|
87 |
- # or indirectly.
|
|
88 |
- #
|
|
89 |
- # Args:
|
|
90 |
- # other (LoadElement): Another LoadElement
|
|
91 |
- #
|
|
92 |
- # Returns:
|
|
93 |
- # (bool): True if this LoadElement depends on 'other'
|
|
94 |
- #
|
|
95 |
- def depends(self, other):
|
|
96 |
- self._ensure_depends_cache()
|
|
97 |
- return self._dep_cache.get(other.full_name) is not None
|
|
98 |
- |
|
99 |
- ###########################################
|
|
100 |
- # Private Methods #
|
|
101 |
- ###########################################
|
|
102 |
- def _ensure_depends_cache(self):
|
|
103 |
- |
|
104 |
- if self._dep_cache:
|
|
105 |
- return
|
|
106 |
- |
|
107 |
- self._dep_cache = {}
|
|
108 |
- for dep in self.deps:
|
|
109 |
- elt = self._loader.get_element_for_dep(dep)
|
|
110 |
- |
|
111 |
- # Ensure the cache of the element we depend on
|
|
112 |
- elt._ensure_depends_cache()
|
|
113 |
- |
|
114 |
- # We depend on this element
|
|
115 |
- self._dep_cache[elt.full_name] = True
|
|
116 |
- |
|
117 |
- # And we depend on everything this element depends on
|
|
118 |
- self._dep_cache.update(elt._dep_cache)
|
|
119 |
- |
|
120 | 84 |
|
121 | 85 |
# _extract_depends_from_node():
|
122 | 86 |
#
|
... | ... | @@ -149,12 +149,9 @@ class Loader(): |
149 | 149 |
# Sort direct dependencies of elements by their dependency ordering
|
150 | 150 |
#
|
151 | 151 |
for target in targets:
|
152 |
- profile_start(Topics.SORT_DEPENDENCIES, target)
|
|
153 |
- junction, name, loader = self._parse_name(target, rewritable, ticker,
|
|
154 |
- fetch_subprojects=fetch_subprojects)
|
|
155 |
- #loader._sort_dependencies(name)
|
|
156 |
- profile_end(Topics.SORT_DEPENDENCIES, target)
|
|
157 |
- # Finally, wrap what we have into LoadElements and return the target
|
|
152 |
+ _junction, name, loader = self._parse_name(target, rewritable, ticker,
|
|
153 |
+ fetch_subprojects=fetch_subprojects)
|
|
154 |
+ # Wrap what we have into LoadElements and return the target
|
|
158 | 155 |
#
|
159 | 156 |
ret.append(loader._collect_element(name))
|
160 | 157 |
|
... | ... | @@ -297,9 +294,6 @@ class Loader(): |
297 | 294 |
raise SystemExit("Can't order stuff")
|
298 | 295 |
|
299 | 296 |
# Load all dependency files for the new LoadElement
|
300 |
- ### FIXME: HERE WE CODE
|
|
301 |
- ###
|
|
302 |
- ###
|
|
303 | 297 |
for dep in sorted(element.deps, key=cmp_to_key(sort_deps)):
|
304 | 298 |
if dep.junction:
|
305 | 299 |
self._load_file(dep.junction, rewritable, ticker, fetch_subprojects, yaml_cache)
|
... | ... | @@ -380,82 +374,6 @@ class Loader(): |
380 | 374 |
# Eliminate duplicate paths
|
381 | 375 |
validated[element_name] = True
|
382 | 376 |
|
383 |
- # _sort_dependencies():
|
|
384 |
- #
|
|
385 |
- # Sort dependencies of each element by their dependencies,
|
|
386 |
- # so that direct dependencies which depend on other direct
|
|
387 |
- # dependencies (directly or indirectly) appear later in the
|
|
388 |
- # list.
|
|
389 |
- #
|
|
390 |
- # This avoids the need for performing multiple topological
|
|
391 |
- # sorts throughout the build process.
|
|
392 |
- #
|
|
393 |
- # Args:
|
|
394 |
- # element_name (str): The element-path relative element name to sort
|
|
395 |
- #
|
|
396 |
- def _sort_dependencies(self, element_name, visited=None):
|
|
397 |
- if visited is None:
|
|
398 |
- visited = {}
|
|
399 |
- |
|
400 |
- element = self._elements[element_name]
|
|
401 |
- |
|
402 |
- # element name must be unique across projects
|
|
403 |
- # to be usable as key for the visited dict
|
|
404 |
- element_name = element.full_name
|
|
405 |
- |
|
406 |
- if visited.get(element_name) is not None:
|
|
407 |
- return
|
|
408 |
- |
|
409 |
- for dep in element.deps:
|
|
410 |
- loader = self._get_loader_for_dep(dep)
|
|
411 |
- loader._sort_dependencies(dep.name, visited=visited)
|
|
412 |
- |
|
413 |
- def dependency_cmp(dep_a, dep_b):
|
|
414 |
- element_a = self.get_element_for_dep(dep_a)
|
|
415 |
- element_b = self.get_element_for_dep(dep_b)
|
|
416 |
- |
|
417 |
- # Sort on inter element dependency first
|
|
418 |
- if element_a.depends(element_b):
|
|
419 |
- return 1
|
|
420 |
- elif element_b.depends(element_a):
|
|
421 |
- return -1
|
|
422 |
- |
|
423 |
- # If there are no inter element dependencies, place
|
|
424 |
- # runtime only dependencies last
|
|
425 |
- if dep_a.dep_type != dep_b.dep_type:
|
|
426 |
- if dep_a.dep_type == Symbol.RUNTIME:
|
|
427 |
- return 1
|
|
428 |
- elif dep_b.dep_type == Symbol.RUNTIME:
|
|
429 |
- return -1
|
|
430 |
- |
|
431 |
- # All things being equal, string comparison.
|
|
432 |
- if dep_a.name > dep_b.name:
|
|
433 |
- return 1
|
|
434 |
- elif dep_a.name < dep_b.name:
|
|
435 |
- return -1
|
|
436 |
- |
|
437 |
- # Sort local elements before junction elements
|
|
438 |
- # and use string comparison between junction elements
|
|
439 |
- if dep_a.junction and dep_b.junction:
|
|
440 |
- if dep_a.junction > dep_b.junction:
|
|
441 |
- return 1
|
|
442 |
- elif dep_a.junction < dep_b.junction:
|
|
443 |
- return -1
|
|
444 |
- elif dep_a.junction:
|
|
445 |
- return -1
|
|
446 |
- elif dep_b.junction:
|
|
447 |
- return 1
|
|
448 |
- |
|
449 |
- # This wont ever happen
|
|
450 |
- return 0
|
|
451 |
- |
|
452 |
- # Now dependency sort, we ensure that if any direct dependency
|
|
453 |
- # directly or indirectly depends on another direct dependency,
|
|
454 |
- # it is found later in the list.
|
|
455 |
- element.deps.sort(key=cmp_to_key(dependency_cmp))
|
|
456 |
- |
|
457 |
- visited[element_name] = True
|
|
458 |
- |
|
459 | 377 |
# _collect_element()
|
460 | 378 |
#
|
461 | 379 |
# Collect the toplevel elements we have
|
... | ... | @@ -63,7 +63,11 @@ class Dependency(): |
63 | 63 |
self.dep_type = dep_type
|
64 | 64 |
self.junction = junction
|
65 | 65 |
self.provenance = provenance
|
66 |
+ self._index = None
|
|
66 | 67 |
|
67 | 68 |
@property
|
68 | 69 |
def index(self):
|
69 |
- return self.loader.get_element_for_dep(self).index
|
|
70 |
+ """Get the index of the load element to which this dependency refers."""
|
|
71 |
+ if self._index is None:
|
|
72 |
+ self._index = self.loader.get_element_for_dep(self).index
|
|
73 |
+ return self._index
|
... | ... | @@ -43,7 +43,6 @@ initialized = False |
43 | 43 |
# The special 'all' value will enable all profiles.
|
44 | 44 |
class Topics():
|
45 | 45 |
CIRCULAR_CHECK = 'circ-dep-check'
|
46 |
- SORT_DEPENDENCIES = 'sort-deps'
|
|
47 | 46 |
LOAD_LOADER = 'load-loader'
|
48 | 47 |
LOAD_CONTEXT = 'load-context'
|
49 | 48 |
LOAD_PROJECT = 'load-project'
|