diff --git a/odoo/addons/base/models/assetsbundle.py b/odoo/addons/base/models/assetsbundle.py index 1b8b378eab6..5502d725587 100644 --- a/odoo/addons/base/models/assetsbundle.py +++ b/odoo/addons/base/models/assetsbundle.py @@ -22,7 +22,7 @@ except ImportError: from odoo import SUPERUSER_ID from odoo.http import request from odoo.modules.module import get_resource_path -from odoo.tools import func, misc, transpile_javascript, is_odoo_module, SourceMapGenerator +from odoo.tools import func, misc, transpile_javascript, is_odoo_module, SourceMapGenerator, profiler from odoo.tools.misc import html_escape as escape from odoo.tools.pycompat import to_text @@ -1016,6 +1016,7 @@ class ScssStylesheetAsset(PreprocessedCSS): return super(ScssStylesheetAsset, self).compile(source) try: + profiler.force_hook() return libsass.compile( string=source, include_paths=[ diff --git a/odoo/tools/profiler.py b/odoo/tools/profiler.py index a0a0bfe035b..23c24192db5 100644 --- a/odoo/tools/profiler.py +++ b/odoo/tools/profiler.py @@ -59,6 +59,18 @@ def make_session(name=''): return f'{datetime.datetime.now():%Y-%m-%d %H:%M:%S} {name}' +def force_hook(): + """ + Force periodic profiling collectors to generate some stack trace. This is + useful before long calls that do not release the GIL, so that the time + spent in those calls is attributed to a specific stack trace, instead of + some arbitrary former frame. + """ + thread = threading.current_thread() + for func in getattr(thread, 'profile_hooks', ()): + func() + + class Collector: """ Base class for objects that collect profiling data. @@ -187,11 +199,18 @@ class PeriodicCollector(Collector): interval = self.profiler.params.get('traces_async_interval') if interval: self.frame_interval = min(max(float(interval), 0.001), 1) + + init_thread = self.profiler.init_thread + if not hasattr(init_thread, 'profile_hooks'): + init_thread.profile_hooks = [] + init_thread.profile_hooks.append(self.add) + self.thread.start() def stop(self): self.active = False self.thread.join() + self.profiler.init_thread.profile_hooks.remove(self.add) def add(self, entry=None, frame=None): """ Add an entry (dict) to this collector. """