Skip to content

Commit e3440af

Browse files
committed
Implement profiling and caching utilities for performance optimization
- Introduced `profiling` module with tools for benchmarking, profiling queries, and test suite performance. - Added `cache.py` for element and role caching with statistics and context management. - Enhanced `queries.py` to integrate caching for ARIA role retrieval and optimize query functions. - Updated `Justfile` with new commands: `benchmark`, `benchmark-cache`, `profile-queries`, and `profile-tests`.
1 parent 0fd97ca commit e3440af

14 files changed

Lines changed: 1488 additions & 150 deletions

Justfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,19 @@ enable-pre-push:
8181
disable-pre-push:
8282
@chmod -x .git/hooks/pre-push 2>/dev/null || true
8383
@echo "Pre-push hook disabled. Use 'just enable-pre-push' to re-enable."
84+
85+
# Run performance benchmark
86+
benchmark:
87+
uv run python -m aria_testing.profiling.benchmark
88+
89+
# Run caching performance benchmark
90+
benchmark-cache:
91+
uv run python -m aria_testing.profiling.benchmark_caching
92+
93+
# Profile query operations
94+
profile-queries:
95+
uv run python -m aria_testing.profiling.profiler_queries
96+
97+
# Profile test suite
98+
profile-tests:
99+
uv run python -m aria_testing.profiling.profiler_tests

README.md

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,50 @@ Built with cutting-edge Python 3.14+ features:
131131

132132
## Performance
133133

134-
aria-testing is optimized for speed:
134+
aria-testing is highly optimized for speed with multiple performance strategies:
135135

136-
- **Cached role mappings** - Zero allocation overhead for role lookups
136+
### Optimization Techniques
137+
138+
- **Two-level caching** - Element list and role computation caching
139+
- **Early-exit strategies** - Stops searching after finding matches
140+
- **Iterative traversal** - Non-recursive DOM traversal for large trees
141+
- **String interning** - Fast identity-based comparisons for common roles
137142
- **Set-based class matching** - O(1) instead of O(n) for class queries
138-
- **Early-exit strategies** - Stops searching after finding first match when possible
139-
- **Efficient traversal** - Modern pattern matching avoids type checks
140143

141-
144 tests complete in 0.07 seconds ⚡
144+
### Benchmark Results
145+
146+
*Measured on December 6, 2024 - Apple M-series CPU, Python 3.14*
147+
148+
**Test Suite Performance**:
149+
- 154 tests complete in **0.07 seconds**
150+
151+
**Query Performance** (200-element DOM, 100 iterations per query):
152+
153+
| Query Type | Without Caching | With Caching | Speedup |
154+
|------------|----------------|--------------|---------|
155+
| Role queries | 4.1μs | 1.7μs | **2.4x faster** |
156+
| Text queries | 13.4μs | 10.8μs | **1.2x faster** |
157+
| Class queries | 3.2μs | 0.8μs | **4.1x faster** |
158+
| Tag queries | 3.2μs | 3.1μs | **1.0x faster** |
159+
| **Average** | **5.6μs** | **3.6μs** | **1.55x faster** |
160+
161+
**Cache Efficiency**:
162+
- Element list cache: **99.8% hit rate**
163+
- Role cache: **99.5% hit rate**
164+
165+
*Run benchmarks yourself*:
166+
```bash
167+
just benchmark # General performance
168+
just benchmark-cache # Caching comparison
169+
```
170+
171+
### Performance Tips
172+
173+
1. **Reuse containers** - Query the same DOM multiple times to benefit from caching
174+
2. **Use appropriate queries** - `query_all_*` gets full caching benefits
175+
3. **Let caching work** - Caches auto-clear between pytest tests
176+
177+
See `CACHING_IMPLEMENTATION.md` for detailed performance analysis.
142178

143179
## Requirements
144180

src/aria_testing/__init__.py

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,47 @@
66
"The more your tests resemble the way your software is used, the more confidence they can give you."
77
"""
88

9+
from .cache import (
10+
CacheContext,
11+
clear_all_caches,
12+
get_cache_stats,
13+
print_cache_stats,
14+
)
15+
from .errors import AriaTestingLibraryError, ElementNotFoundError, MultipleElementsError
916
from .queries import (
10-
get_by_text,
11-
query_by_text,
12-
get_all_by_text,
13-
query_all_by_text,
14-
get_by_test_id,
15-
query_by_test_id,
16-
get_all_by_test_id,
17-
query_all_by_test_id,
18-
get_by_role,
19-
query_by_role,
17+
AriaRole,
18+
Container,
19+
get_all_by_class,
20+
get_all_by_label_text,
2021
get_all_by_role,
21-
query_all_by_role,
22+
get_all_by_tag_name,
23+
get_all_by_test_id,
24+
get_all_by_text,
25+
get_by_class,
26+
get_by_id,
2227
get_by_label_text,
23-
query_by_label_text,
24-
get_all_by_label_text,
25-
query_all_by_label_text,
28+
get_by_role,
2629
get_by_tag_name,
27-
query_by_tag_name,
28-
get_all_by_tag_name,
30+
get_by_test_id,
31+
get_by_text,
32+
query_all_by_class,
33+
query_all_by_label_text,
34+
query_all_by_role,
2935
query_all_by_tag_name,
30-
get_by_id,
31-
query_by_id,
32-
get_by_class,
36+
query_all_by_test_id,
37+
query_all_by_text,
3338
query_by_class,
34-
get_all_by_class,
35-
query_all_by_class,
36-
# Type exports
37-
AriaRole,
38-
Container,
39+
query_by_id,
40+
query_by_label_text,
41+
query_by_role,
42+
query_by_tag_name,
43+
query_by_test_id,
44+
query_by_text,
3945
)
4046
from .utils import get_text_content, normalize_text
41-
from .errors import AriaTestingLibraryError, ElementNotFoundError, MultipleElementsError
4247

4348
__all__ = [
49+
# Query functions
4450
"get_by_text",
4551
"query_by_text",
4652
"get_all_by_text",
@@ -67,11 +73,18 @@
6773
"query_by_class",
6874
"get_all_by_class",
6975
"query_all_by_class",
76+
# Utilities
7077
"get_text_content",
7178
"normalize_text",
79+
# Errors
7280
"AriaTestingLibraryError",
7381
"ElementNotFoundError",
7482
"MultipleElementsError",
83+
# Cache management
84+
"CacheContext",
85+
"clear_all_caches",
86+
"get_cache_stats",
87+
"print_cache_stats",
7588
# Type exports
7689
"AriaRole",
7790
"Container",

0 commit comments

Comments
 (0)