High-level overview of BenchBox's design, components, and extension points.
BenchBox is built on three core principles:
- Separation of Concerns: Benchmark logic, platform adapters, and query execution are independent layers
- Extensibility: New benchmarks and platforms can be added without modifying core code
- Standards Compliance: TPC benchmarks follow official specifications for reproducibility
┌─────────────────────────────────────────────────────────────┐
│ CLI / Python API │
│ (User Entry Points) │
└──────────────────┬──────────────────────────────────────────┘
│
┌──────────────────┴──────────────────────────────────────────┐
│ Orchestration Layer │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Run Configuration │ Query Selection │ │
│ │ Parameter Generation│ Result Collection │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────┬──────────────────────────────────────────┘
│
┌─────────────┼─────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│Benchmark│ │Platform │ │ Results │
│ Layer │ │ Adapter │ │ Model │
└─────────┘ └─────────┘ └─────────┘
│ │ │
┌────▼────────────▼─────────────▼────┐
│ Database Connection │
│ (Platform-Specific Driver) │
└────────────────────────────────────┘
The repository separates the installable product from its documentation, tests, examples, and project operations:
| Path | Purpose |
|---|---|
benchbox/ |
Python package, benchmark implementations, platform adapters, CLI, and result model |
docs/ |
User guides, concepts, reference material, design records, and contributor documentation |
tests/ |
Unit, integration, end-to-end, performance, and live test suites |
examples/ |
Runnable examples, notebooks, tuning files, and workflow patterns |
results-explorer/ |
Browser application for published benchmark results |
results-data/ |
Public result corpus and its validation metadata |
This map describes ownership boundaries rather than every directory. Use the linked component documentation below for implementation details.
Location: Public wrappers live in benchbox/*.py on benchbox.base.BaseBenchmark.
Core implementations live under benchbox/core/{benchmark}/.
Responsibility: Encapsulates benchmark-specific logic
Key Classes:
BaseBenchmark: Public wrapper base inbenchbox/base.pyfor benchmark construction and therun_with_platformAPI. It remains a supported public base; it is not a retired execution model.{Benchmark}: Implementation class (e.g.,TPCH,TPCDS){Benchmark}Generator: Data generation logic{Benchmark}Queries: Query templates and parameterization
A benchmark class knows how to generate data (the dbgen invocation), how to retrieve queries (with parameter
substitution), its schema definitions, and its validation rules.
Example:
from benchbox import TPCHLocation: benchbox/platforms/{platform}/
Responsibility: Abstracts database-specific connection and execution logic
Key Classes:
{Platform}Adapter: Main adapter class (e.g.,DuckDBAdapter){Platform}Connection: Connection wrapper implementingDatabaseConnection- Platform-specific optimizations (bulk loading, query hints)
An adapter handles connection management, data loading strategies (COPY, INSERT, external tables), query execution and error handling, and result collection and formatting.
Example:
from benchbox.platforms.duckdb import DuckDBAdapterSupported Adapters:
- DuckDB (embedded, local files)
- ClickHouse (native protocol)
- Databricks (SQL Warehouse, Unity Catalog)
- BigQuery (serverless, cloud storage)
- Snowflake (warehouse, stages)
- Redshift (serverless, provisioned)
- SQLite (testing, minimal datasets)
Location: benchbox/core/results/
Responsibility: Structured representation of benchmark execution results
Key Classes:
QueryResult: Schema-facing query row model used by compatibility and validation boundaries (benchbox/core/schemas.py); it is not the canonical in-memory execution object.QueryExecution: Canonical in-memory result for one executed query (benchbox/core/results/models.py), including timing, status, validation, resource usage, and optional plan data.BenchmarkResults: Aggregate benchmark result with timing, metadata, validation, and query-result summaries.ExecutionPhases: Setup, power test, throughput test phasesValidationResult: Data quality and correctness checks
Schema:
{
"benchmark_name": "TPC-H",
"platform": "DuckDB",
"scale_factor": 1.0,
"execution_id": "tpch_1234567890",
"timestamp": "2025-10-12T10:30:00Z",
"total_execution_time": 45.2,
"query_results": [
{
"query_id": "q1",
"execution_time": 2.1,
"status": "SUCCESS",
"row_count": 4
}
],
"execution_phases": { ... },
"validation_status": "PASSED"
}Location: benchbox/core/connection.py
Responsibility: Unified interface for database operations
Key Interface:
class DatabaseConnection(ABC):
@abstractmethod
def execute(self, query: str) -> Any:
pass
@abstractmethod
def fetchall(self, cursor) -> list:
pass
@abstractmethod
def close(self) -> None:
passexecute runs a query and returns a cursor or result, fetchall fetches all results from a cursor, and close closes the connection. All platform adapters implement this interface, enabling benchmark code to remain platform-agnostic.
Location: benchbox/core/{benchmark}/generator.py
Responsibility: Create synthetic benchmark data
Mechanisms:
- TPC Benchmarks: Invoke official C binaries (
dbgen,dsdgen,datagen) - Custom Benchmarks: Python-based generation using Faker, NumPy, Pandas
- Output Formats: Parquet (default), CSV, JSON
Example: TPC-H uses the official dbgen binary, and generate() returns a list of .parquet files. Custom
benchmarks use Python, and the coffee shop generator generates data with Faker.
generator = TPCHGenerator(scale_factor=1.0, output_dir="./data")
file_paths = generator.generate()
generator = CoffeeShopGenerator(scale_factor=0.001)
file_paths = generator.generate()Location: benchbox/cli/
Responsibility: Command-line interface and workflow orchestration
Commands: the examples run a benchmark end-to-end, generate data only, do a dry run that previews queries, and check dependencies.
benchbox run --benchmark tpch --platform duckdb --scale 1
benchbox datagen --benchmark tpcds --scale 0.1
benchbox run --benchmark tpch --dry-run ./output
benchbox check-deps --matrixOrchestrator Flow:
- Parse CLI arguments and config files
- Validate platform dependencies
- Initialize benchmark and platform adapter
- Execute benchmark phases (setup, queries, validation)
- Collect and save results
- Generate reports
See: CLI Quick Start
1. User Command
├── benchbox run --benchmark tpch --platform duckdb --scale 1
└── Parsed by CLI → creates RunConfiguration
2. Benchmark Initialization
├── TPCH(scale_factor=1.0)
├── Checks if data exists at output_dir
└── generate_data() if needed
3. Platform Adapter Setup
├── DuckDBAdapter()
├── Establishes database connection
└── Creates schema (CREATE TABLE statements)
4. Data Loading Phase
├── Platform-specific bulk load (COPY FROM, external tables)
├── Validates row counts
└── Creates indexes/constraints
5. Query Execution Phase
├── For each query in benchmark:
│ ├── Get query text with parameters
│ ├── Execute via platform adapter
│ ├── Measure execution time
│ └── Collect results
└── Aggregate timing statistics
6. Results Collection
├── Create BenchmarkResults object
├── Include execution metadata (platform info, system profile)
├── Validate results (if validation rules exist)
└── Save to JSON file
7. Output
├── Print summary to console
├── Save detailed JSON to output_dir
└── Optional: Upload to cloud storage
- Create
benchbox/core/{benchmark}/directory - Implement classes:
{Benchmark}BenchmarkImpl(BaseBenchmark){Benchmark}Generator{Benchmark}Queries{Benchmark}Schema
- Register in
benchbox/__init__.py
- Create
benchbox/platforms/{platform}/directory - Implement:
{Platform}Adapter{Platform}Connection(DatabaseConnection)
- Add platform extras to
pyproject.toml - Add the platform's canonical entry to
benchbox/core/platform_manifest.py, including one explicitsupport_status. The registry's_OPTIONAL_ADAPTERSand_build_platform_metadata()paths are live pass-throughs, not independent registration authorities.
Platforms can optionally support --table-mode external by setting
supports_external_tables = True and implementing create_external_tables().
In external mode the runner skips native schema creation and load_data(),
calling create_external_tables() instead to register views or external table
definitions over staged Parquet files.
Shared logic for Hive-style external tables (Trino, Presto) lives in
HiveExternalTableMixin (benchbox/platforms/base/external_table_mixin.py).
Shared logic for managed Spark external tables (Athena Spark, EMR Serverless,
Dataproc Serverless, Glue) lives in SparkExternalTableMixin
(benchbox/platforms/base/cloud_spark/external_tables.py).
Platforms that need pre-flight validation (e.g. Athena checking for an S3 bucket)
can implement validate_external_table_requirements(), which the runner calls
before proceeding.
See: Adding New Platforms
TPC benchmarks support query variants with different parameter substitutions. The first call returns a query with random parameters (the default), the second returns a query with specific parameters, and the third generates multiple variants for a seed sweep:
query = benchmark.get_query("q1")
query = benchmark.get_query("q1", params={"date": "1998-09-02", "quantity": 24})
variants = benchmark.generate_query_variants("q1", count=5, seed_start=42)See: TPC Patterns Usage
Platform adapters isolate database-specific logic, allowing benchmarks to remain platform-agnostic.
The lifecycle is orchestrated by the core run service and lifecycle runner:
configuration and platform setup flow through execute_run(...), which calls
run_benchmark_lifecycle(...). BaseBenchmark remains the public wrapper base
and benchmark-facing API boundary; it is not the owner of the entire runtime
execution workflow.
Data loading strategies vary by platform (bulk COPY, INSERT batches, external tables) but implement a common interface.
get_platform_adapter(name) creates appropriate adapter instances based on configuration.
- Parquet Format: Columnar storage for fast analytical queries
- Bulk Loading: Platform-specific optimizations (DuckDB COPY, ClickHouse INSERT, BigQuery external tables)
- Parallel Loading: Multi-threaded data ingestion where supported
- Connection Pooling: Reuse connections across queries
- Result Streaming: Fetch results incrementally for large result sets
- Query Compilation: Use platform-specific prepared statements
- Scale Factor Validation: Prevent OOM by validating scale vs. available memory
- Streaming Results: Don't materialize full result sets unless needed
- Cleanup: Explicit connection and resource cleanup
- Environment variables for sensitive data
- Support for platform-specific auth (OAuth, IAM, service accounts)
- No credentials in configuration files or logs
- Parameterized queries where possible
- Input validation on query IDs and parameters
- No direct string concatenation into SQL
- Support for synthetic data only (no real customer data)
- Anonymization support for custom benchmarks
- Data residency controls for cloud platforms
- Unit Tests (
tests/unit/): Component-level testing - Integration Tests (
tests/integration/): Database interaction tests - Live Tests (
tests/integration/platforms/): Real cloud platform testing
See: Testing Guide
- Workflow Concepts - Typical benchmarking workflows
- Data Model - Result schema and data structures
- Platform Selection Guide - Choosing a platform
- Custom Benchmarks - Creating new benchmarks
- Adding Platforms - Platform development