From 1628558e2bb9ddd4deb2c4882401f02dfbf8ce2b Mon Sep 17 00:00:00 2001
From: Frank Winklmeier <frank.winklmeier@cern.ch>
Date: Tue, 25 Apr 2023 15:36:12 +0200
Subject: [PATCH 1/2] AthConfigFlags: add cache for hasCategory

The lookup of categories can be very slow for jobs with many flags. Add
a cache for already found categories.
---
 .../AthenaConfiguration/python/AthConfigFlags.py  | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/Control/AthenaConfiguration/python/AthConfigFlags.py b/Control/AthenaConfiguration/python/AthConfigFlags.py
index 9a2a090903df..35e03d5fbc15 100644
--- a/Control/AthenaConfiguration/python/AthConfigFlags.py
+++ b/Control/AthenaConfiguration/python/AthConfigFlags.py
@@ -144,7 +144,8 @@ class AthConfigFlags(object):
         self._flagdict=dict()
         self._locked=False
         self._dynaflags = dict()
-        self._loaded    = set() # dynamic dlags that were loaded
+        self._loaded    = set()      # dynamic dlags that were loaded
+        self._categoryCache = set()  # cache for already found categories
         self._hash = None
         self._parser = None
         self._args = None # user args from parser
@@ -251,13 +252,21 @@ class AthConfigFlags(object):
                 self._loadDynaFlags( prefix )
 
     def hasCategory(self, name):
-        path = name+'.'
+        # We cache successfully found categories
+        if name in self._categoryCache:
+            return True
+
+        # If not found do search through all keys.
+        # TODO: could be improved by using a trie for _flagdict
         for f in self._flagdict.keys():
-            if f.startswith(path):
+            if f.startswith(name+'.'):
+                self._categoryCache.add(name)
                 return True
         for c in self._dynaflags.keys():
             if c.startswith(name):
+                self._categoryCache.add(name)
                 return True
+
         return False
 
     def hasFlag(self, name):
-- 
GitLab


From 033329db1459e3713b0131440324af39304849aa Mon Sep 17 00:00:00 2001
From: Frank Winklmeier <frank.winklmeier@cern.ch>
Date: Tue, 25 Apr 2023 16:01:44 +0200
Subject: [PATCH 2/2] AthConfigFlags: minor optimization for set and get

Avoid duplicate lookups in flags dictionary and streamline error message code.
---
 .../python/AthConfigFlags.py                  | 24 ++++++++-----------
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/Control/AthenaConfiguration/python/AthConfigFlags.py b/Control/AthenaConfiguration/python/AthConfigFlags.py
index 35e03d5fbc15..21191a6a31db 100644
--- a/Control/AthenaConfiguration/python/AthConfigFlags.py
+++ b/Control/AthenaConfiguration/python/AthConfigFlags.py
@@ -274,24 +274,20 @@ class AthConfigFlags(object):
 
     def _set(self,name,value):
         self._tryModify()
-        if name in self._flagdict:
+        try:
             self._flagdict[name].set(value)
-            return
-        errString="No flag with name \'{}\' found".format( name )
-        closestMatch=get_close_matches(name,self._flagdict.keys(),1)
-        if len(closestMatch)>0:
-            errString+=". Did you mean \'{}\'?".format(  closestMatch[0] )
-        raise KeyError(errString)
+        except KeyError:
+            closestMatch = get_close_matches(name,self._flagdict.keys(),1)
+            raise KeyError(f"No flag with name '{name}' found" +
+                           (f". Did you mean '{closestMatch[0]}'?" if closestMatch else ""))
 
     def _get(self,name):
-        if name in self._flagdict:
+        try:
             return self._flagdict[name].get(self)
-
-        errString="No flag with name \'{}\' found".format( name )
-        closestMatch=get_close_matches(name,self._flagdict.keys(),1)
-        if len(closestMatch)>0:
-            errString+=". Did you mean \'{}\'?".format( closestMatch[0] )
-        raise KeyError(errString)
+        except KeyError:
+            closestMatch = get_close_matches(name,self._flagdict.keys(),1)
+            raise KeyError(f"No flag with name '{name}' found" +
+                           (f". Did you mean '{closestMatch[0]}'?" if closestMatch else ""))
 
     def __call__(self,name):
         return self._get(name)
-- 
GitLab