From 4d8e3f97853c5a698899afdbadbed35577f35748 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Thu, 30 Sep 2021 14:53:09 +0000 Subject: [PATCH] [ADD] developer/reference: add a reference page on performance closes odoo/documentation#1180 Signed-off-by: Antoine Vandevenne (anv) Co-authored-by: Antoine Vandevenne (anv) --- .../applications/general/developer_mode.rst | 2 + .../development/coding_guidelines.rst | 26 - content/developer/cli.rst | 8 +- content/developer/howtos.rst | 1 - content/developer/howtos/profilecode.rst | 131 ----- .../howtos/profilecode/flamegraph.svg | 315 ---------- content/developer/reference/backend.rst | 1 + .../reference/backend/performance.rst | 540 ++++++++++++++++++ .../performance/enable_profiling_wizard.png | Bin 0 -> 10392 bytes .../performance/flamegraph_example.png | Bin 0 -> 23080 bytes .../performance/profiling_debug_menu.png | Bin 0 -> 3925 bytes .../performance/profiling_example_after.png | Bin 0 -> 3572 bytes .../performance/profiling_example_before.png | Bin 0 -> 8512 bytes .../backend/performance/profiling_web.png | Bin 0 -> 54746 bytes .../backend/performance/speedscope_modes.png | Bin 0 -> 4410 bytes .../developer/reference/backend/testing.rst | 84 --- static/css/performance.css | 7 + 17 files changed, 554 insertions(+), 561 deletions(-) delete mode 100644 content/developer/howtos/profilecode.rst delete mode 100644 content/developer/howtos/profilecode/flamegraph.svg create mode 100644 content/developer/reference/backend/performance.rst create mode 100644 content/developer/reference/backend/performance/enable_profiling_wizard.png create mode 100644 content/developer/reference/backend/performance/flamegraph_example.png create mode 100644 content/developer/reference/backend/performance/profiling_debug_menu.png create mode 100644 content/developer/reference/backend/performance/profiling_example_after.png create mode 100644 content/developer/reference/backend/performance/profiling_example_before.png create mode 100644 content/developer/reference/backend/performance/profiling_web.png create mode 100644 content/developer/reference/backend/performance/speedscope_modes.png create mode 100644 static/css/performance.css diff --git a/content/applications/general/developer_mode.rst b/content/applications/general/developer_mode.rst index 47176f8ce..0a01bbefe 100644 --- a/content/applications/general/developer_mode.rst +++ b/content/applications/general/developer_mode.rst @@ -59,6 +59,8 @@ debug mode, add `?debug=0` instead. :ref:`assets mode `, and `?debug=tests` enables the :ref:`tests mode `. +.. _developer-mode/mode-tools: + Locate the mode tools ===================== diff --git a/content/contributing/development/coding_guidelines.rst b/content/contributing/development/coding_guidelines.rst index 802d3b776..9463be5d0 100644 --- a/content/contributing/development/coding_guidelines.rst +++ b/content/contributing/development/coding_guidelines.rst @@ -589,32 +589,6 @@ Programming in Odoo - As in python, use ``filtered``, ``mapped``, ``sorted``, ... methods to ease code reading and performance. - -Make your method work in batch -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When adding a function, make sure it can process multiple records by iterating -on self to treat each record. - -.. code-block:: python - - def my_method(self) - for record in self: - record.do_cool_stuff() - -For performance issue, when developing a 'stat button' (for instance), do not -perform a ``search`` or a ``search_count`` in a loop. It -is recommended to use ``read_group`` method, to compute all value in only one request. - -.. code-block:: python - - def _compute_equipment_count(self): - """ Count the number of equipment per category """ - equipment_data = self.env['hr.equipment'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id']) - mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in equipment_data]) - for category in self: - category.equipment_count = mapped_data.get(category.id, 0) - - Propagate the context ~~~~~~~~~~~~~~~~~~~~~ The context is a ``frozendict`` that cannot be modified. To call a method with diff --git a/content/developer/cli.rst b/content/developer/cli.rst index 9250935bd..e55858cb4 100644 --- a/content/developer/cli.rst +++ b/content/developer/cli.rst @@ -702,8 +702,9 @@ Database Population .. program:: odoo-bin populate Odoo CLI supports database population features. If the feature is -:ref:`implemented on a given model `, it allows automatic data -generation of the model's records to test your modules in databases containing non-trivial amounts of records. +:ref:`implemented on a given model `, it allows automatic +data generation of the model's records to test your modules in databases containing non-trivial +amounts of records. .. code-block:: console @@ -720,8 +721,7 @@ generation of the model's records to test your modules in databases containing n of a given model (cf. the :file:`populate` folder of modules for further details). .. seealso:: - - :ref:`reference/testing/populate` + :ref:`reference/performance/populate` .. _reference/cmdline/cloc: diff --git a/content/developer/howtos.rst b/content/developer/howtos.rst index 431b7b532..c7d96af7a 100644 --- a/content/developer/howtos.rst +++ b/content/developer/howtos.rst @@ -12,7 +12,6 @@ Tutorials howtos/website howtos/backend howtos/web_services - howtos/profilecode howtos/company howtos/accounting_localization howtos/translations diff --git a/content/developer/howtos/profilecode.rst b/content/developer/howtos/profilecode.rst deleted file mode 100644 index aa1c7a6c4..000000000 --- a/content/developer/howtos/profilecode.rst +++ /dev/null @@ -1,131 +0,0 @@ -=================== -Profiling Odoo code -=================== - -.. warning:: - - This tutorial requires :ref:`having installed Odoo ` - and :doc:`writing Odoo code ` - -Graph a method -============== - -Odoo embeds a profiler of code. This embedded profiler output can be used to -generate a graph of calls triggered by the method, number of queries, percentage -of time taken in the method itself as well as the time that the method took and -its sub-called methods. - -.. code:: python - - from odoo.tools.misc import profile - [...] - @profile('/temp/prof.profile') - def mymethod(...) - -This produces a file called /temp/prof.profile - -A tool called *gprof2dot* will produce a graph with this result: - -.. code:: bash - - gprof2dot -f pstats -o /temp/prof.xdot /temp/prof.profile - -A tool called *xdot* will display the resulting graph: - -.. code:: bash - - xdot /temp/prof.xdot - -Log a method -============ - -Another profiler can be used to log statistics on a method: - -.. code:: python - - from odoo.tools.profiler import profile - [...] - @profile - @api.model - def mymethod(...): - -The statistics will be displayed into the logs once the method to be analysed is -completely reviewed. - -.. code:: bash - - 2018-03-28 06:18:23,196 22878 INFO openerp odoo.tools.profiler: - calls queries ms - project.task ------------------------ /home/odoo/src/odoo/addons/project/models/project.py, 638 - - 1 0 0.02 @profile - @api.model - def create(self, vals): - # context: no_log, because subtype already handle this - 1 0 0.01 context = dict(self.env.context, mail_create_nolog=True) - - # for default stage - 1 0 0.01 if vals.get('project_id') and not context.get('default_project_id'): - context['default_project_id'] = vals.get('project_id') - # user_id change: update date_assign - 1 0 0.01 if vals.get('user_id'): - vals['date_assign'] = fields.Datetime.now() - # Stage change: Update date_end if folded stage - 1 0 0.0 if vals.get('stage_id'): - vals.update(self.update_date_end(vals['stage_id'])) - 1 108 631.8 task = super(Task, self.with_context(context)).create(vals) - 1 0 0.01 return task - - Total: - 1 108 631.85 - -Dump stack -========== - -Sending the SIGQUIT signal to an Odoo process (only available on POSIX) makes -this process output the current stack trace to log, with info level. When an -odoo process seems stuck, sending this signal to the process permit to know -what the process is doing, and letting the process continue his job. - -Tracing code execution -====================== - -Instead of sending the SIGQUIT signal to an Odoo process often enough, to check -where the processes are performing worse than expected, we can use the `py-spy`_ tool to -do it for us. - -Install py-spy --------------- - -.. code:: bash - - python3 -m pip install py-spy - -Record executed code --------------------- - -As py-spy is installed, we now record the executed code lines. -This tool will record, multiple times a second, the stacktrace of the process. - -.. code:: bash - - # record to raw file - py-spy record -o profile.json -f speedscope --pid - - # OR record directly to svg - py-spy record -o profile.svg --pid - -where is the process ID of the odoo process you want to graph. - -To open profile.json you can use online tool `speedscope.app`_. - -To open profile.svg you should use browser, because other viewer may not -support interactive part. - - -.. image:: profilecode/flamegraph.svg - - -.. _py-spy: https://github.com/benfred/py-spy - -.. _speedscope.app: https://www.speedscope.app/ diff --git a/content/developer/howtos/profilecode/flamegraph.svg b/content/developer/howtos/profilecode/flamegraph.svg deleted file mode 100644 index a20921ad0..000000000 --- a/content/developer/howtos/profilecode/flamegraph.svg +++ /dev/null @@ -1,315 +0,0 @@ -Flame GraphReset ZoomSearch/datas/progs/odoo/odoo/models.py:browse:4237 (11 samples, 8.33%)/datas/prog../datas/progs/odoo/odoo/fields.py:__get__:948 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:735 (3 samples, 2.27%)/../datas/progs/odoo/odoo/fields.py:__get__:948 (38 samples, 28.79%)/datas/progs/odoo/odoo/fields.py:__get__:948/datas/progs/odoo/odoo/api.py:__new__:736 (5 samples, 3.79%)/dat..<string>:__new__:14 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_normalize_ids:5206 (1 samples, 0.76%)<frozen importlib._bootstrap>:_call_with_frames_removed:219 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:sudo:4310 (3 samples, 2.27%)/..<frozen importlib._bootstrap>:_call_with_frames_removed:219 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:736 (1 samples, 0.76%)<frozen importlib._bootstrap_external>:exec_module:678 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:convert_to_cache:1230 (6 samples, 4.55%)/data../datas/progs/odoo/odoo/api.py:__new__:736 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__hash__:777 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:736 (1 samples, 0.76%)/datas/progs/odoo/odoo/sql_db.py:execute:242 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_read_group_raw:1924 (7 samples, 5.30%)/datas../datas/progs/odoo/odoo/models.py:qualify:2612 (1 samples, 0.76%)/datas/progs/odoo/addons/auth_signup/models/ir_http.py:_dispatch:19 (128 samples, 96.97%)/datas/progs/odoo/addons/auth_signup/models/ir_http.py:_dispatch:19/datas/progs/odoo/odoo/api.py:__new__:742 (1 samples, 0.76%)<string>:change_digit:9 (6 samples, 4.55%)<stri../usr/local/lib/python3.6/encodings/utf_8.py:decode:16 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:convert_to_cache:1230 (7 samples, 5.30%)/datas../datas/progs/odoo/odoo/models.py:_read_group_resolve_many2one_fields:1944 (6 samples, 4.55%)/data../datas/progs/odoo/addons/stock_account/models/product.py:do_change_standard_price:126 (20 samples, 15.15%)/datas/progs/odoo/addon../datas/progs/odoo/odoo/models.py:read_group:1828 (13 samples, 9.85%)/datas/progs/o../datas/progs/odoo/odoo/api.py:__new__:736 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:convert_to_record:1989 (3 samples, 2.27%)/../datas/progs/odoo/odoo/models.py:recompute:4791 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:__get__:944 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:browse:4235 (2 samples, 1.52%)/datas/progs/odoo/odoo/api.py:add:939 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/expression.py:<listcomp>:1204 (1 samples, 0.76%)<decorator-gen-112>:precision_get:2 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/expression.py:get_unaccent_wrapper:455 (1 samples, 0.76%)/usr/local/lib/python3.6/site-packages/werkzeug/routing.py:add:1197 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_read_group_raw:1924 (3 samples, 2.27%)/../usr/local/lib/python3.6/site-packages/werkzeug/serving.py:run_wsgi:193 (132 samples, 100.00%)/usr/local/lib/python3.6/site-packages/werkzeug/serving.py:run_wsgi:193/datas/progs/odoo/odoo/api.py:get_todo:911 (1 samples, 0.76%)odoo-bin:<module>:8 (132 samples, 100.00%)odoo-bin:<module>:8/datas/progs/odoo/odoo/fields.py:__set__:966 (7 samples, 5.30%)/datas../datas/progs/odoo/odoo/modules/loading.py:load_modules:339 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:60 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_read_from_database:2618 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:<listcomp>:2618 (1 samples, 0.76%)all (132 samples, 100%)/usr/local/lib/python3.6/sre_compile.py:compile:566 (1 samples, 0.76%)/datas/progs/odoo/odoo/service/server.py:run:743 (132 samples, 100.00%)/datas/progs/odoo/odoo/service/server.py:run:743/datas/progs/odoo/odoo/api.py:__call__:789 (9 samples, 6.82%)/datas/pr../datas/progs/odoo/odoo/cli/server.py:main:169 (132 samples, 100.00%)/datas/progs/odoo/odoo/cli/server.py:main:169/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities_dict:124 (13 samples, 9.85%)/datas/progs/o../datas/progs/odoo/odoo/models.py:__setitem__:4666 (7 samples, 5.30%)/datas../datas/progs/odoo/odoo/models.py:_read_group_raw:1889 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:__bool__:4521 (1 samples, 0.76%)/datas/progs/odoo/odoo/addons/base/res/ir_property.py:get_multi:160 (6 samples, 4.55%)/data../datas/progs/odoo/odoo/fields.py:__get__:948 (96 samples, 72.73%)/datas/progs/odoo/odoo/fields.py:__get__:948/datas/progs/odoo/odoo/fields.py:convert_to_cache:1227 (1 samples, 0.76%)/datas/progs/odoo/odoo/addons/base/res/ir_property.py:get_multi:150 (5 samples, 3.79%)/dat../datas/progs/odoo/odoo/models.py:_prefetch_field:2533 (27 samples, 20.45%)/datas/progs/odoo/odoo/models.py../usr/local/lib/python3.6/_weakrefset.py:__iter__:60 (3 samples, 2.27%)/../datas/progs/odoo/odoo/models.py:_search:3664 (4 samples, 3.03%)/da../usr/local/lib/python3.6/_weakrefset.py:__iter__:61 (3 samples, 2.27%)/../datas/progs/odoo/odoo/models.py:_where_calc:3469 (3 samples, 2.27%)/../datas/progs/odoo/odoo/addons/base/ir/ir_http.py:_find_handler:84 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:736 (2 samples, 1.52%)/datas/progs/odoo/odoo/api.py:__new__:103 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__call__:789 (6 samples, 4.55%)/data../datas/progs/odoo/addons/stock/models/product.py:<lambda>:200 (38 samples, 28.79%)/datas/progs/odoo/addons/stock/models/product../datas/progs/odoo/odoo/modules/registry.py:setup_models:276 (3 samples, 2.27%)/../datas/progs/odoo/odoo/api.py:__new__:735 (2 samples, 1.52%)/datas/progs/odoo/odoo/api.py:call_kw_multi:680 (1 samples, 0.76%)<frozen importlib._bootstrap>:_handle_fromlist:1017 (1 samples, 0.76%)/datas/progs/odoo/odoo/http.py:dispatch:683 (127 samples, 96.21%)/datas/progs/odoo/odoo/http.py:dispatch:683/datas/progs/odoo/odoo/fields.py:determine_value:1049 (38 samples, 28.79%)/datas/progs/odoo/odoo/fields.py:determine_va../usr/local/lib/python3.6/site-packages/werkzeug/serving.py:handle_one_request:251 (132 samples, 100.00%)/usr/local/lib/python3.6/site-packages/werkzeug/serving.py:handle_one_request:251/datas/progs/odoo/odoo/sql_db.py:wrapper:155 (2 samples, 1.52%)/datas/progs/odoo/odoo/http.py:routing_map:978 (1 samples, 0.76%)<frozen importlib._bootstrap>:_handle_fromlist:1017 (1 samples, 0.76%)/datas/progs/odoo/addons/fetchmail/models/fetchmail.py:<module>:21 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:read:2509 (1 samples, 0.76%)/datas/progs/odoo/odoo/http.py:_call_function:339 (127 samples, 96.21%)/datas/progs/odoo/odoo/http.py:_call_function:339/datas/progs/odoo/odoo/fields.py:compute_value:1015 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:59 (1 samples, 0.76%)/usr/local/lib/python3.6/sre_compile.py:_code:551 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/expression.py:get_alias_from_query:380 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:determine_value:1049 (1 samples, 0.76%)/datas/progs/odoo/addons/stock_account/models/product.py:do_change_standard_price:131 (96 samples, 72.73%)/datas/progs/odoo/addons/stock_account/models/product.py:do_change_standard_price:131/datas/progs/odoo/odoo/fields.py:__get__:951 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:read:2509 (5 samples, 3.79%)/dat../datas/progs/odoo/addons/web/controllers/main.py:call_button:928 (126 samples, 95.45%)/datas/progs/odoo/addons/web/controllers/main.py:call_button:928/datas/progs/odoo/odoo/models.py:_read_group_raw:1854 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_where_calc:3462 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:determine_value:1059 (1 samples, 0.76%)/datas/progs/odoo/odoo/service/server.py:process_request:767 (132 samples, 100.00%)/datas/progs/odoo/odoo/service/server.py:process_request:767/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities_dict:123 (9 samples, 6.82%)/datas/pr../datas/progs/odoo/odoo/tools/cache.py:lookup:81 (1 samples, 0.76%)/datas/progs/odoo/odoo/modules/module.py:load_module:82 (1 samples, 0.76%)/datas/progs/odoo/odoo/modules/loading.py:load_modules:346 (3 samples, 2.27%)/../datas/progs/odoo/odoo/fields.py:__set__:966 (6 samples, 4.55%)/data../usr/local/lib/python3.6/sre_compile.py:_compile:81 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_browse:4218 (1 samples, 0.76%)<frozen importlib._bootstrap>:_call_with_frames_removed:219 (1 samples, 0.76%)<frozen importlib._bootstrap>:_load_unlocked:656 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:<listcomp>:2618 (1 samples, 0.76%)<frozen importlib._bootstrap>:_load_backward_compatible:626 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/query.py:get_sql:144 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:735 (2 samples, 1.52%)/datas/progs/odoo/odoo/models.py:_read_from_database:2589 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_browse:4224 (5 samples, 3.79%)/dat../datas/progs/odoo/odoo/osv/expression.py:is_leaf:422 (1 samples, 0.76%)/datas/progs/odoo/odoo/service/server.py:process_work:776 (132 samples, 100.00%)/datas/progs/odoo/odoo/service/server.py:process_work:776/datas/progs/odoo/odoo/fields.py:digits:1209 (3 samples, 2.27%)/../datas/progs/odoo/odoo/fields.py:__get__:956 (3 samples, 2.27%)/../datas/progs/odoo/odoo/http.py:dispatch:1456 (4 samples, 3.03%)/da../datas/progs/odoo/odoo/api.py:__call__:789 (4 samples, 3.03%)/da../usr/local/lib/python3.6/_weakrefset.py:__iter__:60 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_where_calc:3469 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:60 (2 samples, 1.52%)/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities:85 (8 samples, 6.06%)/datas/p../datas/progs/odoo/odoo/models.py:_where_calc:3471 (1 samples, 0.76%)/datas/progs/odoo/odoo/tools/lru.py:__getitem__:45 (1 samples, 0.76%)/usr/local/lib/python3.6/site-packages/werkzeug/serving.py:handle:216 (132 samples, 100.00%)/usr/local/lib/python3.6/site-packages/werkzeug/serving.py:handle:216/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities:86 (7 samples, 5.30%)/datas../datas/progs/odoo/odoo/models.py:__getitem__:4657 (5 samples, 3.79%)/dat../datas/progs/odoo/odoo/service/server.py:process_spawn:539 (132 samples, 100.00%)/datas/progs/odoo/odoo/service/server.py:process_spawn:539/usr/local/lib/python3.6/http/server.py:handle:418 (132 samples, 100.00%)/usr/local/lib/python3.6/http/server.py:handle:418/datas/progs/odoo/odoo/api.py:__new__:744 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:60 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:qualify:2612 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:60 (1 samples, 0.76%)<frozen importlib._bootstrap>:_find_and_load_unlocked:955 (1 samples, 0.76%)/datas/progs/odoo/addons/product/models/product.py:name_get:372 (1 samples, 0.76%)/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities:81 (72 samples, 54.55%)/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities:81/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities:84 (3 samples, 2.27%)/../datas/progs/odoo/odoo/addons/base/res/ir_property.py:_get_domain:134 (2 samples, 1.52%)/datas/progs/odoo/odoo/models.py:_read_from_database:2628 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__call__:789 (8 samples, 6.06%)/datas/p../datas/progs/odoo/odoo/models.py:_in_cache_without:4684 (27 samples, 20.45%)/datas/progs/odoo/odoo/models.py../datas/progs/odoo/odoo/osv/expression.py:__leaf_to_sql:1204 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:61 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:735 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_read_group_resolve_many2one_fields:1944 (3 samples, 2.27%)/../datas/progs/odoo/odoo/fields.py:_compute_company_dependent:636 (11 samples, 8.33%)/datas/prog../datas/progs/odoo/odoo/fields.py:convert_to_cache:1230 (3 samples, 2.27%)/../datas/progs/odoo/odoo/api.py:__new__:735 (4 samples, 3.03%)/da..<frozen importlib._bootstrap>:_load_unlocked:665 (1 samples, 0.76%)/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities_dict:93 (38 samples, 28.79%)/datas/progs/odoo/addons/stock/models/product../datas/progs/odoo/addons/stock/models/product.py:_get_domain_locations:191 (38 samples, 28.79%)/datas/progs/odoo/addons/stock/models/product../usr/local/lib/python3.6/enum.py:__and__:804 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:call_kw_multi:680 (126 samples, 95.45%)/datas/progs/odoo/odoo/api.py:call_kw_multi:680/datas/progs/odoo/odoo/addons/base/res/res_company.py:_company_default_get:181 (3 samples, 2.27%)/../usr/local/lib/python3.6/_weakrefset.py:__iter__:61 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:with_context:4333 (9 samples, 6.82%)/datas/pr../datas/progs/odoo/odoo/models.py:_read_from_database:2618 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_add_field:288 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__getitem__:760 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:determine_value:1059 (96 samples, 72.73%)/datas/progs/odoo/odoo/fields.py:determine_value:1059<string>:change_digit:9 (6 samples, 4.55%)<stri../datas/progs/odoo/odoo/models.py:browse:4237 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:read:2520 (5 samples, 3.79%)/dat../datas/progs/odoo/odoo/osv/expression.py:parse:813 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_prefetch_field:2565 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:61 (1 samples, 0.76%)/datas/progs/odoo/odoo/service/wsgi_server.py:application:166 (132 samples, 100.00%)/datas/progs/odoo/odoo/service/wsgi_server.py:application:166/datas/progs/odoo/odoo/service/server.py:run:635 (132 samples, 100.00%)/datas/progs/odoo/odoo/service/server.py:run:635/datas/progs/odoo/odoo/models.py:_inherits_join_calc:1985 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_browse:4219 (2 samples, 1.52%)/datas/progs/odoo/odoo/api.py:__new__:736 (5 samples, 3.79%)/dat../datas/progs/odoo/odoo/fields.py:convert_to_cache:1230 (7 samples, 5.30%)/datas../datas/progs/odoo/odoo/tools/lru.py:__setitem__:56 (1 samples, 0.76%)<frozen importlib._bootstrap_external>:exec_module:678 (1 samples, 0.76%)/datas/progs/odoo/odoo/__init__.py:registry:76 (4 samples, 3.03%)/da../datas/progs/odoo/odoo/fields.py:convert_to_column:776 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:735 (4 samples, 3.03%)/da..<frozen importlib._bootstrap>:_load_unlocked:665 (1 samples, 0.76%)<string>:change_digit:10 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:__set__:966 (3 samples, 2.27%)/../datas/progs/odoo/odoo/fields.py:_compute_company_dependent:638 (7 samples, 5.30%)/datas../datas/progs/odoo/addons/stock/models/product.py:_get_domain_locations_new:200 (38 samples, 28.79%)/datas/progs/odoo/addons/stock/models/product../datas/progs/odoo/odoo/modules/loading.py:load_marked_modules:242 (1 samples, 0.76%)/datas/progs/odoo/odoo/sql_db.py:execute:232 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:call_kw:689 (1 samples, 0.76%)/datas/progs/odoo/odoo/modules/registry.py:new:85 (4 samples, 3.03%)/da..<decorator-gen-37>:check:2 (1 samples, 0.76%)<frozen importlib._bootstrap>:_find_and_load:971 (1 samples, 0.76%)/datas/progs/odoo/addons/web/controllers/main.py:_call_kw:916 (126 samples, 95.45%)/datas/progs/odoo/addons/web/controllers/main.py:_call_kw:916/datas/progs/odoo/odoo/fields.py:digits:1209 (7 samples, 5.30%)/datas../usr/local/lib/python3.6/socketserver.py:__init__:696 (132 samples, 100.00%)/usr/local/lib/python3.6/socketserver.py:__init__:696/datas/progs/odoo/odoo/service/model.py:wrapper:97 (127 samples, 96.21%)/datas/progs/odoo/odoo/service/model.py:wrapper:97/datas/progs/odoo/odoo/addons/base/ir/ir_http.py:_dispatch:208 (127 samples, 96.21%)/datas/progs/odoo/odoo/addons/base/ir/ir_http.py:_dispatch:208/datas/progs/odoo/odoo/http.py:__call__:1272 (132 samples, 100.00%)/datas/progs/odoo/odoo/http.py:__call__:1272/usr/local/lib/python3.6/_weakrefset.py:__iter__:60 (2 samples, 1.52%)<frozen importlib._bootstrap>:_find_and_load_unlocked:955 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_read_group_raw:1918 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:filtered:4439 (38 samples, 28.79%)/datas/progs/odoo/odoo/models.py:filtered:4439/datas/progs/odoo/addons/stock_account/models/product.py:do_change_standard_price:156 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:735 (4 samples, 3.03%)/da../datas/progs/odoo/odoo/service/server.py:worker_spawn:457 (132 samples, 100.00%)/datas/progs/odoo/odoo/service/server.py:worker_spawn:457/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities_dict:125 (3 samples, 2.27%)/../datas/progs/odoo/odoo/models.py:_read_from_database:2597 (1 samples, 0.76%)/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities_dict:134 (9 samples, 6.82%)/datas/pr../datas/progs/odoo/odoo/osv/expression.py:__init__:668 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_where_calc:3471 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:__iter__:4531 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:cache_key:766 (2 samples, 1.52%)/datas/progs/odoo/odoo/fields.py:__set__:966 (8 samples, 6.06%)/datas/p../datas/progs/odoo/odoo/models.py:_read_group_raw:1851 (2 samples, 1.52%)/datas/progs/odoo/odoo/models.py:_prefetch_field:2565 (11 samples, 8.33%)/datas/prog../datas/progs/odoo/odoo/models.py:check_access_rights:2781 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_generate_translated_field:3553 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:61 (1 samples, 0.76%)/usr/local/lib/python3.6/site-packages/werkzeug/wsgi.py:__call__:599 (132 samples, 100.00%)/usr/local/lib/python3.6/site-packages/werkzeug/wsgi.py:__call__:599/datas/progs/odoo/odoo/models.py:read_group:1830 (1 samples, 0.76%)/datas/progs/odoo/odoo/http.py:response_wrap:512 (127 samples, 96.21%)/datas/progs/odoo/odoo/http.py:response_wrap:512/datas/progs/odoo/odoo/models.py:_browse:4224 (1 samples, 0.76%)<decorator-gen-112>:precision_get:2 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:735 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:<listcomp>:4439 (38 samples, 28.79%)/datas/progs/odoo/odoo/models.py:<listcomp>:4../datas/progs/odoo/odoo/sql_db.py:execute:239 (1 samples, 0.76%)/datas/progs/odoo/addons/fetchmail/models/__init__.py:<module>:4 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_read_group_resolve_many2one_fields:1943 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_read_group_raw:1924 (5 samples, 3.79%)/dat../datas/progs/odoo/odoo/api.py:__call__:789 (4 samples, 3.03%)/da../usr/local/lib/python3.6/_weakrefset.py:__enter__:24 (1 samples, 0.76%)/datas/progs/odoo/addons/web_editor/models/ir_http.py:_dispatch:21 (128 samples, 96.97%)/datas/progs/odoo/addons/web_editor/models/ir_http.py:_dispatch:21/datas/progs/odoo/odoo/sql_db.py:execute:232 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_in_cache_without:4684 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:_setup_attrs:446 (1 samples, 0.76%)/datas/progs/odoo/addons/http_routing/models/ir_http.py:_dispatch:325 (1 samples, 0.76%)/usr/local/lib/python3.6/enum.py:__call__:291 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/query.py:_get_alias_mapping:75 (1 samples, 0.76%)/datas/progs/odoo/odoo/addons/base/res/res_users.py:_get_company:217 (3 samples, 2.27%)/../datas/progs/odoo/odoo/service/wsgi_server.py:application_unproxied:154 (132 samples, 100.00%)/datas/progs/odoo/odoo/service/wsgi_server.py:application_unproxied:154/datas/progs/odoo/odoo/api.py:__new__:736 (5 samples, 3.79%)/dat../usr/local/lib/python3.6/inspect.py:getmembers:333 (1 samples, 0.76%)/datas/progs/odoo/odoo/http.py:dispatch:1473 (128 samples, 96.97%)/datas/progs/odoo/odoo/http.py:dispatch:1473/datas/progs/odoo/odoo/models.py:_add_field:284 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/expression.py:distribute_not:302 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_browse:4224 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:747 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/expression.py:to_sql:1271 (1 samples, 0.76%)<string>:change_digit:10 (1 samples, 0.76%)/datas/progs/odoo/addons/http_routing/models/ir_http.py:_dispatch:397 (127 samples, 96.21%)/datas/progs/odoo/addons/http_routing/models/ir_http.py:_dispatch:397/datas/progs/odoo/odoo/sql_db.py:wrapper:155 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_setup_base:2311 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:__get__:2523 (1 samples, 0.76%)/datas/progs/odoo/odoo/modules/registry.py:__new__:61 (4 samples, 3.03%)/da..<frozen importlib._bootstrap>:_find_and_load_unlocked:955 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:compute_value:1015 (96 samples, 72.73%)/datas/progs/odoo/odoo/fields.py:compute_value:1015/datas/progs/odoo/odoo/fields.py:cache_key:765 (2 samples, 1.52%)/datas/progs/odoo/odoo/fields.py:convert_to_cache:1230 (7 samples, 5.30%)/datas../datas/progs/odoo/odoo/sql_db.py:wrapper:155 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_browse:4222 (2 samples, 1.52%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:61 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_read_group_resolve_many2one_fields:1944 (5 samples, 3.79%)/dat../datas/progs/odoo/odoo/models.py:sudo:4310 (4 samples, 3.03%)/da..<frozen importlib._bootstrap>:_call_with_frames_removed:219 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/expression.py:__leaf_to_sql:1197 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/expression.py:to_sql:1271 (1 samples, 0.76%)/datas/progs/odoo/odoo/cli/command.py:main:60 (132 samples, 100.00%)/datas/progs/odoo/odoo/cli/command.py:main:60/datas/progs/odoo/odoo/models.py:read:2516 (1 samples, 0.76%)/usr/local/lib/python3.6/re.py:compile:233 (1 samples, 0.76%)/datas/progs/odoo/addons/stock/models/product.py:_compute_quantities:83 (6 samples, 4.55%)/data../datas/progs/odoo/addons/stock_account/models/product.py:do_change_standard_price:125 (9 samples, 6.82%)/datas/pr..<frozen importlib._bootstrap>:_find_and_load:971 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:create:3278 (1 samples, 0.76%)/datas/progs/odoo/odoo/sql_db.py:dbname:477 (1 samples, 0.76%)/datas/progs/odoo/addons/product/models/product.py:name_get:376 (6 samples, 4.55%)/data../datas/progs/odoo/odoo/api.py:__call__:789 (3 samples, 2.27%)/../datas/progs/odoo/odoo/http.py:__call__:927 (127 samples, 96.21%)/datas/progs/odoo/odoo/http.py:__call__:927/datas/progs/odoo/odoo/fields.py:__get__:948 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_add_magic_fields:330 (1 samples, 0.76%)/datas/progs/odoo/odoo/modules/registry.py:<dictcomp>:201 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:_compute_value:1006 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:read_group:1828 (8 samples, 6.06%)/datas/p../usr/local/lib/python3.6/site-packages/werkzeug/routing.py:bind:681 (1 samples, 0.76%)/datas/progs/odoo/odoo/tools/misc.py:__init__:990 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:determine_value:1057 (1 samples, 0.76%)/datas/progs/odoo/odoo/addons/base/ir/ir_http.py:routing_map:238 (1 samples, 0.76%)/usr/local/lib/python3.6/site-packages/werkzeug/routing.py:compile:742 (1 samples, 0.76%)/datas/progs/odoo/odoo/http.py:checked_call:332 (127 samples, 96.21%)/datas/progs/odoo/odoo/http.py:checked_call:332/datas/progs/odoo/odoo/osv/expression.py:to_sql:1280 (1 samples, 0.76%)/datas/progs/odoo/addons/web/controllers/main.py:_call_kw:916 (1 samples, 0.76%)/datas/progs/odoo/addons/product/models/product.py:name_get:376 (4 samples, 3.03%)/da../datas/progs/odoo/odoo/models.py:_inherits_join_calc:1973 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_setup_base:2308 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:__get__:948 (19 samples, 14.39%)/datas/progs/odoo/odo../datas/progs/odoo/odoo/modules/module.py:load_openerp_module:368 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:call_kw:689 (126 samples, 95.45%)/datas/progs/odoo/odoo/api.py:call_kw:689/datas/progs/odoo/odoo/fields.py:digits:1209 (6 samples, 4.55%)/data../datas/progs/odoo/odoo/models.py:_where_calc:3471 (1 samples, 0.76%)/datas/progs/odoo/odoo/http.py:__call__:1298 (132 samples, 100.00%)/datas/progs/odoo/odoo/http.py:__call__:1298/datas/progs/odoo/addons/account/models/account_move.py:create:126 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:735 (4 samples, 3.03%)/da../datas/progs/odoo/odoo/osv/expression.py:__init__:665 (1 samples, 0.76%)/datas/progs/odoo/odoo/tools/cache.py:lookup:84 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:736 (2 samples, 1.52%)/usr/local/lib/python3.6/socketserver.py:finish_request:361 (132 samples, 100.00%)/usr/local/lib/python3.6/socketserver.py:finish_request:361/datas/progs/odoo/odoo/osv/query.py:add_join:136 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:set_all_attrs:360 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/expression.py:__init__:660 (1 samples, 0.76%)/usr/local/lib/python3.6/re.py:_compile:301 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:_compute_value:1008 (18 samples, 13.64%)/datas/progs/odoo/od../datas/progs/odoo/odoo/fields.py:digits:1209 (7 samples, 5.30%)/datas../datas/progs/odoo/odoo/api.py:get:959 (1 samples, 0.76%)/datas/progs/odoo/odoo/cli/server.py:run:175 (132 samples, 100.00%)/datas/progs/odoo/odoo/cli/server.py:run:175/datas/progs/odoo/odoo/fields.py:determine_value:1059 (18 samples, 13.64%)/datas/progs/odoo/od../datas/progs/odoo/odoo/models.py:_read_from_database:2646 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:search:1407 (6 samples, 4.55%)/data../datas/progs/odoo/addons/stock_account/wizard/stock_change_standard_price.py:change_price:43 (126 samples, 95.45%)/datas/progs/odoo/addons/stock_account/wizard/stock_change_standard_price.py:change_price:43/datas/progs/odoo/odoo/models.py:compute_concurrency_field_with_access:356 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:60 (3 samples, 2.27%)/../datas/progs/odoo/odoo/models.py:_search:3674 (2 samples, 1.52%)/datas/progs/odoo/odoo/models.py:read_group:1828 (3 samples, 2.27%)/../usr/local/lib/python3.6/_weakrefset.py:add:84 (1 samples, 0.76%)/datas/progs/odoo/odoo/osv/expression.py:get_unaccent_wrapper:455 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__new__:735 (3 samples, 2.27%)/../datas/progs/odoo/odoo/fields.py:__set__:966 (7 samples, 5.30%)/datas../datas/progs/odoo/odoo/api.py:__new__:735 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:__call__:789 (3 samples, 2.27%)/../datas/progs/odoo/odoo/tools/func.py:wrapper:68 (1 samples, 0.76%)/datas/progs/odoo/odoo/service/server.py:start:991 (132 samples, 100.00%)/datas/progs/odoo/odoo/service/server.py:start:991/datas/progs/odoo/odoo/modules/registry.py:field_sequence:200 (1 samples, 0.76%)/datas/progs/odoo/odoo/tools/func.py:wrapper:68 (1 samples, 0.76%)<string>:change_digit:9 (3 samples, 2.27%)<../datas/progs/odoo/odoo/models.py:sudo:4310 (6 samples, 4.55%)/data../datas/progs/odoo/odoo/api.py:__new__:736 (3 samples, 2.27%)/../datas/progs/odoo/odoo/models.py:_read_group_raw:1851 (4 samples, 3.03%)/da../datas/progs/odoo/odoo/models.py:read:2520 (1 samples, 0.76%)/datas/progs/odoo/addons/product/models/product.py:name_get:376 (3 samples, 2.27%)/..<string>:<module>:4 (1 samples, 0.76%)/usr/local/lib/python3.6/socketserver.py:process_request:348 (132 samples, 100.00%)/usr/local/lib/python3.6/socketserver.py:process_request:348/datas/progs/odoo/odoo/api.py:get_records:1009 (27 samples, 20.45%)/datas/progs/odoo/odoo/api.py:ge..<frozen importlib._bootstrap>:_find_and_load:971 (1 samples, 0.76%)/datas/progs/odoo/odoo/tools/func.py:__get__:23 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:__getitem__:4657 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:61 (2 samples, 1.52%)/datas/progs/odoo/odoo/api.py:__new__:736 (7 samples, 5.30%)/datas../datas/progs/odoo/odoo/osv/expression.py:__init__:660 (1 samples, 0.76%)/usr/local/lib/python3.6/_weakrefset.py:__iter__:61 (1 samples, 0.76%)/datas/progs/odoo/odoo/api.py:user:798 (3 samples, 2.27%)/../datas/progs/odoo/odoo/models.py:_create:3435 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:_compute_value:1006 (96 samples, 72.73%)/datas/progs/odoo/odoo/fields.py:_compute_value:1006/datas/progs/odoo/odoo/models.py:_normalize_ids:5197 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:setup_base:389 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:sudo:4310 (4 samples, 3.03%)/da../datas/progs/odoo/odoo/models.py:with_context:4333 (8 samples, 6.06%)/datas/p../datas/progs/odoo/odoo/modules/loading.py:load_module_graph:121 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_browse:4218 (1 samples, 0.76%)<string>:change_digit:9 (7 samples, 5.30%)<strin../datas/progs/odoo/odoo/addons/base/res/ir_property.py:_get_domain:138 (3 samples, 2.27%)/../datas/progs/odoo/odoo/fields.py:compute_value:1015 (18 samples, 13.64%)/datas/progs/odoo/od..<string>:change_digit:9 (6 samples, 4.55%)<stri../usr/local/lib/python3.6/site-packages/werkzeug/serving.py:execute:181 (132 samples, 100.00%)/usr/local/lib/python3.6/site-packages/werkzeug/serving.py:execute:181/datas/progs/odoo/odoo/api.py:<listcomp>:1010 (27 samples, 20.45%)/datas/progs/odoo/odoo/api.py:<l../datas/progs/odoo/addons/web/controllers/main.py:call_kw:924 (1 samples, 0.76%)/datas/progs/odoo/odoo/models.py:_setup_base:2312 (1 samples, 0.76%)/datas/progs/odoo/odoo/fields.py:digits:1209 (7 samples, 5.30%)/datas.. \ No newline at end of file diff --git a/content/developer/reference/backend.rst b/content/developer/reference/backend.rst index ead2caa7c..16938a300 100644 --- a/content/developer/reference/backend.rst +++ b/content/developer/reference/backend.rst @@ -14,6 +14,7 @@ Python framework backend/module backend/reports backend/security + backend/performance backend/testing backend/http backend/mixins diff --git a/content/developer/reference/backend/performance.rst b/content/developer/reference/backend/performance.rst new file mode 100644 index 000000000..1167d9e17 --- /dev/null +++ b/content/developer/reference/backend/performance.rst @@ -0,0 +1,540 @@ +:custom-css: performance.css + +=========== +Performance +=========== + +.. _performance/profiling: + +Profiling +========= + +.. currentmodule:: odoo.tools.profiler + +Profiling is about analysing the execution of a program and measure aggregated data. These data can +be the elapsed time for each function, the executed SQL queries... + +While profiling does not improve the performance of a program by itself, it can prove very helpful +in finding performance issues and identifying which part of the program is responsible for them. + +Odoo provides an integrated profiling tool that allows recording all executed queries and stack +traces during execution. It can be used to profile either a set of requests of a user session, or a +specific portion of code. Profiling results can be either inspected with the integrated `speedscope +`_ :dfn:`open source app allowing to visualize a flamegraph` +view or analyzed with custom tools by first saving them in a JSON file or in the database. + +.. _performance/profiling/enable: + +Enable the profiler +------------------- + +The profiler can either be enabled from the user interface, which is the easiest way to do so but +allows profiling only web requests, or from Python code, which allows profiling any piece of code +including tests. + +.. tabs:: + + .. tab:: Enable from the user interface + + #. :ref:`Enable the developer mode `. + #. Before starting a profiling session, the profiler must be enabled globally on the database. + This can be done in two ways: + + - Open the :ref:`developer mode tools `, then toggle the + :guilabel:`Enable profiling` button. A wizard suggests a set of expiry times for the + profiling. Click on :guilabel:`ENABLE PROFILING` to enable the profiler globally. + + .. image:: performance/enable_profiling_wizard.png + + - Go to :guilabel:`Settings --> General Settings --> Performance` and set the desired time to + the field :guilabel:`Enable profiling until`. + + #. After the profiler is enabled on the database, users can enable it on their session. To do + so, toggle the :guilabel:`Enable profiling` button in the :ref:`developer mode tools + ` again. By default, the recommended options :guilabel:`Record + sql` and :guilabel:`Record traces` are enabled. To learn more about the different options, + head over to :ref:`performance/profiling/collectors`. + + .. image:: performance/profiling_debug_menu.png + + When the profiler is enabled, all the requests made to the server are profiled and saved into + an `ir.profile` record. Such records are grouped into the current profiling session which + spans from when the profiler was enabled until it is disabled. + + .. note:: + Odoo Online (SaaS) databases cannot be profiled. + + .. tab:: Enable from Python code + + Starting the profiler manually can be convenient to profile a specific method or a part of the + code. This code can be a test, a compute method, the entire loading, etc. + + To start the profiler from Python code, call it as a context manager. You may specify *what* + you want to record through the parameters. A shortcut is available for profiling test classes: + :code:`self.profile()`. See :ref:`performance/profiling/collectors` for more information on + the `collectors` parameter. + + .. example:: + + .. code-block:: python + + with Profiler(): + do_stuff() + + .. example:: + + .. code-block:: python + + with Profiler(collectors=['sql', PeriodicCollector(interval=0.1)]): + do_stuff() + + .. example:: + + .. code-block:: python + + with self.profile(): + with self.assertQueryCount(__system__=1211): + do_stuff() + + .. note:: + The profiler is called outside of the `assertQueryCount` in order to catch queries made + when exiting the context manager (e.g., flush). + + .. autoclass:: Profiler() + :special-members: __init__ + + When the profiler is enabled, all executions of a test method are profiled and saved into an + `ir.profile` record. Such records are grouped into a single profiling session. This is + especially useful when using the :code:`@warmup` and :code:`@users` decorators. + + .. tip:: + It can be complicated to analyze profiling results of a method that is called several times + because all the calls are grouped together in the stack trace. Add an **execution context** + as a context manager to break down the results into multiple frames. + + .. example:: + + .. code-block:: python + + for index in range(max_index): + with ExecutionContext(current_index=index): # Identify each call in speedscope results. + do_stuff() + +.. _performance/profiling/analyse: + +Analyse the results +------------------- + +To browse the profiling results, make sure that the :ref:`profiler is enabled globally on the +database `, then open the :ref:`developer mode tools +` and click on the button in the top-right corner of the profiling +section. A list view of the `ir.profile` records grouped by profiling session opens. + +.. image:: performance/profiling_web.png + :align: center + +Each record has a clickable link that opens the speedscope results in a new tab. + +.. image:: performance/flamegraph_example.png + :align: center + +Speedscope falls out of the scope of this documentation but there are a lot of tools to try: search, +highlight of similar frames, zoom on frame, timeline, left heavy, sandwich view... + +Depending on the profiling options that were activated, Odoo generates different view modes that you +can access from the top menu. + +.. image:: performance/speedscope_modes.png + :align: center + +- The :guilabel:`Combined` view shows all the SQL queries and traces merged togethers. +- The :guilabel:`Combined no context` view shows the same result but ignores the saved execution + context `. +- The :guilabel:`sql (no gap)` view shows all the SQL queries as if they were executed one after + another, without any Python logic. This is useful for optimizing SQL only. +- The :guilabel:`sql (density)` view shows only all the SQL queries, leaving gap between them. This + can be useful to spot if eiter SQL or Python code is the problem, and to identify zones in where + many small queries could be batched. +- The :guilabel:`frames` view shows the results of only the :ref:`periodic collector + `. + +.. important:: + Even though the profiler has been designed to be as light as possible, it can still impact + performance, especially when using the :ref:`Sync collector + `. Keep that in mind when analyzing speedscope results. + +.. _performance/profiling/collectors: + +Collectors +---------- + +Whereas the profiler is about the *when* of profiling, the collectors take care of the *what*. + +Each collector specializes in collecting profiling data in its own format and manner. They can be +individually enabled from the user interface through their dedicated toggle button in the +:ref:`developer mode tools `, or from Python code through their key or +class. + +There are currently four collectors available in Odoo: + +.. list-table:: + :header-rows: 1 + + * - Name + - Toggle button + - Python key + - Python class + * - :ref:`SQL collector ` + - :guilabel:`Record sql` + - `sql` + - `SqlCollector` + * - :ref:`Periodic collector ` + - :guilabel:`Record traces` + - `traces_async` + - `PeriodicCollector` + * - :ref:`QWeb collector ` + - :guilabel:`Record qweb` + - `qweb` + - `QwebCollector` + * - :ref:`Sync collector ` + - No + - `traces_sync` + - `SyncCollector` + +By default, the profiler enables the SQL and the Periodic collectors. Both when it is enabled from +the user interface or Python code. + +.. _performance/profiling/collectors/sql: + +SQL collector +~~~~~~~~~~~~~ + +The SQL collector saves all the SQL queries made to the database in the current thread (for all +cursors), as well as the stack trace. The overhead of the collector is added to the analysed thread +for each query, which means that using it on a lot of small queries may impact execution time and +other profilers. + +It is especially useful to debug query counts, or to add information to the :ref:`Periodic collector +` in the combined speedscope view. + +.. autoclass:: SQLCollector + +.. _performance/profiling/collectors/periodic: + +Periodic collector +~~~~~~~~~~~~~~~~~~ + +This collector runs in a separate thread and saves the stack trace of the analysed thread at every +interval. The interval (by default 10 ms) can be defined through the :guilabel:`Interval` option in +the user interface, or the `interval` parameter in Python code. + +.. warning:: + If the interval is set at a very low value, profiling long requests will generate memory issues. + If the interval is set at a very high value, information on short function executions will be + lost. + +It is one of the best way to analyse performance as it should have a very low impact on the +execution time thanks to its separate thread. + +.. autoclass:: PeriodicCollector + +.. _performance/profiling/collectors/qweb: + +QWeb collector +~~~~~~~~~~~~~~ + +This collector saves the Python execution time and queries of all directives. As for the :ref:`SQL +collector `, the overhead can be important when executing a +lot of small directives. The results are different from other collectors in terms of collected data, +and can be analysed from the `ir.profile` form view using a custom widget. + +It is mainly useful for optimizing views. + +.. autoclass:: QwebCollector + +.. _performance/profiling/collectors/sync: + +Sync collector +~~~~~~~~~~~~~~ + +This collector saves the stack for every function's call and return and runs on the same thread, +which greatly impacts performance. + +It can be useful to debug and understand complex flows, and follow their execution in the code. It +is however not recommended for performance analysis because the overhead is high. + +.. autoclass:: SyncCollector + +.. _performance/profiling/pitfalls: + +Performance pitfalls +-------------------- + +- Be careful with randomness. Multiple executions may lead to different results. E.g., a garbage + collector being triggered during execution. +- Be careful with blocking calls. In some cases, external `c_call` may take some time before + releasing the GIL, thus leading to unexpected long frames with the :ref:`Periodic collector + `. This should be detected by the profiler and give a + warning. It is possible to trigger the profiler manually before such calls if needed. +- Pay attention to the cache. Profiling before that the `view`/`assets`/... are in cache can lead to + different results. +- Be aware of the profiler's overhead. The :ref:`SQL collector + `'s overhead can be important when a lot of small queries + are executed. Profiling is practical to spot a problem but you may want to disable the profiler in + order to measure the real impact of a code change. +- Profiling results can be memory intensive. In some cases (e.g., profiling an install or a long + request), it is possible that you reach memory limit, especially when rendering the speedscope + results, which can lead to an HTTP 500 error. In this case, you may need to start the server with + a higher memory limit: `--limit-memory-hard $((8*1024**3))`. + +.. _reference/performance/populate: + +Database population +=================== + +Odoo CLI offers a :ref:`database population ` feature through the CLI +command :command:`odoo-bin populate`. + +Instead of the tedious manual, or programmatic, specification of test data, one can use this feature +to fill a database on demand with the desired number of test data. This can be used to detect +diverse bugs or performance issues in tested flows. + +.. _reference/performance/populate/methods: + +To populate a given model, the following methods and attributes can be defined. + +.. currentmodule:: odoo.models + +.. autoattribute:: Model._populate_sizes +.. autoattribute:: Model._populate_dependencies +.. automethod:: Model._populate +.. automethod:: Model._populate_factories + +.. note:: + You have to define at least :meth:`~odoo.models.Model._populate` or + :meth:`~odoo.models.Model._populate_factories` on the model to enable database population. + +.. example:: + .. code-block:: python + + from odoo.tools import populate + + class CustomModel(models.Model) + _inherit = "custom.some_model" + _populate_sizes = {"small": 100, "medium": 2000, "large": 10000} + _populate_dependencies = ["custom.some_other_model"] + + def _populate_factories(self): + # Record ids of previously populated models are accessible in the registry + some_other_ids = self.env.registry.populated_models["custom.some_other_model"] + + def get_some_field(values=None, random=None, **kwargs): + """ Choose a value for some_field depending on other fields values. + + :param dict values: + :param random: seeded :class:`random.Random` object + """ + field_1 = values['field_1'] + if field_1 in [value2, value3]: + return random.choice(some_field_values) + return False + + return [ + ("field_1", populate.randomize([value1, value2, value3])), + ("field_2", populate.randomize([value_a, value_b], [0.5, 0.5])), + ("some_other_id", populate.randomize(some_other_ids)), + ("some_field", populate.compute(get_some_field, seed="some_field")), + ('active', populate.cartesian([True, False])), + ] + + def _populate(self, size): + records = super()._populate(size) + + # If you want to update the generated records + # E.g setting the parent-child relationships + records.do_something() + + return records + +Population tools +---------------- + +Multiple population tools are available to easily create the needed data generators. + +.. automodule:: odoo.tools.populate + :members: cartesian, compute, constant, iterate, randint, randomize + +.. _performance/good_practices: + +Good practices +============== + +.. _performance/good_practices/batch: + +Batch operations +---------------- + +When working with recordsets, it is almost always better to batch operations. + +.. example:: + Don't call a method that runs SQL queries while looping over a recordset because it will do so + for each record of the set. + + .. rst-class:: bad-example + .. code-block:: python + + def _compute_count(self): + for record in self: + domain = [('related_id', '=', record.id)] + record.count = other_model.search_count(domain) + + Instead, replace the `search_count` with a `read_group` to execute one SQL query for the entire + batch of records. + + .. rst-class:: good-example + .. code-block:: python + + def _compute_count(self): + if self.ids: + domain = [('related_id', 'in', self.ids)] + counts_data = other_model.read_group(domain, ['related_id'], ['related_id']) + mapped_data = { + count['related_id'][0]: count['related_id_count'] for count in counts_data + } + else: + mapped_data = {} + for record in self: + record.count = mapped_data.get(record.id, 0) + + .. note:: + This example is not optimal nor correct in all cases. It is only a substitute for a + `search_count`. Another solution could be to prefetch and count the inverse `One2many` field. + +.. example:: + Don't create records one after another. + + .. rst-class:: bad-example + .. code-block:: python + + for name in ['foo', 'bar']: + model.create({'name': name}) + + Instead, accumulate the create values and call the `create` method on the batch. Doing so has + mostly no impact and helps the framework optimize fields computation. + + .. rst-class:: good-example + .. code-block:: python + + create_values = [] + for name in ['foo', 'bar']: + create_values.append({'name': name}) + records = model.create(create_values) + +.. example:: + Fail to prefetch the fields of a recordset while browsing a single record inside a loop. + + .. rst-class:: bad-example + .. code-block:: python + + for record_id in record_ids: + model.browse(record_id) + record.foo # One query is executed per record. + + Instead, browse the entire recordset first. + + .. rst-class:: good-example + .. code-block:: python + + records = model.browse(record_ids) + for record in records: + record.foo # One query is executed for the entire recordset. + + We can verify that the records are prefetched in batch by reading the field `prefetch_ids` which + includes each of the record ids.browsing all records together is unpractical, + + If needed, the `with_prefetch` method can be used to disable batch prefetching: + + .. code-block:: python + + for values in values_list: + message = self.browse(values['id']).with_prefetch(self.ids) + +.. _performance/good_practices/algorithmic_complexity: + +Reduce the algorithmic complexity +--------------------------------- + +Algorithmic complexity is a measure of how long an algorithm would take to complete in regard to the +size `n` of the input. When the complexity is high, the execution time can grow quickly as the input +becomes larger. In some cases, the algorithmic complexity can be reduced by preparing the input's +data correctly. + +.. example:: + For a given problem, let's consider a naive algorithm crafted with two nested loops for which the + complexity in in O(n²). + + .. rst-class:: bad-example + .. code-block:: python + + for record in self: + for result in results: + if results['id'] == record.id: + record.foo = results['foo'] + break + + Assuming that all results have a different id, we can prepare the data to reduce the complexity. + + .. rst-class:: good-example + .. code-block:: python + + mapped_result = {result['id']: result['foo'] for result in results} + for record in self: + record.foo = mapped_result.get(record.id) + +.. example:: + Choosing the bad data structure to hold the input can lead to quadratic complexity. + + .. rst-class:: bad-example + .. code-block:: python + + invalid_ids = self.search(domain).ids + for record in self: + if record.id in invalid_ids: + ... + + If `invalid_ids` is a list-like data structure, the complexity of the algorithm may be quadratic. + + Instead, prefer using set operations like casting `invalid_ids` to a set. + + .. rst-class:: good-example + .. code-block:: python + + invalid_ids = set(invalid_ids) + for record in self: + if record.id in invalid_ids: + ... + + Depending on the input, recordset operations can also be used. + + .. rst-class:: good-example + .. code-block:: python + + invalid_ids = self.search(domain) + for record in self - invalid_ids: + ... + +.. _performance/good_practices/index: + +Use indexes +----------- + +Database indexes can help fasten search operations, be it from a search in the or through the user +interface. + +.. code-block:: python + + name = fields.Char(string="Name", index=True) + +.. warning:: + Be careful not to index every field as indexes consume space and impact on performance when + executing one of `INSERT`, `UPDATE`, and `DELETE`. diff --git a/content/developer/reference/backend/performance/enable_profiling_wizard.png b/content/developer/reference/backend/performance/enable_profiling_wizard.png new file mode 100644 index 0000000000000000000000000000000000000000..7fa2870d32a03bfc51ecb18935ec5ee5b9faa1cc GIT binary patch literal 10392 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 literal 0 HcmV?d00001 diff --git a/content/developer/reference/backend/performance/profiling_example_after.png b/content/developer/reference/backend/performance/profiling_example_after.png new file mode 100644 index 0000000000000000000000000000000000000000..b832aa4ca8017f005dd292d33f3c66ea2b79ee29 GIT binary patch literal 3572 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

ITbiBbww-mKy#THsUy8d^t&oE9r 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 literal 0 HcmV?d00001 diff --git a/content/developer/reference/backend/performance/speedscope_modes.png b/content/developer/reference/backend/performance/speedscope_modes.png new file mode 100644 index 0000000000000000000000000000000000000000..e08a70620ff99e9a0034d407c933241ee80a07ac GIT binary patch literal 4410 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 feature. - -.. code-block:: console - - odoo-bin populate - -Instead of the tedious manual, or programmatic, specification of test data, -one can use this feature to fill a database on demand with the desired number of test data. -This can be used to detect diverse bugs or performance issues in tested flows. - -.. _reference/testing/populate/methods: - -To specify this feature for a given model, the following methods and attributes can be defined. - -.. currentmodule:: odoo.models - -.. autoattribute:: Model._populate_sizes -.. autoattribute:: Model._populate_dependencies -.. automethod:: Model._populate -.. automethod:: Model._populate_factories - -.. note:: - - You have to define at least :meth:`~odoo.models.Model._populate` or :meth:`~odoo.models.Model._populate_factories` - on the model to enable database population. - -Example model -~~~~~~~~~~~~~ - -.. code-block:: python - - from odoo.tools import populate - - class CustomModel(models.Model) - _inherit = "custom.some_model" - _populate_sizes = {"small": 100, "medium": 2000, "large": 10000} - _populate_dependencies = ["custom.some_other_model"] - - def _populate_factories(self): - # Record ids of previously populated models are accessible in the registry - some_other_ids = self.env.registry.populated_models["custom.some_other_model"] - - def get_some_field(values=None, random=None, **kwargs): - """ Choose a value for some_field depending on other fields values. - - :param dict values: - :param random: seeded :class:`random.Random` object - """ - field_1 = values['field_1'] - if field_1 in [value2, value3]: - return random.choice(some_field_values) - return False - - return [ - ("field_1", populate.randomize([value1, value2, value3])), - ("field_2", populate.randomize([value_a, value_b], [0.5, 0.5])), - ("some_other_id", populate.randomize(some_other_ids)), - ("some_field", populate.compute(get_some_field, seed="some_field")), - ('active', populate.cartesian([True, False])), - ] - - def _populate(self, size): - records = super()._populate(size) - - # If you want to update the generated records - # E.g setting the parent-child relationships - records.do_something() - - return records - -Population tools -~~~~~~~~~~~~~~~~ - -Multiple population tools are available to easily create -the needed data generators. - -.. automodule:: odoo.tools.populate - :members: cartesian, compute, constant, iterate, randint, randomize - .. _qunit: https://qunitjs.com/ .. _qunit_config.js: https://github.com/odoo/odoo/blob/51ee0c3cb59810449a60dae0b086b49b1ed6f946/addons/web/static/tests/helpers/qunit_config.js#L49 .. _web.tests_assets: https://github.com/odoo/odoo/blob/51ee0c3cb59810449a60dae0b086b49b1ed6f946/addons/web/views/webclient_templates.xml#L594 diff --git a/static/css/performance.css b/static/css/performance.css new file mode 100644 index 000000000..25b6af75d --- /dev/null +++ b/static/css/performance.css @@ -0,0 +1,7 @@ +.bad-example { + border-left: 3px solid red; +} + +.good-example { + border-left: 3px solid green; +}