summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2021-11-02 09:02:15 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2021-11-03 10:12:42 +0000
commit34e4eebc32c4836fc40098e90b17c00f51398967 (patch)
tree20f3ba43c0341cbed8b454c92d60e0fc326b9d50
parent791d6e63be09b361dd3397707a0507399b9a9ce7 (diff)
downloadpoky-34e4eebc32c4836fc40098e90b17c00f51398967.tar.gz
bitbake: lib/bb: Fix string concatination potential performance issues
Python scales badly when concatinating strings in loops. Most of these references aren't problematic but at least one (in data.py) is probably a performance issue as the issue is compounded as strings become large. The way to handle this in python is to create lists which don't reconstruct all the objects when appending to them. We may as well fix all the references since it stops them being copy/pasted into something problematic in the future. This patch was based on issues highligthted by a report from AWS Codeguru. (Bitbake rev: d654139a833127b16274dca0ccbbab7e3bb33ed0) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/bb/data.py24
-rw-r--r--bitbake/lib/bb/data_smart.py6
-rw-r--r--bitbake/lib/bb/fetch2/__init__.py16
-rw-r--r--bitbake/lib/bb/runqueue.py37
-rw-r--r--bitbake/lib/bb/server/process.py6
-rw-r--r--bitbake/lib/bb/ui/buildinfohelper.py16
6 files changed, 53 insertions, 52 deletions
diff --git a/bitbake/lib/bb/data.py b/bitbake/lib/bb/data.py
index 9d18b1e2bf..ee5557abfa 100644
--- a/bitbake/lib/bb/data.py
+++ b/bitbake/lib/bb/data.py
@@ -285,21 +285,19 @@ def build_dependencies(key, keys, shelldeps, varflagsexcl, d):
285 vardeps = varflags.get("vardeps") 285 vardeps = varflags.get("vardeps")
286 286
287 def handle_contains(value, contains, d): 287 def handle_contains(value, contains, d):
288 newvalue = "" 288 newvalue = []
289 if value:
290 newvalue.append(str(value))
289 for k in sorted(contains): 291 for k in sorted(contains):
290 l = (d.getVar(k) or "").split() 292 l = (d.getVar(k) or "").split()
291 for item in sorted(contains[k]): 293 for item in sorted(contains[k]):
292 for word in item.split(): 294 for word in item.split():
293 if not word in l: 295 if not word in l:
294 newvalue += "\n%s{%s} = Unset" % (k, item) 296 newvalue.append("\n%s{%s} = Unset" % (k, item))
295 break 297 break
296 else: 298 else:
297 newvalue += "\n%s{%s} = Set" % (k, item) 299 newvalue.append("\n%s{%s} = Set" % (k, item))
298 if not newvalue: 300 return "".join(newvalue)
299 return value
300 if not value:
301 return newvalue
302 return value + newvalue
303 301
304 def handle_remove(value, deps, removes, d): 302 def handle_remove(value, deps, removes, d):
305 for r in sorted(removes): 303 for r in sorted(removes):
@@ -406,7 +404,9 @@ def generate_dependency_hash(tasklist, gendeps, lookupcache, whitelist, fn):
406 404
407 if data is None: 405 if data is None:
408 bb.error("Task %s from %s seems to be empty?!" % (task, fn)) 406 bb.error("Task %s from %s seems to be empty?!" % (task, fn))
409 data = '' 407 data = []
408 else:
409 data = [data]
410 410
411 gendeps[task] -= whitelist 411 gendeps[task] -= whitelist
412 newdeps = gendeps[task] 412 newdeps = gendeps[task]
@@ -424,12 +424,12 @@ def generate_dependency_hash(tasklist, gendeps, lookupcache, whitelist, fn):
424 424
425 alldeps = sorted(seen) 425 alldeps = sorted(seen)
426 for dep in alldeps: 426 for dep in alldeps:
427 data = data + dep 427 data.append(dep)
428 var = lookupcache[dep] 428 var = lookupcache[dep]
429 if var is not None: 429 if var is not None:
430 data = data + str(var) 430 data.append(str(var))
431 k = fn + ":" + task 431 k = fn + ":" + task
432 basehash[k] = hashlib.sha256(data.encode("utf-8")).hexdigest() 432 basehash[k] = hashlib.sha256("".join(data).encode("utf-8")).hexdigest()
433 taskdeps[task] = alldeps 433 taskdeps[task] = alldeps
434 434
435 return taskdeps, basehash 435 return taskdeps, basehash
diff --git a/bitbake/lib/bb/data_smart.py b/bitbake/lib/bb/data_smart.py
index 8d235da121..7ed7112bdc 100644
--- a/bitbake/lib/bb/data_smart.py
+++ b/bitbake/lib/bb/data_smart.py
@@ -810,7 +810,7 @@ class DataSmart(MutableMapping):
810 expanded_removes[r] = self.expand(r).split() 810 expanded_removes[r] = self.expand(r).split()
811 811
812 parser.removes = set() 812 parser.removes = set()
813 val = "" 813 val = []
814 for v in __whitespace_split__.split(parser.value): 814 for v in __whitespace_split__.split(parser.value):
815 skip = False 815 skip = False
816 for r in removes: 816 for r in removes:
@@ -819,8 +819,8 @@ class DataSmart(MutableMapping):
819 skip = True 819 skip = True
820 if skip: 820 if skip:
821 continue 821 continue
822 val = val + v 822 val.append(v)
823 parser.value = val 823 parser.value = "".join(val)
824 if expand: 824 if expand:
825 value = parser.value 825 value = parser.value
826 826
diff --git a/bitbake/lib/bb/fetch2/__init__.py b/bitbake/lib/bb/fetch2/__init__.py
index 1d6e4e0964..43b312ce7e 100644
--- a/bitbake/lib/bb/fetch2/__init__.py
+++ b/bitbake/lib/bb/fetch2/__init__.py
@@ -402,24 +402,24 @@ def encodeurl(decoded):
402 402
403 if not type: 403 if not type:
404 raise MissingParameterError('type', "encoded from the data %s" % str(decoded)) 404 raise MissingParameterError('type', "encoded from the data %s" % str(decoded))
405 url = '%s://' % type 405 url = ['%s://' % type]
406 if user and type != "file": 406 if user and type != "file":
407 url += "%s" % user 407 url.append("%s" % user)
408 if pswd: 408 if pswd:
409 url += ":%s" % pswd 409 url.append(":%s" % pswd)
410 url += "@" 410 url.append("@")
411 if host and type != "file": 411 if host and type != "file":
412 url += "%s" % host 412 url.append("%s" % host)
413 if path: 413 if path:
414 # Standardise path to ensure comparisons work 414 # Standardise path to ensure comparisons work
415 while '//' in path: 415 while '//' in path:
416 path = path.replace("//", "/") 416 path = path.replace("//", "/")
417 url += "%s" % urllib.parse.quote(path) 417 url.append("%s" % urllib.parse.quote(path))
418 if p: 418 if p:
419 for parm in p: 419 for parm in p:
420 url += ";%s=%s" % (parm, p[parm]) 420 url.append(";%s=%s" % (parm, p[parm]))
421 421
422 return url 422 return "".join(url)
423 423
424def uri_replace(ud, uri_find, uri_replace, replacements, d, mirrortarball=None): 424def uri_replace(ud, uri_find, uri_replace, replacements, d, mirrortarball=None):
425 if not ud.url or not uri_find or not uri_replace: 425 if not ud.url or not uri_find or not uri_replace:
diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py
index 87c00462c1..774cdbca0b 100644
--- a/bitbake/lib/bb/runqueue.py
+++ b/bitbake/lib/bb/runqueue.py
@@ -1061,12 +1061,12 @@ class RunQueueData:
1061 seen_pn.append(pn) 1061 seen_pn.append(pn)
1062 else: 1062 else:
1063 bb.fatal("Multiple versions of %s are due to be built (%s). Only one version of a given PN should be built in any given build. You likely need to set PREFERRED_VERSION_%s to select the correct version or don't depend on multiple versions." % (pn, " ".join(prov_list[prov]), pn)) 1063 bb.fatal("Multiple versions of %s are due to be built (%s). Only one version of a given PN should be built in any given build. You likely need to set PREFERRED_VERSION_%s to select the correct version or don't depend on multiple versions." % (pn, " ".join(prov_list[prov]), pn))
1064 msg = "Multiple .bb files are due to be built which each provide %s:\n %s" % (prov, "\n ".join(prov_list[prov])) 1064 msgs = ["Multiple .bb files are due to be built which each provide %s:\n %s" % (prov, "\n ".join(prov_list[prov]))]
1065 # 1065 #
1066 # Construct a list of things which uniquely depend on each provider 1066 # Construct a list of things which uniquely depend on each provider
1067 # since this may help the user figure out which dependency is triggering this warning 1067 # since this may help the user figure out which dependency is triggering this warning
1068 # 1068 #
1069 msg += "\nA list of tasks depending on these providers is shown and may help explain where the dependency comes from." 1069 msgs.append("\nA list of tasks depending on these providers is shown and may help explain where the dependency comes from.")
1070 deplist = {} 1070 deplist = {}
1071 commondeps = None 1071 commondeps = None
1072 for provfn in prov_list[prov]: 1072 for provfn in prov_list[prov]:
@@ -1086,12 +1086,12 @@ class RunQueueData:
1086 commondeps &= deps 1086 commondeps &= deps
1087 deplist[provfn] = deps 1087 deplist[provfn] = deps
1088 for provfn in deplist: 1088 for provfn in deplist:
1089 msg += "\n%s has unique dependees:\n %s" % (provfn, "\n ".join(deplist[provfn] - commondeps)) 1089 msgs.append("\n%s has unique dependees:\n %s" % (provfn, "\n ".join(deplist[provfn] - commondeps)))
1090 # 1090 #
1091 # Construct a list of provides and runtime providers for each recipe 1091 # Construct a list of provides and runtime providers for each recipe
1092 # (rprovides has to cover RPROVIDES, PACKAGES, PACKAGES_DYNAMIC) 1092 # (rprovides has to cover RPROVIDES, PACKAGES, PACKAGES_DYNAMIC)
1093 # 1093 #
1094 msg += "\nIt could be that one recipe provides something the other doesn't and should. The following provider and runtime provider differences may be helpful." 1094 msgs.append("\nIt could be that one recipe provides something the other doesn't and should. The following provider and runtime provider differences may be helpful.")
1095 provide_results = {} 1095 provide_results = {}
1096 rprovide_results = {} 1096 rprovide_results = {}
1097 commonprovs = None 1097 commonprovs = None
@@ -1118,16 +1118,16 @@ class RunQueueData:
1118 else: 1118 else:
1119 commonrprovs &= rprovides 1119 commonrprovs &= rprovides
1120 rprovide_results[provfn] = rprovides 1120 rprovide_results[provfn] = rprovides
1121 #msg += "\nCommon provides:\n %s" % ("\n ".join(commonprovs)) 1121 #msgs.append("\nCommon provides:\n %s" % ("\n ".join(commonprovs)))
1122 #msg += "\nCommon rprovides:\n %s" % ("\n ".join(commonrprovs)) 1122 #msgs.append("\nCommon rprovides:\n %s" % ("\n ".join(commonrprovs)))
1123 for provfn in prov_list[prov]: 1123 for provfn in prov_list[prov]:
1124 msg += "\n%s has unique provides:\n %s" % (provfn, "\n ".join(provide_results[provfn] - commonprovs)) 1124 msgs.append("\n%s has unique provides:\n %s" % (provfn, "\n ".join(provide_results[provfn] - commonprovs)))
1125 msg += "\n%s has unique rprovides:\n %s" % (provfn, "\n ".join(rprovide_results[provfn] - commonrprovs)) 1125 msgs.append("\n%s has unique rprovides:\n %s" % (provfn, "\n ".join(rprovide_results[provfn] - commonrprovs)))
1126 1126
1127 if self.warn_multi_bb: 1127 if self.warn_multi_bb:
1128 logger.verbnote(msg) 1128 logger.verbnote("".join(msgs))
1129 else: 1129 else:
1130 logger.error(msg) 1130 logger.error("".join(msgs))
1131 1131
1132 self.init_progress_reporter.next_stage() 1132 self.init_progress_reporter.next_stage()
1133 1133
@@ -1935,7 +1935,7 @@ class RunQueueExecute:
1935 self.stats.taskFailed() 1935 self.stats.taskFailed()
1936 self.failed_tids.append(task) 1936 self.failed_tids.append(task)
1937 1937
1938 fakeroot_log = "" 1938 fakeroot_log = []
1939 if fakerootlog and os.path.exists(fakerootlog): 1939 if fakerootlog and os.path.exists(fakerootlog):
1940 with open(fakerootlog) as fakeroot_log_file: 1940 with open(fakerootlog) as fakeroot_log_file:
1941 fakeroot_failed = False 1941 fakeroot_failed = False
@@ -1945,12 +1945,12 @@ class RunQueueExecute:
1945 fakeroot_failed = True 1945 fakeroot_failed = True
1946 if 'doing new pid setup and server start' in line: 1946 if 'doing new pid setup and server start' in line:
1947 break 1947 break
1948 fakeroot_log = line + fakeroot_log 1948 fakeroot_log.append(line)
1949 1949
1950 if not fakeroot_failed: 1950 if not fakeroot_failed:
1951 fakeroot_log = None 1951 fakeroot_log = []
1952 1952
1953 bb.event.fire(runQueueTaskFailed(task, self.stats, exitcode, self.rq, fakeroot_log=fakeroot_log), self.cfgData) 1953 bb.event.fire(runQueueTaskFailed(task, self.stats, exitcode, self.rq, fakeroot_log=("".join(fakeroot_log) or None)), self.cfgData)
1954 1954
1955 if self.rqdata.taskData[''].abort: 1955 if self.rqdata.taskData[''].abort:
1956 self.rq.state = runQueueCleanUp 1956 self.rq.state = runQueueCleanUp
@@ -2608,12 +2608,13 @@ class RunQueueExecute:
2608 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn] 2608 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
2609 if not check_setscene_enforce_whitelist(pn, taskname, self.rqdata.setscenewhitelist): 2609 if not check_setscene_enforce_whitelist(pn, taskname, self.rqdata.setscenewhitelist):
2610 if tid in self.rqdata.runq_setscene_tids: 2610 if tid in self.rqdata.runq_setscene_tids:
2611 msg = 'Task %s.%s attempted to execute unexpectedly and should have been setscened' % (pn, taskname) 2611 msg = ['Task %s.%s attempted to execute unexpectedly and should have been setscened' % (pn, taskname)]
2612 else: 2612 else:
2613 msg = 'Task %s.%s attempted to execute unexpectedly' % (pn, taskname) 2613 msg = ['Task %s.%s attempted to execute unexpectedly' % (pn, taskname)]
2614 for t in self.scenequeue_notcovered: 2614 for t in self.scenequeue_notcovered:
2615 msg = msg + "\nTask %s, unihash %s, taskhash %s" % (t, self.rqdata.runtaskentries[t].unihash, self.rqdata.runtaskentries[t].hash) 2615 msg.append("\nTask %s, unihash %s, taskhash %s" % (t, self.rqdata.runtaskentries[t].unihash, self.rqdata.runtaskentries[t].hash))
2616 logger.error(msg + '\nThis is usually due to missing setscene tasks. Those missing in this build were: %s' % pprint.pformat(self.scenequeue_notcovered)) 2616 msg.append('\nThis is usually due to missing setscene tasks. Those missing in this build were: %s' % pprint.pformat(self.scenequeue_notcovered))
2617 logger.error("".join(msg))
2617 return True 2618 return True
2618 return False 2619 return False
2619 2620
diff --git a/bitbake/lib/bb/server/process.py b/bitbake/lib/bb/server/process.py
index 8fdcc66dc7..1636616660 100644
--- a/bitbake/lib/bb/server/process.py
+++ b/bitbake/lib/bb/server/process.py
@@ -326,10 +326,10 @@ class ProcessServer():
326 if e.errno != errno.ENOENT: 326 if e.errno != errno.ENOENT:
327 raise 327 raise
328 328
329 msg = "Delaying shutdown due to active processes which appear to be holding bitbake.lock" 329 msg = ["Delaying shutdown due to active processes which appear to be holding bitbake.lock"]
330 if procs: 330 if procs:
331 msg += ":\n%s" % str(procs.decode("utf-8")) 331 msg.append(":\n%s" % str(procs.decode("utf-8")))
332 serverlog(msg) 332 serverlog("".join(msg))
333 333
334 def idle_commands(self, delay, fds=None): 334 def idle_commands(self, delay, fds=None):
335 nextsleep = delay 335 nextsleep = delay
diff --git a/bitbake/lib/bb/ui/buildinfohelper.py b/bitbake/lib/bb/ui/buildinfohelper.py
index 8588849dd4..835e92c299 100644
--- a/bitbake/lib/bb/ui/buildinfohelper.py
+++ b/bitbake/lib/bb/ui/buildinfohelper.py
@@ -571,7 +571,7 @@ class ORMWrapper(object):
571 assert isinstance(build_obj, Build) 571 assert isinstance(build_obj, Build)
572 assert isinstance(target_obj, Target) 572 assert isinstance(target_obj, Target)
573 573
574 errormsg = "" 574 errormsg = []
575 for p in packagedict: 575 for p in packagedict:
576 # Search name swtiches round the installed name vs package name 576 # Search name swtiches round the installed name vs package name
577 # by default installed name == package name 577 # by default installed name == package name
@@ -636,7 +636,7 @@ class ORMWrapper(object):
636 if packagefile_objects: 636 if packagefile_objects:
637 Package_File.objects.bulk_create(packagefile_objects) 637 Package_File.objects.bulk_create(packagefile_objects)
638 except KeyError as e: 638 except KeyError as e:
639 errormsg += " stpi: Key error, package %s key %s \n" % ( p, e ) 639 errormsg.append(" stpi: Key error, package %s key %s \n" % (p, e))
640 640
641 # save disk installed size 641 # save disk installed size
642 packagedict[p]['object'].installed_size = packagedict[p]['size'] 642 packagedict[p]['object'].installed_size = packagedict[p]['size']
@@ -678,8 +678,8 @@ class ORMWrapper(object):
678 else: 678 else:
679 logger.info("No package dependencies created") 679 logger.info("No package dependencies created")
680 680
681 if len(errormsg) > 0: 681 if errormsg:
682 logger.warning("buildinfohelper: target_package_info could not identify recipes: \n%s", errormsg) 682 logger.warning("buildinfohelper: target_package_info could not identify recipes: \n%s", "".join(errormsg))
683 683
684 def save_target_image_file_information(self, target_obj, file_name, file_size): 684 def save_target_image_file_information(self, target_obj, file_name, file_size):
685 Target_Image_File.objects.create(target=target_obj, 685 Target_Image_File.objects.create(target=target_obj,
@@ -1404,7 +1404,7 @@ class BuildInfoHelper(object):
1404 assert 'pn' in event._depgraph 1404 assert 'pn' in event._depgraph
1405 assert 'tdepends' in event._depgraph 1405 assert 'tdepends' in event._depgraph
1406 1406
1407 errormsg = "" 1407 errormsg = []
1408 1408
1409 # save layer version priorities 1409 # save layer version priorities
1410 if 'layer-priorities' in event._depgraph.keys(): 1410 if 'layer-priorities' in event._depgraph.keys():
@@ -1496,7 +1496,7 @@ class BuildInfoHelper(object):
1496 elif dep in self.internal_state['recipes']: 1496 elif dep in self.internal_state['recipes']:
1497 dependency = self.internal_state['recipes'][dep] 1497 dependency = self.internal_state['recipes'][dep]
1498 else: 1498 else:
1499 errormsg += " stpd: KeyError saving recipe dependency for %s, %s \n" % (recipe, dep) 1499 errormsg.append(" stpd: KeyError saving recipe dependency for %s, %s \n" % (recipe, dep))
1500 continue 1500 continue
1501 recipe_dep = Recipe_Dependency(recipe=target, 1501 recipe_dep = Recipe_Dependency(recipe=target,
1502 depends_on=dependency, 1502 depends_on=dependency,
@@ -1537,8 +1537,8 @@ class BuildInfoHelper(object):
1537 taskdeps_objects.append(Task_Dependency( task = target, depends_on = dep )) 1537 taskdeps_objects.append(Task_Dependency( task = target, depends_on = dep ))
1538 Task_Dependency.objects.bulk_create(taskdeps_objects) 1538 Task_Dependency.objects.bulk_create(taskdeps_objects)
1539 1539
1540 if len(errormsg) > 0: 1540 if errormsg:
1541 logger.warning("buildinfohelper: dependency info not identify recipes: \n%s", errormsg) 1541 logger.warning("buildinfohelper: dependency info not identify recipes: \n%s", "".join(errormsg))
1542 1542
1543 1543
1544 def store_build_package_information(self, event): 1544 def store_build_package_information(self, event):