Skip to content

Commit 12dc2fc

Browse files
authored
Tune cache (#73)
* +--------------------+-----------+-----------+-----------+---------+ | Case | A ns/call | B ns/call | Delta ns | Speedup | +--------------------+-----------+-----------+-----------+---------+ | ext_compile_cached | 264.1 | 172.9 | -91.2 | 1.53x | | ext_match_module | 454.0 | 351.3 | -102.7 | 1.29x | +--------------------+-----------+-----------+-----------+---------+ * 0.2.12 version update
1 parent b02415c commit 12dc2fc

6 files changed

Lines changed: 27 additions & 37 deletions

File tree

pcre/cache.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@ def __init__(self) -> None:
4848
_THREAD_LOCAL = _ThreadCacheState()
4949
_GLOBAL_STATE = _GlobalCacheState()
5050
_CACHE_STRATEGY = _CacheStrategy.THREAD_LOCAL
51-
_CACHE_STRATEGY_LOCKED = False
52-
53-
54-
def _lock_cache_strategy() -> None:
55-
global _CACHE_STRATEGY_LOCKED
56-
if not _CACHE_STRATEGY_LOCKED:
57-
_CACHE_STRATEGY_LOCKED = True
5851

5952

6053
def _normalize_strategy(value: str) -> _CacheStrategy:
@@ -178,8 +171,6 @@ def cached_compile(
178171
) -> T:
179172
"""Compile *pattern* with *flags*, caching wrapper results when hashable."""
180173

181-
_lock_cache_strategy()
182-
183174
if _CACHE_STRATEGY is _CacheStrategy.THREAD_LOCAL:
184175
return _cached_compile_thread_local(pattern, flags, wrapper, jit=jit)
185176
return _cached_compile_global(pattern, flags, wrapper, jit=jit)

pcre/pcre.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,31 @@ def parallel_map(
473473

474474

475475
def compile(pattern: Any, flags: FlagInput = 0) -> Pattern:
476+
# Fast path for the dominant shape: compile(pattern) with default flags.
477+
if flags == 0:
478+
if isinstance(pattern, Pattern):
479+
return pattern
480+
481+
if isinstance(pattern, _CPattern):
482+
wrapper = Pattern(pattern)
483+
if get_thread_default():
484+
wrapper.enable_auto_threads()
485+
else:
486+
wrapper.disable_threads()
487+
return wrapper
488+
489+
adjusted_pattern = _apply_regex_compat(pattern, bool(_DEFAULT_COMPAT_REGEX))
490+
if isinstance(adjusted_pattern, str):
491+
native_flags = _pcre2.PCRE2_UTF | _pcre2.PCRE2_UCP
492+
else:
493+
native_flags = 0
494+
compiled = cached_compile(adjusted_pattern, native_flags, Pattern, jit=_DEFAULT_JIT)
495+
if get_thread_default():
496+
compiled.enable_auto_threads()
497+
else:
498+
compiled.disable_threads()
499+
return compiled
500+
476501
resolved_flags = _normalise_flags(flags)
477502
threads_requested = bool(resolved_flags & THREADS)
478503
no_threads_requested = bool(resolved_flags & NO_THREADS)

pcre_ext/pattern_cache.c

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -211,27 +211,6 @@ pattern_cache_teardown(void)
211211
atomic_store_explicit(&pattern_cache_global_mode, 0, memory_order_release);
212212
}
213213

214-
static void
215-
pattern_cache_touch(PatternCacheState *state, PyObject *cache_key)
216-
{
217-
if (state->order == NULL) {
218-
return;
219-
}
220-
Py_ssize_t idx = PySequence_Index(state->order, cache_key);
221-
if (idx >= 0) {
222-
if (PySequence_DelItem(state->order, idx) < 0) {
223-
PyErr_Clear();
224-
return;
225-
}
226-
} else if (PyErr_Occurred()) {
227-
PyErr_Clear();
228-
return;
229-
}
230-
if (PyList_Append(state->order, cache_key) < 0) {
231-
PyErr_Clear();
232-
}
233-
}
234-
235214
int
236215
pattern_cache_lookup(PyObject *cache_key, PatternObject **out_pattern)
237216
{
@@ -256,7 +235,6 @@ pattern_cache_lookup(PyObject *cache_key, PatternObject **out_pattern)
256235
if (cached != NULL) {
257236
Py_INCREF(cached);
258237
*out_pattern = (PatternObject *)cached;
259-
pattern_cache_touch(state, cache_key);
260238
} else if (PyErr_Occurred()) {
261239
pattern_cache_release_state(lock_held);
262240
return -1;

pcre_ext/pcre2.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,11 +1806,6 @@ Pattern_compile_cached(PyObject *pattern_obj, uint32_t flags, int jit, int jit_e
18061806
return NULL;
18071807
}
18081808

1809-
if (PyObject_Hash(cache_key) == -1) {
1810-
PyErr_Clear();
1811-
use_cache = 0;
1812-
}
1813-
18141809
if (use_cache) {
18151810
PatternObject *cached = NULL;
18161811
if (pattern_cache_lookup(cache_key, &cached) == 0) {

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
99

1010
[project]
1111
name = "PyPcre"
12-
version = "0.2.11"
12+
version = "0.2.12"
1313
description = "Modern, GIL-friendly, Fast Python bindings for PCRE2 with auto caching and JIT of compiled patterns."
1414
readme = "README.md"
1515
requires-python = ">=3.9"

tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Project test package marker to avoid third-party `tests` package shadowing."""

0 commit comments

Comments
 (0)