""" Benchmark for cache key computation in odoo/tools/cache.py Focuses on the determine_key() and key() methods which are pure Python. """ import time from inspect import Parameter, signature # Simulate the key computation logic from ormcache def build_cache_key_eval(method, cache_args): """Current implementation using eval - generates lambda from string""" args = ", ".join( str(params.replace(annotation=Parameter.empty)) for params in signature(method).parameters.values() ) values = ["self._name", "method", *cache_args] code = ( f"lambda {args}: ({''.join(a for arg in values for a in (arg, ','))})" ) return eval(code, {"method": method}) # Test methods with various signatures class MockModel: _name = "test.model" def simple_method(self, arg1, arg2): return arg1 + arg2 def complex_method(self, model_name, mode="read", limit=None, offset=0): return f"{model_name}:{mode}:{limit}:{offset}" def many_args_method(self, a, b, c, d, e, f, g, h): return sum([a, b, c, d, e, f, g, h]) def benchmark_key_computation(): """Benchmark the key computation overhead""" model = MockModel() print("=== Cache Key Computation Benchmark ===\n") # Scenario 1: Simple method, many lookups print("Scenario 1: Simple method (2 args), 100k lookups") key_func = build_cache_key_eval(MockModel.simple_method, ["arg1", "arg2"]) start = time.perf_counter() for i in range(100_000): _ = key_func(model, i, i * 2) elapsed = time.perf_counter() - start print(f" Total: {elapsed:.3f}s") print(f" Per call: {elapsed / 100_000 * 1e6:.2f} µs\n") # Scenario 2: Complex method with defaults, many lookups print("Scenario 2: Complex method (4 args with defaults), 100k lookups") key_func = build_cache_key_eval( MockModel.complex_method, ["model_name", "mode", "limit", "offset"] ) start = time.perf_counter() for i in range(100_000): _ = key_func(model, "res.partner", "read", 10, i) elapsed = time.perf_counter() - start print(f" Total: {elapsed:.3f}s") print(f" Per call: {elapsed / 100_000 * 1e6:.2f} µs\n") # Scenario 3: Many args method print("Scenario 3: Many args method (8 args), 100k lookups") key_func = build_cache_key_eval( MockModel.many_args_method, ["a", "b", "c", "d", "e", "f", "g", "h"] ) start = time.perf_counter() for i in range(100_000): _ = key_func(model, 1, 2, 3, 4, 5, 6, 7, 8) elapsed = time.perf_counter() - start print(f" Total: {elapsed:.3f}s") print(f" Per call: {elapsed / 100_000 * 1e6:.2f} µs\n") # Scenario 4: Key function creation overhead print("Scenario 4: Key function creation (determine_key), 10k methods") start = time.perf_counter() for i in range(10_000): _ = build_cache_key_eval(MockModel.simple_method, ["arg1", "arg2"]) elapsed = time.perf_counter() - start print(f" Total: {elapsed:.3f}s") print(f" Per call: {elapsed / 10_000 * 1e6:.2f} µs\n") if __name__ == "__main__": benchmark_key_computation()