You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by tv...@apache.org on 2021/02/04 07:55:02 UTC

[buildstream] 18/27: _variables.pyx: Avoid dictionary lookups in Value.resolve()

This is an automated email from the ASF dual-hosted git repository.

tvb pushed a commit to branch tristan/partial-variables-manual-string-join
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit c763970d83cdeb3748f3e09b17ef750540bde9dc
Author: Tristan van Berkom <tr...@codethink.co.uk>
AuthorDate: Fri Jul 3 18:40:35 2020 +0900

    _variables.pyx: Avoid dictionary lookups in Value.resolve()
    
    Instead feed the list of already resolved variables to the function.
---
 src/buildstream/_variables.pyx | 74 +++++++++++++++++++++++++-----------------
 1 file changed, 45 insertions(+), 29 deletions(-)

diff --git a/src/buildstream/_variables.pyx b/src/buildstream/_variables.pyx
index c2e0b29..6f439c6 100644
--- a/src/buildstream/_variables.pyx
+++ b/src/buildstream/_variables.pyx
@@ -217,18 +217,30 @@ cdef class Variables:
     #
     cpdef str _subst(self, ScalarNode node):
         cdef Value value = Value()
+        cdef Value iter_value
         cdef ObjectArray *dependencies
         cdef Py_ssize_t idx = 0
         cdef str dep_name
+        cdef str resolve_value
+
+        cdef ObjectArray values
+        object_array_init(&(values), -1)
 
         value.init(node)
         dependencies = value.dependencies()
         while idx < dependencies.length:
             dep_name = <str> dependencies.array[idx]
-            self._resolve(dep_name, node)
+            iter_value = self._do_resolve(dep_name, node)
+
+            object_array_append(&(values), <PyObject *>iter_value)
+
             idx += 1
 
-        return value.resolve(self._values)
+        resolved_value = value.resolve(&values, 0)
+
+        object_array_free(&(values))
+
+        return resolved_value
 
     # _expand()
     #
@@ -253,7 +265,14 @@ cdef class Variables:
         else:
             assert False, "Unknown 'Node' type"
 
-    # _resolve()
+    # XXX
+    #
+    cdef str _resolve(self, str name, ScalarNode pnode):
+        cdef Value value
+        value = self._do_resolve(name, pnode)
+        return value._resolved
+
+    # _do_resolve()
     #
     # Helper to expand and cache a variable definition in the context of
     # the given dictionary of expansion strings.
@@ -269,7 +288,7 @@ cdef class Variables:
     #    (LoadError): In case there was any undefined variables or circular
     #                 references encountered when resolving the variable.
     #
-    cdef str _resolve(self, str name, ScalarNode pnode):
+    cdef Value _do_resolve(self, str name, ScalarNode pnode):
         cdef ResolutionStep step
         cdef ResolutionStep new_step
         cdef ResolutionStep this_step
@@ -280,9 +299,6 @@ cdef class Variables:
         cdef ObjectArray *iter_value_deps
         cdef Py_ssize_t idx = 0
 
-        cdef str resolved_value = None
-        cdef bint first_iteration = True
-
         # We'll be collecting the values to resolve at the end in here
         cdef ObjectArray values
         object_array_init(&(values), -1)
@@ -314,27 +330,23 @@ cdef class Variables:
                 iter_value = self._get_checked_value(iter_name, this_step.referee, pnode)
                 idx += 1
 
-                # Earliest return for an already resolved value
+                # Queue up this value.
                 #
-                if first_iteration:
-                    if iter_value._resolved is not None:
-                        return iter_value.resolve(self._values)
-                    first_iteration = False
-
-                # Queue up this value to be resolved in the next loop
-                if iter_value._resolved is None:
+                # Even if the value was already resolved, we need it in context to resolve
+                # previously enqueued variables
+                object_array_append(&(values), <PyObject *>iter_value)
 
-                    object_array_append(&(values), <PyObject *>iter_value)
-
-                    # Queue up it's dependencies for resolution
-                    iter_value_deps = iter_value.dependencies()
-                    if iter_value_deps:
-                        new_step = ResolutionStep()
-                        new_step.init(iter_name, iter_value_deps, this_step)
+                # Queue up the values dependencies.
+                #
+                # These will be NULL if this value has previously been resolved.
+                iter_value_deps = iter_value.dependencies()
+                if iter_value_deps:
+                    new_step = ResolutionStep()
+                    new_step.init(iter_name, iter_value_deps, this_step)
 
-                        # Link it to the end of the stack
-                        new_step.prev = step
-                        step = new_step
+                    # Link it to the end of the stack
+                    new_step.prev = step
+                    step = new_step
 
         # We've now constructed the dependencies queue such that
         # later dependencies are on the right, we can now safely peddle
@@ -344,7 +356,7 @@ cdef class Variables:
         idx = values.length -1
         while idx >= 0:
             iter_value = <Value>values.array[idx]
-            resolved_value = iter_value.resolve(self._values)
+            iter_value.resolve(&values, idx + 1)
             idx -= 1
 
         # Cleanup
@@ -352,7 +364,7 @@ cdef class Variables:
         object_array_free(&(initial_deps))
         object_array_free(&(values))
 
-        return resolved_value
+        return iter_value
 
     # _get_checked_value()
     #
@@ -517,7 +529,7 @@ cdef class Value:
     # Returns:
     #    (str): The resolved value
     #
-    cdef str resolve(self, dict values):
+    cdef str resolve(self, ObjectArray *resolved_values, Py_ssize_t idx):
         cdef str dep_name
         cdef Value part_var
         cdef ValuePart *part
@@ -529,7 +541,11 @@ cdef class Value:
 
             while part:
                 if part.is_variable:
-                    part_var = <Value> values[<str>part.text]
+
+                    # Consume one variable
+                    part_var = <Value> resolved_values.array[idx]
+                    idx += 1
+
                     parts.append(part_var._resolved)
                 else:
                     parts.append(<str>part.text)