From e3db01cd487c5b666366885367c8bfff4a6a09da Mon Sep 17 00:00:00 2001 From: tanaka takashi Date: Tue, 30 Jun 2026 23:55:29 +0900 Subject: 検索インデックスのhash table化 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/implementation-status.md | 16 +- scripts/python/README.md | 21 +- scripts/python/benchmark.py | 131 +- scripts/python/benchmark_results.json | 2325 +++++++++++++++++++-------------- scripts/python/benchmark_results.md | 49 +- src/domain/search.c | 334 ++++- tests/CMakeLists.txt | 28 + tests/function-coverage.md | 1 + tests/mcp_protocol_test.py | 37 + tests/search_index_benchmark.c | 110 ++ tests/search_index_test.c | 161 +++ 11 files changed, 2143 insertions(+), 1070 deletions(-) create mode 100644 tests/search_index_benchmark.c create mode 100644 tests/search_index_test.c diff --git a/docs/implementation-status.md b/docs/implementation-status.md index 71bd226..52c037b 100644 --- a/docs/implementation-status.md +++ b/docs/implementation-status.md @@ -22,14 +22,19 @@ | 構成 | ビルド | CTest | 実施日 | 結果 | |---|---|---|---|---| -| Windows x64 / MSVC / Debug | ✅ 実施済 | ✅ 実施済 | 2026-06-30 | 14/14成功 | -| Windows x64 / MSVC / Release | ✅ 実施済 | ✅ 実施済 | 2026-06-30 | 14/14成功 | -| Windows x64 / MSVC / ASan | ✅ 実施済 | ✅ 実施済 | 2026-06-30 | 14/14成功 | +| Windows x64 / MSVC / Debug | ✅ 実施済 | ✅ 実施済 | 2026-06-30 | 15/15成功 | +| Windows x64 / MSVC / Release | ✅ 実施済 | ✅ 実施済 | 2026-06-30 | 15/15成功 | +| Windows x64 / MSVC / ASan | ✅ 実施済 | ✅ 実施済 | 2026-06-30 | 15/15成功 | | Windows以外 | ⬜ 未実施 | ⬜ 未実施 | ― | v1対象外 | Python MCP SDK 1.28.1によるglobal/scoped検索1000回交互呼出しも、Debug・Release・ASanの 各構成で成功し、接続切断・異常終了・ASan診断がないことを確認しました。 +P1のgram bucket hash table化後、Releaseの32KiB write p50は128.242msから5.907msへ +約21.7倍高速化しました。1MiB write p50は90.093ms、domain単体のindex構築平均は +1KiB 0.217ms、8KiB 1.299ms、32KiB 3.948ms、1MiB 34.988msで、payload増加に対する +二次的悪化がないことを確認しました。 + 実行コマンド: ```powershell @@ -121,9 +126,11 @@ ctest --preset windows-vs2026-asan | 設計項目 | 実装 | テスト作成 | テスト実施 | 補足・残作業 | |---|---|---|---|---| | Unicode codepoint 2/3-gram逆引き索引 | ✅ 実装済 | ✅ 作成済 | ✅ Debug/Release | contentとtagsを索引化 | +| gram bucket hash table | ✅ 実装済 | ✅ 作成済 | ✅ Debug/Release/ASan | open addressing、最大load factor 70%、完全key照合 | | ASCII case folding | ✅ 実装済 | ✅ 作成済 | ✅ Debug/Release | `CURRY`/`curry` を確認 | | 日本語検索 | ✅ 実装済 | ✅ 作成済 | ✅ Debug/Release | `設計` tagを確認 | -| hash衝突時の実codepoint照合 | ✅ 実装済 | 🟡 実装経路のみ | 🟡 間接実施 | 意図的なhash collision fixtureは未作成 | +| hash衝突時の実codepoint照合 | ✅ 実装済 | ✅ 作成済 | ✅ Debug/Release/ASan | test hashを8-bit化し、300個の異なるgramで衝突を強制 | +| index追加のallocation failure atomicity | ✅ 実装済 | ✅ 作成済 | ✅ Debug/Release/ASan | 全allocation位置を掃引し、部分登録・leakなしを確認 | | 1 codepoint query fallback | ✅ 実装済 | ⬜ 未作成 | ⬜ 未実施 | 全候補からscore計算する経路が未確認 | | 起動時索引構築 | ✅ 実装済 | 🟡 再起動で間接確認 | ✅ Debug/Release | 大量データ時の時間/メモリ試験なし | | write時索引更新 | ✅ 実装済 | ✅ MCP検索で確認 | ✅ Debug/Release | index allocation失敗のfault injectionなし | @@ -200,6 +207,7 @@ ctest --preset windows-vs2026-asan |---|---|---|---|---|---| | `tiny-convmem-mcp.smoke` | MCP E2E | ✅ 作成済 | ✅ 成功 | ✅ 成功 | initialize、6 tool schema、write/read/search/rebuild/health、検証エラー | | `tiny-convmem-mcp.domain` | Unit | ✅ 作成済 | ✅ 成功 | ✅ 成功 | role/tier、UTF-8、ULID、deep copy、ASCII/日本語n-gram | +| `tiny-convmem-mcp.search-index` | Unit | ✅ 作成済 | ✅ 成功 | ✅ 成功 | hash衝突、rehash、Unicode、allocation failure atomicity | | `tiny-convmem-mcp.mcpc` | Unit | ✅ 作成済 | ✅ 成功 | ✅ 成功 | required属性、NULL callback拒否、fork API | | `tiny-convmem-mcp.protocol` | MCP E2E | ✅ 作成済 | ✅ 成功 | ✅ 成功 | JSON-RPC異常系、schema/default、1000回交互検索、終了診断 | | `tiny-convmem-mcp.storage` | Unit/Integration | ✅ 作成済 | ✅ 成功 | ✅ 成功 | lock、write/reopen、ULID順、temp失敗、CRC破損拒否 | diff --git a/scripts/python/README.md b/scripts/python/README.md index 7018313..8d8ed53 100644 --- a/scripts/python/README.md +++ b/scripts/python/README.md @@ -43,14 +43,15 @@ cd scripts\python すべての操作は stdio MCP プロトコル経由で実際のサーバプロセスに対して行います。 -1. **write_message** — 小 (~20B)、中 (1KiB)、大 (32KiB) content サイズ別 -2. **write_message (with tags)** — `metadata_json` 文字列に tags / `memory_tier` を含む書き込み -3. **read_messages** — 100 件のメッセージを読み出し、件数を検証 -4. **search_messages** — 同じデータ・同じ query で global / session-scoped を比較 -5. **delete_message** — `message_id` 指定削除 -6. **rebuild_index** — compaction + snapshot 再生成(5 回反復) -7. **get_system_health** — ストレージ健全性取得 -8. **recovery** — プロセス再起動後の復旧を 3 段階で計測 +1. **write_message** — 小 (~20B)、1KiB、8KiB、32KiB、1MiB content サイズ別 +2. **P1 startup/rebuild** — 各payloadを20件保存し、再起動時のindex構築とrebuildを計測 +3. **write_message (with tags)** — `metadata_json` 文字列に tags / `memory_tier` を含む書き込み +4. **read_messages** — 100 件のメッセージを読み出し、件数を検証 +5. **search_messages** — 同じデータ・同じ query で global / session-scoped を比較 +6. **delete_message** — `message_id` 指定削除 +7. **rebuild_index** — compaction + snapshot 再生成(5 回反復) +8. **get_system_health** — ストレージ健全性取得 +9. **recovery** — プロセス再起動後の復旧を 3 段階で計測 - restart + count check(1 回) - restart + small read(5 回) - restart + full read 100 msgs(5 回) @@ -63,6 +64,10 @@ cd scripts\python - `.json`: 詳細な計測結果(全サンプル含む) - `.md`: Markdown レポート +Releaseビルドにはdomain index構築だけを測る`tiny-convmem-search-benchmark.exe`も含まれます。 +`benchmark.py`は同じpayload matrixでこれを実行し、E2E時間と切り分けた構築時間および +peak working setをJSON/Markdownへ記録します。 + ## 結果の見方 ```text diff --git a/scripts/python/benchmark.py b/scripts/python/benchmark.py index 69219c9..5a146ce 100644 --- a/scripts/python/benchmark.py +++ b/scripts/python/benchmark.py @@ -39,9 +39,12 @@ from mcp.types import CallToolResult # --------------------------------------------------------------------------- DEFAULT_ITERATIONS = 100 DEFAULT_CONTENT_MEDIUM = 1024 # bytes +DEFAULT_CONTENT_8K = 8 * 1024 # bytes DEFAULT_CONTENT_LARGE = 32 * 1024 # bytes +DEFAULT_CONTENT_MAX = 1024 * 1024 # bytes WARMUP_COUNT = 5 REBUILD_ITERATIONS = 5 +P1_CORPUS_MESSAGES = 20 ROOT = Path(__file__).resolve().parent.parent.parent DEFAULT_RELEASE_EXE = ( @@ -90,6 +93,7 @@ class BenchmarkReport: iterations: int warmup: int scenarios: list[ScenarioResult] = field(default_factory=list) + domain_index: list[dict[str, Any]] = field(default_factory=list) health_after: dict[str, Any] | None = None schema_check: dict[str, Any] | None = None errors: list[str] = field(default_factory=list) @@ -142,6 +146,25 @@ def summarize(name: str, samples: list[LatencySample]) -> ScenarioResult: return result +def single_sample(name: str, duration_ms: float, notes: str) -> ScenarioResult: + return ScenarioResult( + name=name, + iterations=1, + successes=1, + failures=0, + samples=[duration_ms], + throughput_ops_per_sec=1000.0 / duration_ms if duration_ms > 0 else 0.0, + latency_p50_ms=duration_ms, + latency_p95_ms=duration_ms, + latency_p99_ms=duration_ms, + latency_min_ms=duration_ms, + latency_max_ms=duration_ms, + latency_mean_ms=duration_ms, + total_duration_ms=duration_ms, + notes=notes, + ) + + def text_content(result: CallToolResult) -> str: if result.isError: raise RuntimeError(f"tool returned isError: {result.content!r}") @@ -168,6 +191,24 @@ def make_metadata_json(tags: list[str] | None = None, tier: str = "short") -> st return json.dumps(obj, separators=(",", ":")) +def run_domain_index_benchmarks(server: Path) -> list[dict[str, Any]]: + if len(server.parents) < 3: + return [] + benchmark = server.parents[2] / "tests" / server.parent.name / "tiny-convmem-search-benchmark.exe" + if not benchmark.exists(): + return [] + results: list[dict[str, Any]] = [] + for size, iterations in ((1024, 100), (8192, 100), (32768, 50), (1048576, 5)): + completed = subprocess.run( + [str(benchmark), str(size), str(iterations)], + check=True, + capture_output=True, + text=True, + ) + results.append(json.loads(completed.stdout)) + return results + + # --------------------------------------------------------------------------- # クライアント・サーバランチャー # --------------------------------------------------------------------------- @@ -377,6 +418,64 @@ class ScenarioRunner: "write_message (large 32KiB)", ) + async def run_write_8k(self, iterations: int) -> ScenarioResult: + content = random_content(DEFAULT_CONTENT_8K) + return await self.run_write( + content, + make_metadata_json(), + iterations, + "write_message (P1 8KiB)", + ) + + async def run_write_max(self, iterations: int) -> ScenarioResult: + content = random_content(DEFAULT_CONTENT_MAX) + return await self.run_write( + content, + make_metadata_json(), + iterations, + "write_message (P1 1MiB)", + ) + + async def run_p1_startup_rebuild( + self, size: int + ) -> tuple[ScenarioResult, ScenarioResult]: + data_dir = self.new_data_dir() + session_id = f"p1-{size}" + content = random_content(size) + try: + async with ServerContext(self.exe, data_dir) as session: + for _ in range(P1_CORPUS_MESSAGES): + await write_message(session, session_id, content) + + started = time.perf_counter() + async with ServerContext(self.exe, data_dir) as session: + startup_ms = (time.perf_counter() - started) * 1000.0 + health = await get_system_health(session) + if health.get("active_messages") != P1_CORPUS_MESSAGES: + raise RuntimeError(f"P1 corpus count mismatch: {health}") + + rebuild_started = time.perf_counter() + payload = await rebuild_index(session) + rebuild_ms = (time.perf_counter() - rebuild_started) * 1000.0 + if payload.get("status") != "OK": + raise RuntimeError(f"P1 rebuild failed: {payload}") + + label = f"{size // 1024}KiB" if size < 1024 * 1024 else "1MiB" + return ( + single_sample( + f"startup index build (P1 {label} x{P1_CORPUS_MESSAGES})", + startup_ms, + "process start + initialize; corpus is loaded from the persisted log", + ), + single_sample( + f"rebuild_index (P1 {label} x{P1_CORPUS_MESSAGES})", + rebuild_ms, + "compaction and complete in-memory search index rebuild", + ), + ) + finally: + self.cleanup(data_dir) + async def run_write_with_tags(self, iterations: int) -> ScenarioResult: content = "tagged message" metadata_json = make_metadata_json(tags=["benchmark", "tagged"], tier="short") @@ -686,6 +785,13 @@ def print_report(report: BenchmarkReport) -> None: print("\nfinal health:") for k, v in report.health_after.items(): print(f" {k}: {v}") + if report.domain_index: + print("\ndomain search index:") + for item in report.domain_index: + print( + f" {item['size_bytes']:>7} bytes: {item['mean_ms']:.3f} ms, " + f"peak working set {item['peak_working_set_bytes']} bytes" + ) def write_json(report: BenchmarkReport, path: Path) -> None: @@ -722,6 +828,17 @@ def write_markdown(report: BenchmarkReport, json_path: Path, md_path: Path) -> N lines.append(json.dumps(report.schema_check, indent=2, ensure_ascii=False)) lines.append("\n```\n\n") + if report.domain_index: + lines.append("## Domain検索index構築\n\n") + lines.append("| payload | iterations | mean[ms] | peak working set[bytes] |\n") + lines.append("|---:|---:|---:|---:|\n") + for item in report.domain_index: + lines.append( + f"| {item['size_bytes']} | {item['iterations']} | {item['mean_ms']:.3f} | " + f"{item['peak_working_set_bytes']} |\n" + ) + lines.append("\n") + if report.health_after: lines.append("## 最終 health\n\n") lines.append("```json\n") @@ -794,13 +911,25 @@ async def amain(argv: list[str]) -> int: iterations=args.iterations, warmup=args.warmup, ) + report.domain_index = run_domain_index_benchmarks(exe.resolve()) # シナリオ実行 report.scenarios.append(await runner.run_write_small(args.iterations)) report.scenarios.append(await runner.run_write_medium(args.iterations)) + report.scenarios.append(await runner.run_write_8k(min(args.iterations, 100))) report.scenarios.append(await runner.run_write_large(args.iterations)) + report.scenarios.append(await runner.run_write_max(min(args.iterations, 5))) report.scenarios.append(await runner.run_write_with_tags(args.iterations)) + for payload_size in ( + DEFAULT_CONTENT_MEDIUM, + DEFAULT_CONTENT_8K, + DEFAULT_CONTENT_LARGE, + DEFAULT_CONTENT_MAX, + ): + startup_result, p1_rebuild_result = await runner.run_p1_startup_rebuild(payload_size) + report.scenarios.extend((startup_result, p1_rebuild_result)) + report.scenarios.append(await runner.run_read(args.iterations)) search_global, search_scoped = await runner.run_search(args.iterations) @@ -859,4 +988,4 @@ def main() -> int: if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/scripts/python/benchmark_results.json b/scripts/python/benchmark_results.json index 70c5f84..05d1ec2 100644 --- a/scripts/python/benchmark_results.json +++ b/scripts/python/benchmark_results.json @@ -1,7 +1,7 @@ { "server": "build\\windows-vs2026\\src\\Release\\tiny-convmem-mcp.exe", "build_type": "release", - "exe_mtime": "2026-06-30 18:49:00", + "exe_mtime": "2026-06-30 21:51:05", "iterations": 100, "warmup": 5, "scenarios": [ @@ -11,115 +11,115 @@ "successes": 100, "failures": 0, "samples": [ - 0.377499993192032, - 0.37880000309087336, - 0.37930000689812005, - 0.3795999800786376, - 0.37960000918246806, - 0.3798999823629856, - 0.38040001527406275, - 0.38120002136565745, - 0.38120002136565745, - 0.38180002593435347, - 0.3828000044450164, - 0.3831000067293644, - 0.38339997990988195, - 0.38399998447857797, - 0.38519999361597, - 0.3865000035148114, - 0.3865000035148114, - 0.387699983548373, - 0.38800001493655145, - 0.38809998659417033, - 0.38819998735561967, - 0.3884999896399677, - 0.3887999919243157, - 0.3889000217895955, - 0.3893999964930117, - 0.3907000063918531, - 0.39090000791475177, - 0.39140001172199845, - 0.39190001552924514, - 0.39209998794831336, - 0.3921999887097627, - 0.39220001781359315, - 0.3924000193364918, - 0.3926999925170094, - 0.39280002238228917, - 0.39319999632425606, - 0.39339999784715474, - 0.3935999993700534, - 0.39370000013150275, - 0.39370000013150275, - 0.3938000008929521, - 0.3938000008929521, - 0.3938000008929521, - 0.3939000016544014, - 0.39400000241585076, - 0.394199974834919, - 0.39480000850744545, - 0.39480000850744545, - 0.3960000176448375, - 0.3964999923482537, - 0.3974999999627471, - 0.3974999999627471, - 0.3981000045314431, - 0.39909998304210603, - 0.3994000144302845, - 0.3994999860879034, + 0.39679999463260174, + 0.3997000167146325, 0.4000000189989805, - 0.40049999370239675, - 0.4026000096928328, - 0.40309998439624906, - 0.40309998439624906, - 0.40439999429509044, - 0.4059000057168305, - 0.4059000057168305, - 0.4064000095240772, - 0.4079999926034361, - 0.4081999941263348, - 0.4093000025022775, - 0.4096000047866255, - 0.4107000131625682, - 0.4146999854128808, - 0.4169000021647662, - 0.41810001130215824, - 0.4227000172249973, - 0.4233999934513122, - 0.42699999175965786, - 0.4324999754317105, - 0.4336999845691025, - 0.4364999767858535, - 0.4375999851617962, - 0.440200004959479, - 0.45950000640004873, - 0.5039999959990382, - 0.5614999972749501, - 0.6695000047329813, - 0.6759999960195273, - 0.6922000029589981, - 0.6971000111661851, - 0.7052999862935394, - 0.751899991882965, - 0.7538000063505024, - 0.8036000072024763, - 0.8623999892733991, - 1.1503999994602054, - 1.2338999949861318, - 1.280700002098456, - 1.3685000012628734, - 1.7575999954715371, - 1.973899983568117, - 9.826800000155345 + 0.4005999944638461, + 0.4029999836347997, + 0.4034999874420464, + 0.40690001333132386, + 0.4078999918419868, + 0.40809999336488545, + 0.4090000002179295, + 0.41030001011677086, + 0.41069998405873775, + 0.4144999838899821, + 0.4146000137552619, + 0.4149000160396099, + 0.41519998922012746, + 0.4154999915044755, + 0.41649999911896884, + 0.41700000292621553, + 0.41790000977925956, + 0.4181999829597771, + 0.42139997822232544, + 0.4225999873597175, + 0.42290001874789596, + 0.4230000195093453, + 0.42440000106580555, + 0.42639998719096184, + 0.4265999887138605, + 0.42710002162493765, + 0.4282000008970499, + 0.4290999786462635, + 0.43070001993328333, + 0.4330000083427876, + 0.43500002357177436, + 0.4354999982751906, + 0.437700015027076, + 0.4397000011522323, + 0.4406000080052763, + 0.44189998880028725, + 0.4427999956533313, + 0.4445999802555889, + 0.4454999871086329, + 0.4474000015761703, + 0.4521000082604587, + 0.45419999514706433, + 0.454399996669963, + 0.4600000102072954, + 0.4634000069927424, + 0.4675000091083348, + 0.4689999914262444, + 0.4712000081781298, + 0.4769999941345304, + 0.47709999489597976, + 0.4785000055562705, + 0.4802000185009092, + 0.4878999898210168, + 0.4963999963365495, + 0.49760000547394156, + 0.5103999865241349, + 0.513100007083267, + 0.513700011651963, + 0.5177999846637249, + 0.5205999768804759, + 0.5283000064082444, + 0.5318000039551407, + 0.5335000168997794, + 0.5366000114008784, + 0.5367999838199466, + 0.5376000190153718, + 0.5401000089477748, + 0.5429999728221446, + 0.5455999926198274, + 0.5458999949041754, + 0.5536999960895628, + 0.5549999768845737, + 0.5603999888990074, + 0.5636999849230051, + 0.5658000009134412, + 0.5659000016748905, + 0.5673000123351812, + 0.5716999876312912, + 0.5747999821323901, + 0.5797999911010265, + 0.598300015553832, + 0.6763999990653247, + 0.6834000232629478, + 0.6843000010121614, + 0.7117000059224665, + 0.7415000000037253, + 0.7436999876517802, + 0.7517000194638968, + 0.7579000084660947, + 0.7619000098202378, + 0.7890999841038138, + 0.7892999856267124, + 0.8261000039055943, + 0.9229000133927912, + 0.9807000169530511, + 0.9993999847210944, + 10.222899989457801 ], - "throughput_ops_per_sec": 1696.8824880031802, - "latency_p50_ms": 0.3969999961555004, - "latency_p95_ms": 1.2362399953417478, - "latency_p99_ms": 2.0524289837340293, - "latency_min_ms": 0.377499993192032, - "latency_max_ms": 9.826800000155345, - "latency_mean_ms": 0.5893159998231567, - "total_duration_ms": 58.931599982315674, + "throughput_ops_per_sec": 1626.8759922518768, + "latency_p50_ms": 0.4700999998021871, + "latency_p95_ms": 0.7911399865406564, + "latency_p99_ms": 1.0916349847685085, + "latency_min_ms": 0.39679999463260174, + "latency_max_ms": 10.222899989457801, + "latency_mean_ms": 0.6146749996696599, + "total_duration_ms": 61.46749996696599, "total_bytes_in": 2000, "total_bytes_out": 0, "notes": "" @@ -130,472 +130,775 @@ "successes": 100, "failures": 0, "samples": [ - 0.8056999940890819, - 0.8100999984890223, - 0.8107999747153372, - 0.8131999929901212, - 0.8137999975588173, - 0.8156000112649053, - 0.8162000158336014, - 0.8164000173565, - 0.8188999781850725, - 0.8194000110961497, - 0.819500011857599, - 0.8214999979827553, - 0.8218000002671033, - 0.8222999749705195, - 0.822600006358698, - 0.823500013211742, - 0.8236000139731914, - 0.8238999871537089, - 0.8243999909609556, - 0.8249999955296516, - 0.8258000016212463, - 0.8268000092357397, - 0.8273999847006053, - 0.827599986223504, - 0.8299000037368387, + 0.6837999972049147, + 0.6912000244483352, + 0.6928000075276941, + 0.6981000187806785, + 0.7001000049058348, + 0.700899981893599, + 0.7056000176817179, + 0.7065999961923808, + 0.7066999969538301, + 0.7119000074453652, + 0.7173999911174178, + 0.7190000033006072, + 0.7248999900184572, + 0.7254999945871532, + 0.7268000044859946, + 0.7270000060088933, + 0.7271999784279615, + 0.7362000178545713, + 0.7427999807987362, + 0.746000005165115, + 0.7468000112567097, + 0.7488000264856964, + 0.7507999835070223, + 0.7517999911215156, + 0.7533000025432557, + 0.753700005589053, + 0.7542000093962997, + 0.7548000139649957, + 0.7602999976370484, + 0.7604000275023282, + 0.763599993661046, + 0.7650999759789556, + 0.7679999980609864, + 0.7686000026296824, + 0.7696000102441758, + 0.7729999779257923, + 0.7742999878246337, + 0.7749999931547791, + 0.7754999969620258, + 0.7823999912943691, + 0.7842000050004572, + 0.7862000202294439, + 0.7874000002630055, + 0.7879000040702522, + 0.7937000191304833, + 0.8018999942578375, + 0.8059999963734299, + 0.80750000779517, + 0.8142000006046146, + 0.8165999897755682, + 0.8173999958671629, + 0.8230999810621142, 0.8302000060211867, - 0.8316999883390963, - 0.8323999936692417, - 0.8329999982379377, - 0.8358000195585191, - 0.835899991216138, - 0.8376000041607767, - 0.8384000102523714, - 0.8393999887630343, - 0.8409000001847744, - 0.8412000024691224, - 0.8419999794568866, - 0.84299998707138, - 0.8470999891869724, - 0.8492999768350273, - 0.8534000080544502, - 0.8553999941796064, - 0.8567000040784478, - 0.8581999863963574, - 0.8596999978180975, - 0.8598999993409961, - 0.8613999816589057, - 0.8622000168543309, - 0.8679000020492822, - 0.8693000127095729, - 0.8707999950274825, - 0.8709999965503812, - 0.8719000034034252, - 0.8793000015430152, - 0.8824000251479447, - 0.8836000051815063, - 0.8919000101741403, - 0.8924999856390059, - 0.9094999986700714, - 0.9098000009544194, - 0.9155000152532011, - 0.915899989195168, - 0.9159999899566174, - 0.9193999867420644, - 0.9273000177927315, - 0.9369000035803765, - 0.9418000117875636, - 0.9563000057823956, - 0.9693999891169369, - 0.9743999980855733, - 0.9797000093385577, - 0.9907999774441123, - 0.9986000077333301, - 1.0103000095114112, - 1.018200011458248, - 1.0212999768555164, - 1.0246000019833446, - 1.0355999984312803, - 1.039100025082007, - 1.0526999831199646, - 1.056100009009242, - 1.1101000127382576, - 1.11420001485385, - 1.1374999885447323, - 1.1451999889686704, - 1.1455999920144677, - 1.1590999783948064, - 1.1867000139318407, - 1.1878000223077834, - 1.2843000004068017, - 1.302599994232878, - 1.3070999993942678, - 1.3109999999869615, - 1.3165000127628446, - 1.5024000022094697, - 1.510500005679205, - 1.6747000045143068, - 2.070499991532415, - 3.095799998845905, - 7.35470000654459 + 0.8354000165127218, + 0.8366999973077327, + 0.8368999988306314, + 0.8405999979004264, + 0.8415000047534704, + 0.8444999984931201, + 0.8453000045847148, + 0.8496000082232058, + 0.8511999913025647, + 0.8512999920640141, + 0.8513000211678445, + 0.8588999917265028, + 0.8591999940108508, + 0.8611000084783882, + 0.8643000037409365, + 0.8687000081408769, + 0.8690000104252249, + 0.8699000172782689, + 0.8716000011190772, + 0.8742999925743788, + 0.8761000062804669, + 0.8788999984972179, + 0.880700012203306, + 0.8818999922368675, + 0.8824999968055636, + 0.8941999985836446, + 0.8967999892774969, + 0.9025000035762787, + 0.9160999907180667, + 0.920199992833659, + 0.9315999923273921, + 0.9342000121250749, + 0.9632000001147389, + 0.98230000003241, + 1.0001000191550702, + 1.0201999975834042, + 1.0275000240653753, + 1.0303000162821263, + 1.2755999923683703, + 1.406800001859665, + 1.4902999973855913, + 1.6694999940227717, + 1.722100016195327, + 1.7783000075723976, + 1.9802000024355948, + 2.10240000160411, + 2.2775999968871474 ], - "throughput_ops_per_sec": 960.9231013956091, - "latency_p50_ms": 0.8700500038685277, - "latency_p95_ms": 1.5028050023829564, - "latency_p99_ms": 3.1383889989229137, - "latency_min_ms": 0.8056999940890819, - "latency_max_ms": 7.35470000654459, - "latency_mean_ms": 1.0406659997534007, - "total_duration_ms": 104.06659997534007, + "throughput_ops_per_sec": 1116.0689354321871, + "latency_p50_ms": 0.8169999928213656, + "latency_p95_ms": 1.6721299951313993, + "latency_p99_ms": 2.1041520015569413, + "latency_min_ms": 0.6837999972049147, + "latency_max_ms": 2.2775999968871474, + "latency_mean_ms": 0.8960020015365444, + "total_duration_ms": 89.60020015365444, "total_bytes_in": 102400, "total_bytes_out": 0, "notes": "" }, + { + "name": "write_message (P1 8KiB)", + "iterations": 100, + "successes": 100, + "failures": 0, + "samples": [ + 1.8390000041108578, + 1.8749999871943146, + 1.8853999790735543, + 1.9096999894827604, + 1.9123000092804432, + 1.9241999834775925, + 1.9346000044606626, + 1.9357000128366053, + 1.9375999982003123, + 1.9481999916024506, + 1.9563000241760164, + 1.974799990421161, + 1.9859000167343765, + 1.9884000066667795, + 2.0019999938085675, + 2.008899988140911, + 2.017799997702241, + 2.0218999998178333, + 2.025499998126179, + 2.0278000156395137, + 2.0286999933887273, + 2.0337000023573637, + 2.0374000014271587, + 2.0398999913595617, + 2.0417000050656497, + 2.0425999828148633, + 2.04459999804385, + 2.046799985691905, + 2.04899997333996, + 2.057599980616942, + 2.057700010482222, + 2.0620999857783318, + 2.069499983917922, + 2.074799995170906, + 2.075600001262501, + 2.0798000041395426, + 2.081799990264699, + 2.082199993310496, + 2.0908000005874783, + 2.103300008457154, + 2.103999984683469, + 2.1145000064279884, + 2.116899995598942, + 2.130799985025078, + 2.136600000085309, + 2.1409000037238, + 2.143599995179102, + 2.146600018022582, + 2.1487000049091876, + 2.163299999665469, + 2.1702999947592616, + 2.177199989091605, + 2.1875999809708446, + 2.187999984016642, + 2.1881999855395406, + 2.1946000051684678, + 2.1994000126142055, + 2.2004999918863177, + 2.2016999719198793, + 2.222300012363121, + 2.234999992651865, + 2.2379999863915145, + 2.2433999984059483, + 2.2524000087287277, + 2.2680000110995024, + 2.2696999949403107, + 2.2730999917257577, + 2.289399999426678, + 2.2991999867372215, + 2.306199981831014, + 2.307699993252754, + 2.3558999819215387, + 2.359000005526468, + 2.367899985983968, + 2.372899994952604, + 2.377700002398342, + 2.37800000468269, + 2.394999988609925, + 2.440700016450137, + 2.4816000077407807, + 2.4935999826993793, + 2.542000001994893, + 2.5631999887991697, + 2.6406999968457967, + 2.662999992026016, + 2.6916000060737133, + 2.834699989762157, + 2.8565000102389604, + 3.080700000282377, + 3.1029999954625964, + 3.1956000020727515, + 3.282599995145574, + 3.287899977294728, + 3.2937999931164086, + 3.4334000083617866, + 3.5893000022042543, + 3.6401000106707215, + 3.905700024915859, + 4.000399989308789, + 5.172100005438551 + ], + "throughput_ops_per_sec": 426.68123125412774, + "latency_p50_ms": 2.1667999972123653, + "latency_p95_ms": 3.4411950080539095, + "latency_p99_ms": 4.012116989470093, + "latency_min_ms": 1.8390000041108578, + "latency_max_ms": 5.172100005438551, + "latency_mean_ms": 2.343669997062534, + "total_duration_ms": 234.3669997062534, + "total_bytes_in": 819200, + "total_bytes_out": 0, + "notes": "" + }, { "name": "write_message (large 32KiB)", "iterations": 100, "successes": 100, "failures": 0, "samples": [ - 125.11520000407472, - 125.15000000712462, - 125.35799999022856, - 125.3632000007201, - 125.42379999649711, - 125.43210000148974, - 125.53900000057183, - 125.77370001235977, - 125.86850000661798, - 125.9147000091616, - 125.91969998902641, - 126.06720000621863, - 126.1858000070788, - 126.27499998779967, - 126.4798000047449, - 126.50889999349602, - 126.54379999730736, - 126.61420000949875, - 126.64339999901131, - 126.7128000035882, - 126.7682000179775, - 126.86439999379218, - 126.87880001612939, - 126.8860999844037, - 126.91540000378154, - 126.93329999456182, - 127.01460000243969, - 127.02749998425134, - 127.05469998763874, - 127.07289998070337, - 127.24030000390485, - 127.27080000331625, - 127.27389999781735, - 127.32390000019222, - 127.35260001500137, - 127.4136999854818, - 127.45729999733157, - 127.45970001560636, - 127.47339997440577, - 127.54390001646243, - 127.78029998298734, - 127.81939998967573, - 127.96220000018366, - 128.00500000594184, - 128.0274000018835, - 128.07460001204163, - 128.12179999309592, - 128.2068000000436, - 128.22879999293946, - 128.23929998558015, - 128.24489999911748, - 128.34130000555888, - 128.36620002053678, - 128.3730999857653, - 128.49940001615323, - 128.55559997842647, - 128.56750001083128, - 128.64119998994283, - 128.70810000458732, - 128.88639999437146, - 128.93649999750778, - 128.96880001062527, - 129.1536999924574, - 129.15849999990314, - 129.2675999866333, - 129.30149998283014, - 129.32770000770688, - 129.37650000094436, - 129.3846000044141, - 129.65940000140108, - 129.78940000175498, - 129.8231999971904, - 129.8806999984663, - 129.9128000100609, - 129.92979999398813, - 130.0004000077024, - 130.02430001506582, - 130.08550001541153, - 130.09509997209534, - 130.15910002286546, - 130.23970002541319, - 130.28650000342168, - 130.31850001425482, - 130.6365999917034, - 130.67969999974594, - 131.08530000317842, - 131.48440001532435, - 131.66660000570118, - 132.17470000381581, - 132.41049999487586, - 132.53900001291186, - 132.6581999892369, - 132.873099995777, - 132.99919999553822, - 133.32520000403747, - 133.37250001495704, - 133.39540001470596, - 133.44799997867085, - 133.55840000440367, - 133.7197999819182 + 5.058799986727536, + 5.05959999281913, + 5.0731000083032995, + 5.1417000067885965, + 5.178999999770895, + 5.183100001886487, + 5.265800020424649, + 5.272200010949746, + 5.30270001036115, + 5.369899998186156, + 5.378400004701689, + 5.399500019848347, + 5.406799988122657, + 5.462800007080659, + 5.489000002853572, + 5.500100000062957, + 5.503899999894202, + 5.513700016308576, + 5.561300000408664, + 5.571499990765005, + 5.5856000108178705, + 5.608500010566786, + 5.622199998470023, + 5.629499995848164, + 5.629699997371063, + 5.653400003211573, + 5.684200004907325, + 5.69970000651665, + 5.707600008463487, + 5.711699981475249, + 5.719100008718669, + 5.719900014810264, + 5.733999976655468, + 5.738000007113442, + 5.740299995522946, + 5.751699995016679, + 5.756999977165833, + 5.758199986303225, + 5.782199994428083, + 5.80350001109764, + 5.824599997140467, + 5.828499997733161, + 5.831300019053742, + 5.835599993588403, + 5.8391999918967485, + 5.839999997988343, + 5.845400010002777, + 5.851699999766424, + 5.895500013139099, + 5.902000004425645, + 5.91159999021329, + 5.928600003244355, + 5.934000015258789, + 5.947500001639128, + 5.9529000136535615, + 5.9714000090025365, + 5.979300010949373, + 5.987400014419109, + 5.996799998683855, + 6.041800021193922, + 6.0643999895546585, + 6.080400024075061, + 6.1645000241696835, + 6.199900002684444, + 6.2818999867886305, + 6.294200022239238, + 6.3265000062529, + 6.348800001433119, + 6.3627999916207045, + 6.408300017938018, + 6.411100010154769, + 6.4122000185307115, + 6.423499988159165, + 6.4252000011038035, + 6.492000014986843, + 6.543099996633828, + 6.572199985384941, + 6.598900014068931, + 6.724800012307242, + 6.77239999640733, + 6.798100017476827, + 6.847099983133376, + 6.847699987702072, + 6.92800001706928, + 6.940200022654608, + 6.97089999448508, + 7.027499988907948, + 7.0488999772351235, + 7.21390001126565, + 7.214800018118694, + 7.314199989195913, + 7.3917999980039895, + 7.449800003087148, + 7.652200001757592, + 7.658200018340722, + 7.723899994743988, + 9.109500009799376, + 9.228499984601513, + 9.315500006778166, + 10.534499975619838 ], - "throughput_ops_per_sec": 7.774314812877668, - "latency_p50_ms": 128.2420999923488, - "latency_p95_ms": 133.32756500458345, - "latency_p99_ms": 133.5600140041788, - "latency_min_ms": 125.11520000407472, - "latency_max_ms": 133.7197999819182, - "latency_mean_ms": 128.62869900040096, - "total_duration_ms": 12862.869900040096, + "throughput_ops_per_sec": 161.2912850582387, + "latency_p50_ms": 5.906799997319467, + "latency_p95_ms": 7.661485017160885, + "latency_p99_ms": 9.32769000646659, + "latency_min_ms": 5.058799986727536, + "latency_max_ms": 10.534499975619838, + "latency_mean_ms": 6.199963002582081, + "total_duration_ms": 619.9963002582081, "total_bytes_in": 3276800, "total_bytes_out": 0, "notes": "" }, + { + "name": "write_message (P1 1MiB)", + "iterations": 5, + "successes": 5, + "failures": 0, + "samples": [ + 83.64589998382144, + 86.25629998277873, + 90.09279997553676, + 90.86070000194013, + 91.56170001369901 + ], + "throughput_ops_per_sec": 11.301544650995181, + "latency_p50_ms": 90.09279997553676, + "latency_p95_ms": 91.42150001134723, + "latency_p99_ms": 91.53366001322865, + "latency_min_ms": 83.64589998382144, + "latency_max_ms": 91.56170001369901, + "latency_mean_ms": 88.48347999155521, + "total_duration_ms": 442.41739995777607, + "total_bytes_in": 5242880, + "total_bytes_out": 0, + "notes": "" + }, { "name": "write_message (with tags)", "iterations": 100, "successes": 100, "failures": 0, "samples": [ - 0.3721999819390476, - 0.3733999910764396, - 0.3758000093512237, - 0.3761000116355717, - 0.37650001468136907, - 0.37659998633898795, - 0.3767999878618866, - 0.37719999090768397, - 0.37779999547638, - 0.3803999861702323, - 0.3816999960690737, - 0.381799996830523, - 0.3831999783869833, - 0.38400001358240843, - 0.3843999875243753, - 0.3852000227198005, - 0.38579999818466604, - 0.3859999997075647, - 0.3859999997075647, + 0.37590001011267304, + 0.377499993192032, + 0.3797999816015363, + 0.3825000021606684, + 0.3825000021606684, + 0.38259997381828725, + 0.3826000029221177, + 0.3848000196740031, + 0.3853000234812498, + 0.3853000234812498, + 0.3853999951388687, + 0.385499995900318, + 0.3858999989461154, + 0.3858999989461154, 0.38610000046901405, - 0.38660000427626073, - 0.3868000057991594, - 0.3870000073220581, + 0.38610000046901405, + 0.38649997441098094, + 0.38670000503771007, 0.3871000080835074, + 0.387399981264025, + 0.387399981264025, 0.38740001036785543, - 0.38750001112930477, - 0.38759998278692365, - 0.38759998278692365, + 0.387699983548373, + 0.3878000134136528, + 0.3879000141751021, + 0.38800001493655145, + 0.3881000156980008, + 0.3884000179823488, + 0.3884999896399677, + 0.3884999896399677, 0.388599990401417, - 0.38869999116286635, + 0.3886000195052475, 0.38869999116286635, 0.3887999919243157, 0.3887999919243157, - 0.38889999268576503, - 0.38899999344721437, - 0.38910002331249416, - 0.38910002331249416, - 0.3892999957315624, - 0.38930002483539283, - 0.38949999725446105, - 0.38979999953880906, - 0.39000000106170774, - 0.39000000106170774, - 0.3902000025846064, - 0.3902000025846064, + 0.3887999919243157, + 0.3890999942086637, + 0.38919999497011304, + 0.3893999964930117, + 0.3893999964930117, + 0.3893999964930117, + 0.3893999964930117, + 0.3899000003002584, 0.39030000334605575, 0.39030000334605575, - 0.3904000041075051, - 0.39060000563040376, + 0.39030000334605575, + 0.39080000715330243, + 0.3910000086762011, 0.39110000943765044, + 0.3911999810952693, + 0.39129998185671866, 0.3913000109605491, 0.391699984902516, - 0.39220001781359315, - 0.39259999175556004, - 0.3929999948013574, - 0.39339999784715474, + 0.39179998566396534, + 0.39209998794831336, + 0.39250002009794116, 0.39339999784715474, 0.3934999986086041, - 0.39370000013150275, - 0.3939000016544014, - 0.3944000054616481, 0.39450000622309744, - 0.39480000850744545, - 0.3952000115532428, - 0.39579998701810837, - 0.39629999082535505, - 0.39709999691694975, - 0.3971999976783991, - 0.3999000182375312, + 0.3955000138375908, + 0.39569998625665903, + 0.3968999953940511, + 0.3974999999627471, + 0.3974999999627471, + 0.39840000681579113, + 0.3992999845650047, + 0.4000999906565994, + 0.4002000205218792, 0.4002000205218792, - 0.40049999370239675, - 0.4026000096928328, - 0.40329998591914773, - 0.40339998668059707, - 0.40400002035312355, - 0.4047999973408878, - 0.40550000267103314, - 0.4056000034324825, - 0.40610000723972917, - 0.4157000221312046, - 0.4163999983575195, - 0.4254999803379178, - 0.42699999175965786, - 0.44070000876672566, - 0.4676000098697841, - 0.48760001664049923, - 0.5067000165581703, - 0.5569999921135604, - 0.6055999838281423, - 0.609799986705184, - 0.6585999799426645, - 0.6604999944102019, - 0.6605999951716512, - 0.6743999838363379, - 0.6996000010985881, - 0.7108999998308718, - 0.7702000148128718, - 0.7889999833423644, - 1.1153999948874116, - 1.4324000221677125 + 0.4005999944638461, + 0.40099999750964344, + 0.4025000089313835, + 0.40370001806877553, + 0.4073000163771212, + 0.40779999108053744, + 0.4172000044491142, + 0.42719999328255653, + 0.43330001062713563, + 0.4427999956533313, + 0.44540001545101404, + 0.46320000546984375, + 0.510600017150864, + 0.5321999778971076, + 0.5518999823834747, + 0.5732999998144805, + 0.5739000043831766, + 0.5785000103060156, + 0.6148999964352697, + 0.6457999988924712, + 0.6615000020246953, + 0.6667000125162303, + 0.6698000070173293, + 0.6949000235181302, + 0.7845000072848052, + 0.8818000205792487, + 0.894600001629442, + 1.046899997163564, + 1.1187999916728586, + 1.369300007354468, + 1.9825999916065484 ], - "throughput_ops_per_sec": 2255.4830781503824, - "latency_p50_ms": 0.3912000101990998, - "latency_p95_ms": 0.7001650010352023, - "latency_p99_ms": 1.1185699951602162, - "latency_min_ms": 0.3721999819390476, - "latency_max_ms": 1.4324000221677125, - "latency_mean_ms": 0.44336400023894385, - "total_duration_ms": 44.336400023894385, + "throughput_ops_per_sec": 2115.4126815145105, + "latency_p50_ms": 0.391249981475994, + "latency_p95_ms": 0.8824400196317583, + "latency_p99_ms": 1.375433007196992, + "latency_min_ms": 0.37590001011267304, + "latency_max_ms": 1.9825999916065484, + "latency_mean_ms": 0.4727210008422844, + "total_duration_ms": 47.27210008422844, "total_bytes_in": 1400, "total_bytes_out": 0, "notes": "" }, + { + "name": "startup index build (P1 1KiB x20)", + "iterations": 1, + "successes": 1, + "failures": 0, + "samples": [ + 21.178900002269074 + ], + "throughput_ops_per_sec": 47.21680540032115, + "latency_p50_ms": 21.178900002269074, + "latency_p95_ms": 21.178900002269074, + "latency_p99_ms": 21.178900002269074, + "latency_min_ms": 21.178900002269074, + "latency_max_ms": 21.178900002269074, + "latency_mean_ms": 21.178900002269074, + "total_duration_ms": 21.178900002269074, + "total_bytes_in": 0, + "total_bytes_out": 0, + "notes": "process start + initialize; corpus is loaded from the persisted log" + }, + { + "name": "rebuild_index (P1 1KiB x20)", + "iterations": 1, + "successes": 1, + "failures": 0, + "samples": [ + 13.273499993374571 + ], + "throughput_ops_per_sec": 75.33807966995495, + "latency_p50_ms": 13.273499993374571, + "latency_p95_ms": 13.273499993374571, + "latency_p99_ms": 13.273499993374571, + "latency_min_ms": 13.273499993374571, + "latency_max_ms": 13.273499993374571, + "latency_mean_ms": 13.273499993374571, + "total_duration_ms": 13.273499993374571, + "total_bytes_in": 0, + "total_bytes_out": 0, + "notes": "compaction and complete in-memory search index rebuild" + }, + { + "name": "startup index build (P1 8KiB x20)", + "iterations": 1, + "successes": 1, + "failures": 0, + "samples": [ + 44.86150000593625 + ], + "throughput_ops_per_sec": 22.290828435689313, + "latency_p50_ms": 44.86150000593625, + "latency_p95_ms": 44.86150000593625, + "latency_p99_ms": 44.86150000593625, + "latency_min_ms": 44.86150000593625, + "latency_max_ms": 44.86150000593625, + "latency_mean_ms": 44.86150000593625, + "total_duration_ms": 44.86150000593625, + "total_bytes_in": 0, + "total_bytes_out": 0, + "notes": "process start + initialize; corpus is loaded from the persisted log" + }, + { + "name": "rebuild_index (P1 8KiB x20)", + "iterations": 1, + "successes": 1, + "failures": 0, + "samples": [ + 41.8274000112433 + ], + "throughput_ops_per_sec": 23.907773367008176, + "latency_p50_ms": 41.8274000112433, + "latency_p95_ms": 41.8274000112433, + "latency_p99_ms": 41.8274000112433, + "latency_min_ms": 41.8274000112433, + "latency_max_ms": 41.8274000112433, + "latency_mean_ms": 41.8274000112433, + "total_duration_ms": 41.8274000112433, + "total_bytes_in": 0, + "total_bytes_out": 0, + "notes": "compaction and complete in-memory search index rebuild" + }, + { + "name": "startup index build (P1 32KiB x20)", + "iterations": 1, + "successes": 1, + "failures": 0, + "samples": [ + 107.5905000034254 + ], + "throughput_ops_per_sec": 9.29450090824155, + "latency_p50_ms": 107.5905000034254, + "latency_p95_ms": 107.5905000034254, + "latency_p99_ms": 107.5905000034254, + "latency_min_ms": 107.5905000034254, + "latency_max_ms": 107.5905000034254, + "latency_mean_ms": 107.5905000034254, + "total_duration_ms": 107.5905000034254, + "total_bytes_in": 0, + "total_bytes_out": 0, + "notes": "process start + initialize; corpus is loaded from the persisted log" + }, + { + "name": "rebuild_index (P1 32KiB x20)", + "iterations": 1, + "successes": 1, + "failures": 0, + "samples": [ + 104.67490000883117 + ], + "throughput_ops_per_sec": 9.55338863390968, + "latency_p50_ms": 104.67490000883117, + "latency_p95_ms": 104.67490000883117, + "latency_p99_ms": 104.67490000883117, + "latency_min_ms": 104.67490000883117, + "latency_max_ms": 104.67490000883117, + "latency_mean_ms": 104.67490000883117, + "total_duration_ms": 104.67490000883117, + "total_bytes_in": 0, + "total_bytes_out": 0, + "notes": "compaction and complete in-memory search index rebuild" + }, + { + "name": "startup index build (P1 1MiB x20)", + "iterations": 1, + "successes": 1, + "failures": 0, + "samples": [ + 912.2578999958932 + ], + "throughput_ops_per_sec": 1.0961812443657672, + "latency_p50_ms": 912.2578999958932, + "latency_p95_ms": 912.2578999958932, + "latency_p99_ms": 912.2578999958932, + "latency_min_ms": 912.2578999958932, + "latency_max_ms": 912.2578999958932, + "latency_mean_ms": 912.2578999958932, + "total_duration_ms": 912.2578999958932, + "total_bytes_in": 0, + "total_bytes_out": 0, + "notes": "process start + initialize; corpus is loaded from the persisted log" + }, + { + "name": "rebuild_index (P1 1MiB x20)", + "iterations": 1, + "successes": 1, + "failures": 0, + "samples": [ + 1074.864800000796 + ], + "throughput_ops_per_sec": 0.9303495658237756, + "latency_p50_ms": 1074.864800000796, + "latency_p95_ms": 1074.864800000796, + "latency_p99_ms": 1074.864800000796, + "latency_min_ms": 1074.864800000796, + "latency_max_ms": 1074.864800000796, + "latency_mean_ms": 1074.864800000796, + "total_duration_ms": 1074.864800000796, + "total_bytes_in": 0, + "total_bytes_out": 0, + "notes": "compaction and complete in-memory search index rebuild" + }, { "name": "read_messages (100 msgs)", "iterations": 100, "successes": 100, "failures": 0, "samples": [ - 0.31820000731386244, - 0.31939998734742403, - 0.31999999191612005, - 0.3208999987691641, - 0.3212000010535121, - 0.321599974995479, - 0.32240001019090414, - 0.3234000178053975, - 0.3234999894630164, - 0.32359999022446573, - 0.32589997863397, - 0.3259000077378005, - 0.32619998091831803, - 0.3271000168751925, - 0.3274999908171594, - 0.3276999923400581, - 0.32770002144388855, - 0.32820002525113523, - 0.32839999767020345, - 0.3285999991931021, - 0.3291000030003488, - 0.3294000052846968, - 0.3294000052846968, - 0.32970000756904483, - 0.32980000833049417, - 0.3299000090919435, - 0.3302999830339104, - 0.3305999853182584, - 0.33069998607970774, - 0.33080001594498754, - 0.33080001594498754, - 0.33099998836405575, - 0.33170002279803157, - 0.33290000283159316, - 0.33370000892318785, - 0.33370000892318785, - 0.3341000119689852, - 0.3341000119689852, - 0.33489998895674944, - 0.3352999920025468, - 0.33549999352544546, - 0.33569999504834414, - 0.3364000003784895, - 0.33650000113993883, - 0.3378999826963991, - 0.33820001408457756, - 0.33840001560747623, - 0.3384999872650951, - 0.3387999895494431, - 0.3391999925952405, - 0.33939999411813915, - 0.3395999956410378, - 0.3400999994482845, - 0.34080000477842987, - 0.34089997643604875, - 0.3412999794818461, - 0.3415999817661941, - 0.3422000154387206, - 0.34229998709633946, - 0.34240001696161926, - 0.3431999939493835, - 0.34329999471083283, - 0.34329999471083283, - 0.34389999927952886, - 0.3440000000409782, - 0.3451000084169209, - 0.3452999808359891, - 0.3457000129856169, - 0.34630001755431294, - 0.34680002136155963, - 0.3468999930191785, - 0.3476999991107732, - 0.34840000444091856, - 0.34890000824816525, - 0.34920001053251326, - 0.3512000257615, - 0.35650000791065395, - 0.3569999826140702, - 0.3603999793995172, - 0.361700018402189, - 0.3696999920066446, - 0.3711000026669353, - 0.37269998574629426, - 0.3735999925993383, - 0.38109999150037766, + 0.3730999887920916, + 0.37369999336078763, + 0.3738999948836863, + 0.374399998690933, + 0.374399998690933, + 0.3744999994523823, + 0.374700000975281, + 0.374700000975281, + 0.3749000024981797, + 0.375000003259629, + 0.3752000047825277, + 0.3760000108741224, + 0.3761000116355717, + 0.37670001620426774, + 0.3769000177271664, + 0.37719999090768397, + 0.37739999243058264, + 0.3775999939534813, + 0.3775999939534813, + 0.3775999939534813, + 0.3776000230573118, + 0.378400000045076, + 0.3795000084210187, + 0.3797000099439174, + 0.3803999861702323, + 0.380899989977479, + 0.381199992261827, + 0.381499994546175, + 0.3819999983534217, + 0.382099999114871, + 0.382099999114871, + 0.382099999114871, + 0.38219999987632036, + 0.3823000006377697, + 0.38240000139921904, + 0.38270000368356705, + 0.3827999753411859, + 0.38300000596791506, + 0.3831999783869833, + 0.38350000977516174, + 0.38350000977516174, + 0.3836000105366111, + 0.3839000128209591, + 0.38410001434385777, + 0.3843999875243753, 0.3845000173896551, + 0.38469998980872333, + 0.38479999057017267, + 0.384899991331622, + 0.38529999437741935, + 0.38579999818466604, + 0.38579999818466604, + 0.3858999989461154, + 0.38590002804994583, + 0.3862000012304634, + 0.3873000096064061, + 0.3874999820254743, + 0.38759998278692365, + 0.3876000118907541, + 0.387999985832721, + 0.38800001493655145, + 0.38800001493655145, + 0.3882000164594501, + 0.3884000179823488, + 0.3887999919243157, + 0.3892999957315624, + 0.3896999987773597, + 0.39099997957237065, + 0.391699984902516, + 0.39190001552924514, + 0.39239999023266137, + 0.3924999909941107, + 0.39259999175556004, + 0.39319999632425606, 0.39420000393874943, - 0.4026000096928328, - 0.4251000063959509, - 0.4325999761931598, - 0.4352999967522919, - 0.544899987289682, - 0.682699988828972, - 0.739200011594221, - 0.7657000096514821, - 0.8477999945171177, - 0.9815999947022647, - 1.0258000111207366, - 1.3758999994024634, - 2.2730999917257577 + 0.39489998016506433, + 0.3960999893024564, + 0.39739999920129776, + 0.39739999920129776, + 0.3999000182375312, + 0.40019999141804874, + 0.4042000218760222, + 0.4067000118084252, + 0.40950000402517617, + 0.4159000236541033, + 0.4174000059720129, + 0.41989999590441585, + 0.43340001138858497, + 0.448200007667765, + 0.4532000166364014, + 0.45399999362416565, + 0.45510000200010836, + 0.46449998626485467, + 0.4667000030167401, + 0.4773999971803278, + 0.5267999949865043, + 0.5945000157225877, + 0.6286999850999564, + 1.1400000075809658, + 1.6858000017236918 ], - "throughput_ops_per_sec": 2471.63795559416, - "latency_p50_ms": 0.3392999933566898, - "latency_p95_ms": 0.7698050088947637, - "latency_p99_ms": 1.384871999325701, - "latency_min_ms": 0.31820000731386244, - "latency_max_ms": 2.2730999917257577, - "latency_mean_ms": 0.40458999981638044, - "total_duration_ms": 40.458999981638044, + "throughput_ops_per_sec": 2392.333047257046, + "latency_p50_ms": 0.3855499962810427, + "latency_p95_ms": 0.47986999707063643, + "latency_p99_ms": 1.145458007522396, + "latency_min_ms": 0.3730999887920916, + "latency_max_ms": 1.6858000017236918, + "latency_mean_ms": 0.41800200066063553, + "total_duration_ms": 41.80020006606355, "total_bytes_in": 0, "total_bytes_out": 0, "notes": "" @@ -606,115 +909,115 @@ "successes": 100, "failures": 0, "samples": [ - 0.14349998673424125, - 0.14409999130293727, - 0.14450002345256507, - 0.1446000242140144, - 0.14489999739453197, - 0.14509999891743064, - 0.14540000120177865, - 0.145500001963228, - 0.145800004247576, - 0.14590000500902534, - 0.14590000500902534, - 0.14600000577047467, - 0.146100006531924, - 0.1461999781895429, - 0.14629997895099223, - 0.14630000805482268, - 0.14640000881627202, - 0.14640000881627202, - 0.14640000881627202, - 0.14669998199678957, - 0.14670001110062003, - 0.14670001110062003, - 0.1467999827582389, - 0.14680001186206937, - 0.14689998351968825, - 0.14709998504258692, - 0.1474000164307654, - 0.14750001719221473, - 0.1475999888498336, - 0.14779999037273228, - 0.14779999037273228, - 0.14799999189563096, - 0.14799999189563096, - 0.1480999926570803, - 0.14829999417997897, - 0.1483999949414283, - 0.1483999949414283, - 0.14840002404525876, - 0.14860002556815743, - 0.14869999722577631, - 0.14890002785250545, - 0.14899999951012433, - 0.14899999951012433, - 0.149200001033023, - 0.14960000407882035, - 0.14980000560171902, - 0.15020000864751637, - 0.15020000864751637, - 0.15020000864751637, - 0.15029998030513525, - 0.1503999810665846, - 0.15050001093186438, - 0.15079998411238194, - 0.15100001473911107, - 0.15140001778490841, - 0.15169999096542597, - 0.15199999324977398, - 0.15239999629557133, - 0.15239999629557133, - 0.15249999705702066, - 0.15259999781847, - 0.15259999781847, - 0.152900000102818, - 0.15300000086426735, - 0.1531000016257167, - 0.1531000016257167, - 0.15380000695586205, - 0.15380000695586205, - 0.15399997937493026, - 0.15399997937493026, - 0.15480001457035542, - 0.1548999862279743, - 0.15539999003522098, - 0.15559999155811965, - 0.15720000374130905, - 0.15740000526420772, - 0.1579000090714544, - 0.15819998225197196, - 0.16039999900385737, - 0.16160000814124942, - 0.1640999980736524, - 0.16450000111944973, - 0.1650999765843153, - 0.16529997810721397, - 0.16590001177974045, - 0.16640001558698714, - 0.16709999181330204, - 0.16709999181330204, - 0.16769999638199806, - 0.16820000018924475, - 0.17189999925903976, - 0.1742000167723745, - 0.17829998978413641, - 0.18599999020807445, - 0.18870001076720655, - 0.19990000873804092, - 0.22330001229420304, - 0.2859000233002007, - 0.7118000066839159, - 1.6556000045966357 + 0.17519999528303742, + 0.17549999756738544, + 0.17559999832883477, + 0.1756999990902841, + 0.1756999990902841, + 0.1756999990902841, + 0.1756999990902841, + 0.1756999990902841, + 0.17579999985173345, + 0.17579999985173345, + 0.17590000061318278, + 0.17610000213608146, + 0.17610000213608146, + 0.17629997455514967, + 0.17640000442042947, + 0.17660000594332814, + 0.17670000670477748, + 0.17670000670477748, + 0.17670000670477748, + 0.17680000746622682, + 0.17680000746622682, + 0.1768999791238457, + 0.17690000822767615, + 0.17709998064674437, + 0.17709998064674437, + 0.17710000975057483, + 0.17720001051202416, + 0.1773000112734735, + 0.1773000112734735, + 0.1773000112734735, + 0.17739998293109238, + 0.17740001203492284, + 0.17749998369254172, + 0.17750001279637218, + 0.1776000135578215, + 0.1776000135578215, + 0.1776999852154404, + 0.1776999852154404, + 0.1776999852154404, + 0.17779998597688973, + 0.17789998673833907, + 0.17809998826123774, + 0.1781000173650682, + 0.1781000173650682, + 0.17820001812651753, + 0.17860002117231488, + 0.17869999282993376, + 0.17899999511428177, + 0.17919999663718045, + 0.17919999663718045, + 0.17939999816007912, + 0.1795999996829778, + 0.1799000019673258, + 0.18000000272877514, + 0.18009997438639402, + 0.18010000349022448, + 0.18010000349022448, + 0.18020000425167382, + 0.18020000425167382, + 0.1802999759092927, + 0.18060000729747117, + 0.18060000729747117, + 0.18079997971653938, + 0.18080000882036984, + 0.1810000103432685, + 0.1810999820008874, + 0.18110001110471785, + 0.18140001338906586, + 0.18140001338906586, + 0.18160001491196454, + 0.18229999113827944, + 0.18279999494552612, + 0.18319999799132347, + 0.1836999726947397, + 0.1838000025600195, + 0.1841000048443675, + 0.1841000048443675, + 0.18430000636726618, + 0.18480001017451286, + 0.18539998563937843, + 0.18649999401532114, + 0.18709999858401716, + 0.18709999858401716, + 0.18730000010691583, + 0.19049999536946416, + 0.19219997921027243, + 0.19409999367780983, + 0.19749999046325684, + 0.19950000569224358, + 0.21009999909438193, + 0.21580001339316368, + 0.22419999004341662, + 0.22990000434219837, + 0.23219999275170267, + 0.28399997972883284, + 0.2945000014733523, + 0.538099993718788, + 0.5551000067498535, + 0.913099996978417, + 0.9215000027325004 ], - "throughput_ops_per_sec": 5675.11122125873, - "latency_p50_ms": 0.15034998068585992, - "latency_p95_ms": 0.18926001066574824, - "latency_p99_ms": 0.7212380066630478, - "latency_min_ms": 0.14349998673424125, - "latency_max_ms": 1.6556000045966357, - "latency_mean_ms": 0.176208000339102, - "total_duration_ms": 17.6208000339102, + "throughput_ops_per_sec": 4844.53876816329, + "latency_p50_ms": 0.17929999739862978, + "latency_p95_ms": 0.28452498081605876, + "latency_p99_ms": 0.9131839970359579, + "latency_min_ms": 0.17519999528303742, + "latency_max_ms": 0.9215000027325004, + "latency_mean_ms": 0.20641799928853288, + "total_duration_ms": 20.64179992885329, "total_bytes_in": 0, "total_bytes_out": 0, "notes": "" @@ -725,115 +1028,115 @@ "successes": 100, "failures": 0, "samples": [ - 0.1453000004403293, - 0.14540000120177865, - 0.14590000500902534, - 0.146100006531924, - 0.1467999827582389, - 0.14680001186206937, - 0.14689998351968825, - 0.1469000126235187, - 0.14710001414641738, - 0.14720001490786672, - 0.1472999865654856, - 0.1472999865654856, - 0.1474000164307654, - 0.1474000164307654, - 0.14749998808838427, - 0.14749998808838427, - 0.1475999888498336, - 0.14769998961128294, - 0.14769998961128294, - 0.14779999037273228, - 0.14789999113418162, - 0.1480999926570803, - 0.14810002176091075, - 0.14819999341852963, - 0.1483999949414283, - 0.1483999949414283, - 0.14840002404525876, - 0.14860002556815743, - 0.14869999722577631, - 0.14869999722577631, - 0.148899998748675, - 0.14930000179447234, - 0.14930000179447234, - 0.14930000179447234, - 0.14940000255592167, - 0.14960000407882035, - 0.14990000636316836, - 0.1500000071246177, - 0.15010000788606703, - 0.15010000788606703, - 0.1503000094089657, - 0.15050001093186438, - 0.15050001093186438, - 0.15059998258948326, - 0.1506999833509326, - 0.15079998411238194, - 0.15079998411238194, - 0.1509999856352806, - 0.15150001854635775, - 0.15159999020397663, - 0.15159999020397663, - 0.1516000193078071, - 0.15209999401122332, - 0.15269999857991934, - 0.152900000102818, - 0.15300000086426735, - 0.15300000086426735, - 0.15300000086426735, - 0.15350000467151403, - 0.15360000543296337, - 0.1537999778520316, - 0.15399997937493026, - 0.15410000924021006, - 0.15429998165927827, - 0.15440001152455807, - 0.1545000122860074, - 0.15460001304745674, - 0.15469998470507562, - 0.15509998775087297, - 0.15550001990050077, - 0.15550001990050077, - 0.15559999155811965, - 0.15589999384246767, - 0.156299996888265, - 0.15669999993406236, - 0.15750000602565706, - 0.15839998377487063, - 0.15880001592449844, - 0.15899998834356666, - 0.16170000890269876, - 0.16309999045915902, - 0.16540000797249377, - 0.166199984960258, - 0.16960001084953547, - 0.18049997743219137, - 0.18440000712871552, - 0.19439999596215785, - 0.2193999825976789, - 0.21989998640492558, - 0.2463000128045678, - 0.25069998810067773, - 0.2605999761726707, - 0.2620999875944108, - 0.27439999394118786, - 0.4681999853346497, - 0.5210000090301037, - 0.6234000029508024, - 0.7620000105816871, - 0.8063999994192272, - 0.9846999892033637 + 0.17559999832883477, + 0.17559999832883477, + 0.17590000061318278, + 0.17610000213608146, + 0.1762000028975308, + 0.17630000365898013, + 0.17630000365898013, + 0.17630000365898013, + 0.17640000442042947, + 0.17660000594332814, + 0.17660000594332814, + 0.17670000670477748, + 0.17679997836239636, + 0.17680000746622682, + 0.17690000822767615, + 0.1770000089891255, + 0.17709998064674437, + 0.1773000112734735, + 0.1773000112734735, + 0.17740001203492284, + 0.17749998369254172, + 0.1776000135578215, + 0.17770001431927085, + 0.1778000150807202, + 0.17789998673833907, + 0.17790001584216952, + 0.17790001584216952, + 0.17790001584216952, + 0.1779999874997884, + 0.1779999874997884, + 0.1779999874997884, + 0.17800001660361886, + 0.17819998902268708, + 0.17820001812651753, + 0.17829998978413641, + 0.17829998978413641, + 0.1784000196494162, + 0.1784999913070351, + 0.1784999913070351, + 0.1784999913070351, + 0.1784999913070351, + 0.17860002117231488, + 0.17860002117231488, + 0.1787999935913831, + 0.1787999935913831, + 0.1790999958757311, + 0.17910002497956157, + 0.17929999739862978, + 0.17939999816007912, + 0.17939999816007912, + 0.17939999816007912, + 0.1795999996829778, + 0.17960002878680825, + 0.18020000425167382, + 0.18020000425167382, + 0.18020000425167382, + 0.1802999759092927, + 0.18030000501312315, + 0.1804000057745725, + 0.18050000653602183, + 0.1805999781936407, + 0.1807000080589205, + 0.18080000882036984, + 0.18090000958181918, + 0.1810999820008874, + 0.18110001110471785, + 0.1813999842852354, + 0.18140001338906586, + 0.18170001567341387, + 0.18209998961538076, + 0.1824999926611781, + 0.1826000225264579, + 0.1829999964684248, + 0.18370000179857016, + 0.1841000048443675, + 0.18420000560581684, + 0.18439997802488506, + 0.18450000789016485, + 0.18450000789016485, + 0.18459997954778373, + 0.18679999629966915, + 0.18730000010691583, + 0.18820000695995986, + 0.18989999080076814, + 0.19029999384656549, + 0.19099999917671084, + 0.19179997616447508, + 0.19420002354308963, + 0.19459999748505652, + 0.1947999990079552, + 0.2023999986704439, + 0.20619999850168824, + 0.21269998978823423, + 0.2263000060338527, + 0.22690001060254872, + 0.23809997946955264, + 0.2508000179659575, + 0.7984999974723905, + 0.8185000042431056, + 1.741599990054965 ], - "throughput_ops_per_sec": 5209.038750416192, - "latency_p50_ms": 0.15159999020397663, - "latency_p95_ms": 0.4708399865194222, - "latency_p99_ms": 0.8081829993170695, - "latency_min_ms": 0.1453000004403293, - "latency_max_ms": 0.9846999892033637, - "latency_mean_ms": 0.19197399902623147, - "total_duration_ms": 19.197399902623147, + "throughput_ops_per_sec": 4725.138656681065, + "latency_p50_ms": 0.17939999816007912, + "latency_p95_ms": 0.2274600090458989, + "latency_p99_ms": 0.827731004101229, + "latency_min_ms": 0.17559999832883477, + "latency_max_ms": 1.741599990054965, + "latency_mean_ms": 0.2116340011707507, + "total_duration_ms": 21.16340011707507, "total_bytes_in": 0, "total_bytes_out": 0, "notes": "" @@ -844,115 +1147,115 @@ "successes": 100, "failures": 0, "samples": [ - 0.357700017048046, - 0.3607999824453145, - 0.361100013833493, - 0.3622999938670546, - 0.3623999946285039, - 0.36269999691285193, - 0.3628999984357506, - 0.36290002753958106, - 0.3630999999586493, - 0.3637000045273453, - 0.3640000068116933, - 0.36429997999221087, - 0.3643000090960413, - 0.364800012903288, - 0.36559998989105225, - 0.3657999914139509, - 0.36600002204068005, - 0.36669999826699495, - 0.3729000163730234, - 0.3732000186573714, - 0.37349999183788896, - 0.37429999792948365, - 0.3744999994523823, - 0.374700000975281, - 0.3752000047825277, - 0.3755999787244946, - 0.37609998253174126, - 0.3761000116355717, - 0.37629998405463994, - 0.3775999939534813, - 0.37819999852217734, - 0.37880000309087336, - 0.3794000076595694, - 0.3795000084210187, - 0.3795000084210187, - 0.3809999907389283, - 0.3816999960690737, - 0.38320000749081373, - 0.3836000105366111, - 0.3837000112980604, - 0.3837000112980604, - 0.38389998371712863, - 0.38469998980872333, - 0.3848000196740031, - 0.38640000275336206, - 0.3871000080835074, - 0.38740001036785543, + 0.3868000057991594, + 0.3868000057991594, + 0.3870000073220581, + 0.3870000073220581, + 0.38720000884495676, + 0.38720000884495676, + 0.38729998050257564, + 0.3874999820254743, + 0.3874999820254743, + 0.38750001112930477, 0.38759998278692365, + 0.38770001265220344, + 0.3878000134136528, + 0.38789998507127166, + 0.38819998735561967, + 0.38830001722089946, + 0.3884000179823488, + 0.3884999896399677, + 0.388599990401417, + 0.388599990401417, + 0.38869999116286635, + 0.38889999268576503, + 0.3889000217895955, + 0.38910002331249416, + 0.38919999497011304, + 0.3892999957315624, + 0.3892999957315624, + 0.38930002483539283, 0.38949999725446105, - 0.3896999987773597, - 0.39010000182315707, + 0.3895999980159104, + 0.3895999980159104, + 0.38979999953880906, + 0.38979999953880906, + 0.39000000106170774, + 0.3902999742422253, + 0.3905000048689544, + 0.39069997728802264, + 0.39080000715330243, + 0.3913000109605491, + 0.39140001172199845, + 0.39159998414106667, + 0.391699984902516, + 0.39170001400634646, + 0.39209998794831336, + 0.39229998947121203, + 0.3924999909941107, + 0.39339999784715474, + 0.3946000069845468, + 0.39500001003034413, + 0.39560001459904015, + 0.39569998625665903, 0.3957000153604895, - 0.3966999938711524, - 0.39820000529289246, - 0.4026000096928328, - 0.40290001197718084, - 0.40350001654587686, - 0.4078000201843679, - 0.41259999852627516, - 0.41429998236708343, - 0.41719997534528375, - 0.42189998202957213, - 0.4236000240780413, - 0.4243000003043562, - 0.42570001096464694, - 0.4329000075813383, - 0.4335000121500343, - 0.4374999844003469, - 0.4382000188343227, - 0.45029999455437064, - 0.46370000927709043, - 0.4668000037781894, - 0.47259998973459005, - 0.4845999937970191, - 0.49330000183545053, - 0.4965999978594482, - 0.5030999891459942, - 0.5033000197727233, - 0.5043999990448356, - 0.5099999834783375, - 0.5201000021770597, - 0.5224999913480133, - 0.5225000204518437, - 0.523299997439608, - 0.5238000012468547, - 0.529799988726154, - 0.5446999857667834, - 0.5487999878823757, - 0.5502999993041158, - 0.5794999888166785, - 0.585700006922707, - 0.5951999919489026, - 0.6125000072643161, - 0.614999997196719, - 0.7118000066839159, - 0.7120000082068145, - 0.7795999990776181, - 0.8068000024650246, - 0.8276000153273344, - 0.918099976843223 + 0.3963000199291855, + 0.3992000129073858, + 0.39930001366883516, + 0.39939998532645404, + 0.39950001519173384, + 0.4003999929409474, + 0.4005999944638461, + 0.4008999967481941, + 0.40099999750964344, + 0.40099999750964344, + 0.4010999982710928, + 0.4011999990325421, + 0.4015000013168901, + 0.40160000207833946, + 0.4017999744974077, + 0.4022000066470355, + 0.4025000089313835, + 0.4026999813504517, + 0.40309998439624906, + 0.40370001806877553, + 0.40469999657943845, + 0.40740001713857055, + 0.4106000124011189, + 0.4123999970033765, + 0.41439998312853277, + 0.4155999922659248, + 0.4215999797452241, + 0.4230999911669642, + 0.4293000092729926, + 0.43420001748017967, + 0.43819998973049223, + 0.444200006313622, + 0.4610000178217888, + 0.461199990240857, + 0.47339999582618475, + 0.5020000098738819, + 0.5164000031072646, + 0.5303000216372311, + 0.5390000005718321, + 0.6174000154715031, + 0.6195000023581088, + 0.8196000126190484, + 0.9128000237978995, + 0.970900000538677, + 1.2361000117380172, + 1.3457000022754073, + 1.4962000132072717, + 1.574800000526011 ], - "throughput_ops_per_sec": 2248.605859510455, - "latency_p50_ms": 0.3899000003002584, - "latency_p95_ms": 0.7118100067600608, - "latency_p99_ms": 0.8285050149424937, - "latency_min_ms": 0.357700017048046, - "latency_max_ms": 0.918099976843223, - "latency_mean_ms": 0.4447200009599328, - "total_duration_ms": 44.47200009599328, + "throughput_ops_per_sec": 2154.137123254582, + "latency_p50_ms": 0.3956500004278496, + "latency_p95_ms": 0.9157050226349382, + "latency_p99_ms": 1.4969860130804595, + "latency_min_ms": 0.3868000057991594, + "latency_max_ms": 1.574800000526011, + "latency_mean_ms": 0.46422300103586167, + "total_duration_ms": 46.42230010358617, "total_bytes_in": 0, "total_bytes_out": 0, "notes": "" @@ -963,20 +1266,20 @@ "successes": 5, "failures": 0, "samples": [ - 5.564399994909763, - 5.966299999272451, - 6.8909999972675, - 7.271500013303012, - 7.908600004157051 + 6.5218999807257205, + 6.8715999950654805, + 8.48659998155199, + 9.70879997476004, + 9.97569999890402 ], - "throughput_ops_per_sec": 148.8015522583377, - "latency_p50_ms": 6.8909999972675, - "latency_p95_ms": 7.7811800059862435, - "latency_p99_ms": 7.88311600452289, - "latency_min_ms": 5.564399994909763, - "latency_max_ms": 7.908600004157051, - "latency_mean_ms": 6.720360001781955, - "total_duration_ms": 33.60180000890978, + "throughput_ops_per_sec": 120.29467403269754, + "latency_p50_ms": 8.48659998155199, + "latency_p95_ms": 9.922319994075224, + "latency_p99_ms": 9.96502399793826, + "latency_min_ms": 6.5218999807257205, + "latency_max_ms": 9.97569999890402, + "latency_mean_ms": 8.31291998620145, + "total_duration_ms": 41.56459993100725, "total_bytes_in": 0, "total_bytes_out": 0, "notes": "" @@ -987,115 +1290,115 @@ "successes": 100, "failures": 0, "samples": [ - 0.09960000170394778, - 0.09960000170394778, - 0.09980000322684646, - 0.0999000039882958, - 0.10070001007989049, - 0.10070001007989049, - 0.10080001084133983, - 0.10080001084133983, - 0.10090001160278916, - 0.10119998478330672, - 0.10129998554475605, - 0.10129998554475605, - 0.10139998630620539, - 0.10149998706765473, - 0.10160001693293452, - 0.10179998935200274, - 0.10199999087490141, - 0.10200001997873187, - 0.10219999239780009, - 0.10239999392069876, - 0.1024999946821481, - 0.10269999620504677, - 0.10269999620504677, - 0.10289999772794545, - 0.10309999925084412, - 0.10309999925084412, - 0.10350000229664147, - 0.1039999770000577, - 0.10449998080730438, - 0.10450000991113484, - 0.10470001143403351, - 0.10499998461455107, - 0.1050999853760004, - 0.10540001676417887, - 0.10550001752562821, - 0.10560001828707755, - 0.1058999914675951, - 0.1060000213328749, - 0.10609999299049377, - 0.10609999299049377, - 0.10620002285577357, - 0.10679999832063913, - 0.10710000060498714, - 0.10740000288933516, - 0.10750000365078449, - 0.10830000974237919, - 0.10869998368434608, - 0.10939998901449144, - 0.10989999282173812, - 0.10989999282173812, - 0.1100999943446368, - 0.11130000348202884, - 0.11160000576637685, - 0.11210000957362354, - 0.11249998351559043, - 0.11270001414231956, - 0.1128000149037689, - 0.11309998808428645, - 0.11350002023391426, - 0.11419999646022916, - 0.11480000102892518, - 0.11530000483617187, - 0.11589998030103743, - 0.11610001092776656, - 0.11610001092776656, - 0.11679998715408146, - 0.1168999879155308, - 0.11749999248422682, - 0.11799999629147351, - 0.11860000086016953, - 0.11910000466741621, - 0.1196000084746629, - 0.12079998850822449, - 0.1210999907925725, - 0.12110001989640296, - 0.12119999155402184, - 0.12129999231547117, - 0.12139999307692051, - 0.12250000145286322, - 0.12389998300932348, - 0.12519999290816486, - 0.12569999671541154, - 0.12620000052265823, - 0.1264000020455569, - 0.12889999197795987, - 0.12919999426230788, - 0.13169998419471085, - 0.1328999933321029, + 0.13189998571760952, + 0.13190001482143998, + 0.13200001558288932, + 0.13219998800195754, + 0.13229998876340687, + 0.1323999895248562, + 0.13259999104775488, + 0.13260002015158534, + 0.13270002091303468, + 0.13270002091303468, + 0.13280002167448401, + 0.13290002243593335, + 0.13299999409355223, + 0.1330000231973827, + 0.1330000231973827, + 0.13309999485500157, + 0.13309999485500157, + 0.13339999713934958, + 0.1338999718427658, + 0.1340000017080456, 0.1340000017080456, + 0.13410000246949494, + 0.13410000246949494, + 0.1343000039923936, + 0.1343999756500125, + 0.13440000475384295, + 0.13440000475384295, + 0.13440000475384295, + 0.13440000475384295, + 0.13459997717291117, + 0.13460000627674162, + 0.13460000627674162, + 0.13479997869580984, + 0.13489997945725918, + 0.13490000856108963, + 0.13500000932253897, + 0.1351000100839883, + 0.1351000100839883, + 0.1351000100839883, + 0.1351000100839883, + 0.1351000100839883, + 0.1351000100839883, + 0.1351999817416072, + 0.1351999817416072, + 0.13520001084543765, + 0.13530001160688698, + 0.1354999840259552, + 0.13559998478740454, + 0.135600013891235, + 0.13580001541413367, + 0.13589998707175255, + 0.13619998935610056, + 0.13619998935610056, + 0.13620001845993102, + 0.13639999087899923, + 0.13649999164044857, + 0.13689999468624592, + 0.1370999962091446, + 0.1370999962091446, + 0.13719999697059393, + 0.13760000001639128, + 0.13770000077784061, + 0.1379000023007393, + 0.13810000382363796, + 0.13810000382363796, + 0.13829997624270618, + 0.13849997776560485, + 0.13860000763088465, + 0.13880000915378332, + 0.1388999808114022, + 0.13910001143813133, + 0.13960001524537802, + 0.1396999869029969, + 0.14029999147169292, + 0.14030002057552338, + 0.14039999223314226, + 0.14099999680183828, + 0.14119999832473695, + 0.14150000060908496, + 0.14170000213198364, + 0.14210000517778099, + 0.14230000670067966, + 0.142700009746477, + 0.142700009746477, 0.14310001279227436, - 0.15010000788606703, - 0.15830001211725175, - 0.16319999122060835, - 0.16820000018924475, - 0.17540002590976655, - 0.21830000332556665, - 0.2316000172868371, - 0.25749998167157173, - 0.7612000044900924, - 0.8997000113595277 + 0.1453000004403293, + 0.145800004247576, + 0.14640000881627202, + 0.1480999926570803, + 0.14940000255592167, + 0.15259999781847, + 0.1543999824207276, + 0.1618000096641481, + 0.16490000416524708, + 0.17250000382773578, + 0.17739998293109238, + 0.18020000425167382, + 0.18440000712871552, + 0.30610000248998404, + 0.30670000705868006 ], - "throughput_ops_per_sec": 7587.0807292005875, - "latency_p50_ms": 0.10999999358318746, - "latency_p95_ms": 0.17754502478055645, - "latency_p99_ms": 0.7625850045587874, - "latency_min_ms": 0.09960000170394778, - "latency_max_ms": 0.8997000113595277, - "latency_mean_ms": 0.1318029998219572, - "total_duration_ms": 13.18029998219572, + "throughput_ops_per_sec": 7011.000220270736, + "latency_p50_ms": 0.1358500012429431, + "latency_p95_ms": 0.17274500278290358, + "latency_p99_ms": 0.306106002535671, + "latency_min_ms": 0.13189998571760952, + "latency_max_ms": 0.30670000705868006, + "latency_mean_ms": 0.14263300079619512, + "total_duration_ms": 14.263300079619512, "total_bytes_in": 0, "total_bytes_out": 0, "notes": "" @@ -1106,16 +1409,16 @@ "successes": 1, "failures": 0, "samples": [ - 20.377600012579933 + 21.361299994168803 ], - "throughput_ops_per_sec": 49.073492432016465, - "latency_p50_ms": 20.377600012579933, - "latency_p95_ms": 20.377600012579933, - "latency_p99_ms": 20.377600012579933, - "latency_min_ms": 20.377600012579933, - "latency_max_ms": 20.377600012579933, - "latency_mean_ms": 20.377600012579933, - "total_duration_ms": 20.377600012579933, + "throughput_ops_per_sec": 46.813630269364666, + "latency_p50_ms": 21.361299994168803, + "latency_p95_ms": 21.361299994168803, + "latency_p99_ms": 21.361299994168803, + "latency_min_ms": 21.361299994168803, + "latency_max_ms": 21.361299994168803, + "latency_mean_ms": 21.361299994168803, + "total_duration_ms": 21.361299994168803, "total_bytes_in": 0, "total_bytes_out": 0, "notes": "includes process shutdown + startup + initialize + read count" @@ -1126,20 +1429,20 @@ "successes": 5, "failures": 0, "samples": [ - 16.233500005910173, - 16.51690001017414, - 16.59829998970963, - 16.701499989721924, - 16.76729999599047 + 16.0219999961555, + 16.140899999300018, + 16.201599995838478, + 16.705499991076067, + 19.42379999672994 ], - "throughput_ops_per_sec": 60.373713291427464, - "latency_p50_ms": 16.59829998970963, - "latency_p95_ms": 16.75413999473676, - "latency_p99_ms": 16.764667995739728, - "latency_min_ms": 16.233500005910173, - "latency_max_ms": 16.76729999599047, - "latency_mean_ms": 16.563499998301268, - "total_duration_ms": 82.81749999150634, + "throughput_ops_per_sec": 59.17593955102951, + "latency_p50_ms": 16.201599995838478, + "latency_p95_ms": 18.880139995599166, + "latency_p99_ms": 19.315067996503785, + "latency_min_ms": 16.0219999961555, + "latency_max_ms": 19.42379999672994, + "latency_mean_ms": 16.89875999582, + "total_duration_ms": 84.4937999791, "total_bytes_in": 0, "total_bytes_out": 0, "notes": "" @@ -1150,25 +1453,55 @@ "successes": 5, "failures": 0, "samples": [ - 15.85620001424104, - 15.893400006461889, - 16.1155000096187, - 16.868900012923405, - 18.851200002245605 + 16.14199997857213, + 16.34070000727661, + 16.480599995702505, + 16.584500001044944, + 16.741700004786253 ], - "throughput_ops_per_sec": 59.81920240998151, - "latency_p50_ms": 16.1155000096187, - "latency_p95_ms": 18.454740004381165, - "latency_p99_ms": 18.771908002672717, - "latency_min_ms": 15.85620001424104, - "latency_max_ms": 18.851200002245605, - "latency_mean_ms": 16.717040009098127, - "total_duration_ms": 83.58520004549064, + "throughput_ops_per_sec": 60.761093465954424, + "latency_p50_ms": 16.480599995702505, + "latency_p95_ms": 16.71026000403799, + "latency_p99_ms": 16.7354120046366, + "latency_min_ms": 16.14199997857213, + "latency_max_ms": 16.741700004786253, + "latency_mean_ms": 16.45789999747649, + "total_duration_ms": 82.28949998738244, "total_bytes_in": 0, "total_bytes_out": 0, "notes": "" } ], + "domain_index": [ + { + "size_bytes": 1024, + "iterations": 100, + "total_ms": 21.72, + "mean_ms": 0.217, + "peak_working_set_bytes": 4665344 + }, + { + "size_bytes": 8192, + "iterations": 100, + "total_ms": 129.899, + "mean_ms": 1.299, + "peak_working_set_bytes": 6803456 + }, + { + "size_bytes": 32768, + "iterations": 50, + "total_ms": 197.41, + "mean_ms": 3.948, + "peak_working_set_bytes": 10264576 + }, + { + "size_bytes": 1048576, + "iterations": 5, + "total_ms": 174.942, + "mean_ms": 34.988, + "peak_working_set_bytes": 17416192 + } + ], "health_after": { "status": "OK", "format_version": 1, diff --git a/scripts/python/benchmark_results.md b/scripts/python/benchmark_results.md index 9d512a3..857e9ea 100644 --- a/scripts/python/benchmark_results.md +++ b/scripts/python/benchmark_results.md @@ -1,29 +1,39 @@ # tiny-convmem-mcp 負荷テストレポート - サーバ: `build\windows-vs2026\src\Release\tiny-convmem-mcp.exe` - ビルド: release -- exe mtime: 2026-06-30 18:49:00 +- exe mtime: 2026-06-30 21:51:05 - iterations: 100 - warmup: 5 -- 計測日: 2026-06-30 18:49:14 +- 計測日: 2026-06-30 21:56:23 - raw JSON: `benchmark_results.json` ## レイテンシサマリ | scenario | succ | fail | p50[ms] | p95[ms] | p99[ms] | mean[ms] | ops/s | |---|---|---|---|---|---|---|---| -| write_message (small ~20B) | 100 | 0 | 0.397 | 1.236 | 2.052 | 0.589 | 1696.88 | -| write_message (medium 1KiB) | 100 | 0 | 0.870 | 1.503 | 3.138 | 1.041 | 960.92 | -| write_message (large 32KiB) | 100 | 0 | 128.242 | 133.328 | 133.560 | 128.629 | 7.77 | -| write_message (with tags) | 100 | 0 | 0.391 | 0.700 | 1.119 | 0.443 | 2255.48 | -| read_messages (100 msgs) | 100 | 0 | 0.339 | 0.770 | 1.385 | 0.405 | 2471.64 | -| search_messages (global, no session) | 100 | 0 | 0.150 | 0.189 | 0.721 | 0.176 | 5675.11 | -| search_messages (scoped to session) | 100 | 0 | 0.152 | 0.471 | 0.808 | 0.192 | 5209.04 | -| delete_message | 100 | 0 | 0.390 | 0.712 | 0.829 | 0.445 | 2248.61 | -| rebuild_index | 5 | 0 | 6.891 | 7.781 | 7.883 | 6.720 | 148.80 | -| get_system_health | 100 | 0 | 0.110 | 0.178 | 0.763 | 0.132 | 7587.08 | -| recovery (restart + count check) | 1 | 0 | 20.378 | 20.378 | 20.378 | 20.378 | 49.07 | -| recovery small read (1 message check) | 5 | 0 | 16.598 | 16.754 | 16.765 | 16.563 | 60.37 | -| recovery full read (100 msgs) | 5 | 0 | 16.116 | 18.455 | 18.772 | 16.717 | 59.82 | +| write_message (small ~20B) | 100 | 0 | 0.470 | 0.791 | 1.092 | 0.615 | 1626.88 | +| write_message (medium 1KiB) | 100 | 0 | 0.817 | 1.672 | 2.104 | 0.896 | 1116.07 | +| write_message (P1 8KiB) | 100 | 0 | 2.167 | 3.441 | 4.012 | 2.344 | 426.68 | +| write_message (large 32KiB) | 100 | 0 | 5.907 | 7.661 | 9.328 | 6.200 | 161.29 | +| write_message (P1 1MiB) | 5 | 0 | 90.093 | 91.422 | 91.534 | 88.483 | 11.30 | +| write_message (with tags) | 100 | 0 | 0.391 | 0.882 | 1.375 | 0.473 | 2115.41 | +| startup index build (P1 1KiB x20) | 1 | 0 | 21.179 | 21.179 | 21.179 | 21.179 | 47.22 | +| rebuild_index (P1 1KiB x20) | 1 | 0 | 13.273 | 13.273 | 13.273 | 13.273 | 75.34 | +| startup index build (P1 8KiB x20) | 1 | 0 | 44.862 | 44.862 | 44.862 | 44.862 | 22.29 | +| rebuild_index (P1 8KiB x20) | 1 | 0 | 41.827 | 41.827 | 41.827 | 41.827 | 23.91 | +| startup index build (P1 32KiB x20) | 1 | 0 | 107.591 | 107.591 | 107.591 | 107.591 | 9.29 | +| rebuild_index (P1 32KiB x20) | 1 | 0 | 104.675 | 104.675 | 104.675 | 104.675 | 9.55 | +| startup index build (P1 1MiB x20) | 1 | 0 | 912.258 | 912.258 | 912.258 | 912.258 | 1.10 | +| rebuild_index (P1 1MiB x20) | 1 | 0 | 1074.865 | 1074.865 | 1074.865 | 1074.865 | 0.93 | +| read_messages (100 msgs) | 100 | 0 | 0.386 | 0.480 | 1.145 | 0.418 | 2392.33 | +| search_messages (global, no session) | 100 | 0 | 0.179 | 0.285 | 0.913 | 0.206 | 4844.54 | +| search_messages (scoped to session) | 100 | 0 | 0.179 | 0.227 | 0.828 | 0.212 | 4725.14 | +| delete_message | 100 | 0 | 0.396 | 0.916 | 1.497 | 0.464 | 2154.14 | +| rebuild_index | 5 | 0 | 8.487 | 9.922 | 9.965 | 8.313 | 120.29 | +| get_system_health | 100 | 0 | 0.136 | 0.173 | 0.306 | 0.143 | 7011.00 | +| recovery (restart + count check) | 1 | 0 | 21.361 | 21.361 | 21.361 | 21.361 | 46.81 | +| recovery small read (1 message check) | 5 | 0 | 16.202 | 18.880 | 19.315 | 16.899 | 59.18 | +| recovery full read (100 msgs) | 5 | 0 | 16.481 | 16.710 | 16.735 | 16.458 | 60.76 | ## MCP 準拠 / エラーチェック @@ -66,6 +76,15 @@ } ``` +## Domain検索index構築 + +| payload | iterations | mean[ms] | peak working set[bytes] | +|---:|---:|---:|---:| +| 1024 | 100 | 0.217 | 4665344 | +| 8192 | 100 | 1.299 | 6803456 | +| 32768 | 50 | 3.948 | 10264576 | +| 1048576 | 5 | 34.988 | 17416192 | + ## 最終 health ```json diff --git a/src/domain/search.c b/src/domain/search.c index b0ac440..0f9179d 100644 --- a/src/domain/search.c +++ b/src/domain/search.c @@ -19,11 +19,17 @@ typedef struct gram_bucket struct tiny_search_index { gram_bucket_t *buckets; - size_t count; - size_t capacity; + size_t bucket_count; + size_t bucket_capacity; + size_t *slots; + size_t slot_capacity; size_t message_count; }; +#define EMPTY_SLOT SIZE_MAX +#define INITIAL_BUCKET_CAPACITY 64U +#define INITIAL_SLOT_CAPACITY 128U + static bool decode_codepoints(const char *text, uint32_t **output, size_t *count) { @@ -100,71 +106,227 @@ gram_hash(const uint32_t *points, size_t width) hash ^= points[index]; hash *= 1099511628211ULL; } +#ifdef TINY_SEARCH_TEST_HASH_BITS + hash &= (UINT64_C(1) << TINY_SEARCH_TEST_HASH_BITS) - 1; +#endif return hash; } -static gram_bucket_t * -find_bucket(const tiny_search_index_t *index, const uint32_t *points, unsigned width) +static bool +bucket_matches(const gram_bucket_t *bucket, uint64_t hash, const uint32_t *points, unsigned width) { - const uint64_t hash = gram_hash(points, width); - size_t position; - for (position = 0; position < index->count; ++position) + return bucket->hash == hash && bucket->width == width + && memcmp(bucket->points, points, width * sizeof(uint32_t)) == 0; +} + +static size_t +slot_start(uint64_t hash, size_t capacity) +{ + hash ^= hash >> 32; + return (size_t)hash & (capacity - 1); +} + +static void +insert_slot(size_t *slots, size_t capacity, const gram_bucket_t *buckets, size_t bucket_index) +{ + size_t position = slot_start(buckets[bucket_index].hash, capacity); + while (slots[position] != EMPTY_SLOT) + { + position = (position + 1) & (capacity - 1); + } + slots[position] = bucket_index; +} + +static const gram_bucket_t * +find_bucket_const(const tiny_search_index_t *index, const uint32_t *points, unsigned width) +{ + uint64_t hash; + size_t position, bucket_index; + if (index->slot_capacity == 0) { - if (index->buckets[position].hash == hash && index->buckets[position].width == width - && memcmp(index->buckets[position].points, points, width * sizeof(uint32_t)) == 0) + return NULL; + } + hash = gram_hash(points, width); + position = slot_start(hash, index->slot_capacity); + while ((bucket_index = index->slots[position]) != EMPTY_SLOT) + { + if (bucket_index >= index->bucket_count) { - return &index->buckets[position]; + return NULL; } + if (bucket_matches(&index->buckets[bucket_index], hash, points, width)) + { + return &index->buckets[bucket_index]; + } + position = (position + 1) & (index->slot_capacity - 1); } return NULL; } +static gram_bucket_t * +find_bucket_mutable(tiny_search_index_t *index, const uint32_t *points, unsigned width) +{ + return (gram_bucket_t *)find_bucket_const(index, points, width); +} + static bool -add_gram(tiny_search_index_t *index, const uint32_t *points, unsigned width, size_t message_index) +reserve_buckets(tiny_search_index_t *index, size_t required) { - gram_bucket_t *bucket = find_bucket(index, points, width); - if (bucket == NULL) + gram_bucket_t *resized; + size_t capacity = index->bucket_capacity; + if (required <= capacity) + { + return true; + } + if (required > SIZE_MAX / sizeof(*resized)) + { + return false; + } + capacity = capacity ? capacity : INITIAL_BUCKET_CAPACITY; + while (capacity < required) { - gram_bucket_t *resized; - size_t capacity; - if (index->count == index->capacity) + if (capacity > SIZE_MAX / 2) { - capacity = index->capacity ? index->capacity * 2 : 64; - resized = realloc(index->buckets, capacity * sizeof(*resized)); - if (!resized) - { - return false; - } - index->buckets = resized; - index->capacity = capacity; + return false; } - bucket = &index->buckets[index->count++]; - memset(bucket, 0, sizeof(*bucket)); - bucket->hash = gram_hash(points, width); - bucket->width = width; - memcpy(bucket->points, points, width * sizeof(uint32_t)); + capacity *= 2; + } + resized = realloc(index->buckets, capacity * sizeof(*resized)); + if (!resized) + { + return false; + } + index->buckets = resized; + index->bucket_capacity = capacity; + return true; +} + +static bool +ensure_slots(tiny_search_index_t *index, size_t required_buckets) +{ + size_t capacity = index->slot_capacity; + size_t *slots; + size_t position; + if (capacity != 0 && required_buckets <= (capacity / 10) * 7) + { + return true; } - if (bucket->count > 0 && bucket->messages[bucket->count - 1] == message_index) + capacity = capacity ? capacity : INITIAL_SLOT_CAPACITY; + while (required_buckets > (capacity / 10) * 7) + { + if (capacity > SIZE_MAX / 2) + { + return false; + } + capacity *= 2; + } + if (capacity > SIZE_MAX / sizeof(*slots)) + { + return false; + } + slots = malloc(capacity * sizeof(*slots)); + if (!slots) + { + return false; + } + for (position = 0; position < capacity; ++position) + { + slots[position] = EMPTY_SLOT; + } + for (position = 0; position < index->bucket_count; ++position) + { + insert_slot(slots, capacity, index->buckets, position); + } + free(index->slots); + index->slots = slots; + index->slot_capacity = capacity; + return true; +} + +static bool +reserve_messages(gram_bucket_t *bucket, size_t required) +{ + size_t capacity = bucket->capacity; + size_t *resized; + if (required <= capacity) { return true; } - if (bucket->count == bucket->capacity) + if (required > SIZE_MAX / sizeof(*resized)) { - const size_t capacity = bucket->capacity ? bucket->capacity * 2 : 8; - size_t *resized = realloc(bucket->messages, capacity * sizeof(*resized)); - if (!resized) + return false; + } + capacity = capacity ? capacity : 8; + while (capacity < required) + { + if (capacity > SIZE_MAX / 2) { return false; } - bucket->messages = resized; - bucket->capacity = capacity; + capacity *= 2; } - bucket->messages[bucket->count++] = message_index; + resized = realloc(bucket->messages, capacity * sizeof(*resized)); + if (!resized) + { + return false; + } + bucket->messages = resized; + bucket->capacity = capacity; return true; } static bool -index_text(tiny_search_index_t *index, const char *text, size_t message_index) +add_gram_direct(tiny_search_index_t *index, + const uint32_t *points, + unsigned width, + size_t message_index) +{ + gram_bucket_t *bucket = find_bucket_mutable(index, points, width); + if (bucket != NULL) + { + if (bucket->count > 0 && bucket->messages[bucket->count - 1] == message_index) + { + return true; + } + if (bucket->count == SIZE_MAX || !reserve_messages(bucket, bucket->count + 1)) + { + return false; + } + bucket->messages[bucket->count++] = message_index; + return true; + } + else + { + size_t *messages = malloc(8 * sizeof(*messages)); + size_t new_index; + if (!messages) + { + return false; + } + if (index->bucket_count == SIZE_MAX || !reserve_buckets(index, index->bucket_count + 1) + || !ensure_slots(index, index->bucket_count + 1)) + { + free(messages); + return false; + } + new_index = index->bucket_count; + bucket = &index->buckets[new_index]; + memset(bucket, 0, sizeof(*bucket)); + bucket->hash = gram_hash(points, width); + bucket->width = width; + memcpy(bucket->points, points, width * sizeof(uint32_t)); + messages[0] = message_index; + bucket->messages = messages; + bucket->count = 1; + bucket->capacity = 8; + insert_slot(index->slots, index->slot_capacity, index->buckets, new_index); + index->bucket_count++; + return true; + } +} + +static bool +index_text_direct(tiny_search_index_t *index, const char *text, size_t message_index) { uint32_t *points = NULL; size_t count = 0, offset; @@ -177,7 +339,7 @@ index_text(tiny_search_index_t *index, const char *text, size_t message_index) { for (offset = 0; offset + width <= count; ++offset) { - if (!add_gram(index, points + offset, width, message_index)) + if (!add_gram_direct(index, points + offset, width, message_index)) { free(points); return false; @@ -202,19 +364,83 @@ tiny_search_index_free(tiny_search_index_t *index) { return; } - for (position = 0; position < index->count; ++position) + for (position = 0; position < index->bucket_count; ++position) { free(index->buckets[position].messages); } free(index->buckets); + free(index->slots); free(index); } +static bool +merge_delta(tiny_search_index_t *index, tiny_search_index_t *delta, size_t message_index) +{ + size_t position, new_buckets = 0, required; + for (position = 0; position < delta->bucket_count; ++position) + { + gram_bucket_t *source = &delta->buckets[position]; + if (!find_bucket_const(index, source->points, source->width)) + { + if (new_buckets == SIZE_MAX) + { + return false; + } + new_buckets++; + } + } + if (new_buckets > SIZE_MAX - index->bucket_count) + { + return false; + } + required = index->bucket_count + new_buckets; + if (!reserve_buckets(index, required) || !ensure_slots(index, required)) + { + return false; + } + for (position = 0; position < delta->bucket_count; ++position) + { + gram_bucket_t *source = &delta->buckets[position]; + gram_bucket_t *target = find_bucket_mutable(index, source->points, source->width); + if (target && !(target->count > 0 && target->messages[target->count - 1] == message_index) + && (target->count == SIZE_MAX || !reserve_messages(target, target->count + 1))) + { + return false; + } + } + for (position = 0; position < delta->bucket_count; ++position) + { + gram_bucket_t *source = &delta->buckets[position]; + gram_bucket_t *target = find_bucket_mutable(index, source->points, source->width); + if (target) + { + if (!(target->count > 0 && target->messages[target->count - 1] == message_index)) + { + target->messages[target->count++] = message_index; + } + } + else + { + size_t new_index = index->bucket_count; + index->buckets[new_index] = *source; + source->messages = NULL; + source->count = 0; + source->capacity = 0; + insert_slot(index->slots, index->slot_capacity, index->buckets, new_index); + index->bucket_count++; + } + } + index->message_count + = message_index + 1 > index->message_count ? message_index + 1 : index->message_count; + return true; +} + bool tiny_search_index_add(tiny_search_index_t *index, const tiny_message_t *message, size_t message_index) { + tiny_search_index_t *delta; size_t tag; if (index == NULL || message == NULL || message->content == NULL || (message->metadata.tag_count != 0 && message->metadata.tags == NULL) @@ -222,21 +448,30 @@ tiny_search_index_add(tiny_search_index_t *index, { return false; } - if (!index_text(index, message->content, message_index)) + delta = tiny_search_index_create(); + if (!delta) + { + return false; + } + if (!index_text_direct(delta, message->content, message_index)) { + tiny_search_index_free(delta); return false; } for (tag = 0; tag < message->metadata.tag_count; ++tag) { - if (!index_text(index, message->metadata.tags[tag], message_index)) + if (!index_text_direct(delta, message->metadata.tags[tag], message_index)) { + tiny_search_index_free(delta); return false; } } - if (message_index >= index->message_count) + if (!merge_delta(index, delta, message_index)) { - index->message_count = message_index + 1; + tiny_search_index_free(delta); + return false; } + tiny_search_index_free(delta); return true; } @@ -283,15 +518,22 @@ tiny_search_index_candidates(const tiny_search_index_t *index, } else { - gram_bucket_t *bucket; + const gram_bucket_t *bucket; width = point_count >= 3 ? 3 : 2; for (offset = 0; offset + width <= point_count; ++offset) { - if ((bucket = find_bucket(index, points + offset, (unsigned)width)) != NULL) + if ((bucket = find_bucket_const(index, points + offset, (unsigned)width)) != NULL) { size_t item; for (item = 0; item < bucket->count; ++item) { + if (bucket->messages[item] >= index->message_count) + { + free(points); + free(items); + free(seen); + return false; + } if (!seen[bucket->messages[item]]) { seen[bucket->messages[item]] = true; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9ce564e..9a02ee0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,6 +22,33 @@ if(MSVC) endif() add_test(NAME tiny-convmem-mcp.domain COMMAND tiny-convmem-domain-test) +add_executable(tiny-convmem-search-index-test + search_index_test.c + "${PROJECT_SOURCE_DIR}/src/domain/message.c" + "${PROJECT_SOURCE_DIR}/src/domain/search.c" +) +target_include_directories(tiny-convmem-search-index-test PRIVATE "${PROJECT_SOURCE_DIR}/src") +target_compile_features(tiny-convmem-search-index-test PRIVATE c_std_17) +target_compile_definitions(tiny-convmem-search-index-test PRIVATE TINY_SEARCH_TEST_HASH_BITS=8) +target_link_libraries(tiny-convmem-search-index-test PRIVATE tiny-convmem-base) +if(MSVC) + target_compile_options(tiny-convmem-search-index-test PRIVATE /utf-8 /W4) +endif() +add_test(NAME tiny-convmem-mcp.search-index COMMAND tiny-convmem-search-index-test) + +add_executable(tiny-convmem-search-benchmark + search_index_benchmark.c + "${PROJECT_SOURCE_DIR}/src/domain/message.c" + "${PROJECT_SOURCE_DIR}/src/domain/search.c" +) +target_include_directories(tiny-convmem-search-benchmark PRIVATE "${PROJECT_SOURCE_DIR}/src") +target_compile_features(tiny-convmem-search-benchmark PRIVATE c_std_17) +target_link_libraries(tiny-convmem-search-benchmark PRIVATE tiny-convmem-base) +if(MSVC) + target_compile_options(tiny-convmem-search-benchmark PRIVATE /utf-8 /W4) + target_link_libraries(tiny-convmem-search-benchmark PRIVATE psapi) +endif() + add_executable(tiny-convmem-mcpc-test mcpc_test.c) target_include_directories(tiny-convmem-mcpc-test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") target_compile_features(tiny-convmem-mcpc-test PRIVATE c_std_17) @@ -111,6 +138,7 @@ if(TINY_CONVMEM_ENABLE_ASAN AND MSVC) TEST tiny-convmem-mcp.smoke tiny-convmem-mcp.domain + tiny-convmem-mcp.search-index tiny-convmem-mcp.mcpc tiny-convmem-mcp.protocol tiny-convmem-mcp.boundaries diff --git a/tests/function-coverage.md b/tests/function-coverage.md index 66c2e4a..8787918 100644 --- a/tests/function-coverage.md +++ b/tests/function-coverage.md @@ -10,6 +10,7 @@ byte/encoding logic is exposed through internal headers and tested directly. | `storage/codec.c` | `tiny_codec_put_u32`, `tiny_codec_put_u64`, `tiny_codec_get_u32`, `tiny_codec_get_u64`, `tiny_codec_crc32` | `boundaries`: offsets 0–15, integer limits, empty/NULL and known CRC | | `sys/system.c` | test-hook helpers; UTF adapters; `native_file`; argument, path, directory, file, clock and random APIs | `boundaries`, `storage`, `smoke`: NULL/invalid handle, Unicode paths, short I/O, operation failure, cleanup | | `domain/message.c` | `duplicate_string`, `copy_failed`, all `tiny_message_*`, role/tier parse/name, `tiny_utf8_valid`, `tiny_message_id_valid` | `domain`: enum failure, UTF-8 invalidity, ULID alphabet/length, deep copy and ownership | +| `domain/search.c` | Unicode decode/score、open-addressing lookup/rehash、transactional delta merge、candidate union | `domain`, `search-index`: ASCII/日本語、8-bit hash衝突、複数rehash、allocation failure全位置、leak balance | | `domain/search.c` | `decode_codepoints`, `gram_hash`, `find_bucket`, `add_gram`, `index_text`, all `tiny_search_*` | `domain`: ASCII case folding, Unicode grams/tags, candidates, scoring and ownership | | `storage/store.c` | error/I/O helpers, ULID, entry growth/search, record codec, replay/snapshot/recovery, all `tiny_store_*` | `storage`, `lifecycle`: lock, append/reopen, corruption, rebuild rollback, Unicode path | | `mcp/json.c` | `reserve`, all `tiny_json_*` | `boundaries`: empty append, growth, control escaping, signed/unsigned integer limits, OOM | diff --git a/tests/mcp_protocol_test.py b/tests/mcp_protocol_test.py index 118043f..f739168 100644 --- a/tests/mcp_protocol_test.py +++ b/tests/mcp_protocol_test.py @@ -81,6 +81,15 @@ def tool_payload(response: Mapping[str, Any], expect_error: bool = False) -> dic return json.loads(result["content"][0]["text"]) +def assert_stable_recency_order(messages: list[dict[str, Any]]) -> None: + for left, right in zip(messages, messages[1:]): + left_time = int(left["timestamp"]) + right_time = int(right["timestamp"]) + assert left_time > right_time or ( + left_time == right_time and left["message_id"] <= right["message_id"] + ), (left, right) + + def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--server", type=Path, required=True) @@ -156,6 +165,22 @@ def main() -> None: next_id += 1 assert len(history) == 20 + ranked = tool_payload( + tool_call( + server, + next_id, + "search_messages", + {"query": "needle target", "limit": 100}, + ) + )["results"] + next_id += 1 + assert len(ranked) == 30 + assert all(item["session_id"] == "target" for item in ranked[:20]) + assert all(item["session_id"] == "other" for item in ranked[20:]) + assert_stable_recency_order(ranked[:20]) + assert_stable_recency_order(ranked[20:]) + ranked_ids_before = [item["message_id"] for item in ranked] + for index in range(args.iterations): arguments: dict[str, Any] = {"query": "needle"} if index % 2: @@ -192,6 +217,18 @@ def main() -> None: next_id += 1 tool_payload(tool_call(server, next_id, "rebuild_index", {})) next_id += 1 + ranked_after_rebuild = tool_payload( + tool_call( + server, + next_id, + "search_messages", + {"query": "needle target", "limit": 100}, + ) + )["results"] + next_id += 1 + assert [item["message_id"] for item in ranked_after_rebuild] == [ + message_id for message_id in ranked_ids_before if message_id != message_ids[0] + ] assert tool_payload(tool_call(server, next_id, "get_system_health", {}))["status"] == "OK" next_id += 1 diff --git a/tests/search_index_benchmark.c b/tests/search_index_benchmark.c new file mode 100644 index 0000000..f17335a --- /dev/null +++ b/tests/search_index_benchmark.c @@ -0,0 +1,110 @@ +#include "domain/message.h" +#include "domain/search.h" + +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +#include "base/allocator.h" + +static double +now_milliseconds(void) +{ + struct timespec value; + timespec_get(&value, TIME_UTC); + return (double)value.tv_sec * 1000.0 + (double)value.tv_nsec / 1000000.0; +} + +static uint64_t +peak_working_set(void) +{ +#ifdef _WIN32 + PROCESS_MEMORY_COUNTERS counters; + if (GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) + { + return (uint64_t)counters.PeakWorkingSetSize; + } +#endif + return 0; +} + +static char * +make_content(size_t size) +{ + static const char alphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "; + uint32_t state = UINT32_C(0x9e3779b9); + char *content; + size_t position; + if (size == SIZE_MAX) + { + return NULL; + } + content = malloc(size + 1); + if (!content) + { + return NULL; + } + for (position = 0; position < size; ++position) + { + state = state * UINT32_C(1664525) + UINT32_C(1013904223); + content[position] = alphabet[state % (sizeof(alphabet) - 1)]; + } + content[size] = '\0'; + return content; +} + +int +main(int argc, char **argv) +{ + tiny_message_t message; + size_t size, iterations, iteration; + char *content; + double started, elapsed; + if (argc != 3) + { + fprintf(stderr, "usage: %s SIZE_BYTES ITERATIONS\n", argv[0]); + return 2; + } + size = (size_t)strtoull(argv[1], NULL, 10); + iterations = (size_t)strtoull(argv[2], NULL, 10); + if (size == 0 || size > TINY_CONTENT_MAX || iterations == 0) + { + fprintf(stderr, "size or iterations is out of range\n"); + return 2; + } + content = make_content(size); + if (!content) + { + return 1; + } + tiny_message_init(&message); + message.content = content; + started = now_milliseconds(); + for (iteration = 0; iteration < iterations; ++iteration) + { + tiny_search_index_t *index = tiny_search_index_create(); + if (!index || !tiny_search_index_add(index, &message, 0)) + { + tiny_search_index_free(index); + free(content); + return 1; + } + tiny_search_index_free(index); + } + elapsed = now_milliseconds() - started; + printf("{\"size_bytes\":%zu,\"iterations\":%zu,\"total_ms\":%.3f," + "\"mean_ms\":%.3f,\"peak_working_set_bytes\":%llu}\n", + size, + iterations, + elapsed, + elapsed / (double)iterations, + (unsigned long long)peak_working_set()); + free(content); + return tiny_allocator_outstanding() == 0 ? 0 : 1; +} diff --git a/tests/search_index_test.c b/tests/search_index_test.c new file mode 100644 index 0000000..5a477ad --- /dev/null +++ b/tests/search_index_test.c @@ -0,0 +1,161 @@ +#include "domain/message.h" +#include "domain/search.h" + +#include +#include +#include +#include + +#include "base/allocator.h" + +static int failures; + +#define CHECK(value) \ + do \ + { \ + if (!(value)) \ + { \ + fprintf(stderr, "CHECK failed at line %d: %s\n", __LINE__, #value); \ + failures++; \ + } \ + } \ + while (0) + +static tiny_message_t +make_message(const char *content, char **tags, size_t tag_count) +{ + tiny_message_t message; + tiny_message_init(&message); + message.content = (char *)content; + message.metadata.tags = tags; + message.metadata.tag_count = tag_count; + return message; +} + +static bool +candidate_contains(tiny_search_index_t *index, const char *query, size_t expected) +{ + size_t *candidates = NULL; + size_t count = 0, position; + bool found = false; + if (!tiny_search_index_candidates(index, query, &candidates, &count)) + { + return false; + } + for (position = 0; position < count; ++position) + { + if (candidates[position] == expected) + { + found = true; + break; + } + } + free(candidates); + return found; +} + +static void +test_collision_rehash_and_unicode(void) +{ + tiny_search_index_t *index = tiny_search_index_create(); + char contents[300][4]; + size_t position; + char *tags[] = { "設計メモ" }; + tiny_message_t tagged = make_message("tagged content", tags, 1); + tiny_message_t duplicate = make_message("aaaaaa", NULL, 0); + size_t *candidates = NULL; + size_t count = 0; + + CHECK(index != NULL); + for (position = 0; index && position < 300; ++position) + { + tiny_message_t message; + contents[position][0] = (char)('a' + (position / (26 * 26)) % 26); + contents[position][1] = (char)('a' + (position / 26) % 26); + contents[position][2] = (char)('a' + position % 26); + contents[position][3] = '\0'; + message = make_message(contents[position], NULL, 0); + CHECK(tiny_search_index_add(index, &message, position)); + } + for (position = 0; index && position < 300; ++position) + { + CHECK(candidate_contains(index, contents[position], position)); + } + + CHECK(tiny_search_index_add(index, &tagged, 300)); + CHECK(candidate_contains(index, "設計", 300)); + CHECK(candidate_contains(index, "TAGGED", 300)); + CHECK(tiny_search_index_add(index, &duplicate, 301)); + CHECK(tiny_search_index_candidates(index, "aaa", &candidates, &count)); + { + size_t duplicate_hits = 0; + for (position = 0; position < count; ++position) + { + if (candidates[position] == 301) + { + duplicate_hits++; + } + } + CHECK(duplicate_hits == 1); + } + free(candidates); + candidates = NULL; + CHECK(tiny_search_index_candidates(index, "a", &candidates, &count)); + CHECK(count == 302); + free(candidates); + tiny_search_index_free(index); +} + +static void +test_transactional_allocation_failure(void) +{ + const tiny_message_t baseline = make_message("baseline-only", NULL, 0); + char *tags[] = { "transaction-tag", "日本語追加" }; + const tiny_message_t addition + = make_message("zyxwvutsrqponmlkjihgfedcba-transactional-new-token", tags, 2); + size_t failure_index; + bool reached_success = false; + + for (failure_index = 0; failure_index < 512; ++failure_index) + { + tiny_search_index_t *index; + size_t baseline_allocations = tiny_allocator_outstanding(); + tiny_allocator_reset(); + index = tiny_search_index_create(); + CHECK(index != NULL); + CHECK(tiny_search_index_add(index, &baseline, 0)); + + tiny_allocator_fail_after(failure_index); + if (tiny_search_index_add(index, &addition, 1)) + { + tiny_allocator_reset(); + CHECK(candidate_contains(index, "transactional-new-token", 1)); + reached_success = true; + tiny_search_index_free(index); + CHECK(tiny_allocator_outstanding() == baseline_allocations); + break; + } + + tiny_allocator_reset(); + CHECK(candidate_contains(index, "baseline-only", 0)); + CHECK(!candidate_contains(index, "transactional-new-token", 1)); + CHECK(tiny_search_index_add(index, &addition, 1)); + CHECK(candidate_contains(index, "transactional-new-token", 1)); + tiny_search_index_free(index); + CHECK(tiny_allocator_outstanding() == baseline_allocations); + } + CHECK(reached_success); +} + +int +main(void) +{ + tiny_allocator_reset(); + CHECK(tiny_allocator_outstanding() == 0); + test_collision_rehash_and_unicode(); + CHECK(tiny_allocator_outstanding() == 0); + test_transactional_allocation_failure(); + tiny_allocator_reset(); + CHECK(tiny_allocator_outstanding() == 0); + return failures == 0 ? 0 : 1; +} -- cgit v1.2.3