mirror of
https://github.com/element-hq/synapse.git
synced 2026-11-05 21:57:42 +00:00
`createroom_bench.py` takes levels such as `full+rooms`, which add `rust_room_creation: on` to a `rust_event_persistence` level, and runs `off`, `full` and `full+rooms` by default. `persist_bench.Server` takes extra experimental features for that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PVLsNh6akt4ifEizY4D1ta
154 lines
5.1 KiB
Python
Executable File
154 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# This file is licensed under the Affero General Public License (AGPL) version 3.
|
|
#
|
|
# Copyright (C) 2026 Element Creations Ltd
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# See the GNU Affero General Public License for more details:
|
|
# <https://www.gnu.org/licenses/agpl-3.0.html>.
|
|
#
|
|
|
|
"""Time `/createRoom` against a real Synapse on Postgres.
|
|
|
|
Starts the server the way `persist_bench.py` does, once per
|
|
`rust_event_persistence` level. For each scenario it creates five warm-up
|
|
rooms, then `--rooms` rooms one after another, and reports the mean and median
|
|
request time and the CPU of the reactor thread and of the process per room.
|
|
|
|
poetry run python scripts-dev/createroom_bench.py --levels off,full,full+rooms
|
|
|
|
A level with `+rooms` also turns on `rust_room_creation`. `--psycopg2` runs
|
|
the server on psycopg2 instead of the native driver.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import statistics
|
|
import sys
|
|
import tempfile
|
|
import time
|
|
from typing import Any
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
import persist_bench as pb # noqa: E402
|
|
|
|
SCENARIOS: dict[str, dict[str, Any]] = {
|
|
"plain": {},
|
|
"private_invite": {"preset": "private_chat", "invite": ["@invitee:bench"]},
|
|
"public_named": {"preset": "public_chat", "name": "Bench room", "topic": "A topic"},
|
|
"initial_state": {
|
|
"initial_state": [
|
|
{
|
|
"type": "m.room.encryption",
|
|
"state_key": "",
|
|
"content": {"algorithm": "m.megolm.v1.aes-sha2"},
|
|
},
|
|
{
|
|
"type": "m.room.guest_access",
|
|
"state_key": "",
|
|
"content": {"guest_access": "can_join"},
|
|
},
|
|
{
|
|
"type": "m.space.child",
|
|
"state_key": "!a:bench",
|
|
"content": {"via": ["bench"]},
|
|
},
|
|
{
|
|
"type": "m.space.child",
|
|
"state_key": "!b:bench",
|
|
"content": {"via": ["bench"]},
|
|
},
|
|
]
|
|
},
|
|
}
|
|
|
|
CREATE_ROOM = "/_matrix/client/v3/createRoom"
|
|
|
|
|
|
def bench_level(level: str, rooms: int, rust_driver: bool) -> list[dict[str, Any]]:
|
|
"""Benchmark a server at `level`: a `rust_event_persistence` level,
|
|
optionally followed by `+rooms` for `rust_room_creation: on`."""
|
|
results = []
|
|
persist_level, _, extra = level.partition("+")
|
|
if extra not in ("", "rooms"):
|
|
raise ValueError(f"unknown level suffix {extra!r} in {level!r}")
|
|
experimental = {"rust_room_creation": "on"} if extra == "rooms" else {}
|
|
workdir = tempfile.mkdtemp(prefix=f"createroom-bench-{persist_level}-")
|
|
server = pb.Server(
|
|
persist_level, workdir, rust_driver=rust_driver, experimental=experimental
|
|
)
|
|
try:
|
|
server.start()
|
|
token = pb.register("creator")
|
|
pb.register("invitee")
|
|
for name, body in SCENARIOS.items():
|
|
for _ in range(5):
|
|
pb.ok("POST", CREATE_ROOM, body, token)
|
|
before = server.sample()
|
|
times = []
|
|
for _ in range(rooms):
|
|
t0 = time.perf_counter()
|
|
pb.ok("POST", CREATE_ROOM, body, token)
|
|
times.append(time.perf_counter() - t0)
|
|
after = server.sample()
|
|
row = {
|
|
"level": level,
|
|
"scenario": name,
|
|
"mean_ms": 1000 * statistics.mean(times),
|
|
"p50_ms": 1000 * statistics.median(times),
|
|
"reactor_cpu_ms": 1000
|
|
* (after.reactor_cpu - before.reactor_cpu)
|
|
/ rooms,
|
|
"process_cpu_ms": 1000
|
|
* (after.process_cpu - before.process_cpu)
|
|
/ rooms,
|
|
}
|
|
results.append(row)
|
|
print(row, flush=True)
|
|
finally:
|
|
server.stop()
|
|
return results
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument(
|
|
"--levels",
|
|
default="off,full,full+rooms",
|
|
help="comma-separated `rust_event_persistence` levels; append `+rooms`"
|
|
" to a level for `rust_room_creation: on`",
|
|
)
|
|
parser.add_argument("--rooms", type=int, default=40)
|
|
parser.add_argument("--psycopg2", action="store_true")
|
|
parser.add_argument("--json", help="also write the results to this file")
|
|
args = parser.parse_args()
|
|
|
|
results = []
|
|
for level in args.levels.split(","):
|
|
results += bench_level(level, args.rooms, rust_driver=not args.psycopg2)
|
|
|
|
print(
|
|
f"\n{'scenario':<16} {'level':<12} {'mean ms':>8} {'p50 ms':>8}"
|
|
f" {'reactor ms':>11} {'process ms':>11}"
|
|
)
|
|
for r in results:
|
|
print(
|
|
f"{r['scenario']:<16} {r['level']:<12} {r['mean_ms']:>8.1f}"
|
|
f" {r['p50_ms']:>8.1f} {r['reactor_cpu_ms']:>11.1f}"
|
|
f" {r['process_cpu_ms']:>11.1f}"
|
|
)
|
|
if args.json:
|
|
with open(args.json, "w") as f:
|
|
json.dump(results, f, indent=2)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|