Performance Baselines
Overview
This document defines performance baselines for StellaOps scanner operations. All metrics are measured against reference images and workloads to ensure consistent, reproducible benchmarks.
Last Updated: 2025-12-14 Next Review: 2026-03-14
Reference Images
Standard images used for performance benchmarking:
| Image | Size | Components | Expected Vulns | Category |
|---|---|---|---|---|
alpine:3.19 | 7MB | ~15 | ~5 | Minimal |
debian:12-slim | 75MB | ~90 | ~40 | Minimal |
ubuntu:22.04 | 77MB | ~100 | ~50 | Standard |
node:20-alpine | 180MB | ~200 | ~100 | Application |
python:3.12 | 1GB | ~300 | ~150 | Application |
mcr.microsoft.com/dotnet/aspnet:8.0 | 220MB | ~150 | ~75 | Application |
nginx:1.25 | 190MB | ~120 | ~60 | Application |
postgres:16-alpine | 240MB | ~140 | ~70 | Database |
Scan Performance Targets
Container Image Scanning
| Image Category | P50 Time | P95 Time | Max Memory | CPU Cores |
|---|---|---|---|---|
| Minimal (<100MB) | < 5s | < 10s | < 256MB | 1 |
| Standard (100-500MB) | < 15s | < 30s | < 512MB | 2 |
| Large (500MB-2GB) | < 45s | < 90s | < 1.5GB | 2 |
| Very Large (>2GB) | < 120s | < 240s | < 2GB | 4 |
Per-Image Targets
| Image | P50 Time | P95 Time | Max Memory |
|---|---|---|---|
| alpine:3.19 | < 3s | < 8s | < 200MB |
| debian:12-slim | < 8s | < 15s | < 300MB |
| ubuntu:22.04 | < 10s | < 20s | < 400MB |
| node:20-alpine | < 20s | < 40s | < 600MB |
| python:3.12 | < 35s | < 70s | < 1.2GB |
| dotnet/aspnet:8.0 | < 25s | < 50s | < 800MB |
| nginx:1.25 | < 18s | < 35s | < 500MB |
| postgres:16-alpine | < 22s | < 45s | < 600MB |
Reachability Analysis Targets
By Codebase Size
| Codebase Size | P50 Time | P95 Time | Memory | Notes |
|---|---|---|---|---|
| Tiny (<5k LOC) | < 10s | < 20s | < 256MB | Single service |
| Small (5-20k LOC) | < 30s | < 60s | < 512MB | Small service |
| Medium (20-50k LOC) | < 2min | < 4min | < 1GB | Typical microservice |
| Large (50-100k LOC) | < 5min | < 10min | < 2GB | Large service |
| Very Large (100-500k LOC) | < 15min | < 30min | < 4GB | Monolith |
| Monorepo (>500k LOC) | < 45min | < 90min | < 8GB | Enterprise monorepo |
By Language
| Language | Relative Speed | Notes |
|---|---|---|
| Go | 1.0x (baseline) | Fast due to simple module system |
| Java | 1.2x | Maven/Gradle resolution adds overhead |
| C# | 1.3x | MSBuild/NuGet resolution |
| TypeScript | 1.5x | npm/yarn resolution, complex imports |
| Python | 1.8x | Virtual env resolution, dynamic imports |
| JavaScript | 2.0x | Complex bundler configurations |
SBOM Generation Targets
| Format | P50 Time | P95 Time | Output Size | Notes |
|---|---|---|---|---|
| CycloneDX 1.7 (JSON) | < 1s | < 3s | ~50KB/100 components | Standard (Baseline with 1.6; 1.7 performance expected similar - re-benchmark pending) |
| CycloneDX 1.7 (XML) | < 1.5s | < 4s | ~80KB/100 components | Verbose (Baseline with 1.6; 1.7 performance expected similar - re-benchmark pending) |
| SPDX 3.0.1 (JSON) | < 1s | < 3s | ~60KB/100 components | Standard |
| SPDX 3.0.1 (Tag-Value) | < 1.2s | < 3.5s | ~70KB/100 components | Legacy format |
Combined Operations
| Operation | P50 Time | P95 Time |
|---|---|---|
| Scan + SBOM | scan_time + 1s | scan_time + 3s |
| Scan + SBOM + Reachability | scan_time + reach_time + 2s | scan_time + reach_time + 5s |
| Full attestation pipeline | total_time + 2s | total_time + 5s |
VEX Processing Targets
| Operation | P50 Time | P95 Time | Notes |
|---|---|---|---|
| VEX document parsing | < 50ms | < 150ms | Per document |
| Lattice state computation | < 100ms | < 300ms | Per 100 vulnerabilities |
| VEX consensus merge | < 200ms | < 500ms | 3-5 sources |
| State transition | < 10ms | < 30ms | Single transition |
CVSS Scoring Targets
| Operation | P50 Time | P95 Time | Notes |
|---|---|---|---|
| MacroVector lookup | < 1μs | < 5μs | Dictionary lookup |
| CVSS v4.0 base score | < 10μs | < 50μs | Full computation |
| CVSS v4.0 full score | < 20μs | < 100μs | Base + threat + env |
| Vector parsing | < 5μs | < 20μs | String parsing |
| Receipt generation | < 100μs | < 500μs | Includes hashing |
| Batch scoring (100 vulns) | < 5ms | < 15ms | Parallel processing |
Attestation Targets
| Operation | P50 Time | P95 Time | Notes |
|---|---|---|---|
| DSSE envelope creation | < 50ms | < 150ms | Includes signing |
| DSSE verification | < 30ms | < 100ms | Signature check |
| Rekor submission | < 500ms | < 2s | Network dependent |
| Rekor verification | < 300ms | < 1s | Network dependent |
| in-toto predicate | < 20ms | < 80ms | JSON serialization |
Database Operation Targets
| Operation | P50 Time | P95 Time | Notes |
|---|---|---|---|
| Receipt insert | < 5ms | < 20ms | Single record |
| Receipt query (by ID) | < 2ms | < 10ms | Indexed lookup |
| Receipt query (by tenant) | < 10ms | < 50ms | Index scan |
| EPSS lookup (single) | < 1ms | < 5ms | Indexed |
| EPSS lookup (batch 100) | < 10ms | < 50ms | Batch query |
| Risk score insert | < 5ms | < 20ms | Single record |
| Risk score update | < 3ms | < 15ms | Single record |
Regression Thresholds
Performance regression is detected when metrics exceed these thresholds compared to baseline:
| Metric | Warning Threshold | Blocking Threshold | Action |
|---|---|---|---|
| P50 Time | > 15% increase | > 25% increase | Block release |
| P95 Time | > 20% increase | > 35% increase | Block release |
| Memory Usage | > 20% increase | > 30% increase | Block release |
| CPU Time | > 15% increase | > 25% increase | Investigate |
| Throughput | > 10% decrease | > 20% decrease | Block release |
Regression Detection Rules
- Warning: Alert engineering team, add to release notes
- Blocking: Cannot merge/release until resolved or waived
- Waiver: Requires documented justification and SME approval
Measurement Methodology
Environment Setup
# Standard test environment
# - CPU: 8 cores (x86_64)
# - Memory: 16GB RAM
# - Storage: NVMe SSD
# - OS: Ubuntu 22.04 LTS
# - Docker: 24.x
# Clear caches before cold start tests
docker system prune -af
sync && echo 3 > /proc/sys/vm/drop_caches
CLI surface. The binary is
stella, notstellaops.scanandsbomare command groups, not leaf commands —stella scan --image …exits 2 withUnrecognized command or argument '--image'. Verify any invocation below againststella <verb> --helpbefore quoting a number produced by it.
Scan Performance
Image scanning is two steps: generate a deterministic SBOM, then match it against the compact vuln DB. Time them separately — they have different cost profiles.
# Cold start measurement (SBOM generation)
time stella sbom generate --image alpine:3.19 --format cyclonedx --output sbom.json --force
# Warm cache measurement (run 3x, take average)
for i in {1..3}; do
time stella sbom generate --image alpine:3.19 --format cyclonedx --output sbom.json --force
done
# Offline match against the compact vuln DB (no backend required)
time stella sbom check --sbom sbom.json --format json > /dev/null
# Memory profiling
/usr/bin/time -v stella sbom generate --image alpine:3.19 --format cyclonedx \
--output sbom.json --force 2>&1 | grep "Maximum resident set size"
# CPU profiling
perf stat stella sbom check --sbom sbom.json --format json > /dev/null
--source-date pins the SBOM timestamp, which is what makes repeat runs byte-identical; leave it at the default only when you are not comparing digests across runs.
Reachability Analysis
Reachability is measured over a call graph extracted from source. stella scan graph does the extraction; stella reachability operates on the result.
# Time measurement — call-graph extraction
time stella scan graph --lang dotnet --target ./src --output callgraph.json
# Memory profiling
/usr/bin/time -v stella scan graph --lang dotnet --target ./src --output callgraph.json 2>&1
# Reachability over an existing SBOM, in one pass (offline engine)
time stella sbom check --sbom sbom.json --reachability --call-graph callgraph.json --format json > /dev/null
--lang accepts dotnet, java, node, python, go, rust, ruby, php. There is no csharp value — .NET projects use dotnet. stella sbom check --reachability additionally accepts --source + --reach-lang (go|rust only) to extract a graph in-process instead of taking a pre-extracted one.
SBOM Generation
# Time measurement
time stella sbom generate --image node:20-alpine --format cyclonedx --output sbom.json --force
# Output size
stella sbom generate --image node:20-alpine --format cyclonedx --output sbom.json --force && \
ls -lh sbom.json
Batch Operations
There is no CLI flag for parallel multi-image scanning. stella sbom generate takes a single --image or --directory; drive concurrency from the shell.
# Process multiple images in parallel (4 at a time)
time xargs -P 4 -I{} sh -c \
'stella sbom generate --image "$1" --format cyclonedx --output "./results/$(echo "$1" | tr "/:" "__").json" --force' _ {} \
< images.txt
# Throughput test (images per minute)
START=$(date +%s)
for i in {1..10}; do
stella sbom generate --image alpine:3.19 --format cyclonedx --output /tmp/sbom.json --force > /dev/null
done
END=$(date +%s)
echo "Throughput: $(( 10 * 60 / (END - START) )) images/minute"
stella scan submit-list --file <ids.txt> --max-concurrent 10 does exist and is throttled, but it takes already-registered SBOM source ids (GUIDs), not image references, and it requires a running backend — it is not a substitute for the local loop above.
CI Integration
Benchmark Workflow
# .gitea/workflows/performance-benchmark.yml
name: Performance Benchmark
on:
pull_request:
branches: [main]
schedule:
- cron: '0 2 * * 1' # Weekly Monday 2am
jobs:
benchmark:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run benchmarks
run: python src/Tools/StellaOps.Bench/Determinism/run_bench.py --output results/
- name: Aggregate results
run: |
dotnet run --project src/Tools/Bench/StellaOps.Bench.Compute.Cli -- \
report results/ --output results/report.json
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: results/
The regression gate is not shipped. Earlier revisions of this page ran
stellaops benchmark compare --baseline … --fail-on-regressionandmake benchmark-performance. Neither exists:stella benchmarkexits 2 (Unrecognized command or argument 'benchmark') and the repository has no rootMakefile. The thresholds in the tables above are targets a reviewer applies by reading the report — nothing enforces them automatically today.Real harnesses, for anyone wiring this up properly:
src/Tools/StellaOps.Bench/Determinism/run_bench.pyandrun_reachability.py— Python, offline-friendly (offline_run.sh).src/Tools/StellaOps.Bench/{Graph,ImpactIndex,PolicyCache,PolicyDelta}/— per-subsystem microbenchmarks.src/Tools/Bench/StellaOps.Bench.Compute.Cli— binary namestella-bench-compute, verbsdiscovery-truth,evidence-score,compare-metrics,report. It is a separate tool fromstella; the comparison it does is scanner-vs-scanner discovery coverage, not run-over-run performance regression.Verify the exact flags with
--helpbefore pasting any of this into CI.
Local Testing
# Run full benchmark suite
make benchmark-performance
# Run specific image benchmark
make benchmark-image IMAGE=alpine:3.19
# Generate baseline
make benchmark-baseline
# Compare against baseline
make benchmark-compare
Optimization Guidelines
For Scan Performance
- Pre-pull images for consistent timing
- Use layered caching for repeat scans
- Enable parallel analysis for multi-ecosystem images
- Consider selective scanning for known-safe layers
For Reachability
- Incremental analysis for unchanged files
- Cache resolved dependencies
- Use language-specific optimizations (e.g., Roslyn for C#)
- Limit call graph depth for very large codebases
For Memory
- Stream large SBOMs instead of loading fully
- Use batched database operations
- Release intermediate data structures early
- Configure GC appropriately for workload
Historical Baselines
Version History
| Version | Date | P50 Scan (alpine) | P50 Reach (50k LOC) | Notes |
|---|---|---|---|---|
| 1.3.0 | 2025-12-14 | TBD | TBD | Current |
| 1.2.0 | 2025-09-01 | TBD | TBD | Previous |
| 1.1.0 | 2025-06-01 | TBD | TBD | Baseline |
Improvement Targets
| Quarter | Focus Area | Target | Status |
|---|---|---|---|
| Q1 2026 | Scan cold start | -20% | Planned |
| Q1 2026 | Reachability memory | -15% | Planned |
| Q2 2026 | SBOM generation | -10% | Planned |
References
- Accuracy Metrics Framework
- Benchmark Submission Guide (pending)
- Scanner Architecture
- Reachability Module
