pg-perf-bench 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. pg_perf_bench-0.2.0/LICENSE +21 -0
  2. pg_perf_bench-0.2.0/PKG-INFO +530 -0
  3. pg_perf_bench-0.2.0/README.md +493 -0
  4. pg_perf_bench-0.2.0/THIRD_PARTY_NOTICES.md +37 -0
  5. pg_perf_bench-0.2.0/pyproject.toml +94 -0
  6. pg_perf_bench-0.2.0/setup.cfg +4 -0
  7. pg_perf_bench-0.2.0/src/pg_perf_bench/__init__.py +3 -0
  8. pg_perf_bench-0.2.0/src/pg_perf_bench/__main__.py +4 -0
  9. pg_perf_bench-0.2.0/src/pg_perf_bench/benchmark.py +646 -0
  10. pg_perf_bench-0.2.0/src/pg_perf_bench/cli.py +820 -0
  11. pg_perf_bench-0.2.0/src/pg_perf_bench/client_tools.py +135 -0
  12. pg_perf_bench-0.2.0/src/pg_perf_bench/collect_info.py +180 -0
  13. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/cpu_info.sh +2 -0
  14. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/df_h.sh +3 -0
  15. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/etc_fstab.sh +3 -0
  16. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/etc_os_release.sh +3 -0
  17. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/ip_br_addr.sh +4 -0
  18. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_bridge.sh +1 -0
  19. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_bus.sh +1 -0
  20. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_communication.sh +1 -0
  21. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_disk.sh +1 -0
  22. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_display.sh +1 -0
  23. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_generic.sh +1 -0
  24. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_input.sh +1 -0
  25. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_memory.sh +1 -0
  26. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_multimedia.sh +1 -0
  27. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_network.sh +1 -0
  28. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_power.sh +1 -0
  29. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_processor.sh +1 -0
  30. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_storage.sh +1 -0
  31. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_system.sh +1 -0
  32. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/lshw_volume.sh +1 -0
  33. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/mount.sh +3 -0
  34. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/pg_config.sh +2 -0
  35. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/sys_memory_total.sh +6 -0
  36. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/sysctl_net_ipv4_tcp.sh +1 -0
  37. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/sysctl_net_ipv4_udp.sh +1 -0
  38. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/sysctl_vm.sh +2 -0
  39. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/total_ram.sh +2 -0
  40. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/bash_commands/uname_a.sh +3 -0
  41. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/sql_commands/available_server_extensions.sql +1 -0
  42. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/sql_commands/full_version.sql +1 -0
  43. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/sql_commands/pg_settings.sql +1 -0
  44. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/sql_commands/server_version.sql +1 -0
  45. pg_perf_bench-0.2.0/src/pg_perf_bench/commands/sql_commands/server_version_major.sql +1 -0
  46. pg_perf_bench-0.2.0/src/pg_perf_bench/config.py +418 -0
  47. pg_perf_bench-0.2.0/src/pg_perf_bench/connections/__init__.py +11 -0
  48. pg_perf_bench-0.2.0/src/pg_perf_bench/connections/common.py +13 -0
  49. pg_perf_bench-0.2.0/src/pg_perf_bench/connections/docker.py +271 -0
  50. pg_perf_bench-0.2.0/src/pg_perf_bench/connections/local.py +115 -0
  51. pg_perf_bench-0.2.0/src/pg_perf_bench/connections/ssh.py +179 -0
  52. pg_perf_bench-0.2.0/src/pg_perf_bench/const.py +102 -0
  53. pg_perf_bench-0.2.0/src/pg_perf_bench/context/__init__.py +5 -0
  54. pg_perf_bench-0.2.0/src/pg_perf_bench/context/base_context.py +79 -0
  55. pg_perf_bench-0.2.0/src/pg_perf_bench/context/benchmark.py +157 -0
  56. pg_perf_bench-0.2.0/src/pg_perf_bench/context/collect_info.py +125 -0
  57. pg_perf_bench-0.2.0/src/pg_perf_bench/context/join.py +14 -0
  58. pg_perf_bench-0.2.0/src/pg_perf_bench/contracts.py +121 -0
  59. pg_perf_bench-0.2.0/src/pg_perf_bench/db_operations/__init__.py +81 -0
  60. pg_perf_bench-0.2.0/src/pg_perf_bench/db_operations/conn_tasks/__init__.py +12 -0
  61. pg_perf_bench-0.2.0/src/pg_perf_bench/db_operations/conn_tasks/common.py +48 -0
  62. pg_perf_bench-0.2.0/src/pg_perf_bench/db_operations/conn_tasks/docker.py +29 -0
  63. pg_perf_bench-0.2.0/src/pg_perf_bench/db_operations/conn_tasks/local.py +35 -0
  64. pg_perf_bench-0.2.0/src/pg_perf_bench/db_operations/conn_tasks/ssh.py +32 -0
  65. pg_perf_bench-0.2.0/src/pg_perf_bench/db_operations/db.py +124 -0
  66. pg_perf_bench-0.2.0/src/pg_perf_bench/errors.py +61 -0
  67. pg_perf_bench-0.2.0/src/pg_perf_bench/executors/__init__.py +5 -0
  68. pg_perf_bench-0.2.0/src/pg_perf_bench/executors/process.py +156 -0
  69. pg_perf_bench-0.2.0/src/pg_perf_bench/join.py +581 -0
  70. pg_perf_bench-0.2.0/src/pg_perf_bench/join_catalog.py +134 -0
  71. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/README.md +29 -0
  72. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/compare-postgresql-major/README.md +19 -0
  73. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/compare-postgresql-major/task.json +18 -0
  74. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/compare-storage/README.md +19 -0
  75. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/compare-storage/task.json +20 -0
  76. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/optimize-db-config/README.md +22 -0
  77. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/optimize-db-config/task.json +14 -0
  78. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/repeatability/README.md +17 -0
  79. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/repeatability/task.json +15 -0
  80. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/scale-cpu/README.md +19 -0
  81. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/scale-cpu/task.json +20 -0
  82. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/scale-memory/README.md +18 -0
  83. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/scale-memory/task.json +20 -0
  84. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/tune-os-kernel/README.md +17 -0
  85. pg_perf_bench-0.2.0/src/pg_perf_bench/join_tasks/tune-os-kernel/task.json +20 -0
  86. pg_perf_bench-0.2.0/src/pg_perf_bench/log.py +74 -0
  87. pg_perf_bench-0.2.0/src/pg_perf_bench/orchestration.py +135 -0
  88. pg_perf_bench-0.2.0/src/pg_perf_bench/report/__init__.py +11 -0
  89. pg_perf_bench-0.2.0/src/pg_perf_bench/report/commands.py +546 -0
  90. pg_perf_bench-0.2.0/src/pg_perf_bench/report/html.py +112 -0
  91. pg_perf_bench-0.2.0/src/pg_perf_bench/report/processing.py +146 -0
  92. pg_perf_bench-0.2.0/src/pg_perf_bench/run.py +36 -0
  93. pg_perf_bench-0.2.0/src/pg_perf_bench/system_metrics.py +218 -0
  94. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/all_info_report_struct.json +274 -0
  95. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/benchmark_report_struct.json +377 -0
  96. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/db_info_report_struct.json +61 -0
  97. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/report.html +806 -0
  98. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/sys_info_report_struct.json +220 -0
  99. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/vendor/THIRD_PARTY_LICENSES.txt +15 -0
  100. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/vendor/echarts-6.1.0.LICENSE-d3.txt +27 -0
  101. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/vendor/echarts-6.1.0.LICENSE.txt +222 -0
  102. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/vendor/echarts-6.1.0.NOTICE.txt +5 -0
  103. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/vendor/echarts-6.1.0.min.js +45 -0
  104. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/vendor/highlight-11.11.1.LICENSE.txt +29 -0
  105. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/vendor/highlight-11.11.1.min.js +1244 -0
  106. pg_perf_bench-0.2.0/src/pg_perf_bench/templates/vendor/highlight-github-dark-11.11.1.min.css +10 -0
  107. pg_perf_bench-0.2.0/src/pg_perf_bench/validator.py +55 -0
  108. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/README.md +16 -0
  109. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/imdb/README.md +18 -0
  110. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/imdb/generator.py +127 -0
  111. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/imdb/profile.json +25 -0
  112. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/imdb/sql/01_company_catalog.sql +16 -0
  113. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/imdb/sql/02_people_by_keyword.sql +18 -0
  114. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/imdb/sql/03_keyword_trends.sql +14 -0
  115. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/imdb/sql/04_genre_cast.sql +14 -0
  116. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/imdb/sql/05_join_stress.sql +22 -0
  117. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/imdb/sql/indexes.sql +20 -0
  118. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/imdb/sql/schema.sql +69 -0
  119. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/pagila/README.md +17 -0
  120. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/pagila/generator.py +203 -0
  121. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/pagila/profile.json +23 -0
  122. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/pagila/sql/01_select.sql +264 -0
  123. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/pagila/sql/02_insert.sql +273 -0
  124. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/pagila/sql/03_update.sql +149 -0
  125. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/pagila/sql/04_delete.sql +27 -0
  126. pg_perf_bench-0.2.0/src/pg_perf_bench/workload_profiles/pagila/sql/pagila-schema.sql +1688 -0
  127. pg_perf_bench-0.2.0/src/pg_perf_bench/workloads.py +297 -0
  128. pg_perf_bench-0.2.0/src/pg_perf_bench.egg-info/PKG-INFO +530 -0
  129. pg_perf_bench-0.2.0/src/pg_perf_bench.egg-info/SOURCES.txt +143 -0
  130. pg_perf_bench-0.2.0/src/pg_perf_bench.egg-info/dependency_links.txt +1 -0
  131. pg_perf_bench-0.2.0/src/pg_perf_bench.egg-info/entry_points.txt +2 -0
  132. pg_perf_bench-0.2.0/src/pg_perf_bench.egg-info/requires.txt +24 -0
  133. pg_perf_bench-0.2.0/src/pg_perf_bench.egg-info/top_level.txt +1 -0
  134. pg_perf_bench-0.2.0/tests/test_benchmark_evidence.py +162 -0
  135. pg_perf_bench-0.2.0/tests/test_cli_contract.py +255 -0
  136. pg_perf_bench-0.2.0/tests/test_client_tools.py +36 -0
  137. pg_perf_bench-0.2.0/tests/test_collection_backend.py +122 -0
  138. pg_perf_bench-0.2.0/tests/test_db_operations.py +48 -0
  139. pg_perf_bench-0.2.0/tests/test_join_regressions.py +183 -0
  140. pg_perf_bench-0.2.0/tests/test_process_executor.py +47 -0
  141. pg_perf_bench-0.2.0/tests/test_report_safety.py +36 -0
  142. pg_perf_bench-0.2.0/tests/test_report_transport.py +91 -0
  143. pg_perf_bench-0.2.0/tests/test_system_metrics.py +80 -0
  144. pg_perf_bench-0.2.0/tests/test_transports.py +71 -0
  145. pg_perf_bench-0.2.0/tests/test_workload_profiles.py +128 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Tantor Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,530 @@
1
+ Metadata-Version: 2.4
2
+ Name: pg-perf-bench
3
+ Version: 0.2.0
4
+ Summary: Reproducible PostgreSQL benchmark runner with environment evidence and portable reports
5
+ Author-email: O2eg <oleg.ispu@yandex.ru>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/O2eg/pg_perf_bench
8
+ Project-URL: Repository, https://github.com/O2eg/pg_perf_bench
9
+ Project-URL: Issues, https://github.com/O2eg/pg_perf_bench/issues
10
+ Keywords: postgresql,benchmark,pgbench,performance,diagnostics
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ License-File: THIRD_PARTY_NOTICES.md
15
+ License-File: src/pg_perf_bench/templates/vendor/THIRD_PARTY_LICENSES.txt
16
+ License-File: src/pg_perf_bench/templates/vendor/echarts-6.1.0.LICENSE-d3.txt
17
+ License-File: src/pg_perf_bench/templates/vendor/echarts-6.1.0.LICENSE.txt
18
+ License-File: src/pg_perf_bench/templates/vendor/highlight-11.11.1.LICENSE.txt
19
+ License-File: src/pg_perf_bench/templates/vendor/echarts-6.1.0.NOTICE.txt
20
+ Requires-Dist: PyYAML<7,>=6.0
21
+ Requires-Dist: asyncpg<1,>=0.29
22
+ Requires-Dist: asyncssh<3,>=2.21
23
+ Requires-Dist: docker<8,>=7.1
24
+ Requires-Dist: pg-diag<1,>=0.10.3
25
+ Requires-Dist: aenum<4,>=3.1; python_version < "3.11"
26
+ Provides-Extra: test
27
+ Requires-Dist: pytest<9,>=8.3; extra == "test"
28
+ Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "test"
29
+ Provides-Extra: dev
30
+ Requires-Dist: build<2,>=1.2; extra == "dev"
31
+ Requires-Dist: pytest<9,>=8.3; extra == "dev"
32
+ Requires-Dist: pytest-cov<8,>=6; extra == "dev"
33
+ Requires-Dist: ruff<1,>=0.12; extra == "dev"
34
+ Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "dev"
35
+ Requires-Dist: twine<7,>=6; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # pg_perf_bench
39
+
40
+ ## Overview
41
+
42
+ Based on [pg_perfbench](https://github.com/TantorLabs/pg_perfbench).
43
+
44
+ `pg_perf_bench` runs controlled PostgreSQL benchmarks and stores the result
45
+ together with the facts required to interpret it: the effective workload,
46
+ PostgreSQL configuration, server version, host properties, execution timing,
47
+ raw command output, and collection diagnostics.
48
+
49
+ Its benchmark question is maximum TPS for one workload profile and one complete
50
+ environment, including OS and PostgreSQL settings. `pg_workload` schedules and
51
+ runs workload profiles; `pg_perf_bench` sweeps load, resets the dataset for each
52
+ point, measures the saturation curve, and preserves the evidence needed for a
53
+ controlled comparison.
54
+
55
+ Every successful collection or benchmark produces two artifacts:
56
+
57
+ - a JSON document for automation and later comparison;
58
+ - a self-contained HTML report with embedded data, styles, ECharts,
59
+ highlight.js, and third-party notices.
60
+
61
+ The HTML report has no runtime network dependency. Python 3.10 or newer is
62
+ required.
63
+
64
+ ## What the utility does
65
+
66
+ The CLI supports three groups of workflows:
67
+
68
+ - `benchmark` recreates a dedicated database before every measured iteration,
69
+ initializes the workload, runs it, and collects final host/database facts;
70
+ - `collect-sys-info`, `collect-db-info`, and `collect-all-info` gather evidence
71
+ without running a workload;
72
+ - `join` validates the comparability of existing reports and builds one
73
+ comparison report with combined tables, charts, logs, and benchmark evidence.
74
+
75
+ Additional commands render HTML, validate packaged content, expose component
76
+ capabilities, validate and summarize report artifacts, and build a deterministic
77
+ execution plan. The versioned [`pg_play` integration contract](doc/pg_play-integration.md)
78
+ documents the machine interface used by the orchestrator.
79
+
80
+ ## Architecture
81
+
82
+ The backend is divided into explicit layers:
83
+
84
+ ```text
85
+ CLI and automation contract
86
+ -> typed configuration and validation
87
+ -> benchmark / collection / join orchestration
88
+ -> Local, Docker, or SSH transport
89
+ -> PostgreSQL lifecycle and bounded process execution
90
+ -> report item collectors
91
+ -> atomic JSON and monolithic HTML persistence
92
+ ```
93
+
94
+ The transport controls PostgreSQL and executes host fact collectors on the
95
+ selected target. The workload commands themselves run on the machine where
96
+ `pg_perf_bench` is invoked:
97
+
98
+ | Transport | Host facts and PostgreSQL lifecycle | `pgbench` / `psql` |
99
+ |---|---|---|
100
+ | `local` | local machine | local machine |
101
+ | `docker` | existing container | local machine through a published port |
102
+ | `ssh` | remote host | local machine through an SSH local-forwarding port |
103
+
104
+ This separation keeps workload generation independent of target management and
105
+ makes the measured client location explicit.
106
+
107
+ Detailed operational guides are indexed in [doc/README.md](doc/README.md).
108
+
109
+ ## Installation
110
+
111
+ Create a virtual environment and install the package:
112
+
113
+ ```bash
114
+ python3 -m venv .venv
115
+ .venv/bin/python -m pip install --upgrade pip
116
+ .venv/bin/python -m pip install .
117
+ .venv/bin/pg-perf-bench --version
118
+ ```
119
+
120
+ For development:
121
+
122
+ ```bash
123
+ python3 -m venv .venv
124
+ .venv/bin/python -m pip install -e ../pg_diag -e '.[dev]'
125
+ .venv/bin/ruff check src tests
126
+ .venv/bin/python -m pytest
127
+ ```
128
+
129
+ The source checkout is needed until the minimum supported `pg_diag` release is
130
+ available from the configured package index. For a PyPI release, publish
131
+ `pg_diag` and `pg_stand` first; the tagged build intentionally verifies those
132
+ declared dependencies from the package index before publishing
133
+ `pg_perf_bench`.
134
+
135
+ `pgbench` and `psql` must be installed on the workload-generator host.
136
+ `pg_perf_bench` discovers every client below `/usr/lib/postgresql/*/bin` and in
137
+ `PATH`, selects the newest installed version, and refuses an explicitly selected
138
+ older client. This keeps the load generator on the current `pgbench` even when
139
+ the target is PostgreSQL 10–18. The target needs the PostgreSQL server utilities
140
+ required for lifecycle operations. `pg_diag` and host `iostat` provide the OS
141
+ sampling engine used during the workload window.
142
+
143
+ ## CLI
144
+
145
+ ```text
146
+ pg-perf-bench benchmark ...
147
+ pg-perf-bench collect-sys-info ...
148
+ pg-perf-bench collect-db-info ...
149
+ pg-perf-bench collect-all-info ...
150
+ pg-perf-bench join ...
151
+ pg-perf-bench render ...
152
+ pg-perf-bench validate-artifact REPORT.json
153
+ pg-perf-bench summarize REPORT.json
154
+ pg-perf-bench validate
155
+ pg-perf-bench profiles
156
+ pg-perf-bench join-tasks
157
+ pg-perf-bench plan ...
158
+ pg-perf-bench capabilities
159
+ ```
160
+
161
+ Use `pg-perf-bench COMMAND --help` for the complete option list. The old
162
+ `--mode=COMMAND` form remains accepted as a compatibility adapter.
163
+
164
+ Common output options:
165
+
166
+ - `--report-name NAME` sets the safe base name of the JSON and HTML artifacts;
167
+ - `--out DIR` selects the artifact directory, default `report` (`--output-dir` is a compatibility alias);
168
+ - `--log-dir DIR` selects the application log directory, default `log`;
169
+ - `--log-level {info,debug,error}` sets verbosity;
170
+ - `--clear-logs` removes old `*.log` files from the selected log directory.
171
+
172
+ ## Safety contract
173
+
174
+ Collection and benchmark modes have deliberately different mutation rules.
175
+
176
+ Collection:
177
+
178
+ - does not replace `postgresql.conf`;
179
+ - does not start or stop PostgreSQL;
180
+ - uses a read-only database session;
181
+ - applies a 10-second PostgreSQL statement timeout;
182
+ - records an item-level error and continues when an optional fact cannot be
183
+ collected.
184
+
185
+ Benchmark:
186
+
187
+ - terminates sessions connected to the selected benchmark database;
188
+ - drops and recreates that database from `template0` before every iteration;
189
+ - refuses `postgres`, `template0`, and `template1`;
190
+ - requires the explicit `--allow-database-reset` confirmation;
191
+ - drops OS filesystem caches only when `--drop-os-caches` is supplied;
192
+ - accepts a replacement PostgreSQL configuration only in benchmark mode.
193
+
194
+ Use only a dedicated disposable database. Prefer a disposable environment
195
+ provisioned by `pg_stand` for development and integration tests.
196
+
197
+ Commands supplied through `--init-command` and `--workload-command` are trusted
198
+ shell input. Do not run workload definitions from an untrusted source.
199
+
200
+ ## Passwords and SSH trust
201
+
202
+ Supply the PostgreSQL password through `PGPASSWORD` or `--password`. The
203
+ legacy `--pg-password` and `--pg-user-password` aliases are also accepted. Known secret fields and the
204
+ effective password value are redacted from logs, plans, reports, and command
205
+ evidence.
206
+
207
+ SSH host-key verification is enabled by default. Provide `--ssh-known-hosts`,
208
+ or use the normal `~/.ssh/known_hosts`. The
209
+ `--ssh-insecure-no-host-key-check` switch is intended only for isolated,
210
+ disposable stands.
211
+
212
+ ## Collecting environment facts
213
+
214
+ Host-only collection does not require PostgreSQL connection options:
215
+
216
+ ```bash
217
+ pg-perf-bench collect-sys-info \
218
+ --connection-type local \
219
+ --report-name host-facts
220
+ ```
221
+
222
+ Database collection requires connection parameters and `--pg-bin-path` for
223
+ the packaged `pg_config` collector:
224
+
225
+ ```bash
226
+ PGPASSWORD=secret pg-perf-bench collect-db-info \
227
+ --connection-type local \
228
+ --host 127.0.0.1 \
229
+ --port 5432 \
230
+ --user postgres \
231
+ --database postgres \
232
+ --pg-bin-path /usr/lib/postgresql/18/bin \
233
+ --report-name db-facts
234
+ ```
235
+
236
+ `collect-all-info` combines host and database facts. A missing optional tool or
237
+ permission does not discard valid data: the affected item becomes `error` or
238
+ `partial`, artifacts are still generated, and the CLI returns exit code 5.
239
+
240
+ Local and SSH hardware collectors invoke `sudo -n lshw`; Docker mode instead
241
+ collects host inventory without sudo and keeps the target container's
242
+ `pg_config` evidence separate. Raw interface state is retained, but runtime
243
+ Docker bridges do not participate in the stable JOIN hardware identity.
244
+
245
+ ## Running a benchmark
246
+
247
+ Exactly one iteration axis is required:
248
+
249
+ - `--pgbench-clients 1,4,16` exposes each value as
250
+ `ARG_PGBENCH_CLIENTS`;
251
+ - `--pgbench-time 10,30,60` exposes each value as `ARG_PGBENCH_TIME`.
252
+
253
+ The axis does not add pgbench options automatically; the workload command must
254
+ use the corresponding placeholder.
255
+
256
+ Example:
257
+
258
+ ```bash
259
+ PGPASSWORD=secret pg-perf-bench benchmark \
260
+ --connection-type local \
261
+ --allow-database-reset \
262
+ --host 127.0.0.1 \
263
+ --port 5432 \
264
+ --user postgres \
265
+ --database pg_perf_bench_test \
266
+ --pg-data-path /var/lib/postgresql/18/main \
267
+ --pg-bin-path /usr/lib/postgresql/18/bin \
268
+ --benchmark-type default \
269
+ --pgbench-clients 1,4,16 \
270
+ --init-command 'ARG_PGBENCH_PATH -i -s 10 -h ARG_PG_HOST -p ARG_PG_PORT -U ARG_PG_USER ARG_PG_DATABASE' \
271
+ --workload-command 'ARG_PGBENCH_PATH -T 60 -c ARG_PGBENCH_CLIENTS -j ARG_PGBENCH_CLIENTS -h ARG_PG_HOST -p ARG_PG_PORT -U ARG_PG_USER ARG_PG_DATABASE' \
272
+ --command-timeout 120 \
273
+ --report-name local-pg18
274
+ ```
275
+
276
+ The command timeout applies independently to initialization and workload
277
+ commands. It must be longer than the expected command duration.
278
+
279
+ ### Workload placeholders
280
+
281
+ | Placeholder | Value source |
282
+ |---|---|
283
+ | `ARG_PG_HOST` | `--host` |
284
+ | `ARG_PG_PORT` | `--port` |
285
+ | `ARG_PG_USER` | `--user` |
286
+ | `ARG_PG_PASSWORD` | `--password` or `PGPASSWORD` |
287
+ | `ARG_PG_DATABASE` | `--database` |
288
+ | `ARG_PGBENCH_PATH` | newest local pgbench, or validated `--pgbench-path` |
289
+ | `ARG_PSQL_PATH` | matching local psql, or validated `--psql-path` |
290
+ | `ARG_WORKLOAD_PATH` | `--workload-path` |
291
+ | `ARG_WORKLOAD_SCALE` | `--workload-scale` |
292
+ | `ARG_PGBENCH_CLIENTS` | current client-axis value |
293
+ | `ARG_PGBENCH_TIME` | current duration-axis value |
294
+
295
+ Unresolved `ARG_*` placeholders fail before target mutation. Prefer
296
+ `PGPASSWORD` to placing `ARG_PG_PASSWORD` directly in a command line.
297
+
298
+ For a custom workload, use `--benchmark-type custom`, supply an existing
299
+ `--workload-path`, and reference files below that path from the command
300
+ templates.
301
+
302
+ For a packaged maximum-TPS workload, use `--workload-profile imdb` or
303
+ `--workload-profile pagila`, `--workload-scale SCALE`, and a
304
+ `--pgbench-clients` sweep. `pg-perf-bench profiles` lists the installed
305
+ collection. Each profile supplies its schema, deterministic Python generator,
306
+ typical SQL query set and command templates. It deliberately does not reuse
307
+ `pg_workload`'s scheduler-specific `profile.yml`.
308
+
309
+ ### Iteration lifecycle
310
+
311
+ For each axis value the backend:
312
+
313
+ 1. verifies access to the PostgreSQL instance;
314
+ 2. drops the dedicated benchmark database;
315
+ 3. stops PostgreSQL or the selected container;
316
+ 4. flushes filesystems and optionally drops host OS caches;
317
+ 5. starts PostgreSQL and recreates the database;
318
+ 6. runs the initialization command;
319
+ 7. runs the workload command while the `pg_diag` Linux sampler records CPU,
320
+ RAM, disk and network metrics on the database host;
321
+ 8. stores raw stdout, stderr, return code, UTC start time, elapsed time, parsed
322
+ pgbench metrics, and iteration metadata.
323
+
324
+ After the final iteration it collects the configured host and PostgreSQL facts
325
+ and optionally archives PostgreSQL logs under `<output-dir>/db_logs/`, alongside
326
+ the JSON and HTML report artifacts.
327
+
328
+ ## Transports
329
+
330
+ ### Local
331
+
332
+ ```bash
333
+ --connection-type local
334
+ ```
335
+
336
+ Lifecycle commands use `pg_ctl` under the `postgres` account. Cache dropping
337
+ requires a narrow non-interactive sudo rule for the specific command.
338
+
339
+ ### Docker
340
+
341
+ ```bash
342
+ --connection-type docker \
343
+ --container-name pg-bench-18
344
+ ```
345
+
346
+ The container must already exist. Collection refuses to start a stopped
347
+ container. Benchmark mode may start it because target mutation was explicitly
348
+ confirmed. Use normal rootless-Docker or Docker-group access; never make the
349
+ Docker socket world-writable.
350
+
351
+ The workload reaches PostgreSQL through the port published on `--host` and
352
+ `--port`.
353
+
354
+ ### SSH
355
+
356
+ ```bash
357
+ --connection-type ssh \
358
+ --ssh-host db-host.example \
359
+ --ssh-port 22 \
360
+ --ssh-user postgres \
361
+ --ssh-key /secure/path/id_ed25519 \
362
+ --ssh-known-hosts /secure/path/known_hosts \
363
+ --remote-pg-host 127.0.0.1 \
364
+ --remote-pg-port 5432 \
365
+ --host 127.0.0.1 \
366
+ --port 55432
367
+ ```
368
+
369
+ For database modes, `--host` and `--port` are the local bind address and
370
+ free port. `--remote-pg-host` and `--remote-pg-port` identify PostgreSQL from
371
+ the SSH server. Host commands run remotely; `asyncpg`, `pgbench`, and `psql`
372
+ connect through native AsyncSSH local forwarding. No `AcceptEnv` change is
373
+ required on the SSH server.
374
+
375
+ ## Report contents
376
+
377
+ A benchmark report contains:
378
+
379
+ - artifact schema and generator versions;
380
+ - runtime and methodology metadata;
381
+ - redacted effective CLI configuration;
382
+ - workload templates and effective commands;
383
+ - complete embedded SQL schemas, queries and setup scripts;
384
+ - complete embedded Python generator source and profile manifest;
385
+ - workload file hashes, scale, pgbench/psql paths, client sweep and exact
386
+ resolved commands;
387
+ - a compatibility preflight containing the PostgreSQL server major, the newest
388
+ local pgbench/psql versions and the supported server range 10–18;
389
+ - raw initialization and workload evidence for every completed iteration;
390
+ - parsed clients, duration, transaction count, average latency, initial
391
+ connection time, and TPS;
392
+ - an explicit `maximum_tps` point with its axis value and complete metrics;
393
+ - a TPS chart for the selected axis;
394
+ - all `pg_diag` OS charts collected during every measured iteration: CPU
395
+ utilization/load, RAM usage/pressure, disk throughput/IOPS/utilization/latency,
396
+ and network throughput/packets;
397
+ - PostgreSQL version, available extensions, and server settings;
398
+ - host, kernel, CPU, memory, storage, network, and filesystem facts;
399
+ - item-level collection status and diagnostic reason;
400
+ - an optional PostgreSQL log archive reference backed by the report-local
401
+ `db_logs/` directory.
402
+
403
+ The JSON and HTML files are written through temporary files and atomically
404
+ renamed into place. Report names cannot contain path separators, `.`/`..`, or a
405
+ NUL byte.
406
+
407
+ Render a JSON report again without rerunning a benchmark:
408
+
409
+ ```bash
410
+ pg-perf-bench render \
411
+ --from-json report/local-pg18.json \
412
+ --out report/local-pg18.html
413
+ ```
414
+
415
+ ## Joining reports
416
+
417
+ Join mode requires at least two benchmark reports with:
418
+
419
+ - unique internal `report_name` values;
420
+ - the same `artifact_schema_version`;
421
+ - complete benchmark chart and result-table structures;
422
+ - equal values at every dotted path listed by the selected join task.
423
+
424
+ The explicitly selected reference remains immutable while every other report
425
+ is compared with it. Non-required differences become report/value comparison
426
+ tables. TPS chart series, pgbench result tables, log references, and raw
427
+ `benchmark_runs` evidence are deep-copied into the joined artifact. OS chart
428
+ blocks are intentionally stacked vertically by source report and iteration;
429
+ CPU profiles therefore remain visually comparable instead of being overlaid.
430
+
431
+ ```bash
432
+ pg-perf-bench join \
433
+ --input-dir report/runs \
434
+ --reference-report local-pg18.json \
435
+ --join-task optimize-db-config \
436
+ --out report/comparisons \
437
+ --report-name clients-comparison
438
+ ```
439
+
440
+ The input directory should contain only source JSON reports intended for that
441
+ comparison. Invalid non-reference JSON files are skipped with a warning. A
442
+ missing, invalid, or structurally incompatible reference fails the operation.
443
+ `pg-perf-bench join-tasks` lists the packaged JOIN catalog of separately
444
+ documented practical scenarios:
445
+ `optimize-db-config`, `scale-cpu`, `scale-memory`, `compare-storage`,
446
+ `tune-os-kernel`, `compare-postgresql-major`, and `repeatability`. Each scenario
447
+ fixes the evidence required by its performance question and permits only its
448
+ declared variable to differ. Definitions and README files are validated by
449
+ `pg-perf-bench validate`. The historic
450
+ `task_compare_dbs_on_single_host.json` name remains an alias for
451
+ `optimize-db-config`.
452
+
453
+ ## Automation contract
454
+
455
+ `--machine` emits one JSON envelope on stdout and sends logs to stderr. It may
456
+ appear before or after the subcommand. `--request-id` is copied to the envelope.
457
+
458
+ ```bash
459
+ pg-perf-bench --machine --request-id run-42 capabilities
460
+ pg-perf-bench --machine --request-id capabilities-42 --component-capabilities
461
+ pg-perf-bench --machine validate
462
+ pg-perf-bench --machine plan collect-sys-info --connection-type local
463
+ ```
464
+
465
+ `plan` validates and redacts a configuration, then produces a deterministic
466
+ SHA-256 plan hash without touching the target. A machine-mode `benchmark` must
467
+ carry that reviewed hash. The hash includes custom workload file or directory
468
+ content, but excludes output paths, log settings, report name, and request id:
469
+
470
+ ```bash
471
+ pg-perf-bench --machine plan benchmark BENCHMARK_OPTIONS...
472
+ pg-perf-bench --machine benchmark BENCHMARK_OPTIONS... --plan-hash sha256:...
473
+ ```
474
+
475
+ All component capabilities use `pg_play/capabilities/v1`; every command declares
476
+ `mutates_target`, `machine_output`, and `accepts_plan_hash`. Generated artifacts
477
+ carry an absolute path, SHA-256 hash, size, kind, and schema version.
478
+
479
+ Stable exit codes:
480
+
481
+ | Code | Meaning |
482
+ |---:|---|
483
+ | 0 | success |
484
+ | 2 | invalid CLI or configuration |
485
+ | 3 | missing precondition or inaccessible dependency |
486
+ | 4 | unsupported operation |
487
+ | 5 | report generated with partial collection results |
488
+ | 6 | execution failure |
489
+ | 7 | cancelled operation |
490
+ | 8 | ownership error |
491
+ | 130 | interrupted by the user |
492
+
493
+ ## Validation and tests
494
+
495
+ Validate the installed templates, command references, Python collectors, and
496
+ join task definitions:
497
+
498
+ ```bash
499
+ pg-perf-bench validate
500
+ ```
501
+
502
+ Run the non-destructive test suite:
503
+
504
+ ```bash
505
+ python -m pytest
506
+ ```
507
+
508
+ Integration tests are excluded by default. The supported end-to-end smoke test
509
+ uses an explicitly provisioned disposable `pg_stand` environment:
510
+
511
+ ```bash
512
+ PG_PERF_BENCH_PG_STAND_INTEGRATION=1 \
513
+ python -m pytest -m integration tests/integration/test_pg_stand_smoke.py
514
+ ```
515
+
516
+ The legacy direct-Docker integration module is disabled unless
517
+ `PG_PERF_BENCH_LEGACY_DOCKER_INTEGRATION=1` is set.
518
+
519
+ ## Current scope
520
+
521
+ The current report captures static environment facts and final PostgreSQL
522
+ state. It does not yet provide continuous CPU, disk, network, wait-event, or
523
+ `pg_stat_*` time-series sampling during the workload. Statistical repetitions,
524
+ warm-up runs, and confidence intervals are outside the current execution model.
525
+
526
+ ## License
527
+
528
+ The project is distributed under the MIT License. Embedded third-party assets
529
+ retain their own license and notice files under
530
+ `src/pg_perf_bench/templates/vendor/` and in `THIRD_PARTY_NOTICES.md`.