From 157651f7b08fdfd010d75ebcf84e8511f23063db Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Tue, 3 Aug 2021 08:23:13 +0000 Subject: [PATCH] [FIX] profiling: add profile entry manually before calling libsass This commit proposes a mechanism to manually add a frame before a blocking c-call and triggers it before calling libsaas.compile. closes odoo/odoo#75519 X-original-commit: f836ff3a67d446cd8b3ab2cf573fab649153e6da Signed-off-by: Raphael Collet (rco) --- odoo/addons/base/models/assetsbundle.py | 3 ++- odoo/tools/profiler.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) 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. """