From 6029b4c319d3247509c1adcf60e69f32214eff9b Mon Sep 17 00:00:00 2001 From: Martin Krizek Date: Wed, 22 Oct 2025 15:25:05 +0200 Subject: [PATCH] Optimize retrieving role variables This patch optimizes performance of getting variables for a role by changing two things: 1. In Role.get_default_vars() we called get_default_vars() recursively for ALL dependencies. It is sufficient to do this just for direct dependencies, the recursive process will take care of the rest of the dependency tree. 2. In Role.get_vars() we called dep.get_vars(include_params=False, only_exports=True) for all dependencies. Looking at what the call returns given the values of its arguments more closely it is just the dep's _role_vars. So replace the expensive call with dep._role_vars. With these two changes the time to run a testing playbook with many roles and variables goes down from: 36,23s user 4,26s system 100% cpu 40,369 total to: 8,32s user 3,78s system 101% cpu 11,965 total I also added two FIXMEs that would make the execution a bit more faster: 7,39s user 3,38s system 101% cpu 10,644 total at the expense of the change being more invasive. Since the performance improvement is very good with minimal changes already, we can do that as a part of future changes. ci_complete --- lib/ansible/playbook/role/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/ansible/playbook/role/__init__.py b/lib/ansible/playbook/role/__init__.py index ab79c55765b..79057de020b 100644 --- a/lib/ansible/playbook/role/__init__.py +++ b/lib/ansible/playbook/role/__init__.py @@ -496,7 +496,9 @@ class Role(Base, Conditional, Taggable, CollectionSearch, Delegatable): dep_chain = [] if dep_chain is None else dep_chain default_vars = dict() - for dep in self.get_all_dependencies(): + # FIXME combining deps' default_vars can be optimized by moving it + # into _load_role_data so it is done just once + for dep in self._dependencies: default_vars = combine_vars(default_vars, dep.get_default_vars()) if dep_chain: for parent in dep_chain: @@ -536,13 +538,15 @@ class Role(Base, Conditional, Taggable, CollectionSearch, Delegatable): all_vars = self.get_inherited_vars(dep_chain, only_exports=only_exports) # get exported variables from meta/dependencies + # FIXME combining deps' role_vars can be optimized by moving it + # into _load_role_data so it is done just once seen = [] for dep in self.get_all_dependencies(): # Avoid rerunning dupe deps since they can have vars from previous invocations and they accumulate in deps # TODO: re-examine dep loading to see if we are somehow improperly adding the same dep too many times if dep not in seen: # only take 'exportable' vars from deps - all_vars = combine_vars(all_vars, dep.get_vars(include_params=False, only_exports=True)) + all_vars = combine_vars(all_vars, dep._role_vars) seen.append(dep) # role_vars come from vars/ in a role