Skip to content

Commit 0588334

Browse files
committed
Use pre-parsed/validated queries in social network benchmark
Pre-parse and pre-validate all queries at module load time so benchmarks measure only execution time, not parsing or validation. This gives cleaner execution-only measurements: - simple: 1.13ms -> 0.18ms (was 84% validation) - complex: 5.64ms -> 3.51ms (was 38% validation) - feed: 7.75ms -> 6.37ms (was 18% validation)
1 parent ef4d669 commit 0588334

File tree

1 file changed

+37
-13
lines changed

1 file changed

+37
-13
lines changed

tests/benchmarks/test_social_network.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
- List fields with multiple items
66
- All async resolvers to test the async execution path
77
- Various query depths and breadths
8+
9+
Queries are pre-parsed and pre-validated to measure only execution time.
810
"""
911

1012
import asyncio
@@ -13,6 +15,7 @@
1315
import pytest
1416

1517
from graphql import (
18+
DocumentNode,
1619
GraphQLArgument,
1720
GraphQLField,
1821
GraphQLInt,
@@ -21,7 +24,9 @@
2124
GraphQLObjectType,
2225
GraphQLSchema,
2326
GraphQLString,
24-
graphql,
27+
execute,
28+
parse,
29+
validate,
2530
)
2631

2732
# Simulated data store
@@ -419,6 +424,25 @@ async def resolve_updated_at(obj: dict, _info: Any) -> str:
419424
"""
420425

421426

427+
def _prepare_query(query_str: str) -> DocumentNode:
428+
"""Parse and validate a query, returning the document for execution."""
429+
document = parse(query_str)
430+
errors = validate(schema, document)
431+
if errors:
432+
raise ValueError(f"Query validation failed: {errors}")
433+
return document
434+
435+
436+
# Pre-parse and pre-validate all queries at module load time
437+
# This ensures benchmarks measure only execution time
438+
DOC_SIMPLE = _prepare_query(QUERY_SIMPLE)
439+
DOC_MEDIUM = _prepare_query(QUERY_MEDIUM)
440+
DOC_COMPLEX = _prepare_query(QUERY_COMPLEX)
441+
DOC_FEED = _prepare_query(QUERY_FEED)
442+
DOC_SOCIAL = _prepare_query(QUERY_SOCIAL)
443+
DOC_DEEP = _prepare_query(QUERY_DEEP)
444+
445+
422446
@pytest.fixture
423447
def event_loop():
424448
"""Create event loop for async benchmarks."""
@@ -428,49 +452,49 @@ def event_loop():
428452

429453

430454
def test_social_simple(benchmark, event_loop):
431-
"""Benchmark simple user query with 4 scalar fields."""
455+
"""Benchmark simple user query with 4 scalar fields (execution only)."""
432456
asyncio.set_event_loop(event_loop)
433-
result = benchmark(lambda: event_loop.run_until_complete(graphql(schema, QUERY_SIMPLE)))
457+
result = benchmark(lambda: event_loop.run_until_complete(execute(schema, DOC_SIMPLE)))
434458
assert not result.errors
435459
assert result.data["user"]["username"] == "user_1"
436460

437461

438462
def test_social_medium(benchmark, event_loop):
439-
"""Benchmark user with posts (5 posts, 5 fields each)."""
463+
"""Benchmark user with posts - 5 posts, 5 fields each (execution only)."""
440464
asyncio.set_event_loop(event_loop)
441-
result = benchmark(lambda: event_loop.run_until_complete(graphql(schema, QUERY_MEDIUM)))
465+
result = benchmark(lambda: event_loop.run_until_complete(execute(schema, DOC_MEDIUM)))
442466
assert not result.errors
443467
assert len(result.data["user"]["posts"]) == 5
444468

445469

446470
def test_social_complex(benchmark, event_loop):
447-
"""Benchmark complex nested query (user -> posts -> comments -> authors)."""
471+
"""Benchmark complex nested query - user -> posts -> comments -> authors (execution only)."""
448472
asyncio.set_event_loop(event_loop)
449-
result = benchmark(lambda: event_loop.run_until_complete(graphql(schema, QUERY_COMPLEX)))
473+
result = benchmark(lambda: event_loop.run_until_complete(execute(schema, DOC_COMPLEX)))
450474
assert not result.errors
451475
assert len(result.data["user"]["posts"]) == 5
452476

453477

454478
def test_social_feed(benchmark, event_loop):
455-
"""Benchmark feed query (10 posts with authors and comments)."""
479+
"""Benchmark feed query - 10 posts with authors and comments (execution only)."""
456480
asyncio.set_event_loop(event_loop)
457-
result = benchmark(lambda: event_loop.run_until_complete(graphql(schema, QUERY_FEED)))
481+
result = benchmark(lambda: event_loop.run_until_complete(execute(schema, DOC_FEED)))
458482
assert not result.errors
459483
assert len(result.data["posts"]) == 10
460484

461485

462486
def test_social_network(benchmark, event_loop):
463-
"""Benchmark social graph query (user with followers and following)."""
487+
"""Benchmark social graph query - user with followers and following (execution only)."""
464488
asyncio.set_event_loop(event_loop)
465-
result = benchmark(lambda: event_loop.run_until_complete(graphql(schema, QUERY_SOCIAL)))
489+
result = benchmark(lambda: event_loop.run_until_complete(execute(schema, DOC_SOCIAL)))
466490
assert not result.errors
467491
assert len(result.data["user"]["followers"]) == 5
468492
assert len(result.data["user"]["following"]) == 5
469493

470494

471495
def test_social_deep(benchmark, event_loop):
472-
"""Benchmark deeply nested query (4 levels deep)."""
496+
"""Benchmark deeply nested query - 4 levels deep (execution only)."""
473497
asyncio.set_event_loop(event_loop)
474-
result = benchmark(lambda: event_loop.run_until_complete(graphql(schema, QUERY_DEEP)))
498+
result = benchmark(lambda: event_loop.run_until_complete(execute(schema, DOC_DEEP)))
475499
assert not result.errors
476500
assert len(result.data["user"]["posts"]) == 3

0 commit comments

Comments
 (0)