mirror of
https://github.com/neondatabase/neon.git
synced 2026-07-08 22:50:37 +00:00
undo the WIP benchmarks, will clean those up and commit in a future PR
This commit is contained in:
@@ -1,102 +0,0 @@
|
||||
"""
|
||||
Creates stack of L0 deltas each of which should have 1 Value::Delta per page in `data`,
|
||||
in your running neon_local setup.
|
||||
|
||||
This showcases the need for concurrent IO.
|
||||
|
||||
I'm not completely sure about it because I don't yet understand the relation between
|
||||
fillfactor and mvcc (does mvcc use the unfilled space in the page?).
|
||||
|
||||
I think there's a chance that some of the deltas are will_init .
|
||||
Could be avoided with disabling fullpage writes.
|
||||
|
||||
TODO: concurrent IO will read beyond will_init and discard the data (I think).
|
||||
Measure impact of that.
|
||||
|
||||
Some commands from shell history used in combination with this script:
|
||||
|
||||
```
|
||||
export NEON_REPO_DIR=$PWD/.neon
|
||||
export NEON_BIN_DIR=$PWD/target/release
|
||||
$NEON_BIN_DIR/neon_local stop
|
||||
rm -rf $NEON_REPO_DIR
|
||||
$NEON_BIN_DIR/neon_local init
|
||||
cat >> $NEON_REPO_DIR/pageserver_1/pageserver.toml <<"EOF"
|
||||
# customizations
|
||||
virtual_file_io_mode = "direct"
|
||||
page_service_pipelining={mode="pipelined", max_batch_size=32, execution="concurrent-futures"}
|
||||
get_vectored_concurrent_io={mode="sidecar-task"}
|
||||
EOF
|
||||
$NEON_BIN_DIR/neon_local start
|
||||
|
||||
psql 'postgresql://localhost:1235/storage_controller' -c 'DELETE FROM tenant_shards'
|
||||
sed 's/.*get_vectored_concurrent_io.*/get_vectored_concurrent_io={mode="sidecar-task"}/' -i $NEON_REPO_DIR/pageserver_1/pageserver.toml
|
||||
$NEON_BIN_DIR/neon_local pageserver restart
|
||||
sleep 2
|
||||
$NEON_BIN_DIR/neon_local tenant create --set-default
|
||||
./target/debug/neon_local endpoint stop foo
|
||||
rm -rf $NEON_REPO_DIR/endpoints/foo
|
||||
./target/debug/neon_local endpoint create foo
|
||||
echo 'full_page_writes=off' >> $NEON_REPO_DIR/endpoints/foo/postgresql.conf
|
||||
./target/debug/neon_local endpoint start foo
|
||||
pushd test_runner; poetry run python3 deep_layers_with_delta.py 20; popd
|
||||
```
|
||||
|
||||
Layer files created:
|
||||
|
||||
christian@neon-hetzner-dev-christian:[~/src/neon]: ls -hlrt .neon/pageserver_1/tenants/*/timelines/*
|
||||
total 67M
|
||||
-rw-r--r-- 1 christian 23M Dec 13 12:38 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__00000000014F1378-00000000014F13F1-v1-00000001
|
||||
-rw-r--r-- 1 christian 9.3M Dec 13 12:41 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__00000000014F13F1-0000000001C4D021-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:41 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000001C4D021-0000000001DC51F1-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:41 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000001DC51F1-0000000001F3D3C1-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:41 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000001F3D3C1-00000000020B55A1-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:41 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__00000000020B55A1-000000000222D771-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:41 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__000000000222D771-00000000023A5941-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__00000000023A5941-000000000251DB11-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__000000000251DB11-0000000002695D19-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000002695D19-000000000280DEE9-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__000000000280DEE9-00000000029860D1-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__00000000029860D1-0000000002AFE2A1-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000002AFE2A1-0000000002C76471-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000002C76471-0000000002DEE679-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000002DEE679-0000000002F66849-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000002F66849-00000000030DEA29-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__00000000030DEA29-0000000003256BF9-v1-00000001
|
||||
-rw-r--r-- 1 christian 2.0M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000003256BF9-00000000033CEE39-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.7M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__00000000033CEE39-0000000003512B91-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.4M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000003512B91-0000000003633D91-v1-00000001
|
||||
-rw-r--r-- 1 christian 1.9M Dec 13 12:42 000000000000000000000000000000000000-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF__0000000003633D91-00000000037AE2E9-v1-00000001
|
||||
-rw-r--r-- 1 christian 0 Dec 13 12:42 ephemeral-22
|
||||
|
||||
Now use pagebench to measure perf, e.g.
|
||||
|
||||
./target/release/pagebench get-page-latest-lsn --num-clients=1 --queue-depth 100 --runtime=5s
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import psycopg2
|
||||
from fixtures.common_types import TenantShardId, TimelineId
|
||||
from fixtures.pageserver.http import PageserverHttpClient
|
||||
from fixtures.pageserver.makelayers.l0stack import L0StackShape, make_l0_stack_standalone
|
||||
|
||||
ps_http = PageserverHttpClient(port=9898, is_testing_enabled_or_skip=lambda: None)
|
||||
vps_http = PageserverHttpClient(port=1234, is_testing_enabled_or_skip=lambda: None)
|
||||
|
||||
tenants = ps_http.tenant_list()
|
||||
assert len(tenants) == 1
|
||||
tenant_shard_id = TenantShardId.parse(tenants[0]["id"])
|
||||
|
||||
timlines = ps_http.timeline_list(tenant_shard_id)
|
||||
assert len(timlines) == 1
|
||||
timeline_id = TimelineId(timlines[0]["timeline_id"])
|
||||
|
||||
connstr = "postgresql://cloud_admin@localhost:55432/postgres"
|
||||
conn = psycopg2.connect(connstr)
|
||||
|
||||
shape = L0StackShape(logical_table_size_mib=50, delta_stack_height=int(sys.argv[1]))
|
||||
|
||||
make_l0_stack_standalone(vps_http, ps_http, tenant_shard_id, timeline_id, conn, shape)
|
||||
@@ -1215,11 +1215,7 @@ class NeonEnv:
|
||||
force=config.config_init_force,
|
||||
)
|
||||
|
||||
def start(
|
||||
self,
|
||||
timeout_in_seconds: int | None = None,
|
||||
extra_ps_env_vars: dict[str, str] | None = None,
|
||||
):
|
||||
def start(self, timeout_in_seconds: int | None = None):
|
||||
# Storage controller starts first, so that pageserver /re-attach calls don't
|
||||
# bounce through retries on startup
|
||||
self.storage_controller.start(timeout_in_seconds=timeout_in_seconds)
|
||||
@@ -1238,10 +1234,7 @@ class NeonEnv:
|
||||
for pageserver in self.pageservers:
|
||||
futs.append(
|
||||
executor.submit(
|
||||
lambda ps=pageserver: ps.start( # type: ignore[misc]
|
||||
extra_env_vars=extra_ps_env_vars or {},
|
||||
timeout_in_seconds=timeout_in_seconds,
|
||||
),
|
||||
lambda ps=pageserver: ps.start(timeout_in_seconds=timeout_in_seconds) # type: ignore[misc]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from psycopg2.extensions import connection as PgConnection
|
||||
|
||||
from fixtures.common_types import Lsn, ShardIndex, TenantShardId, TimelineId
|
||||
from fixtures.log_helper import log
|
||||
from fixtures.neon_fixtures import Endpoint
|
||||
from fixtures.pageserver.http import PageserverHttpClient
|
||||
from fixtures.pageserver.utils import wait_for_last_record_lsn
|
||||
|
||||
|
||||
@dataclass
|
||||
class L0StackShape:
|
||||
logical_table_size_mib: int = 50
|
||||
delta_stack_height: int = 20
|
||||
|
||||
|
||||
def make_l0_stack(endpoint: Endpoint, shape: L0StackShape):
|
||||
env = endpoint.env
|
||||
|
||||
# TDOO: wait for storcon to finish any reonciles before jumping to action here?
|
||||
shards = env.storage_controller.tenant_describe(endpoint.tenant_id)
|
||||
|
||||
shard_idx = ShardIndex.parse(shards[0]["shard_id"])
|
||||
assert shard_idx.shard_count == 1, "see above"
|
||||
tenant_shard_id = TenantShardId(
|
||||
endpoint.tenant_id, shard_idx.shard_number, shard_idx.shard_count
|
||||
)
|
||||
|
||||
ps = env.get_pageserver(shards[0]["node_id"])
|
||||
|
||||
timeline_id = endpoint.show_timeline_id()
|
||||
|
||||
vps_http = env.storage_controller.pageserver_api()
|
||||
ps_http = ps.http_client()
|
||||
endpoint_conn = endpoint.connect()
|
||||
make_l0_stack_standalone(vps_http, ps_http, tenant_shard_id, timeline_id, endpoint_conn, shape)
|
||||
|
||||
|
||||
def make_l0_stack_standalone(
|
||||
vps_http: PageserverHttpClient,
|
||||
ps_http: PageserverHttpClient,
|
||||
tenant_shard_id: TenantShardId,
|
||||
timeline_id: TimelineId,
|
||||
endpoint_conn: PgConnection,
|
||||
shape: L0StackShape,
|
||||
):
|
||||
"""
|
||||
Creates stack of L0 deltas each of which should have 1 Value::Delta per page in `data`.
|
||||
|
||||
Usable from scripts (ad-hoc manual testing in neon_local) and pytest code alike.
|
||||
"""
|
||||
|
||||
assert (
|
||||
not tenant_shard_id.shard_index.is_sharded
|
||||
), "the current implementation only supports unsharded tenants"
|
||||
|
||||
tenant_id = tenant_shard_id.tenant_id
|
||||
conn = endpoint_conn
|
||||
desired_size = shape.logical_table_size_mib * 1024 * 1024
|
||||
|
||||
config = {
|
||||
"gc_period": "0s", # disable periodic gc
|
||||
"checkpoint_timeout": "10 years",
|
||||
"compaction_period": "1h", # doesn't matter, but 0 value will kill walredo every 10s
|
||||
"compaction_threshold": 100000, # we just want L0s
|
||||
"compaction_target_size": 134217728,
|
||||
"checkpoint_distance": 268435456,
|
||||
"image_creation_threshold": 100000, # we just want L0s
|
||||
}
|
||||
|
||||
vps_http.set_tenant_config(tenant_id, config)
|
||||
|
||||
conn.autocommit = True
|
||||
cur = conn.cursor()
|
||||
|
||||
# each tuple is 23 (header) + 100 bytes = 123 bytes
|
||||
# page header si 24 bytes
|
||||
# 8k page size
|
||||
# (8k-24bytes) / 123 bytes = 63 tuples per page
|
||||
# set fillfactor to 10 to have 6 tuples per page
|
||||
cur.execute("DROP TABLE IF EXISTS data")
|
||||
cur.execute("CREATE TABLE data(id bigint, row char(92)) with (fillfactor=10)")
|
||||
need_pages = desired_size // 8192
|
||||
need_rows = need_pages * 6
|
||||
log.info(f"Need {need_pages} pages, {need_rows} rows")
|
||||
cur.execute(f"INSERT INTO data SELECT i,'row'||i FROM generate_series(1, {need_rows}) as i")
|
||||
|
||||
def settle_and_flush():
|
||||
cur.execute("SELECT pg_current_wal_flush_lsn()")
|
||||
flush_lsn = Lsn(cur.fetchall()[0][0])
|
||||
wait_for_last_record_lsn(ps_http, tenant_shard_id, timeline_id, flush_lsn)
|
||||
ps_http.timeline_checkpoint(tenant_id, timeline_id)
|
||||
ps_http.timeline_compact(tenant_id, timeline_id)
|
||||
|
||||
# create an L0 for the initial data we just inserted
|
||||
settle_and_flush()
|
||||
# every iteration updates one tuple in each page
|
||||
delta_stack_height = shape.delta_stack_height
|
||||
for i in range(0, delta_stack_height):
|
||||
log.info(i)
|
||||
cur.execute(f"UPDATE data set row = row||',u' where id % 6 = {i%6}")
|
||||
log.info("modified rows", cur.rowcount)
|
||||
settle_and_flush()
|
||||
@@ -1,10 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -60,15 +56,13 @@ def test_pageserver_characterize_throughput_with_n_tenants(
|
||||
# For reference, the space usage of the snapshots:
|
||||
# sudo du -hs /instance_store/neon/test_output/shared-snapshots/*
|
||||
# 19G /instance_store/neon/test_output/shared-snapshots/max_throughput_latest_lsn-1-136
|
||||
@pytest.mark.parametrize("duration", [20])
|
||||
@pytest.mark.parametrize("duration", [20 * 60])
|
||||
@pytest.mark.parametrize("pgbench_scale", [get_scale_for_db(2048)])
|
||||
# we use 1 client to characterize latencies, and 64 clients to characterize throughput/scalability
|
||||
# we use 64 clients because typically for a high number of connections we recommend the connection pooler
|
||||
# which by default uses 64 connections
|
||||
@pytest.mark.parametrize("n_clients", [1])
|
||||
@pytest.mark.parametrize("n_clients", [1, 64])
|
||||
@pytest.mark.parametrize("n_tenants", [1])
|
||||
@pytest.mark.parametrize("io_concurrency", ["serial", "futures-unordered"])
|
||||
@pytest.mark.parametrize("ps_direct_io_mode", ["direct"])
|
||||
@pytest.mark.timeout(2400)
|
||||
@skip_on_ci(
|
||||
"This test needs lot of resources and should run on dedicated HW, not in github action runners as part of CI"
|
||||
@@ -81,19 +75,9 @@ def test_pageserver_characterize_latencies_with_1_client_and_throughput_with_man
|
||||
pgbench_scale: int,
|
||||
duration: int,
|
||||
n_clients: int,
|
||||
io_concurrency: str,
|
||||
ps_direct_io_mode: str,
|
||||
):
|
||||
setup_and_run_pagebench_benchmark(
|
||||
neon_env_builder,
|
||||
zenbenchmark,
|
||||
pg_bin,
|
||||
n_tenants,
|
||||
pgbench_scale,
|
||||
duration,
|
||||
n_clients,
|
||||
io_concurrency,
|
||||
ps_direct_io_mode,
|
||||
neon_env_builder, zenbenchmark, pg_bin, n_tenants, pgbench_scale, duration, n_clients
|
||||
)
|
||||
|
||||
|
||||
@@ -105,8 +89,6 @@ def setup_and_run_pagebench_benchmark(
|
||||
pgbench_scale: int,
|
||||
duration: int,
|
||||
n_clients: int,
|
||||
io_concurrency: str = "sequential",
|
||||
ps_direct_io_mode: str = "buffered",
|
||||
):
|
||||
def record(metric, **kwargs):
|
||||
zenbenchmark.record(
|
||||
@@ -122,15 +104,6 @@ def setup_and_run_pagebench_benchmark(
|
||||
"pgbench_scale": (pgbench_scale, {"unit": ""}),
|
||||
"duration": (duration, {"unit": "s"}),
|
||||
"n_clients": (n_clients, {"unit": ""}),
|
||||
"config": (
|
||||
0,
|
||||
{
|
||||
"labels": {
|
||||
"io_concurrency": io_concurrency,
|
||||
"ps_direct_io_mode": ps_direct_io_mode,
|
||||
}
|
||||
},
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -140,8 +113,6 @@ def setup_and_run_pagebench_benchmark(
|
||||
neon_env_builder.pageserver_config_override = (
|
||||
f"page_cache_size={page_cache_size}; max_file_descriptors={max_file_descriptors}"
|
||||
)
|
||||
neon_env_builder.pageserver_virtual_file_io_mode = ps_direct_io_mode
|
||||
neon_env_builder.pageserver_get_vectored_concurrent_io = io_concurrency
|
||||
params.update(
|
||||
{
|
||||
"pageserver_config_override.page_cache_size": (
|
||||
@@ -153,14 +124,7 @@ def setup_and_run_pagebench_benchmark(
|
||||
)
|
||||
|
||||
for param, (value, kwargs) in params.items():
|
||||
record(
|
||||
param,
|
||||
metric_value=value,
|
||||
report=MetricReport.TEST_PARAM,
|
||||
labels=kwargs.pop("labels", None),
|
||||
unit=kwargs.pop("unit", ""),
|
||||
**kwargs,
|
||||
)
|
||||
record(param, metric_value=value, report=MetricReport.TEST_PARAM, **kwargs)
|
||||
|
||||
def setup_wrapper(env: NeonEnv):
|
||||
return setup_tenant_template(env, pg_bin, pgbench_scale)
|
||||
@@ -246,61 +210,6 @@ def run_pagebench_benchmark(
|
||||
"""
|
||||
|
||||
ps_http = env.pageserver.http_client()
|
||||
|
||||
@dataclass
|
||||
class Metrics:
|
||||
time: float
|
||||
pageserver_cpu_seconds_total: float
|
||||
pageserver_layers_visited_per_vectored_read_global_buckets: dict[int, int]
|
||||
|
||||
def __sub__(self, other: Metrics) -> Metrics:
|
||||
return Metrics(
|
||||
time=self.time - other.time,
|
||||
pageserver_cpu_seconds_total=self.pageserver_cpu_seconds_total
|
||||
- other.pageserver_cpu_seconds_total,
|
||||
pageserver_layers_visited_per_vectored_read_global_buckets={
|
||||
k: v - other.pageserver_layers_visited_per_vectored_read_global_buckets[k]
|
||||
for k, v in self.pageserver_layers_visited_per_vectored_read_global_buckets.items()
|
||||
},
|
||||
)
|
||||
|
||||
def normalize(self, by) -> Metrics:
|
||||
return Metrics(
|
||||
time=self.time / by,
|
||||
pageserver_cpu_seconds_total=self.pageserver_cpu_seconds_total / by,
|
||||
pageserver_layers_visited_per_vectored_read_global_buckets={
|
||||
k: v / by
|
||||
for k, v in self.pageserver_layers_visited_per_vectored_read_global_buckets.items()
|
||||
},
|
||||
)
|
||||
|
||||
def get_metrics() -> Metrics:
|
||||
pageserver_metrics = ps_http.get_metrics()
|
||||
|
||||
def parse_le_label(s):
|
||||
try:
|
||||
return int(s)
|
||||
except ValueError:
|
||||
if s == "+Inf":
|
||||
return sys.maxsize
|
||||
else:
|
||||
raise
|
||||
|
||||
return Metrics(
|
||||
time=time.time(),
|
||||
pageserver_cpu_seconds_total=pageserver_metrics.query_one(
|
||||
"libmetrics_process_cpu_seconds_highres"
|
||||
).value,
|
||||
pageserver_layers_visited_per_vectored_read_global_buckets={
|
||||
parse_le_label(sample.labels["le"]): int(sample.value)
|
||||
for sample in pageserver_metrics.query_all(
|
||||
"pageserver_layers_visited_per_vectored_read_global_bucket"
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
metrics_before = get_metrics()
|
||||
|
||||
cmd = [
|
||||
str(env.neon_binpath / "pagebench"),
|
||||
"get-page-latest-lsn",
|
||||
@@ -325,14 +234,6 @@ def run_pagebench_benchmark(
|
||||
|
||||
total = results["total"]
|
||||
|
||||
metrics_after = get_metrics()
|
||||
|
||||
metrics = metrics_after - metrics_before
|
||||
|
||||
#
|
||||
# Record the results
|
||||
#
|
||||
|
||||
metric = "request_count"
|
||||
record(
|
||||
metric,
|
||||
@@ -350,24 +251,10 @@ def run_pagebench_benchmark(
|
||||
)
|
||||
|
||||
metric = "latency_percentiles"
|
||||
for bucket, v in total[metric].items():
|
||||
for k, v in total[metric].items():
|
||||
record(
|
||||
f"{metric}.{bucket}",
|
||||
f"{metric}.{k}",
|
||||
metric_value=humantime_to_ms(v),
|
||||
unit="ms",
|
||||
report=MetricReport.LOWER_IS_BETTER,
|
||||
)
|
||||
|
||||
for metric, value in dataclasses.asdict(metrics).items():
|
||||
if isinstance(value, dict):
|
||||
for bucket, v in value.items():
|
||||
record(
|
||||
f"counters.{metric}.{bucket}",
|
||||
metric_value=v,
|
||||
unit="",
|
||||
report=MetricReport.TEST_PARAM,
|
||||
)
|
||||
else:
|
||||
record(
|
||||
f"counters.{metric}", metric_value=value, unit="", report=MetricReport.TEST_PARAM
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ from fixtures.log_helper import log
|
||||
from fixtures.neon_fixtures import NeonEnvBuilder, PgBin, wait_for_last_flush_lsn
|
||||
from fixtures.utils import humantime_to_ms
|
||||
|
||||
TARGET_RUNTIME = 5
|
||||
TARGET_RUNTIME = 30
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -31,9 +31,7 @@ class PageServicePipeliningConfigPipelined(PageServicePipeliningConfig):
|
||||
mode: str = "pipelined"
|
||||
|
||||
|
||||
PS_DIRECT_IO = ["direct"]
|
||||
PS_IO_CONCURRENCY = ["sequential", "sidecar-task"]
|
||||
EXECUTION = ["concurrent-futures"]
|
||||
EXECUTION = ["concurrent-futures", "tasks"]
|
||||
|
||||
NON_BATCHABLE: list[PageServicePipeliningConfig] = [PageServicePipeliningConfigSerial()]
|
||||
for max_batch_size in [1, 32]:
|
||||
@@ -41,45 +39,38 @@ for max_batch_size in [1, 32]:
|
||||
NON_BATCHABLE.append(PageServicePipeliningConfigPipelined(max_batch_size, execution))
|
||||
|
||||
BATCHABLE: list[PageServicePipeliningConfig] = [PageServicePipeliningConfigSerial()]
|
||||
for max_batch_size in [32]:
|
||||
for max_batch_size in [1, 2, 4, 8, 16, 32]:
|
||||
for execution in EXECUTION:
|
||||
BATCHABLE.append(PageServicePipeliningConfigPipelined(max_batch_size, execution))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"tablesize_mib, pipelining_config, target_runtime, ps_io_concurrency, ps_direct_io_mode, effective_io_concurrency, readhead_buffer_size, name",
|
||||
"tablesize_mib, pipelining_config, target_runtime, effective_io_concurrency, readhead_buffer_size, name",
|
||||
[
|
||||
# non-batchable workloads
|
||||
# (A separate benchmark will consider latency).
|
||||
# *[
|
||||
# (
|
||||
# 50,
|
||||
# config,
|
||||
# TARGET_RUNTIME,
|
||||
# ps_io_concurrency,
|
||||
# ps_direct_io_mode,
|
||||
# 1,
|
||||
# 128,
|
||||
# f"not batchable {dataclasses.asdict(config)}",
|
||||
# )
|
||||
# for config in NON_BATCHABLE
|
||||
# for ps_io_concurrency in PS_IO_CONCURRENCY
|
||||
# ],
|
||||
*[
|
||||
(
|
||||
50,
|
||||
config,
|
||||
TARGET_RUNTIME,
|
||||
1,
|
||||
128,
|
||||
f"not batchable {dataclasses.asdict(config)}",
|
||||
)
|
||||
for config in NON_BATCHABLE
|
||||
],
|
||||
# batchable workloads should show throughput and CPU efficiency improvements
|
||||
*[
|
||||
(
|
||||
50,
|
||||
config,
|
||||
TARGET_RUNTIME,
|
||||
ps_io_concurrency,
|
||||
ps_direct_io_mode,
|
||||
100,
|
||||
128,
|
||||
f"batchable {dataclasses.asdict(config)}",
|
||||
)
|
||||
for config in BATCHABLE
|
||||
for ps_io_concurrency in PS_IO_CONCURRENCY
|
||||
for ps_direct_io_mode in PS_DIRECT_IO
|
||||
],
|
||||
],
|
||||
)
|
||||
@@ -89,8 +80,6 @@ def test_throughput(
|
||||
tablesize_mib: int,
|
||||
pipelining_config: PageServicePipeliningConfig,
|
||||
target_runtime: int,
|
||||
ps_io_concurrency: str,
|
||||
ps_direct_io_mode: str,
|
||||
effective_io_concurrency: int,
|
||||
readhead_buffer_size: int,
|
||||
name: str,
|
||||
@@ -128,20 +117,7 @@ def test_throughput(
|
||||
}
|
||||
)
|
||||
# For storing configuration as a metric, insert a fake 0 with labels with actual data
|
||||
params.update(
|
||||
{
|
||||
"config": (
|
||||
0,
|
||||
{
|
||||
"labels": {
|
||||
"pipelining_config": dataclasses.asdict(pipelining_config),
|
||||
"ps_io_concurrency": ps_io_concurrency,
|
||||
"direct_io": ps_direct_io_mode,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
params.update({"pipelining_config": (0, {"labels": dataclasses.asdict(pipelining_config)})})
|
||||
|
||||
log.info("params: %s", params)
|
||||
|
||||
@@ -253,11 +229,7 @@ def test_throughput(
|
||||
return (after - before).normalize(iters - 1)
|
||||
|
||||
env.pageserver.patch_config_toml_nonrecursive(
|
||||
{
|
||||
"page_service_pipelining": dataclasses.asdict(pipelining_config),
|
||||
"virtual_file_io_mode": ps_direct_io_mode,
|
||||
"get_vectored_concurrent_io": {"mode": ps_io_concurrency},
|
||||
}
|
||||
{"page_service_pipelining": dataclasses.asdict(pipelining_config)}
|
||||
)
|
||||
env.pageserver.restart()
|
||||
metrics = workload()
|
||||
@@ -294,19 +266,14 @@ for max_batch_size in [1, 32]:
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"pipelining_config,ps_io_concurrency,name",
|
||||
[
|
||||
(config, ps_io_concurrency, f"{dataclasses.asdict(config)}")
|
||||
for config in PRECISION_CONFIGS
|
||||
for ps_io_concurrency in PS_IO_CONCURRENCY
|
||||
],
|
||||
"pipelining_config,name",
|
||||
[(config, f"{dataclasses.asdict(config)}") for config in PRECISION_CONFIGS],
|
||||
)
|
||||
def test_latency(
|
||||
neon_env_builder: NeonEnvBuilder,
|
||||
zenbenchmark: NeonBenchmarker,
|
||||
pg_bin: PgBin,
|
||||
pipelining_config: PageServicePipeliningConfig,
|
||||
ps_io_concurrency: str,
|
||||
name: str,
|
||||
):
|
||||
"""
|
||||
@@ -325,8 +292,6 @@ def test_latency(
|
||||
def patch_ps_config(ps_config):
|
||||
if pipelining_config is not None:
|
||||
ps_config["page_service_pipelining"] = dataclasses.asdict(pipelining_config)
|
||||
ps_config["get_vectored_concurrent_io"] = {"mode": ps_io_concurrency}
|
||||
# FIXME: parametrize over direct IO mode
|
||||
|
||||
neon_env_builder.pageserver_config_override = patch_ps_config
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ def setup_pageserver_with_tenants(
|
||||
n_tenants: int,
|
||||
setup: Callable[[NeonEnv], tuple[TenantId, TimelineId, dict[str, Any]]],
|
||||
timeout_in_seconds: int | None = None,
|
||||
extra_ps_env_vars: dict[str, str] | None = None,
|
||||
) -> NeonEnv:
|
||||
"""
|
||||
Utility function to set up a pageserver with a given number of identical tenants.
|
||||
@@ -58,6 +57,6 @@ def setup_pageserver_with_tenants(
|
||||
return many_tenants.single_timeline(neon_env_builder, setup, n_tenants)
|
||||
|
||||
env = neon_env_builder.build_and_use_snapshot(name, doit)
|
||||
env.start(timeout_in_seconds=timeout_in_seconds, extra_ps_env_vars=extra_ps_env_vars)
|
||||
env.start(timeout_in_seconds=timeout_in_seconds)
|
||||
ensure_pageserver_ready_for_benchmarking(env, n_tenants)
|
||||
return env
|
||||
|
||||
Reference in New Issue
Block a user