From e16dd314450cb2b85e4984c17fa60403b662ef8c Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Wed, 16 Jul 2025 15:56:38 +0100 Subject: bitbake: cooker/process/utils: Create profiling common function to remove code duplication We have code duplication in the way we handle profiling of code sections. Create a common function in utils which covers this. The main loop and idle loop profile files were also reversed. Fix this and the naming, removing a couple of unused variables containing the profile log names in the process too. (Bitbake rev: b4f6bae97ac9607420fc49fd4c9e957d89c9a5f3) Signed-off-by: Richard Purdie --- bitbake/lib/bb/cooker.py | 16 +--------------- bitbake/lib/bb/server/process.py | 36 ++---------------------------------- bitbake/lib/bb/utils.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 49 deletions(-) (limited to 'bitbake') diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py index dc131939ed..c60fcd2719 100644 --- a/bitbake/lib/bb/cooker.py +++ b/bitbake/lib/bb/cooker.py @@ -2027,21 +2027,7 @@ class Parser(multiprocessing.Process): self.exit = True def run(self): - - if not self.profile: - self.realrun() - return - - try: - import cProfile as profile - except: - import profile - prof = profile.Profile() - try: - profile.Profile.runcall(prof, self.realrun) - finally: - logfile = "profile-parse-%s.log" % multiprocessing.current_process().name - prof.dump_stats(logfile) + bb.utils.profile_function(self.profile, self.realrun, "profile-parse-%s.log" % multiprocessing.current_process().name, process=False) def realrun(self): # Signal handling here is hard. We must not terminate any process or thread holding the write diff --git a/bitbake/lib/bb/server/process.py b/bitbake/lib/bb/server/process.py index 4b35be62cd..2c5057bff1 100644 --- a/bitbake/lib/bb/server/process.py +++ b/bitbake/lib/bb/server/process.py @@ -80,9 +80,6 @@ class idleFinish(): self.msg = msg class ProcessServer(): - profile_filename = "profile.log" - profile_processed_filename = "profile.log.processed" - def __init__(self, lock, lockname, sock, sockname, server_timeout, xmlrpcinterface): self.command_channel = False self.command_channel_reply = False @@ -140,23 +137,7 @@ class ProcessServer(): serverlog("Error writing to lock file: %s" % str(e)) pass - if self.cooker.configuration.profile: - try: - import cProfile as profile - except: - import profile - prof = profile.Profile() - - ret = profile.Profile.runcall(prof, self.main) - - prof.dump_stats("profile.log") - bb.utils.process_profilelog("profile.log") - serverlog("Raw profiling information saved to profile.log and processed statistics to profile.log.processed") - - else: - ret = self.main() - - return ret + return bb.utils.profile_function(self.cooker.configuration.profile, self.main, "profile-mainloop.log") def _idle_check(self): return len(self._idlefuns) == 0 and self.cooker.command.currentAsyncCommand is None @@ -417,20 +398,7 @@ class ProcessServer(): serverlog("".join(msg)) def idle_thread(self): - if self.cooker.configuration.profile: - try: - import cProfile as profile - except: - import profile - prof = profile.Profile() - - ret = profile.Profile.runcall(prof, self.idle_thread_internal) - - prof.dump_stats("profile-mainloop.log") - bb.utils.process_profilelog("profile-mainloop.log") - serverlog("Raw profiling information saved to profile-mainloop.log and processed statistics to profile-mainloop.log.processed") - else: - self.idle_thread_internal() + bb.utils.profile_function(self.cooker.configuration.profile, self.idle_thread_internal, "profile-idleloop.log") def idle_thread_internal(self): def remove_idle_func(function): diff --git a/bitbake/lib/bb/utils.py b/bitbake/lib/bb/utils.py index 1cc74ed546..f688f7dd68 100644 --- a/bitbake/lib/bb/utils.py +++ b/bitbake/lib/bb/utils.py @@ -1418,6 +1418,34 @@ def cpu_count(): def nonblockingfd(fd): fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK) +def profile_function(profile, function, output_fn, process=True): + """Common function to profile a code block and optionally process the + output using or processing function. + + Arguments: + + - ``profile``: a boolean saying whether to enable profiling or not + - ``function``: the function call to profile/run + - ``outputfn``: where to write the profiling data + - ``process``: whether to process the profiling data and write a report + + Returns the wrapped function return value + """ + if profile: + try: + import cProfile as profile + except: + import profile + prof = profile.Profile() + ret = profile.Profile.runcall(prof, function) + prof.dump_stats(output_fn) + if process: + process_profilelog(output_fn) + serverlog("Raw profiling information saved to %s and processed statistics to %s.processed" % (output_fn, output_fn)) + return ret + else: + return function() + def process_profilelog(fn, pout = None): # Either call with a list of filenames and set pout or a filename and optionally pout. if not pout: -- cgit v1.2.3-54-g00ecf