Public release from ruodoo-project: 19.0 - 2026-05-31 21:19:12 UTC
This commit is contained in:
391
dms/tests/test_benchmark.py
Normal file
391
dms/tests/test_benchmark.py
Normal file
@ -0,0 +1,391 @@
|
||||
# Copyright 2017-2019 MuK IT GmbH.
|
||||
# Copyright 2020 Creu Blanca
|
||||
# Copyright 2024 Subteno - Timothée Vannier (https://www.subteno.com).
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
import cProfile
|
||||
import logging
|
||||
import os
|
||||
import unittest
|
||||
import warnings
|
||||
from functools import wraps
|
||||
|
||||
from odoo.tests import common, tagged
|
||||
from odoo.tools import convert_file
|
||||
|
||||
from .common import track_function
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class profile:
|
||||
def __init__(self, fname=None):
|
||||
warnings.warn("Since 16.0.", DeprecationWarning, stacklevel=2)
|
||||
self.fname = fname
|
||||
|
||||
def __call__(self, f):
|
||||
@wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
profile = cProfile.Profile()
|
||||
result = profile.runcall(f, *args, **kwargs)
|
||||
profile.dump_stats(self.fname or (f"{f.__name__}.cprof"))
|
||||
return result
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
# This tests will only be executed if --test-tags benchmark is defined
|
||||
@tagged("-standard", "benchmark")
|
||||
class BenchmarkTestCase(common.TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls._clean_existing_records()
|
||||
cls._setup_benchmark_data()
|
||||
|
||||
@classmethod
|
||||
def _clean_existing_records(cls):
|
||||
cls.env["dms.category"].search([]).sudo().unlink()
|
||||
cls.env["dms.directory"].search([]).sudo().unlink()
|
||||
cls.env["dms.storage"].search([]).sudo().unlink()
|
||||
cls.env["dms.tag"].search([]).sudo().unlink()
|
||||
|
||||
@classmethod
|
||||
def _load(cls, module, *args):
|
||||
path = str(os.path.join(module, *args))
|
||||
convert_file(cls.env, "dms", args[-1], {}, "init", False, "test", path)
|
||||
|
||||
@classmethod
|
||||
def _setup_benchmark_data(cls):
|
||||
cls._load("dms", "tests", "data", "dms.category.csv")
|
||||
cls._load("dms", "tests", "data", "dms.storage.csv")
|
||||
cls._load("dms", "tests", "data", "dms.tag.csv")
|
||||
cls._load("dms", "tests", "data", "dms.directory.csv")
|
||||
cls._load("dms", "tests", "data", "dms.file.csv")
|
||||
|
||||
def _benchmark_table(self, data):
|
||||
columns = len(data[0]) - 1
|
||||
formt = "{:7}" + "| {:28}" * columns
|
||||
|
||||
result = formt.format(*data[0]) + "\n"
|
||||
result += ("-" * 7) + (("+" + "-" * 29) * columns) + "\n"
|
||||
for row in data[1:]:
|
||||
result += formt.format(*row) + "\n"
|
||||
return result
|
||||
|
||||
def _benchmark_function(self, func, args_list):
|
||||
tfunc = track_function(return_tracking=True)(func)
|
||||
benchmark = []
|
||||
for item in args_list:
|
||||
self.registry.clear_all_caches()
|
||||
args = item[0] if len(item) > 0 else []
|
||||
kwargs = item[1] if len(item) > 1 else {}
|
||||
tracking = tuple(tfunc(*args, **kwargs)[1][1:])
|
||||
# pylint: disable=too-few-format-args
|
||||
# pyupgrade: disable=UP030
|
||||
benchmark.append("{}sq {:.3f}s {:.3f}s {:.3f}s".format(*tracking))
|
||||
return benchmark
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# File
|
||||
# ----------------------------------------------------------
|
||||
|
||||
def _file_kanban_fields(self):
|
||||
return [
|
||||
"id",
|
||||
"tag_ids",
|
||||
"name",
|
||||
"color",
|
||||
"active",
|
||||
"mimetype",
|
||||
"create_uid",
|
||||
"write_date",
|
||||
"locked_by",
|
||||
"is_locked",
|
||||
"is_lock_editor",
|
||||
"permission_write",
|
||||
"permission_unlink",
|
||||
]
|
||||
|
||||
def test_file_search_benchmark(self):
|
||||
demo_uid = self.browse_ref("base.user_demo").id
|
||||
admin_uid = self.browse_ref("base.user_admin").id
|
||||
model = self.env["dms.file"].with_context(bin_size=True)
|
||||
args = [
|
||||
[[[]], {"limit": 1}],
|
||||
[[[]], {"limit": 80}],
|
||||
[[[]], {"limit": 500}],
|
||||
[[[]]],
|
||||
]
|
||||
|
||||
benchmark_data_super = ["Super"] + self._benchmark_function(
|
||||
model.sudo().search, args
|
||||
)
|
||||
benchmark_data_admin = ["Admin"] + self._benchmark_function(
|
||||
model.with_user(admin_uid).search, args
|
||||
)
|
||||
benchmark_data_demo = ["Demo"] + self._benchmark_function(
|
||||
model.with_user(demo_uid).search, args
|
||||
)
|
||||
|
||||
info_message = "\n\nSearching files with bin_size = True | "
|
||||
info_message += "Benchmark with Limit 1 / 80 / 500 / None (1500)\n\n"
|
||||
info_message += self._benchmark_table(
|
||||
[
|
||||
[
|
||||
"User",
|
||||
"Search Limit 1",
|
||||
"Search Limit 80",
|
||||
"Search Limit 500",
|
||||
"Search No Limit",
|
||||
],
|
||||
benchmark_data_super,
|
||||
benchmark_data_admin,
|
||||
benchmark_data_demo,
|
||||
]
|
||||
)
|
||||
info_message += "\nLegend: Queries | Query Time | Server Time | Total Time\n"
|
||||
_logger.info(info_message)
|
||||
|
||||
def test_file_search_read_benchmark(self):
|
||||
demo_uid = self.browse_ref("base.user_demo").id
|
||||
admin_uid = self.browse_ref("base.user_admin").id
|
||||
model = self.env["dms.file"].with_context(bin_size=True)
|
||||
args = [[[], {"limit": 1}], [[], {"limit": 80}], [[], {"limit": 500}], [[]]]
|
||||
|
||||
benchmark_data_super = ["Super"] + self._benchmark_function(
|
||||
model.sudo().search_read, args
|
||||
)
|
||||
benchmark_data_admin = ["Admin"] + self._benchmark_function(
|
||||
model.with_user(admin_uid).search_read, args
|
||||
)
|
||||
benchmark_data_demo = ["Demo"] + self._benchmark_function(
|
||||
model.with_user(demo_uid).search_read, args
|
||||
)
|
||||
|
||||
info_message = "\n\nSearching and reading all fields with bin_size = True | "
|
||||
info_message += "Benchmark with Limit 1 / 80 / 500 / None (1500)\n\n"
|
||||
info_message += self._benchmark_table(
|
||||
[
|
||||
[
|
||||
"User",
|
||||
"Search Limit 1",
|
||||
"Search Limit 80",
|
||||
"Search Limit 500",
|
||||
"Search No Limit",
|
||||
],
|
||||
benchmark_data_super,
|
||||
benchmark_data_admin,
|
||||
benchmark_data_demo,
|
||||
]
|
||||
)
|
||||
info_message += "\nLegend: Queries | Query Time | Server Time | Total Time\n"
|
||||
_logger.info(info_message)
|
||||
|
||||
def test_file_search_name_get_benchmark(self):
|
||||
demo_uid = self.browse_ref("base.user_demo").id
|
||||
admin_uid = self.browse_ref("base.user_admin").id
|
||||
model = self.env["dms.file"].with_context(bin_size=True)
|
||||
|
||||
def test_function(model, limit):
|
||||
return model.search([], limit=limit).mapped("display_name")
|
||||
|
||||
model_super = model.sudo()
|
||||
model_admin = model.with_user(admin_uid)
|
||||
model_demo = model.with_user(demo_uid)
|
||||
args_super = [
|
||||
[[model_super, 1]],
|
||||
[[model_super, 800]],
|
||||
[[model_super, 500]],
|
||||
[[model_super, None]],
|
||||
]
|
||||
args_admin = [
|
||||
[[model_admin, 1]],
|
||||
[[model_admin, 800]],
|
||||
[[model_admin, 500]],
|
||||
[[model_admin, None]],
|
||||
]
|
||||
args_demo = [
|
||||
[[model_demo, 1]],
|
||||
[[model_demo, 800]],
|
||||
[[model_demo, 500]],
|
||||
[[model_demo, None]],
|
||||
]
|
||||
|
||||
benchmark_data_super = ["Super"] + self._benchmark_function(
|
||||
test_function, args_super
|
||||
)
|
||||
benchmark_data_admin = ["Admin"] + self._benchmark_function(
|
||||
test_function, args_admin
|
||||
)
|
||||
benchmark_data_demo = ["Demo"] + self._benchmark_function(
|
||||
test_function, args_demo
|
||||
)
|
||||
|
||||
info_message = (
|
||||
"\n\nSearching and 'display_name' function with bin_size = True | "
|
||||
)
|
||||
info_message += "Benchmark with Limit 1 / 80 / 500 / None (1500)\n\n"
|
||||
info_message += self._benchmark_table(
|
||||
[
|
||||
[
|
||||
"User",
|
||||
"Search Limit 1",
|
||||
"Search Limit 80",
|
||||
"Search Limit 500",
|
||||
"Search No Limit",
|
||||
],
|
||||
benchmark_data_super,
|
||||
benchmark_data_admin,
|
||||
benchmark_data_demo,
|
||||
]
|
||||
)
|
||||
info_message += "\nLegend: Queries | Query Time | Server Time | Total Time\n"
|
||||
_logger.info(info_message)
|
||||
|
||||
def test_file_kanban_backend_benchmark(self):
|
||||
demo_uid = self.browse_ref("base.user_demo").id
|
||||
admin_uid = self.browse_ref("base.user_admin").id
|
||||
model = self.env["dms.file"].with_context(bin_size=True)
|
||||
kanban_fields = self._file_kanban_fields()
|
||||
|
||||
def test_function(model, kanban_fields, limit=80):
|
||||
model.search_panel_select_range("directory_id")
|
||||
model.search_panel_select_multi_range("directory_id")
|
||||
model.search_panel_select_multi_range("tag_ids")
|
||||
model.search_read(fields=kanban_fields, limit=limit)
|
||||
|
||||
def function_args(args, kwargs):
|
||||
return [[args, {"limit": arg}] for arg in kwargs]
|
||||
|
||||
args_super = function_args([model.sudo(), kanban_fields], [1, 80, 500, None])
|
||||
args_admin = function_args(
|
||||
[model.with_user(admin_uid), kanban_fields], [1, 80, 500, None]
|
||||
)
|
||||
args_demo = function_args(
|
||||
[model.with_user(demo_uid), kanban_fields], [1, 80, 500, None]
|
||||
)
|
||||
|
||||
benchmark_data_super = ["Super"] + self._benchmark_function(
|
||||
test_function, args_super
|
||||
)
|
||||
benchmark_data_admin = ["Admin"] + self._benchmark_function(
|
||||
test_function, args_admin
|
||||
)
|
||||
benchmark_data_demo = ["Demo"] + self._benchmark_function(
|
||||
test_function, args_demo
|
||||
)
|
||||
|
||||
info_message = "\n\nSimulate kanban view loading on the backend | "
|
||||
info_message += "Benchmark with Limit 1 / 80 / 500 / None (1500)\n\n"
|
||||
info_message += self._benchmark_table(
|
||||
[
|
||||
[
|
||||
"User",
|
||||
"Search Limit 1",
|
||||
"Search Limit 80",
|
||||
"Search Limit 500",
|
||||
"Search No Limit",
|
||||
],
|
||||
benchmark_data_super,
|
||||
benchmark_data_admin,
|
||||
benchmark_data_demo,
|
||||
]
|
||||
)
|
||||
info_message += "\nLegend: Queries | Query Time | Server Time | Total Time || "
|
||||
info_message += "500 Directories | 150 Tags | 50 Categories\n"
|
||||
_logger.info(info_message)
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Directory
|
||||
# ----------------------------------------------------------
|
||||
|
||||
def test_directory_search_benchmark(self):
|
||||
demo_uid = self.browse_ref("base.user_demo").id
|
||||
admin_uid = self.browse_ref("base.user_admin").id
|
||||
model = self.env["dms.directory"].with_context(bin_size=True)
|
||||
args = [
|
||||
[[[]], {"limit": 1}],
|
||||
[[[]], {"limit": 80}],
|
||||
[[[]], {"limit": 500}],
|
||||
[[[]]],
|
||||
]
|
||||
|
||||
benchmark_data_super = ["Super"] + self._benchmark_function(
|
||||
model.sudo().search, args
|
||||
)
|
||||
benchmark_data_admin = ["Admin"] + self._benchmark_function(
|
||||
model.with_user(admin_uid).search, args
|
||||
)
|
||||
benchmark_data_demo = ["Demo"] + self._benchmark_function(
|
||||
model.with_user(demo_uid).search, args
|
||||
)
|
||||
|
||||
info_message = "\n\nSearching directories with bin_size = True | "
|
||||
info_message += "Benchmark with Limit 1 / 80 / 500 / None (1500)\n\n"
|
||||
info_message += self._benchmark_table(
|
||||
[
|
||||
[
|
||||
"User",
|
||||
"Search Limit 1",
|
||||
"Search Limit 80",
|
||||
"Search Limit 500",
|
||||
"Search No Limit",
|
||||
],
|
||||
benchmark_data_super,
|
||||
benchmark_data_admin,
|
||||
benchmark_data_demo,
|
||||
]
|
||||
)
|
||||
info_message += "\nLegend: Queries | Query Time | Server Time | Total Time\n"
|
||||
_logger.info(info_message)
|
||||
|
||||
def test_directory_search_read_benchmark(self):
|
||||
demo_uid = self.browse_ref("base.user_demo").id
|
||||
admin_uid = self.browse_ref("base.user_admin").id
|
||||
model = self.env["dms.directory"].with_context(bin_size=True)
|
||||
args = [[[], {"limit": 1}], [[], {"limit": 80}], [[], {"limit": 500}], [[]]]
|
||||
|
||||
benchmark_data_super = ["Super"] + self._benchmark_function(
|
||||
model.sudo().search_read, args
|
||||
)
|
||||
benchmark_data_admin = ["Admin"] + self._benchmark_function(
|
||||
model.with_user(admin_uid).search_read, args
|
||||
)
|
||||
benchmark_data_demo = ["Demo"] + self._benchmark_function(
|
||||
model.with_user(demo_uid).search_read, args
|
||||
)
|
||||
|
||||
info_message = "\n\nSearching and reading all fields with bin_size = True | "
|
||||
info_message += "Benchmark with Limit 1 / 80 / 500 / None (1500)\n\n"
|
||||
info_message += self._benchmark_table(
|
||||
[
|
||||
[
|
||||
"User",
|
||||
"Search Limit 1",
|
||||
"Search Limit 80",
|
||||
"Search Limit 500",
|
||||
"Search No Limit",
|
||||
],
|
||||
benchmark_data_super,
|
||||
benchmark_data_admin,
|
||||
benchmark_data_demo,
|
||||
]
|
||||
)
|
||||
info_message += "\nLegend: Queries | Query Time | Server Time | Total Time\n"
|
||||
_logger.info(info_message)
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Profiler
|
||||
# ----------------------------------------------------------
|
||||
|
||||
@unittest.skip("Takes to long to be tested every time.")
|
||||
def test_file_search_read_profile_admin(self):
|
||||
@track_function()
|
||||
@profile(minimum_queries=35)
|
||||
def profile_function(model):
|
||||
model.search_read([])
|
||||
|
||||
admin_uid = self.browse_ref("base.user_admin").id
|
||||
model = self.env["dms.file"].with_user(admin_uid)
|
||||
profile_function(model.with_context(bin_size=True))
|
||||
Reference in New Issue
Block a user