This wrapper facilitates the automated execution of an SQLite database benchmark. The benchmark measures SQLite insert performance under concurrent load by creating multiple database instances, each populated with randomized records in parallel. It stresses the I/O subsystem, filesystem journaling (WAL mode), and process scheduling under varying levels of concurrency.
The wrapper provides:
- Automated SQLite benchmark setup and execution.
- Configurable table sizes and concurrency levels.
- Multi-iteration testing with averaged results.
- Result collection, processing, and verification.
- CSV and JSON output formats.
- System configuration metadata capture.
- Integration with test_tools framework.
- Optional Performance Co-Pilot (PCP) integration.
SQLite Options:
--table_entries <a,b,c...>: Comma-separated list of table sizes to create.
Each value specifies the number of rows to insert per database. Default: 5000.
--procs <a,b,c...>: Comma-separated list of process counts to test.
Each value specifies how many concurrent SQLite database processes to run.
If not set, automatically generates intervals up to the number of CPU cores (max 8 intervals).
General test_tools options:
--home_parent <value>: Parent home directory. If not set, defaults to current working directory.
--host_config <value>: Host configuration name, defaults to current hostname.
--iterations <value>: Number of times to run the test, defaults to 1.
--run_user: User that is actually running the test on the test system. Defaults to current user.
--sys_type: Type of system working with (aws, azure, hostname). Defaults to hostname.
--sysname: Name of the system running, used in determining config files. Defaults to hostname.
--tuned_setting: Used in naming the results directory. For RHEL, defaults to current active tuned profile.
For non-RHEL systems, defaults to 'none'.
--use_pcp: Enable Performance Co-Pilot monitoring during test execution.
--tools_git <value>: Git repo to retrieve the required tools from.
Default: https://github.com/redhat-performance/test_tools-wrappers
--usage: Display this usage message.
The run_sqlite.sh script performs the following workflow:
-
Environment Setup:
- Clones the test_tools-wrappers repository if not present (default: ~/test_tools).
- Sources error codes and general setup utilities.
- Gathers system hardware information.
-
Package Installation:
- Installs required dependencies via package_tool: sqlite, sqlite-devel, gcc, git, bc, time, and others.
- Dependencies are defined in sqlite.json for RHEL-based systems.
-
Process List Generation:
- If
--procsis not specified, automatically determines concurrency levels. - Detects the number of CPU cores via
nproc. - Generates evenly spaced intervals up to the core count (capped at 8 intervals).
- If
-
Table Entry Generation:
- Generates a file of SQL INSERT statements with randomized data for each requested table size.
- Each record contains a sequence number, timestamp, a random 4-digit value (F1), and a random 16-digit value (F2).
- Insertion files are cached and reused if they already exist for a given table size.
-
Database Creation and Execution:
- For each combination of iteration, table size, and process count:
- Spawns the requested number of concurrent processes.
- Each process creates its own SQLite database with WAL journaling mode.
- Creates a table
pts1with columns: I (SMALLINT), DT (TIMESTAMP), F1 (VARCHAR(4)), F2 (VARCHAR(16)). - Each process inserts the full set of records 3 times sequentially.
- A ready file synchronizes all processes to start simultaneously.
- Execution time is captured via
/bin/timefor each process.
- For each combination of iteration, table size, and process count:
-
Data Collection:
- Captures elapsed, system, and user time for each process in
sqlite_timeing_*files. - Records start and end timestamps for each process.
- Optionally records PCP performance data during execution.
- Captures elapsed, system, and user time for each process in
-
Result Processing:
- Groups results by table size and process count.
- Averages elapsed time across iterations and processes.
- Sums user and system time across processes, then averages across iterations.
- Generates CSV files with configuration and performance data.
- Creates JSON output for verification.
- Validates results against Pydantic schema (results_schema.py).
-
Verification:
- Validates results against Pydantic schema ensuring:
- Table entries and process counts are positive integers.
- All time values are positive, finite numbers.
- Timestamps are valid datetime objects.
- Uses csv_to_json and verify_results from test_tools.
- Validates results against Pydantic schema ensuring:
-
Output:
- Creates results directory in
${HOME}/export_results/sqlite_<YYYY.MM.DD-HH.MM.SS>. - Saves all raw timing files, processed CSV/JSON, and system metadata.
- Optionally saves PCP performance data.
- Archives results to configured storage location.
- Creates results directory in
General packages required: sqlite, sqlite-devel, gcc, git, bc, time, wget, tcl, tcl-devel, zip, unzip, perf
Additional RHEL packages: lksctp-tools-devel, perl-FindBin, perl-IPC-Cmd, perl-Time-Piece, pcp-zeroconf, pcp-pmda-openmetrics, pcp-pmda-denki
To run:
git clone <repository-url>
cd sqlite-wrapper/sqlite
./run_sqlite.shThe script will automatically detect your CPU configuration and generate appropriate concurrency levels.
The benchmark tests SQLite insert throughput under concurrent load using WAL (Write-Ahead Logging) journaling mode.
Each database instance uses a single table:
CREATE TABLE pts1 (
'I' SMALLINT NOT NULL,
'DT' TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
'F1' VARCHAR(4) NOT NULL,
'F2' VARCHAR(16) NOT NULL
);- I: Sequential record number.
- DT: Insertion timestamp.
- F1: Random 4-digit value.
- F2: Random 16-digit value.
For each process count N:
- N independent SQLite databases are created, each with WAL journaling enabled.
- All N processes wait on a synchronization barrier (ready file).
- Once released, each process inserts the full record set 3 times sequentially.
- Timing is average across allprocess.
Each test configuration reports five key metrics:
- Real_time: Average elapsed (wall-clock) time per process across iterations.
- User_time: Total user-space CPU time summed across processes.
- System_time: Total kernel CPU time summed across processes.
- Start_Date: Timestamp when the test run began.
- End_Date: Timestamp when the test run completed.
The results directory contains:
- results_sqlite_<entries>.csv: CSV file with performance metrics for each table size
- sqlite_verify.json: JSON file with validated results data
- sqlite_timeing_*: Raw timing files from each process in each iteration
- sqlite-insertions_<entries>: Cached SQL insertion files for each table size
- runner_db_*: Generated execution scripts for each database process
- meta_data*.yml: System metadata (CPU info, memory, kernel version)
- PCP data (if --use_pcp option used): Performance Co-Pilot monitoring data
./run_sqlite.shThis runs with:
- 5000 table entries
- Automatically determined process counts (up to 8 intervals across available cores)
- 1 iteration of the complete test suite
./run_sqlite.sh --table_entries 1000,5000,10000Tests with three different table sizes to measure how insert volume affects performance.
./run_sqlite.sh --procs 1,4,8,16Tests with 1, 4, 8, and 16 concurrent database processes.
./run_sqlite.sh --iterations 3Runs the complete test suite 3 times and averages the results for consistency.
./run_sqlite.sh --use_pcpCollects Performance Co-Pilot data during the run for detailed performance analysis.
./run_sqlite.sh --table_entries 5000,10000 --procs 1,4,8 --iterations 3 --use_pcpRuns 3 iterations with PCP monitoring, testing two table sizes across three concurrency levels.
When --procs is not specified:
- The script detects the number of CPU cores via
nproc. - If the system has fewer than 8 cores, it uses the core count as the number of intervals.
- Otherwise, it generates 8 evenly spaced intervals up to the core count.
- For example, on a 32-core system: 4, 8, 12, 16, 20, 24, 28, 32.
Specify exact process counts to test:
- Useful for targeting specific concurrency levels.
- Allows testing beyond the core count for oversubscription analysis.
When running multiple iterations (--iterations > 1):
- Each iteration produces a complete set of timing results for all process/table-entry combinations.
- Raw timing results are saved in separate
sqlite_timeing_*files. - The wrapper extracts metrics from each iteration:
- Elapsed time is averaged across iterations and processes.
- User and system time are summed across processes, then averaged across iterations.
- Summary CSV shows averaged values with 2 decimal places.
This approach:
- Reduces impact of transient system effects.
- Provides more reliable performance measurements.
- Helps identify result variance across runs.
The script uses standardized error codes from test_tools error_codes:
- 0 (E_SUCCESS): Success
- 101: Git clone failure
- E_USAGE: Invalid usage/arguments
- Non-zero exit from csv_to_json or verify_results indicates validation failure.
- Linux: x86_64 and aarch64 architectures
- OS Support: RHEL (primary, with full package definitions in sqlite.json)
- The benchmark is I/O-intensive, particularly with large table sizes and high concurrency.
- WAL journaling mode is used for each database, which allows concurrent reads during writes.
- Each process operates on its own independent database file, so contention is at the filesystem level rather than database lock level.
- Larger table sizes (--table_entries) increase both I/O volume and memory pressure.
- Higher process counts stress the I/O scheduler and filesystem journaling.
- The script caches generated SQL insertion files as
sqlite-insertions_<count>. - Subsequent runs with the same table size reuse the cached file.
- Delete cached files to regenerate with new random data.
Each database is created with PRAGMA journal_mode='wal':
- Write-Ahead Logging provides better concurrency than the default rollback journal.
- Readers do not block writers, and writers do not block readers.
- This is the recommended mode for concurrent SQLite workloads.
- Run multiple iterations (--iterations 3+) to verify consistency.
- Ensure the system is idle (no other workloads) for best results.
- Use a fast storage device (SSD/NVMe) for meaningful I/O benchmarking.
- Consider the filesystem type (ext4, xfs, btrfs) as it affects journaling performance.
- PCP monitoring (--use_pcp) provides detailed I/O and CPU metrics during the test.
- For large table sizes, ensure sufficient disk space for all database files.
- If the script fails to start, verify that sqlite3 is installed and in PATH.
- If timing files are missing, check that
/bin/timeis available (thetimepackage). - If results seem inconsistent, run more iterations and check system I/O load during testing.
- Use --use_pcp to collect detailed performance counters for analysis.
- Check
sqlite_timeing_*files for detailed timing and error information.
- SQLite Official Site: https://www.sqlite.org/
- SQLite WAL Mode Documentation: https://www.sqlite.org/wal.html
- test_tools Framework: https://github.com/redhat-performance/test_tools-wrappers