From 7afc90e2ad8bdffd68b2221f816b53a37eb3cf73 Mon Sep 17 00:00:00 2001 From: He Date: Fri, 3 Jan 2025 11:43:55 +0100 Subject: [PATCH] Add more Codspeed benchmarks (#1834) * Add test_filter_many_filters benchmark * Add bulk_create benchmarks --- .github/workflows/codspeed.yml | 2 +- tests/benchmarks/conftest.py | 86 ++++++++++++++------------ tests/benchmarks/test_bulk_create.py | 35 +++++++++++ tests/benchmarks/test_create.py | 40 +----------- tests/benchmarks/test_filter.py | 24 ++++++- tests/schema/models_postgres_fields.py | 2 +- tortoise/backends/asyncpg/client.py | 2 +- tortoise/backends/mysql/client.py | 2 +- tortoise/backends/odbc/client.py | 2 +- tortoise/backends/sqlite/client.py | 2 +- 10 files changed, 112 insertions(+), 85 deletions(-) create mode 100644 tests/benchmarks/test_bulk_create.py diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml index c2a1e41b3..8c84fe0e3 100644 --- a/.github/workflows/codspeed.yml +++ b/.github/workflows/codspeed.yml @@ -3,7 +3,7 @@ name: CodSpeed on: push: branches: - - main + - develop pull_request: # `workflow_dispatch` allows CodSpeed to trigger backtest # performance analysis in order to generate initial data. diff --git a/tests/benchmarks/conftest.py b/tests/benchmarks/conftest.py index a5de8a443..62becb238 100644 --- a/tests/benchmarks/conftest.py +++ b/tests/benchmarks/conftest.py @@ -1,8 +1,8 @@ from __future__ import annotations import asyncio -from decimal import Decimal import random +from decimal import Decimal import pytest @@ -36,48 +36,54 @@ async def _create() -> list[BenchmarkFewFields]: @pytest.fixture -def many_fields_benchmark_dataset() -> list[BenchmarkManyFields]: +def many_fields_benchmark_dataset(gen_many_fields_data) -> list[BenchmarkManyFields]: async def _create() -> list[BenchmarkManyFields]: res = [] for _ in range(100): - res.append( - await BenchmarkManyFields.create( - level=random.randint(0, 100), # nosec - text="test", - col_float1=2.2, - col_smallint1=2, - col_int1=2000000, - col_bigint1=99999999, - col_char1="value1", - col_text1="Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa", - col_decimal1=Decimal("2.2"), - col_json1={"a": 1, "b": "b", "c": [2], "d": {"e": 3}, "f": True}, - col_float2=0.2, - col_smallint2=None, - col_int2=22, - col_bigint2=None, - col_char2=None, - col_text2=None, - col_decimal2=None, - col_json2=None, - col_float3=2.2, - col_smallint3=2, - col_int3=2000000, - col_bigint3=99999999, - col_char3="value1", - col_text3="Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa", - col_decimal3=Decimal("2.2"), - col_json3={"a": 1, "b": 2, "c": [2]}, - col_float4=0.00004, - col_smallint4=None, - col_int4=4, - col_bigint4=99999999000000, - col_char4="value4", - col_text4="AAAAAAAA", - col_decimal4=None, - col_json4=None, - ) - ) + res.append(await BenchmarkManyFields.create(**gen_many_fields_data())) return res return asyncio.get_event_loop().run_until_complete(_create()) + + +@pytest.fixture +def gen_many_fields_data(): + def _gen(): + return { + "level": random.randint(0, 100), # nosec + "text": "test", + "col_float1": 2.2, + "col_smallint1": 2, + "col_int1": 2000000, + "col_bigint1": 99999999, + "col_char1": "value1", + "col_text1": "Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa", + "col_decimal1": Decimal("2.2"), + "col_json1": {"a": 1, "b": "b", "c": [2], "d": {"e": 3}, "f": True}, + "col_float2": 0.2, + "col_smallint2": None, + "col_int2": 22, + "col_bigint2": None, + "col_char2": None, + "col_text2": None, + "col_decimal2": None, + "col_json2": None, + "col_float3": 2.2, + "col_smallint3": 2, + "col_int3": 2000000, + "col_bigint3": 99999999, + "col_char3": "value1", + "col_text3": "Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa", + "col_decimal3": Decimal("2.2"), + "col_json3": {"a": 1, "b": 2, "c": [2]}, + "col_float4": 0.00004, + "col_smallint4": None, + "col_int4": 4, + "col_bigint4": 99999999000000, + "col_char4": "value4", + "col_text4": "AAAAAAAA", + "col_decimal4": None, + "col_json4": None, + } + + return _gen diff --git a/tests/benchmarks/test_bulk_create.py b/tests/benchmarks/test_bulk_create.py new file mode 100644 index 000000000..bca894009 --- /dev/null +++ b/tests/benchmarks/test_bulk_create.py @@ -0,0 +1,35 @@ +import asyncio +import random + +from tests.testmodels import BenchmarkFewFields, BenchmarkManyFields + + +def test_bulk_create_few_fields(benchmark): + loop = asyncio.get_event_loop() + + data = [ + BenchmarkFewFields( + level=random.choice([10, 20, 30, 40, 50]), text=f"Insert from C, item {i}" # nosec + ) + for i in range(100) + ] + + @benchmark + def bench(): + async def _bench(): + await BenchmarkFewFields.bulk_create(data) + + loop.run_until_complete(_bench()) + + +def test_bulk_create_many_fields(benchmark, gen_many_fields_data): + loop = asyncio.get_event_loop() + + data = [BenchmarkManyFields(**gen_many_fields_data()) for _ in range(100)] + + @benchmark + def bench(): + async def _bench(): + await BenchmarkManyFields.bulk_create(data) + + loop.run_until_complete(_bench()) diff --git a/tests/benchmarks/test_create.py b/tests/benchmarks/test_create.py index ed430707d..167d6b57a 100644 --- a/tests/benchmarks/test_create.py +++ b/tests/benchmarks/test_create.py @@ -1,5 +1,4 @@ import asyncio -from decimal import Decimal import random from tests.testmodels import BenchmarkFewFields, BenchmarkManyFields @@ -17,47 +16,12 @@ async def _bench(): loop.run_until_complete(_bench()) -def test_create_many_fields(benchmark): +def test_create_many_fields(benchmark, gen_many_fields_data): loop = asyncio.get_event_loop() @benchmark def bench(): async def _bench(): - await BenchmarkManyFields.create( - level=random.randint(0, 100), # nosec - text="test", - col_float1=2.2, - col_smallint1=2, - col_int1=2000000, - col_bigint1=99999999, - col_char1="value1", - col_text1="Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa", - col_decimal1=Decimal("2.2"), - col_json1={"a": 1, "b": "b", "c": [2], "d": {"e": 3}, "f": True}, - col_float2=0.2, - col_smallint2=None, - col_int2=22, - col_bigint2=None, - col_char2=None, - col_text2=None, - col_decimal2=None, - col_json2=None, - col_float3=2.2, - col_smallint3=2, - col_int3=2000000, - col_bigint3=99999999, - col_char3="value1", - col_text3="Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa", - col_decimal3=Decimal("2.2"), - col_json3={"a": 1, "b": 2, "c": [2]}, - col_float4=0.00004, - col_smallint4=None, - col_int4=4, - col_bigint4=99999999000000, - col_char4="value4", - col_text4="AAAAAAAA", - col_decimal4=None, - col_json4=None, - ) + await BenchmarkManyFields.create(**gen_many_fields_data()) loop.run_until_complete(_bench()) diff --git a/tests/benchmarks/test_filter.py b/tests/benchmarks/test_filter.py index 06c39b7cc..dd304a04f 100644 --- a/tests/benchmarks/test_filter.py +++ b/tests/benchmarks/test_filter.py @@ -1,7 +1,8 @@ import asyncio import random +from decimal import Decimal -from tests.testmodels import BenchmarkFewFields +from tests.testmodels import BenchmarkFewFields, BenchmarkManyFields def test_filter_few_fields(benchmark, few_fields_benchmark_dataset): @@ -14,3 +15,24 @@ async def _bench(): await BenchmarkFewFields.filter(level__in=random.sample(levels, 5)).limit(5) loop.run_until_complete(_bench()) + + +def test_filter_many_filters(benchmark, many_fields_benchmark_dataset): + loop = asyncio.get_event_loop() + levels = list(set([o.level for o in many_fields_benchmark_dataset])) + + @benchmark + def bench(): + async def _bench(): + await BenchmarkManyFields.filter( + level__in=random.sample(levels, 5), + col_float1__gt=0, + col_smallint1=2, + col_int1__lt=2000001, + col_bigint1__in=[99999999], + col_char1__contains="value1", + col_text1="Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa,Moo,Foo,Baa,Waa", + col_decimal1=Decimal("2.2"), + ).limit(5) + + loop.run_until_complete(_bench()) diff --git a/tests/schema/models_postgres_fields.py b/tests/schema/models_postgres_fields.py index ea49359c7..89ff9fb53 100644 --- a/tests/schema/models_postgres_fields.py +++ b/tests/schema/models_postgres_fields.py @@ -1,5 +1,5 @@ from tortoise import Model -from tortoise.contrib.postgres.fields import TSVectorField, ArrayField +from tortoise.contrib.postgres.fields import ArrayField, TSVectorField class PostgresFields(Model): diff --git a/tortoise/backends/asyncpg/client.py b/tortoise/backends/asyncpg/client.py index 423e5e0c8..165ce2230 100644 --- a/tortoise/backends/asyncpg/client.py +++ b/tortoise/backends/asyncpg/client.py @@ -7,9 +7,9 @@ from tortoise.backends.asyncpg.executor import AsyncpgExecutor from tortoise.backends.asyncpg.schema_generator import AsyncpgSchemaGenerator from tortoise.backends.base.client import ( - TransactionalDBClient, ConnectionWrapper, NestedTransactionContext, + TransactionalDBClient, TransactionContext, TransactionContextPooled, ) diff --git a/tortoise/backends/mysql/client.py b/tortoise/backends/mysql/client.py index 983a1f969..4c034937f 100644 --- a/tortoise/backends/mysql/client.py +++ b/tortoise/backends/mysql/client.py @@ -29,11 +29,11 @@ from tortoise import timezone from tortoise.backends.base.client import ( BaseDBAsyncClient, - TransactionalDBClient, Capabilities, ConnectionWrapper, NestedTransactionContext, PoolConnectionWrapper, + TransactionalDBClient, TransactionContext, TransactionContextPooled, ) diff --git a/tortoise/backends/odbc/client.py b/tortoise/backends/odbc/client.py index 79d1db0e1..f9c8a6173 100644 --- a/tortoise/backends/odbc/client.py +++ b/tortoise/backends/odbc/client.py @@ -8,10 +8,10 @@ from tortoise import BaseDBAsyncClient from tortoise.backends.base.client import ( - TransactionalDBClient, ConnectionWrapper, NestedTransactionContext, PoolConnectionWrapper, + TransactionalDBClient, TransactionContext, ) from tortoise.backends.odbc.executor import ODBCExecutor diff --git a/tortoise/backends/sqlite/client.py b/tortoise/backends/sqlite/client.py index b56fc88c9..870dc9657 100644 --- a/tortoise/backends/sqlite/client.py +++ b/tortoise/backends/sqlite/client.py @@ -20,11 +20,11 @@ from tortoise.backends.base.client import ( BaseDBAsyncClient, - TransactionalDBClient, Capabilities, ConnectionWrapper, NestedTransactionContext, T_conn, + TransactionalDBClient, TransactionContext, ) from tortoise.backends.sqlite.executor import SqliteExecutor