diff options
author | Richard Purdie <richard.purdie@linuxfoundation.org> | 2022-11-27 21:16:16 +0000 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2022-12-17 08:52:28 +0000 |
commit | f3bcd3c9a91f6212c30b9c778c11f3c8a9f6f1d4 (patch) | |
tree | 760b8dac27191ea1a625476d84c0651aa2788a5f /bitbake/lib/bb/codeparser.py | |
parent | a225aa3ec4726161172ca4b03d02751b1250e7ae (diff) | |
download | poky-f3bcd3c9a91f6212c30b9c778c11f3c8a9f6f1d4.tar.gz |
bitbake: ast/data/codeparser: Add dependencies from python module functions
Moving code into python modules is a very effective way to reduce parsing
time and overhead in recipes. The downside has always been that any
dependency information on which variables those functions access is lost
and the hashes can therefore become less reliable.
This patch adds parsing of the imported module functions and that dependency
information is them injected back into the hash dependency information.
Intermodule function references are resolved to the full function
call names in our module namespace to ensure interfunction dependencies
are correctly handled too.
(Bitbake rev: 605c478ce14cdc3c02d6ef6d57146a76d436a83c)
(Bitbake rev: 91441e157e495b02db44e19e836afad366ee8924)
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/codeparser.py')
-rw-r--r-- | bitbake/lib/bb/codeparser.py | 43 |
1 files changed, 38 insertions, 5 deletions
diff --git a/bitbake/lib/bb/codeparser.py b/bitbake/lib/bb/codeparser.py index 9d66d3ae41..c0b1d7966f 100644 --- a/bitbake/lib/bb/codeparser.py +++ b/bitbake/lib/bb/codeparser.py | |||
@@ -27,6 +27,7 @@ import ast | |||
27 | import sys | 27 | import sys |
28 | import codegen | 28 | import codegen |
29 | import logging | 29 | import logging |
30 | import inspect | ||
30 | import bb.pysh as pysh | 31 | import bb.pysh as pysh |
31 | import bb.utils, bb.data | 32 | import bb.utils, bb.data |
32 | import hashlib | 33 | import hashlib |
@@ -58,10 +59,33 @@ def check_indent(codestr): | |||
58 | 59 | ||
59 | return codestr | 60 | return codestr |
60 | 61 | ||
61 | # A custom getstate/setstate using tuples is actually worth 15% cachesize by | 62 | modulecode_deps = {} |
62 | # avoiding duplication of the attribute names! | ||
63 | 63 | ||
64 | def add_module_functions(fn, functions, namespace): | ||
65 | fstat = os.stat(fn) | ||
66 | fixedhash = fn + ":" + str(fstat.st_size) + ":" + str(fstat.st_mtime) | ||
67 | for f in functions: | ||
68 | name = "%s.%s" % (namespace, f) | ||
69 | parser = PythonParser(name, logger) | ||
70 | try: | ||
71 | parser.parse_python(None, filename=fn, lineno=1, fixedhash=fixedhash+f) | ||
72 | #bb.warn("Cached %s" % f) | ||
73 | except KeyError: | ||
74 | lines, lineno = inspect.getsourcelines(functions[f]) | ||
75 | src = "".join(lines) | ||
76 | parser.parse_python(src, filename=fn, lineno=lineno, fixedhash=fixedhash+f) | ||
77 | #bb.warn("Not cached %s" % f) | ||
78 | execs = parser.execs.copy() | ||
79 | # Expand internal module exec references | ||
80 | for e in parser.execs: | ||
81 | if e in functions: | ||
82 | execs.remove(e) | ||
83 | execs.add(namespace + "." + e) | ||
84 | modulecode_deps[name] = [parser.references.copy(), execs, parser.var_execs.copy(), parser.contains.copy()] | ||
85 | #bb.warn("%s: %s\nRefs:%s Execs: %s %s %s" % (name, src, parser.references, parser.execs, parser.var_execs, parser.contains)) | ||
64 | 86 | ||
87 | # A custom getstate/setstate using tuples is actually worth 15% cachesize by | ||
88 | # avoiding duplication of the attribute names! | ||
65 | class SetCache(object): | 89 | class SetCache(object): |
66 | def __init__(self): | 90 | def __init__(self): |
67 | self.setcache = {} | 91 | self.setcache = {} |
@@ -289,11 +313,17 @@ class PythonParser(): | |||
289 | self.unhandled_message = "in call of %s, argument '%s' is not a string literal" | 313 | self.unhandled_message = "in call of %s, argument '%s' is not a string literal" |
290 | self.unhandled_message = "while parsing %s, %s" % (name, self.unhandled_message) | 314 | self.unhandled_message = "while parsing %s, %s" % (name, self.unhandled_message) |
291 | 315 | ||
292 | def parse_python(self, node, lineno=0, filename="<string>"): | 316 | # For the python module code it is expensive to have the function text so it is |
293 | if not node or not node.strip(): | 317 | # uses a different fixedhash to cache against. We can take the hit on obtaining the |
318 | # text if it isn't in the cache. | ||
319 | def parse_python(self, node, lineno=0, filename="<string>", fixedhash=None): | ||
320 | if not fixedhash and (not node or not node.strip()): | ||
294 | return | 321 | return |
295 | 322 | ||
296 | h = bbhash(str(node)) | 323 | if fixedhash: |
324 | h = fixedhash | ||
325 | else: | ||
326 | h = bbhash(str(node)) | ||
297 | 327 | ||
298 | if h in codeparsercache.pythoncache: | 328 | if h in codeparsercache.pythoncache: |
299 | self.references = set(codeparsercache.pythoncache[h].refs) | 329 | self.references = set(codeparsercache.pythoncache[h].refs) |
@@ -311,6 +341,9 @@ class PythonParser(): | |||
311 | self.contains[i] = set(codeparsercache.pythoncacheextras[h].contains[i]) | 341 | self.contains[i] = set(codeparsercache.pythoncacheextras[h].contains[i]) |
312 | return | 342 | return |
313 | 343 | ||
344 | if fixedhash and not node: | ||
345 | raise KeyError | ||
346 | |||
314 | # Need to parse so take the hit on the real log buffer | 347 | # Need to parse so take the hit on the real log buffer |
315 | self.log = BufferedLogger('BitBake.Data.PythonParser', logging.DEBUG, self._log) | 348 | self.log = BufferedLogger('BitBake.Data.PythonParser', logging.DEBUG, self._log) |
316 | 349 | ||