Configure compression for keynote benchmark (#4743)

# Description of Changes

Message compression is now configurable for both the rust and typescript
keynote benchmark clients with the default being no compression. Before
this patch the rust client was using no compression and the typescript
client was using gzip by default.

# API and ABI breaking changes

None

# Expected complexity level and risk

1

# Testing

Manual
This commit is contained in:
joshua-spacetime
2026-04-03 15:19:14 -07:00
committed by GitHub
parent cdd8ba77ac
commit 2043bc9140
11 changed files with 102 additions and 8 deletions
+1
View File
@@ -26,6 +26,7 @@ SQLITE_MODE=default
STDB_URL=ws://127.0.0.1:3000
STDB_MODULE=test-1
STDB_MODULE_PATH=./spacetimedb
STDB_COMPRESSION=none
STDB_CONFIRMED_READS=1
# ===== Supabase =====
+11 -3
View File
@@ -31,6 +31,7 @@ The script will:
- `--concurrency N` - Concurrent connections (default: 50)
- `--alpha N` - Contention level (default: 1.5)
- `--systems a,b,c` - Systems to compare (default: convex,spacetimedb)
- `--stdb-compression none|gzip` - SpacetimeDB client compression mode (default: none)
- `--skip-prep` - Skip database seeding
- `--no-animation` - Disable animated output
@@ -90,6 +91,7 @@ Copy `.env.example` to `.env` and adjust.
- `STDB_URL` WebSocket URL for SpacetimeDB
- `STDB_MODULE` module name to load (e.g. `test-1`)
- `STDB_MODULE_PATH` filesystem path to the module source (for local dev)
- `STDB_COMPRESSION` SpacetimeDB benchmark client compression (`none` or `gzip`)
- `STDB_CONFIRMED_READS` `1` = force confirmed reads on, `0` = force them off
**Supabase:**
@@ -166,7 +168,7 @@ cd ..
### 1. Run a test
```bash
npm run bench -- [test-name] [--seconds N] [--concurrency N] [--alpha A] [--connectors list]
npm run bench -- [test-name] [--seconds N] [--concurrency N] [--alpha A] [--connectors list] [--stdb-compression none|gzip]
```
Examples:
@@ -184,6 +186,9 @@ npm run bench -- test-1 --seconds 10 --concurrency 100
# Heavier skew on hot accounts
npm run bench -- test-1 --alpha 2.0
# Enable gzip for the SpacetimeDB benchmark client
npm run bench -- test-1 --connectors spacetimedb --stdb-compression gzip
# Only run selected connectors
npm run bench -- test-1 --connectors spacetimedb,sqlite_rpc
```
@@ -256,6 +261,7 @@ pnpm run bench-dist-coordinator -- \
--verify 1 \
--stdb-url ws://127.0.0.1:3000 \
--stdb-module test-1 \
--stdb-compression none \
--bind 127.0.0.1 \
--port 8080
```
@@ -287,7 +293,8 @@ pnpm run bench-dist-generator -- \
--open-parallelism 128 \
--control-retries 3 \
--stdb-url ws://127.0.0.1:3000 \
--stdb-module test-1
--stdb-module test-1 \
--stdb-compression none
```
On **generator machine 2**:
@@ -306,7 +313,8 @@ pnpm run bench-dist-generator -- \
--open-parallelism 128 \
--control-retries 3 \
--stdb-url ws://127.0.0.1:3000 \
--stdb-module test-1
--stdb-module test-1 \
--stdb-compression none
```
Repeat that on as many generator machines as needed, adjusting `--id` and `--concurrency` for each process.
+1
View File
@@ -91,6 +91,7 @@ docker compose run --rm bench --seconds 10 --concurrency 50 --alpha XX --connect
- `--concurrency 50`: Number of concurrent client connections
- `--alpha 0`: ~0% contention (uniform account distribution)
- `--alpha 1.5`: ~80% contention (Zipf distribution concentrating on hot accounts)
- `--stdb-compression none|gzip`: SpacetimeDB client compression mode (default: `none`)
### Hardware Configuration
@@ -30,6 +30,21 @@ const CONFIRMED_READS: bool = true;
// Max inflight reducer calls imposed by the server.
const MAX_INFLIGHT_REDUCERS: u64 = 16384;
#[derive(Clone, Copy, Debug, clap::ValueEnum)]
enum CliCompression {
None,
Gzip,
}
impl From<CliCompression> for Compression {
fn from(value: CliCompression) -> Self {
match value {
CliCompression::None => Compression::None,
CliCompression::Gzip => Compression::Gzip,
}
}
}
// When called from within an async context, return a handle to it (and no
// `Runtime`), otherwise create a fresh `Runtime` and return it along with a
// handle to it.
@@ -55,7 +70,7 @@ async fn init_conn(cli: &Common, handle: &Handle) -> (JoinHandle<()>, Recv, Send
let server: &str = &cli.server;
let uri = server.try_into().unwrap();
let params = WsParams {
compression: Compression::None,
compression: cli.compression.into(),
light: true,
confirmed: cli.confirmed_reads.unwrap_or(CONFIRMED_READS).into(),
};
@@ -261,6 +276,9 @@ struct Common {
#[arg(short, long, default_value = MODULE)]
module: String,
#[arg(long, value_enum, default_value_t = CliCompression::None)]
compression: CliCompression,
#[arg(long)]
confirmed_reads: Option<bool>,
+24
View File
@@ -12,6 +12,10 @@ export const validConnectors = [
export type ConnectorKey = (typeof validConnectors)[number];
export const validStdbCompressions = ['none', 'gzip'] as const;
export type StdbCompression = (typeof validStdbCompressions)[number];
export const defaultDemoSystems: readonly ConnectorKey[] = [
'convex',
'spacetimedb',
@@ -39,6 +43,7 @@ export interface SharedRuntimeConfig {
stdbUrl: string;
stdbModule: string;
stdbModulePath: string;
stdbCompression: StdbCompression;
stdbConfirmedReads: boolean;
useDocker: boolean;
useSpacetimeMetricsEndpoint: boolean;
@@ -82,6 +87,7 @@ export type ConnectorRuntimeConfig = Pick<
| 'bunUrl'
| 'convexUrl'
| 'initialBalance'
| 'stdbCompression'
| 'stdbConfirmedReads'
| 'stdbModule'
| 'stdbUrl'
@@ -89,6 +95,7 @@ export type ConnectorRuntimeConfig = Pick<
export interface SpacetimeConnectorConfig {
initialBalance: number;
stdbCompression: StdbCompression;
stdbConfirmedReads: boolean;
stdbModule: string;
stdbUrl: string;
@@ -131,6 +138,19 @@ export function normalizeStdbUrl(url: string): string {
return url.replace(/^(http|ws)s?:\/\//, '');
}
export function parseStdbCompression(
raw: string,
label: string,
): StdbCompression {
if (validStdbCompressions.includes(raw as StdbCompression)) {
return raw as StdbCompression;
}
throw new Error(
`invalid value for ${label}: ${raw} (expected one of: ${validStdbCompressions.join(', ')})`,
);
}
export function readNumberEnv(
name: string,
defaultValue: number,
@@ -210,6 +230,10 @@ export function getSharedRuntimeDefaults(
stdbUrl: normalizeStdbUrl(readStringEnv('STDB_URL', '127.0.0.1:3000', env)),
stdbModule: readStringEnv('STDB_MODULE', 'test-1', env),
stdbModulePath: readStringEnv('STDB_MODULE_PATH', './spacetimedb', env),
stdbCompression: parseStdbCompression(
readStringEnv('STDB_COMPRESSION', 'none', env),
'STDB_COMPRESSION',
),
stdbConfirmedReads: readBooleanEnv('STDB_CONFIRMED_READS', true, env),
useDocker: readBooleanEnv('USE_DOCKER', false, env),
useSpacetimeMetricsEndpoint: readBooleanEnv(
@@ -23,6 +23,7 @@ const toSpacetimeConfig = (
config: ConnectorRuntimeConfig,
): SpacetimeConnectorConfig => ({
initialBalance: config.initialBalance,
stdbCompression: config.stdbCompression,
stdbConfirmedReads: config.stdbConfirmedReads,
stdbModule: config.stdbModule,
stdbUrl: config.stdbUrl,
@@ -6,6 +6,7 @@ import type { SpacetimeConnectorConfig } from '../config.ts';
export function spacetimedb(config: SpacetimeConnectorConfig): ReducerConnector {
const {
initialBalance,
stdbCompression,
stdbConfirmedReads,
stdbModule: moduleName,
stdbUrl: url,
@@ -33,6 +34,7 @@ export function spacetimedb(config: SpacetimeConnectorConfig): ReducerConnector
const builder = Db.builder()
.withUri(deriveWebsocketUrl(url))
.withDatabaseName(moduleName)
.withCompression(stdbCompression)
.withConfirmedReads(stdbConfirmedReads)
.onConnect((ctx) => {
console.log('[stdb] connected');
+3
View File
@@ -23,6 +23,7 @@ const {
noAnimation,
seconds,
skipPrep,
stdbCompression,
stdbConfirmedReads,
stdbModule,
stdbModulePath,
@@ -277,6 +278,8 @@ async function runBenchmarkStdb(): Promise<BenchResult | null> {
'ws://' + stdbUrl,
'--module',
stdbModule,
'--compression',
stdbCompression,
'--duration',
`${seconds}s`,
'--connections',
@@ -6,7 +6,9 @@ import { join } from 'node:path';
import { spacetimedb } from '../connectors/spacetimedb.ts';
import {
getSharedRuntimeDefaults,
parseStdbCompression,
type SpacetimeConnectorConfig,
type StdbCompression,
} from '../config.ts';
import { getSpacetimeCommittedTransfers } from '../core/spacetimeMetrics.ts';
import { normalizeStdbUrl } from '../core/stdbUrl.ts';
@@ -74,13 +76,18 @@ async function readJsonBody<T>(req: IncomingMessage): Promise<T> {
return JSON.parse(raw) as T;
}
async function runVerification(url: string, moduleName: string): Promise<void> {
async function runVerification(
url: string,
moduleName: string,
compression: StdbCompression,
): Promise<void> {
const prevVerify = process.env.VERIFY;
process.env.VERIFY = '1';
const defaults = getSharedRuntimeDefaults();
const config: SpacetimeConnectorConfig = {
initialBalance: defaults.initialBalance,
stdbCompression: compression,
stdbConfirmedReads: defaults.stdbConfirmedReads,
stdbModule: moduleName,
stdbUrl: url,
@@ -110,6 +117,7 @@ class DistributedCoordinator {
private readonly resultsDir: string;
private readonly stdbUrl: string;
private readonly moduleName: string;
private readonly stdbCompression: StdbCompression;
private readonly generators = new Map<string, GeneratorRecord>();
private phase: CoordinatorPhase = 'idle';
@@ -128,6 +136,7 @@ class DistributedCoordinator {
resultsDir: string;
stdbUrl: string;
moduleName: string;
stdbCompression: StdbCompression;
}) {
this.testName = opts.testName;
this.connectorName = opts.connectorName;
@@ -138,6 +147,7 @@ class DistributedCoordinator {
this.resultsDir = opts.resultsDir;
this.stdbUrl = opts.stdbUrl;
this.moduleName = opts.moduleName;
this.stdbCompression = opts.stdbCompression;
}
snapshot(): CoordinatorState {
@@ -326,7 +336,11 @@ class DistributedCoordinator {
if (this.verifyAfterEpoch) {
try {
await runVerification(this.stdbUrl, this.moduleName);
await runVerification(
this.stdbUrl,
this.moduleName,
this.stdbCompression,
);
verification = 'passed';
} catch (err) {
verification = 'failed';
@@ -450,11 +464,16 @@ async function main(): Promise<void> {
process.env.STDB_URL ?? 'ws://127.0.0.1:3000',
);
const stdbUrl = normalizeStdbUrl(rawStdbUrl);
const defaults = getSharedRuntimeDefaults();
const moduleName = getStringFlag(
flags,
'stdb-module',
process.env.STDB_MODULE ?? 'test-1',
);
const stdbCompression = parseStdbCompression(
getStringFlag(flags, 'stdb-compression', defaults.stdbCompression),
'--stdb-compression',
);
const initialIds = getStringListFlag(flags, 'generator-ids');
const coordinator = new DistributedCoordinator({
@@ -467,6 +486,7 @@ async function main(): Promise<void> {
resultsDir,
stdbUrl,
moduleName,
stdbCompression,
});
const server = createServer(async (req, res) => {
@@ -530,7 +550,7 @@ async function main(): Promise<void> {
});
console.log(
`[coordinator] listening on http://${bind}:${port} test=${testName} connector=${connectorName} warmup=${warmupSeconds}s window=${windowSeconds}s verify=${verifyAfterEpoch ? 'on' : 'off'} stdb=${stdbUrl}`,
`[coordinator] listening on http://${bind}:${port} test=${testName} connector=${connectorName} warmup=${warmupSeconds}s window=${windowSeconds}s verify=${verifyAfterEpoch ? 'on' : 'off'} stdb=${stdbUrl} compression=${stdbCompression}`,
);
}
@@ -4,6 +4,7 @@ import { hostname as getHostname } from 'node:os';
import { spacetimedb } from '../connectors/spacetimedb.ts';
import {
getSharedRuntimeDefaults,
parseStdbCompression,
type SpacetimeConnectorConfig,
} from '../config.ts';
import type { ReducerConnector } from '../core/connectors.ts';
@@ -58,8 +59,13 @@ async function main(): Promise<void> {
process.env.STDB_MODULE ?? 'test-1',
);
const defaults = getSharedRuntimeDefaults();
const stdbCompression = parseStdbCompression(
getStringFlag(flags, 'stdb-compression', defaults.stdbCompression),
'--stdb-compression',
);
const connectorConfig: SpacetimeConnectorConfig = {
initialBalance: defaults.initialBalance,
stdbCompression,
stdbConfirmedReads: defaults.stdbConfirmedReads,
stdbModule: moduleName,
stdbUrl,
@@ -123,7 +129,7 @@ async function main(): Promise<void> {
}, pollMs, controlRetries, () => !stopping);
console.log(
`[generator ${id}] ready with ${session.openedConnections} connections to ${stdbUrl}/${moduleName}`,
`[generator ${id}] ready with ${session.openedConnections} connections to ${stdbUrl}/${moduleName} compression=${stdbCompression}`,
);
while (!stopping) {
+10
View File
@@ -4,6 +4,7 @@ import {
defaultBenchTestName,
defaultDemoSystems,
getSharedRuntimeDefaults,
parseStdbCompression,
parseConnectorList,
type BenchOptions,
type ConcurrencyTests,
@@ -151,6 +152,11 @@ function addSharedRuntimeOptions(parser: CLIParser): CLIParser {
.option('--stdb-url <url>', 'SpacetimeDB url', str())
.option('--stdb-module <name>', 'SpacetimeDB module name', str())
.option('--stdb-module-path <dir>', 'SpacetimeDB module path', str())
.option(
'--stdb-compression <mode>',
'SpacetimeDB client compression mode (`none` or `gzip`)',
str(),
)
.option('--no-stdb-confirmed-reads', 'Disable confirmed reads')
.option('--use-docker', 'Use docker')
.option('--no-use-spacetime-metrics-endpoint', '')
@@ -187,6 +193,10 @@ function resolveRuntimeOptions(
stdbUrl: normalizeStdbUrl(options.stdbUrl ?? defaults.stdbUrl),
stdbModule: options.stdbModule ?? defaults.stdbModule,
stdbModulePath: options.stdbModulePath ?? defaults.stdbModulePath,
stdbCompression: parseStdbCompression(
options.stdbCompression ?? defaults.stdbCompression,
'--stdb-compression',
),
stdbConfirmedReads:
options.stdbConfirmedReads ?? defaults.stdbConfirmedReads,
useDocker: options.useDocker ?? defaults.useDocker,