Daily updates from Odoo
Monday, May 13, 2024
1 change
Enhancements to existing features
This update significantly speeds up the process of changing project settings (like billable status) when dealing with projects that have thousands of associated tasks and timesheets. The improvement optimizes how the system processes these changes, reducing the time from over 4 minutes to just over 1 minute—a 3.6x performance boost that directly improves user experience when managing large projects.
Original PR description
## Description The `onchange` triggered when changing the `allow_billable` setting of a large long living project with a high number of associated timesheets can take a quite a while. After…
## Description The `onchange` triggered when changing the `allow_billable` setting of a large long living project with a high number of associated timesheets can take a quite a while. After profiling, a significant portion of the bottleneck was coming from *frequent* calls to the `__hash__` function, called when initializing a new `set` in https://github.com/odoo/odoo/blob/cf9aa2a14761a417c641243fc0b2be121c387b46/odoo/models.py#L6838 Left Heavy profile:  ## Improvements - Invariant hoisting: the `set(self._ids)` can be lifted out of the lambda scope capture, passing only a reference to a local variable for all callsite of the lambda. This prevents the re-computation of `set(self._ids)` for each record in `cache_records` due to the linear iteration done by `filtered`. - `not isdisjoint` vs `intersection`: the lambda is checking for the existence of an intersection between 2 sets. But in python the `&` or `intersection` method *construct* a new instance of a `set`. In our case we don't care about the resulting intersection, only about the existence of it. We can improve the situation by inverting the logic using `not isdisjoint`, as `isdisjoint` is simpler internal implementation and doesn't construct any new set, it just checks for disjunction. - CPython `intersection`: https://github.com/python/cpython/blob/333c7dccd87c637d0b15cf81f9bbec28e39664fd/Objects/setobject.c#L1179-L1256 - CPython `isdisjoint`: https://github.com/python/cpython/blob/333c7dccd87c637d0b15cf81f9bbec28e39664fd/Objects/setobject.c#L1338-L1373 A local small `timeit` benchmark showed +- 25% faster performance in favor of `not isdisjoint`. ## Benchmark On a staging database (saas-17.1, blindly backported), the `onchange` triggered by setting a project `allow_billable` from `True` -> `False`, with 70k tasks, and 25k associated timesheets. | | Before | After | Speed Up | |---------|----------------------|---------------------|-------------| | Timings | 246.66 sec (4.1 min) | 66.83 sec (1.1 min) | 3.6x faster | ## Reference task-3872314 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr