Performance Benchmarks¶
libpresign is designed for high-performance S3 presigned URL generation. This page presents comprehensive benchmarks comparing libpresign with boto3.
Benchmark Methodology¶
All benchmarks were performed using: - Python 3.12 - pytest-benchmark for timing measurements - 1000 iterations per test - Warm-up period to eliminate initialization overhead - Multiple runs to ensure consistency
Test Environment¶
- CPU: Various (Intel/AMD x86_64, Apple M1/M2)
- Memory: 16GB+ RAM
- OS: Linux, macOS, Windows
- Python: CPython 3.8-3.13
Performance Results¶
Single URL Generation¶
Generating a single presigned URL:
Library | Average Time | Median Time | Min Time | Max Time |
---|---|---|---|---|
libpresign | 6 μs | 5 μs | 4 μs | 12 μs |
boto3 | 102 μs | 98 μs | 85 μs | 210 μs |
Speedup | 17x | 19.6x | - | - |
# Benchmark code
import libpresign
import boto3
import time
# libpresign
start = time.perf_counter()
url = libpresign.get(
access_key_id="AKIAIOSFODNN7EXAMPLE",
secret_access_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
region="us-east-1",
bucket="my-bucket",
key="file.txt",
expires=3600
)
elapsed = time.perf_counter() - start
print(f"libpresign: {elapsed * 1_000_000:.2f} μs")
# boto3
client = boto3.client('s3', ...)
start = time.perf_counter()
url = client.generate_presigned_url(
'get_object',
Params={'Bucket': 'my-bucket', 'Key': 'file.txt'},
ExpiresIn=3600
)
elapsed = time.perf_counter() - start
print(f"boto3: {elapsed * 1_000_000:.2f} μs")
Batch URL Generation¶
Generating 1000 URLs sequentially:
Library | Total Time | URLs/Second | Avg per URL |
---|---|---|---|
libpresign | 6 ms | 166,667 | 6 μs |
boto3 | 102 ms | 9,804 | 102 μs |
Speedup | 17x | 17x | 17x |
Memory Usage¶
Memory consumption for generating 1000 URLs:
Library | Memory Used | Per URL | Memory Efficiency |
---|---|---|---|
libpresign | 256 KB | 262 bytes | 6x better |
boto3 | 1.6 MB | 1.6 KB | - |
Concurrent Performance¶
Performance with multiple threads (10 threads, 100 URLs each):
Library | Total Time | Throughput | Thread Safety |
---|---|---|---|
libpresign | 8 ms | 125,000/sec | ✅ Lock-free |
boto3 | 95 ms | 10,526/sec | ✅ Thread-safe |
Speedup | 11.9x | 11.9x | - |
Performance by Platform¶
Linux (x86_64)¶
Operation | libpresign | boto3 | Speedup |
---|---|---|---|
Single URL | 5 μs | 95 μs | 19x |
1000 URLs | 5 ms | 95 ms | 19x |
macOS (Apple Silicon)¶
Operation | libpresign | boto3 | Speedup |
---|---|---|---|
Single URL | 4 μs | 88 μs | 22x |
1000 URLs | 4 ms | 88 ms | 22x |
Windows (AMD64)¶
Operation | libpresign | boto3 | Speedup |
---|---|---|---|
Single URL | 8 μs | 112 μs | 14x |
1000 URLs | 8 ms | 112 ms | 14x |
Real-World Scenarios¶
Web API Response Time¶
Impact on API endpoint response time when generating presigned URLs:
# FastAPI endpoint example
@app.get("/files/{file_id}")
async def get_file_url(file_id: str):
# Database lookup: ~2ms
file_info = await db.get_file(file_id)
# URL generation
# libpresign: ~0.006ms (negligible)
# boto3: ~0.102ms (5% overhead)
url = libpresign.get(...)
return {"url": url}
Response time improvement: 5% faster API responses
Bulk Export Generation¶
Generating download links for 10,000 files:
Library | Time | Cost Impact |
---|---|---|
libpresign | 60 ms | Minimal CPU usage |
boto3 | 1.02 seconds | Higher CPU cost |
Cost savings: Reduced compute time in serverless environments
High-Concurrency Service¶
Service handling 1000 requests/second, each needing a presigned URL:
Metric | libpresign | boto3 |
---|---|---|
CPU Usage | 0.6% | 10.2% |
Thread Pool Size | Not needed | 20 threads |
p99 Latency | 8 μs | 180 μs |
Optimization Details¶
Why libpresign is Faster¶
- Native C++ Implementation
- No Python interpreter overhead
- Optimized string operations
-
Efficient memory management
-
Minimal Dependencies
- Direct OpenSSL integration
- No HTTP client initialization
-
No complex object hierarchies
-
Optimized Algorithm
- Pre-computed constants
- Efficient HMAC-SHA256 implementation
-
Minimal allocations
-
Focused Functionality
- Single purpose: presigned URL generation
- No unnecessary features
- Streamlined code path
When to Use libpresign¶
libpresign is ideal when: - ✅ Generating many presigned URLs - ✅ Low latency is critical - ✅ Running in resource-constrained environments - ✅ Cost optimization is important - ✅ Only GET operations are needed
boto3 may be better when: - ❌ You need PUT/POST/DELETE presigned URLs - ❌ You're already using boto3 for other operations - ❌ You need advanced S3 features - ❌ Performance is not critical
Running Your Own Benchmarks¶
To run benchmarks in your environment:
# Install with test dependencies
pip install libpresign[test]
# Run performance tests
pytest tests/test_performance.py -v
# Run boto3 comparison
pytest tests/test_benchmark_boto3.py -v
# Run with detailed output
pytest tests/test_benchmark_boto3.py -v -s
Custom Benchmark Script¶
import time
import statistics
import libpresign
def benchmark_libpresign(iterations=10000):
"""Benchmark libpresign performance."""
times = []
for _ in range(iterations):
start = time.perf_counter()
url = libpresign.get(
access_key_id="AKIAIOSFODNN7EXAMPLE",
secret_access_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
region="us-east-1",
bucket="benchmark-bucket",
key="test/file.txt",
expires=3600
)
elapsed = time.perf_counter() - start
times.append(elapsed)
print(f"Iterations: {iterations}")
print(f"Average: {statistics.mean(times) * 1_000_000:.2f} μs")
print(f"Median: {statistics.median(times) * 1_000_000:.2f} μs")
print(f"Min: {min(times) * 1_000_000:.2f} μs")
print(f"Max: {max(times) * 1_000_000:.2f} μs")
print(f"Std Dev: {statistics.stdev(times) * 1_000_000:.2f} μs")
if __name__ == "__main__":
benchmark_libpresign()
Conclusion¶
libpresign provides consistent 5-20x performance improvements over boto3 for presigned URL generation across all platforms and use cases. The performance benefits are most pronounced in high-throughput scenarios where the efficiency gains compound into significant cost and latency reductions.