Benchmarks
Performance
Latency, throughput, and memory benchmarks for FastPII detection.
Performance
Detection latency
Per-detector latency measured on a single-core workload:
| Detector | Avg (ms) | Median (ms) | Min (ms) |
|---|---|---|---|
| rodne_cislo | 0.137 | 0.120 | 0.080 |
| ico | 0.042 | 0.038 | 0.025 |
| dic | 0.089 | 0.081 | 0.060 |
| pesel | 0.095 | 0.088 | 0.065 |
| nip | 0.058 | 0.052 | 0.035 |
| steuer_id | 0.063 | 0.058 | 0.040 |
| siren | 0.045 | 0.040 | 0.028 |
| siret | 0.048 | 0.043 | 0.030 |
| 0.009 | 0.007 | 0.005 | |
| phone | 0.025 | 0.022 | 0.015 |
| postal_code | 0.012 | 0.010 | 0.007 |
| address | 0.098 | 0.090 | 0.065 |
| name | 0.115 | 0.105 | 0.075 |
Throughput
| Region | Characters/ms | Docs/sec (avg doc) |
|---|---|---|
| CZ | 625 | 312 |
| PL | 450 | 225 |
| DE | 480 | 240 |
| FR | 420 | 210 |
Memory footprint
- Package size: Zero external dependencies
- Runtime memory: ~50MB with CZ data loaded
- Cold start: <100ms for engine initialization with one country pack
- Warm detection: Sub-millisecond per detector per document
Pattern registry performance
The pattern registry uses @lru_cache(maxsize=1) on get_region_loaders() for cached pattern access:
from fastpii.patterns.registry import get_shared_registry
# First call loads patterns
registry = get_shared_registry()
# Subsequent calls return cached result
registry = get_shared_registry() # cache hitData module benchmarking
from fastpii.data.registry import CountryRegistry
cz = CountryRegistry.get("cz")
times = cz.benchmark_import_times()
for name, ms in times.items():
print(f"{name}: {ms:.1f}ms")Scaling notes
- Detection scales linearly with text length and number of registered detectors
- Validation is O(1) for checksum-based identifiers
- Memory grows with data module size (CZ full data: ~15MB in memory)
- Pattern loading is cached after first access