├── .gitignore ├── LICENSE ├── README.md ├── ansible.cfg ├── config.yml.in ├── copy-results.sh ├── get-results.sh ├── images └── plot-csv.png ├── inventory.yml.in ├── playbooks ├── clean-postgres.yml ├── clean.yml ├── config-system.yml ├── init-dbt2.yml ├── init-pgbench.yml ├── init-postgres.yml ├── init-tprocc.yml ├── init-tproch.yml ├── roles │ ├── common │ │ ├── tasks │ │ │ └── main.yml │ │ └── vars │ │ │ └── main.yml │ ├── create-extensions │ │ └── tasks │ │ │ └── main.yml │ └── log-stats │ │ └── tasks │ │ └── main.yml ├── run-dbt2.yml ├── run-pgbench.yml ├── run-tprocc.yml ├── run-tproch.yml ├── scratch-run-dbt2.yml ├── scratch-run-pgbench.yml ├── scratch-run-tprocc.yml ├── scratch-run-tproch.yml ├── start-postgres.yml ├── stop-postgres.yml ├── tools │ ├── backup-postgres.yml │ ├── clean-postgres.yml │ ├── restore-postgres.yml │ ├── start-buffercache-monitor.yml │ ├── start-pgstatdb-monitor.yml │ ├── start-postgres.yml │ ├── stop-buffercache-monitor.yml │ ├── stop-pgstatdb-monitor.yml │ └── stop-postgres.yml ├── tune-postgres.yml └── tune-sysctls.yml ├── plot-csv.py ├── requirements.yml └── run-benchmark.sh /.gitignore: -------------------------------------------------------------------------------- 1 | config.yml 2 | inventory.yml 3 | results/ 4 | /credentials/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021-2022, EnterpriseDB Corporation 2 | 3 | Permission to use, copy, modify, and distribute this software and its 4 | documentation for any purpose, without fee, and without a written agreement is 5 | hereby granted, provided that the above copyright notice and this paragraph and 6 | the following two paragraphs appear in all copies. 7 | 8 | IN NO EVENT SHALL EnterpriseDB Corporation BE LIABLE TO ANY PARTY FOR DIRECT, 9 | INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 10 | PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 11 | EnterpriseDB Corporation HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | 13 | EnterpriseDB Corporation SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT 14 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 15 | PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND 16 | EnterpriseDB Corporation HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, 17 | UPDATES, ENHANCEMENTS, OR MODIFICATIONS. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible Benchmark Framework 2 | 3 | This directory contains Ansible playbooks used to aid with testing and benchmarking various R&D projects in the EDB 4 | CTO Team. 5 | 6 | The framework is designed to run from a controller machine, which executes everything using Ansible over an SSH 7 | connection. Tests can be run on any number of machines in parallel, from the *benchmark* group in the Ansible 8 | inventory. Add the hostnames/IPs of the machines to run the benchmarks to this group. 9 | 10 | Optionally, the benchmark software can run on a driver machine rather than the benchmark machine. Add driver machines 11 | to the *driver* group in the Ansible inventory, and then add a property called *driver* to each benchmark machine entry 12 | in the inventory, setting the value to the hostname of the driver machine to use. A separate driver must be used for 13 | each benchmark machine. 14 | 15 | ## Quickstart 16 | 17 | * Ensure Ansible has the modules it needs on the controller machine: 18 | 19 | ```bash 20 | ansible-galaxy install -r requirements.yml 21 | ``` 22 | * Install a minimal installation of Rocky on all the benchamrk systems. 23 | * Ensure the login user account can run sudo without a password. 24 | * Accept SSH fingerprints for each server on the machine running Ansible. 25 | * Install the appropriate SSH key to each server from the Ansible host, e.g. by using *ssh-copy-id*. 26 | * Update *inventory.yml* with the hostnames 27 | * Run ```ansible-playbook -i inventory.yml -l benchmark playbooks/config-system.yml``` to install/configure the machines 28 | in the benchmark group. 29 | * Edit config.yml as required. 30 | * Run the *run-benchmark.sh* script to execute a benchmark test. 31 | 32 | ## Configuration files 33 | 34 | The bulk of the framework is controlled by two configuration files: 35 | 36 | ### config.yml 37 | 38 | *config.yml* is used to define the test parameters. By default, it includes the concept of a "run number"; each test 39 | (pgbench, TPROC-C, TPROC-H) can be executed with a different configuration based on the run number, set in the 40 | configuration using Jijna2 templating. Options may be configured similar to the following examples: 41 | 42 | #### Runs with different values for shared_buffers and the vm.nr_hugepages sysctl 43 | 44 | ```yaml 45 | # Sysctls to set on the benchmark machines. Always "reset" these to 46 | # default values if you don't need to adjust them, as there's no 47 | # simple way to reset them short of manually clearing /etc/sysctl.conf 48 | # followed by a system reboot. 49 | SYSCTLS: 50 | - name: vm.nr_hugepages 51 | value: "{{ 17000 if RUN_NUM|int > 6 else 13000 if RUN_NUM|int > 5 else 8600 if RUN_NUM|int > 4 else 4400 if RUN_NUM|int > 3 else 2300 if RUN_NUM|int > 2 else 720 if RUN_NUM|int > 1 else 260 }}" 52 | 53 | # Additional GUCs to set when tuning. 54 | # These will override anything already set. 55 | OVERRIDE_GUCS: 56 | - name: huge_pages 57 | value: on 58 | - name: shared_buffers 59 | value: "{{ '32GB' if RUN_NUM|int > 6 else '24GB' if RUN_NUM|int > 5 else '16GB' if RUN_NUM|int > 4 else '8GB' if RUN_NUM|int > 3 else '4GB' if RUN_NUM|int > 2 else '1GB' if RUN_NUM|int > 1 else '128MB' }}" 60 | ``` 61 | 62 | #### Runs cumulatively enabling features of an extension 63 | 64 | Note that hooks must be added to control what these configuration parameters actually do to enable the features. 65 | 66 | ```yaml 67 | # my_extension parameters 68 | # Note that run 1 will execute with no features enabled 69 | MY_EXTENSION_FEATURE_ONE: "{{ true if RUN_NUM|int > 1 else false }}" 70 | MY_EXTENSION_FEATURE_TWO: "{{ true if RUN_NUM|int > 2 else false }}" 71 | MY_EXTENSION_FEATURE_THREE: "{{ true if RUN_NUM|int > 3 else false }}" 72 | MY_EXTENSION_FEATURE_FOUR: "{{ true if RUN_NUM|int > 4 else false }}" 73 | MY_EXTENSION_FEATURE_FIVE: "{{ true if RUN_NUM|int > 5 else false }}" 74 | ``` 75 | 76 | Note that additional configuration variables can be set using the *config* hook if preferred (this can be useful if you 77 | have other hooks in a different source tree for testing that code for example). See below for more information. 78 | 79 | ### inventory.yml 80 | 81 | *inventory.yml* is used to define the machines that will be used for the test. A template (*inventory.yml.in*) is 82 | provided which can be copied and modified to suit your environment. An example inventory file is shown below. Note that 83 | driver machines are optional; if they are not specified, everything will run on the benchmark machines. 84 | 85 | ```yaml 86 | # Copy this file to inventory.yml, and edit to suit 87 | 88 | # The benchmark group is for servers that will run benchmarks 89 | # The controller group is for servers that will manage the benchmark servers 90 | 91 | # If separate driver machines are to be used, add them to the "driver" group 92 | # and then add a var to the benchmark host called "driver" with a value 93 | # corresponding to the name of the driver host. Don't use the same driver for 94 | # multiple hosts!! 95 | # 96 | # In the example below, server1 will be driven by server6, and server2 by 97 | # server7. server3 and server4 will run HammerDB locally. 98 | 99 | all: 100 | vars: 101 | ansible_timeout: 180 102 | children: 103 | benchmark: 104 | hosts: 105 | server1.example.com: 106 | driver: server6.example.com 107 | server2.example.com: 108 | driver: server7.example.com 109 | server3.example.com: 110 | server4.example.com: 111 | driver: 112 | hosts: 113 | server6.example.com: 114 | server7.example.com: 115 | controller: 116 | hosts: 117 | server5.example.com: 118 | ``` 119 | 120 | ## Hooks 121 | 122 | It's useful to be able to add additional functionality to the framework in order to perform tasks such as enabling an 123 | extension you want to test. There are a number of hook points defined that can be used for this purpose, each of which 124 | is a simple YAML file of Ansible tasks that will be included at the hook point. 125 | 126 | Hooks are created in the *ansible-local/hooks* directory, where *ansible-local* shares the same parent directory as the 127 | framework code. For example, if the framework code is checked out into a directory called *ansible*, the structure will 128 | look as follows: 129 | 130 | - ansible/ 131 | - images/ 132 | - playbooks/ 133 | - ... 134 | - README.md (this file) 135 | - ... 136 | - ansible-local/ 137 | - hooks/ 138 | - clean.yml 139 | - config.yml 140 | - config-system.yml 141 | - ... 142 | 143 | The hooks currently defined are as follows: 144 | 145 | ### clean 146 | __Filename:__ clean.yml 147 | 148 | __Applies to host group:__ benchmark 149 | 150 | __Description:__ Called at the end of the *clean.yml* playbook to remove any additional artifacts that may need to be 151 | cleaned up. 152 | 153 | __Example:__ 154 | 155 | ```yaml 156 | --- 157 | - name: Remove my_extension source tree 158 | file: 159 | path: ~/my_extension 160 | state: absent 161 | ``` 162 | 163 | ### config 164 | __Filename:__ config.yml 165 | 166 | __Applies to host group:__ all 167 | 168 | __Description:__ Contains any local variables that need to be configured to control hook behaviour. 169 | 170 | __Example:__ 171 | 172 | ```yaml 173 | # my_extension private deploy key path 174 | MY_EXTENSION_DEPLOY_KEY: /Users/dpage/.ssh/id_ed25519.my_extension 175 | 176 | # Enable/disable our test extensions 177 | ENABLE_MY_EXTENSION: true 178 | ``` 179 | 180 | ### config-system 181 | __Filename:__ config-system.yml 182 | 183 | __Applies to host group:__ benchmark 184 | 185 | __Description:__ Called at the end of the *config-system.yml* playbook to apply any additional configuration that is 186 | required on the benchmark machines. 187 | 188 | __Example:__ 189 | 190 | ```yaml 191 | --- 192 | - name: Upload the private key used for Github cloning 193 | copy: 194 | src: "{{ MY_EXTENSION_DEPLOY_KEY }}" 195 | dest: ~/.ssh/id_my_extension_deploy_key 196 | mode: u=rw,g=,o= 197 | ``` 198 | 199 | ### create-extensions 200 | __Filename:__ create-extensions.yml 201 | 202 | __Applies to host group:__ Undefined (typically benchmark) 203 | 204 | __Description:__ Called by the *create-extensions* role which is in turn called from various playbooks in order to 205 | create any extensions that are required on the Postgres servers. This always includes pg_prewarm, but may also be 206 | extended with this hook to install other extensions you may wish to test. 207 | 208 | __Example:__ 209 | 210 | ```yaml 211 | --- 212 | - name: Create my_extension extension 213 | shell: | 214 | {{ postgres_bin }}/psql -h /tmp -c "CREATE EXTENSION IF NOT EXISTS my_extension;" {{ database }} 215 | when: ENABLE_MY_EXTENSION == true 216 | ``` 217 | 218 | ### init-postgres 219 | __Filename:__ init-postgres.yml 220 | 221 | __Applies to host group:__ benchmark 222 | 223 | __Description:__ Called towards the end of the *init-postgres* playbook, __prior__ to the database password being set 224 | and the server being restarted. Typically used to set any additional GUCs that may be required to enable extension, for 225 | example, in *shared_preload_libraries*. 226 | 227 | __Example:__ 228 | 229 | ```yaml 230 | --- 231 | - name: Enable/disable my_extension as required 232 | shell: | 233 | echo "shared_preload_libraries = '{{ 'my_extension' if ENABLE_MY_EXTENSION else '' }}'" >> ~/pgsql/data/postgresql.conf 234 | touch ~/pgsql/data/.shared_preload_libraries 235 | args: 236 | creates: ~/pgsql/data/.shared_preload_libraries 237 | ``` 238 | 239 | ### log-stats 240 | __Filename:__ log-stats.yml 241 | 242 | __Applies to host group:__ driver/benchmark 243 | 244 | __Description:__ Called at the end of the main *log-stats* role, this hook is used to log additional data from 245 | the database servers pre and post run. Note that care must be taken to run tasks on the driver machines if present. 246 | 247 | __Example:__ 248 | 249 | ```yaml 250 | --- 251 | - name: Record the my_extension stats 252 | shell: | 253 | echo "" >> {{ log_file }} 254 | echo "my_extension_stats" >> {{ log_file }} 255 | echo "================================================================================" >> {{ log_file }} 256 | echo "" >> {{ log_file }} 257 | 258 | {{ postgres_bin }}/psql -h {{ host }} -c "SELECT * FROM my_extension_stats();" {{ database }} >> {{ log_file }} 259 | 260 | when: ENABLE_MY_EXTENSION 261 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 262 | environment: 263 | PGPASSWORD: "{{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}" 264 | ``` 265 | 266 | ### tune-postgres 267 | __Filename:__ tune-postgres.yml 268 | 269 | __Applies to host group:__ benchmark 270 | 271 | __Description:__ Called at the end of the *tune-postgres* playbook which is in turn called from various playbooks in 272 | order to perform any additional tasks required to tune Postgres prior to a test run. This may be used (for example) to 273 | enable functionality provided by previously loaded extensions, or to run a script that will determine and set a value 274 | for a GUC. 275 | 276 | __Example:__ 277 | 278 | ```yaml 279 | --- 280 | - name: Configure my_extension 281 | shell: | 282 | {{ postgres_bin }}/psql -h /tmp -c "SELECT * FROM my_extension_config();" postgres 283 | when: ENABLE_MY_EXTENSION 284 | ``` 285 | 286 | ## Scripts 287 | 288 | A number of scripts are provided to make it easy to execute multiple runs of a benchmark and to extract the results 289 | from the log files generated. 290 | 291 | ### run-benchmark.sh 292 | 293 | The ```run-benchmark.sh``` script can be used to execute a benchmark run. It takes three command line parameters: 294 | 295 | ```bash 296 | $ ./run-benchmark.sh 297 | Usage: ./run-benchmark.sh pgbench|tprocc|tproch [] [] 298 | 299 | Run a benchmark of the specified type, optionally specifying the number of runs and the first run number. 300 | ``` 301 | 302 | #### Examples 303 | 304 | Execute a standard 6 run pgbench test: 305 | 306 | ```bash 307 | $ ./run-benchmark.sh pgbench 308 | ``` 309 | 310 | Execute run 5 of a TPROC-C test: 311 | ```bash 312 | $ ./run-benchmark.sh tprocc 1 5 313 | ``` 314 | 315 | Execute runs 3 - 6 of a TPROC-H test: 316 | 317 | ```bash 318 | $ ./run-benchmark.sh tproch 3 3 319 | ``` 320 | 321 | ### copy-results.sh 322 | 323 | The ```copy-results.sh``` script can be used to copy a directory containing result log files in to another directory 324 | in which they will be organised into the structure typically used to store them on Google Drive. 325 | 326 | ```bash 327 | $ ./copy-results.sh ~/tmp ~/my_test_results 328 | /Users/dpage/tmp/tprocc-202205121310-cto13-run1-w1250-u250.log 329 | /Users/dpage/tmp/tprocc-202205121310-cto14-run1-w1250-u250.log 330 | /Users/dpage/tmp/tprocc-202205121310-cto15-run1-w1250-u250.log 331 | /Users/dpage/tmp/tprocc-202205121310-cto16-run1-w1250-u250.log 332 | /Users/dpage/tmp/tprocc-202205121426-cto13-run2-w1250-u250.log 333 | /Users/dpage/tmp/tprocc-202205121426-cto14-run2-w1250-u250.log 334 | /Users/dpage/tmp/tprocc-202205121426-cto15-run2-w1250-u250.log 335 | /Users/dpage/tmp/tprocc-202205121426-cto16-run2-w1250-u250.log 336 | /Users/dpage/tmp/tprocc-202205121543-cto13-run3-w1250-u250.log 337 | /Users/dpage/tmp/tprocc-202205121543-cto14-run3-w1250-u250.log 338 | ... 339 | 340 | $ ls -alR ~/my_test_results 341 | total 0 342 | drwxr-xr-x 13 dpage staff 416 May 13 10:53 . 343 | drwxr-xr-x+ 81 dpage staff 2592 May 13 10:53 .. 344 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tprocc Run 1 345 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tprocc Run 2 346 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tprocc Run 3 347 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tprocc Run 4 348 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tprocc Run 5 349 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tprocc Run 6 350 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tproch Run 1 351 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tproch Run 2 352 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tproch Run 3 353 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tproch Run 4 354 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 tproch Run 5 355 | 356 | /Users/dpage/my_test_results/tprocc Run 1: 357 | total 1344 358 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 . 359 | drwxr-xr-x 13 dpage staff 416 May 13 10:53 .. 360 | -rw-r--r-- 1 dpage staff 168812 May 13 10:53 tprocc-202205121310-cto13-run1-w1250-u250.log 361 | -rw-r--r-- 1 dpage staff 168811 May 13 10:53 tprocc-202205121310-cto14-run1-w1250-u250.log 362 | -rw-r--r-- 1 dpage staff 168812 May 13 10:53 tprocc-202205121310-cto15-run1-w1250-u250.log 363 | -rw-r--r-- 1 dpage staff 168811 May 13 10:53 tprocc-202205121310-cto16-run1-w1250-u250.log 364 | 365 | /Users/dpage/my_test_results/tprocc Run 2: 366 | total 1344 367 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 . 368 | drwxr-xr-x 13 dpage staff 416 May 13 10:53 .. 369 | -rw-r--r-- 1 dpage staff 168811 May 13 10:53 tprocc-202205121426-cto13-run2-w1250-u250.log 370 | -rw-r--r-- 1 dpage staff 168811 May 13 10:53 tprocc-202205121426-cto14-run2-w1250-u250.log 371 | -rw-r--r-- 1 dpage staff 168811 May 13 10:53 tprocc-202205121426-cto15-run2-w1250-u250.log 372 | -rw-r--r-- 1 dpage staff 168811 May 13 10:53 tprocc-202205121426-cto16-run2-w1250-u250.log 373 | 374 | /Users/dpage/my_test_results/tprocc Run 3: 375 | total 1344 376 | drwxr-xr-x 6 dpage staff 192 May 13 10:53 . 377 | drwxr-xr-x 13 dpage staff 416 May 13 10:53 .. 378 | -rw-r--r-- 1 dpage staff 168810 May 13 10:53 tprocc-202205121543-cto13-run3-w1250-u250.log 379 | -rw-r--r-- 1 dpage staff 168790 May 13 10:53 tprocc-202205121543-cto14-run3-w1250-u250.log 380 | ... 381 | ``` 382 | 383 | ### get-results.sh 384 | 385 | The ```get-results.sh``` script will extract benchmark results from a directory containing log files, in either text or 386 | table format. The table format will output the results in a comma delimited format for easy copy/pasting into Google 387 | Sheets or similar; paste the entire block of results into a cell, and use the *Split text to columns* option on the 388 | popup menu. 389 | 390 | ```bash 391 | $ ./get-results.sh 392 | Usage: ./get-results.sh pgbench|tprocc|tproch [text|table (default: text)] [] 393 | 394 | Extract benchmark results for the specified test type, and output them in the specified format. 395 | ``` 396 | 397 | #### Examples 398 | 399 | Get TPROC-C results in text format from the current directory: 400 | 401 | ```bash 402 | $ ../get-results.sh tprocc 403 | ./tprocc-202205121310-cto13-run1-w1250-u250.log : 225325 NOPM, 518147 TPM 404 | ./tprocc-202205121310-cto14-run1-w1250-u250.log : 218610 NOPM, 502950 TPM 405 | ./tprocc-202205121310-cto15-run1-w1250-u250.log : 208903 NOPM, 480381 TPM 406 | ./tprocc-202205121310-cto16-run1-w1250-u250.log : 225456 NOPM, 518782 TPM 407 | ./tprocc-202205121426-cto13-run2-w1250-u250.log : 304562 NOPM, 700915 TPM 408 | ./tprocc-202205121426-cto14-run2-w1250-u250.log : 297428 NOPM, 684625 TPM 409 | ... 410 | ``` 411 | 412 | Get TPROC-H results in table format from a different directory: 413 | 414 | ```bash 415 | $ ./get-results.sh tproch table ~/tmp 416 | 417 | 109.736,104.696,96.3778,104.238 418 | 101.064,99.7464,102.222,106.278 419 | 106.196,105.438,102.386,104.676 420 | 108.334,110.552,103.788,97.4538 421 | 113.41,108.528,124.07,116.551 422 | ``` 423 | ### plot-csv.py 424 | 425 | The benchmark framework has the ability to perform additional monitoring whilst tests are running. One option 426 | included will monitor the page usage counts in shared buffers, using the pg_buffercache extension. A CSV file is 427 | generated with each run, which is downloaded to the controller node alongside the log file for the run. For example: 428 | 429 | ```bash 430 | $ head pgbench-buffercache-202205181030-cto13-run1-s15000-c450-T3600.csv 431 | timestamp,usagecount_0,usagecount_1,usagecount_2,usagecount_3,usagecount_4,usagecount_5 432 | 2022-05-18 10:30:26.827807+01,15968,85,58,10,19,244 433 | 2022-05-18 10:30:36.840748+01,1,10438,12,3,2,7 434 | 2022-05-18 10:30:46.852814+01,1,4492,12,3,2,7 435 | 2022-05-18 10:30:56.864921+01,1,13270,12,3,2,7 436 | 2022-05-18 10:31:06.878146+01,1,9678,12,3,2,7 437 | 2022-05-18 10:31:16.891612+01,0,5552,12,3,2,7 438 | 2022-05-18 10:31:26.903931+01,1,9462,12,3,2,7 439 | 2022-05-18 10:31:36.917041+01,1,11517,12,3,2,7 440 | 2022-05-18 10:31:46.929552+01,1,13962,12,3,2,7 441 | ``` 442 | 443 | The *plot-csv.py* script can be used to create a nice graph from this data. Note that it's not overly clever; it 444 | expects the first column to be an ISO8601 formatted timestamp, and subsequent columns to be graphable. 445 | 446 | ```bash 447 | $ python3 ./plot-csv.py -h 448 | usage: plot-csv.py [-h] [--style {line,area}] [--width WIDTH] [--height HEIGHT] [--title TITLE] [--percent] [--colormap COLORMAP] [--xlabel XLABEL] [--ylabel YLABEL] input 449 | 450 | Plot a graph from a CSV file. 451 | 452 | positional arguments: 453 | input the CSV file to plot 454 | 455 | optional arguments: 456 | -h, --help show this help message and exit 457 | --style {line,area}, -s {line,area} 458 | type of chart to create 459 | --width WIDTH plot width in inches (default: 10) 460 | --height HEIGHT plot height in inches (default: 6) 461 | --title TITLE, -t TITLE 462 | plot title (defaults to the input filename without extension) 463 | --percent, -p scale to 100%, rather than printing absolute values 464 | --colormap COLORMAP, -c COLORMAP 465 | matplotlib colormap to use when rendering (default: plasma) 466 | --xlabel XLABEL label to display on the X axis 467 | --ylabel YLABEL label to display on the Y axis 468 | ``` 469 | 470 | > **NOTE**: This script requires the _pandas_ and _matplotlib_ Python modules. Install these into a suitable virtualenv! 471 | 472 | Here's an example: 473 | 474 | ```bash 475 | $ python3 plot-csv.py results/pgbench-buffercache-202205181030-cto13-run1-s15000-c450-T3600.csv -s area -p --ylabel '%age of shared_buffers'  1 ✘ ╱ ml  476 | Wrote results/pgbench-buffercache-202205181030-cto13-run1-s15000-c450-T3600.png 477 | ``` 478 | 479 | ![pgbench-buffercache-202205181030-cto13-run1-s15000-c450-T3600.png](images/plot-csv.png) 480 | 481 | Here is how we might post-process an entire set of results: 482 | 483 | ```bash 484 | for f in *buffercache*.csv; do 485 | python3 ~/git/autotuning/ansible/plot-csv.py $f -s area -p --ylabel '%age of shared_buffers' 486 | done 487 | for f in *pgstatdb*.csv; do 488 | python3 ~/git/autotuning/ansible/plot-csv.py $f -s area -p --ylabel '%age of Blocks' 489 | done 490 | ``` -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [ssh_connection] 2 | retries=5 -------------------------------------------------------------------------------- /config.yml.in: -------------------------------------------------------------------------------- 1 | # Copy this file to config.yml, and edit to suit 2 | 3 | # Postgres variant, should be one of epas or postgres. 4 | POSTGRES_DB_TYPE: postgres 5 | POSTGRES_DB_VERSION: 14 6 | 7 | # Variables necessary for setup / deployment 8 | EDB_REPO_USER: 9 | EDB_REPO_PW: 10 | 11 | # Additional monitoring options 12 | MONITOR_PG_BUFFERCACHE: true 13 | MONITOR_PG_STAT_DATABASE: true 14 | 15 | # Run number. This is used to easily allow multiple benchmark runs using 16 | # incremental sets of Postgres configuration parameters. Generally this 17 | # would be overridden on the command line by a script calling a playbook 18 | # in a loop, e.g: 19 | # 20 | # for n in {1..6} 21 | # do 22 | # ansible-playbook -i inventory.yml --extra-vars "RUN_NUM=$n" playbooks/scratch-run-pgbench.yml 23 | # done 24 | RUN_NUM: 1 25 | 26 | # Sysctls to set on the benchmark machines. Always "reset" these to 27 | # default values if you don't need to adjust them, as there's no 28 | # simple way to reset them short of manually clearing /etc/sysctl.conf 29 | # followed by a system reboot. 30 | SYSCTLS: 31 | - name: vm.nr_hugepages 32 | value: 0 33 | 34 | # Additional GUCs to set when tuning. 35 | # These will override anything already set. 36 | #OVERRIDE_GUCS: 37 | # - name: wal_buffers 38 | # value: 64KB 39 | # - name: max_connections 40 | # value: 120 41 | 42 | # pgbench parameters 43 | PGBENCH_CLEAR_CACHE_AND_PREWARM: true 44 | PGBENCH_SCALE_FACTOR: 10000 45 | PGBENCH_CLIENTS: 75 46 | PGBENCH_RUN_TIME: 3600 47 | 48 | # TPROC-C (HammerDB) parameters 49 | # 50 | # Notes: 51 | # Each virtual user will use up to 10 warehouses, so 52 | # usually warehouses == virtual users * 10 53 | # 54 | # Sizes (PG 14.2, default options): 55 | # Warehouses DB Size 56 | # 1 117 MB 57 | # 5 510 MB 58 | # 10 998 MB 59 | # 20 1974 MB 60 | # 50 4886 MB 61 | # 100 9754 MB 62 | # 200 19 GB 63 | # 400 35 GB 64 | # 750 71 GB 65 | # 1500 143 GB 66 | TPROCC_CLEAR_CACHE_AND_PREWARM: true 67 | TPROCC_WAREHOUSES: 750 68 | TPROCC_SCHEMA_USERS: 15 69 | TPROCC_VIRTUAL_USERS: 75 70 | TPROCC_PARTITION: false 71 | TPROCC_VACUUM: false 72 | TPROCC_DRITA_SNAPS: false 73 | TPROCC_ORACLE_COMPAT: false 74 | TPROCC_STORED_PROCS: false 75 | TPROCC_KEY_AND_THINK: false 76 | TPROCC_RAMPUP_TIME: 5 77 | TPROCC_RUN_TIME: 60 78 | 79 | # TPROC-H (HammerDB) parameters 80 | # 81 | # Notes: 82 | # Scale factor must be one of 1, 10, 30, 100, 300, 1000 83 | # 84 | # Sizes (PG 14.2, default options): 85 | # Scale Factor DB Size 86 | # 1 2065 MB 87 | # 10 20 GB 88 | # 30 50 GB 89 | # 100 159 GB 90 | TPROCH_CLEAR_CACHE_AND_PREWARM: true 91 | TPROCH_VIRTUAL_USERS: 3 92 | TPROCH_SCALE_FACTOR: 30 93 | TPROCH_THREADS: 15 94 | TPROCH_TOTAL_QUERYSETS: 1 95 | TPROCH_REFRESH_ON: false 96 | TPROCH_DEGREE_OF_PARALLEL: 5 97 | TPROCH_UPDATE_SETS: 1 98 | TPROCH_TRICKLE_REFRESH: 1000 99 | 100 | # DBT2 parameters 101 | DBT2_CLEAR_CACHE_AND_PREWARM: true 102 | DBT2_WORKLOAD_TEST_DURATION: 30 103 | DBT2_WORKLOAD_NUMBER_OF_WAREHOUSES: 10 104 | -------------------------------------------------------------------------------- /copy-results.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 2 ]; then 4 | echo "Usage: $0 " 5 | echo 6 | echo "Copy benchmark results from the source directory to the target directory, organising them into the standard structure." 7 | exit 1 8 | fi 9 | 10 | copy_files () { 11 | for FILE in $1/$3-*; do 12 | if [[ ${FILE} =~ .*-run([0-9]+).* ]]; then 13 | TARGET_PATH="$2/$3 Run ${BASH_REMATCH[1]}" 14 | mkdir -p "${TARGET_PATH}" 15 | cp "${FILE}" "${TARGET_PATH}" 16 | echo ${FILE} 17 | fi 18 | done 19 | } 20 | 21 | copy_files "$1" "$2" dbt2 22 | copy_files "$1" "$2" tprocc 23 | copy_files "$1" "$2" tproch 24 | copy_files "$1" "$2" pgbench -------------------------------------------------------------------------------- /get-results.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SYSPREFIX='edb-bench' 4 | 5 | usage () { 6 | echo "Usage: $0 dbt2|pgbench|tprocc|tproch [text|table (default: text)] []" 7 | echo 8 | echo "Extract benchmark results for the specified test type, and output them in the specified format." 9 | exit 1 10 | } 11 | 12 | if [ $# -lt 1 ]; then 13 | usage 14 | fi 15 | 16 | BENCHMARK=$1 17 | FORMAT=${2:-text} 18 | DIRECTORY=${3:-.} 19 | 20 | if [ ${FORMAT} != "text" -a ${FORMAT} != "table" ]; then 21 | usage 22 | fi 23 | 24 | dbt2_text () { 25 | for FILE in $1/dbt2-20*.log 26 | do 27 | grep NOTPM $FILE | awk -v file=$FILE '{print file,":",$3, "NOTPM"}' 28 | done 29 | } 30 | 31 | dbt2_table() { 32 | PREV_RUN=0 33 | 34 | for FILE in $1/dbt2-20*.log 35 | do 36 | BENCH=${FILE/${SYSPREFIX}/} 37 | HOST_NUM=$(echo $BENCH | awk -F '-' '{ print $3 }') 38 | RUN_NUM=$(echo $BENCH | awk -F '-' '{ print $4 }' | sed 's/run//g') 39 | NOTPM=$(grep NOTPM $FILE | awk '{ print $3 }') 40 | 41 | if [ $PREV_RUN -ne $RUN_NUM ]; then 42 | PREV_RUN=$RUN_NUM 43 | echo "" 44 | else 45 | echo -n "," 46 | fi 47 | 48 | echo -n "$NOTPM" 49 | done 50 | 51 | echo "" 52 | } 53 | 54 | pgbench_text () { 55 | for FILE in $1/pgbench-20*.log 56 | do 57 | grep "tps = " $FILE | awk -v file=$FILE '{print file,":",$3,"TPS"}' 58 | done 59 | } 60 | 61 | pgbench_table () { 62 | PREV_RUN=0 63 | 64 | for FILE in $1/pgbench-20*.log 65 | do 66 | BENCH=${FILE/${SYSPREFIX}/} 67 | HOST_NUM=$(echo $BENCH | awk -F '-' '{ print $3 }') 68 | RUN_NUM=$(echo $BENCH | awk -F '-' '{ print $4 }' | sed 's/run//g') 69 | TPS=$(grep "tps = " $FILE | awk '{ print $3 }') 70 | 71 | if [ $PREV_RUN -ne $RUN_NUM ]; then 72 | PREV_RUN=$RUN_NUM 73 | echo "" 74 | else 75 | echo -n "," 76 | fi 77 | 78 | echo -n "$TPS" 79 | done 80 | 81 | echo "" 82 | } 83 | 84 | tprocc_text () { 85 | for FILE in $1/tprocc-20*.log 86 | do 87 | grep NOPM $FILE | awk -v file=$FILE '{print file,":",$7,"NOPM,",$10, "TPM"}' 88 | done 89 | } 90 | 91 | tprocc_table() { 92 | PREV_RUN=0 93 | 94 | for FILE in $1/tprocc-20*.log 95 | do 96 | BENCH=${FILE/${SYSPREFIX}/} 97 | HOST_NUM=$(echo $BENCH | awk -F '-' '{ print $3 }') 98 | RUN_NUM=$(echo $BENCH | awk -F '-' '{ print $4 }' | sed 's/run//g') 99 | NOPM=$(grep NOPM $FILE | awk '{ print $7 }') 100 | TPM=$(grep NOPM $FILE | awk '{ print $10 }') 101 | 102 | if [ $PREV_RUN -ne $RUN_NUM ]; then 103 | PREV_RUN=$RUN_NUM 104 | echo "" 105 | else 106 | echo -n "," 107 | fi 108 | 109 | echo -n "$NOPM.0,$TPM.0" 110 | done 111 | 112 | echo "" 113 | } 114 | 115 | tproch_text () { 116 | for FILE in $1/tproch-20*.log 117 | do 118 | grep Geometric $FILE | awk -v file=$FILE '{s+=$11}END{print file,":",s/NR}' RS="\n" 119 | done 120 | } 121 | 122 | tproch_table () { 123 | PREV_RUN=0 124 | 125 | for FILE in $1/tproch-20*.log 126 | do 127 | BENCH=${FILE/${SYSPREFIX}/} 128 | HOST_NUM=$(echo $BENCH | awk -F '-' '{ print $3 }') 129 | RUN_NUM=$(echo $BENCH | awk -F '-' '{ print $4 }' | sed 's/run//g') 130 | GEOM=$(grep Geometric $FILE | awk '{s+=$11}END{print s/NR}' RS="\n") 131 | 132 | if [ $PREV_RUN -ne $RUN_NUM ]; then 133 | PREV_RUN=$RUN_NUM 134 | echo "" 135 | else 136 | echo -n "," 137 | fi 138 | 139 | echo -n "$GEOM" 140 | done 141 | 142 | echo "" 143 | } 144 | 145 | case ${BENCHMARK} in 146 | dbt2) 147 | if [ ${FORMAT} == "text" ]; then 148 | dbt2_text ${DIRECTORY} 149 | else 150 | dbt2_table ${DIRECTORY} 151 | fi 152 | ;; 153 | pgbench) 154 | if [ ${FORMAT} == "text" ]; then 155 | pgbench_text ${DIRECTORY} 156 | else 157 | pgbench_table ${DIRECTORY} 158 | fi 159 | ;; 160 | tprocc) 161 | if [ ${FORMAT} == "text" ]; then 162 | tprocc_text ${DIRECTORY} 163 | else 164 | tprocc_table ${DIRECTORY} 165 | fi 166 | ;; 167 | tproch) 168 | if [ ${FORMAT} == "text" ]; then 169 | tproch_text ${DIRECTORY} 170 | else 171 | tproch_table ${DIRECTORY} 172 | fi 173 | ;; 174 | esac 175 | -------------------------------------------------------------------------------- /images/plot-csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnterpriseDB/benchmark-framework/653965a6617f807e2a395451c228a261218f2d13/images/plot-csv.png -------------------------------------------------------------------------------- /inventory.yml.in: -------------------------------------------------------------------------------- 1 | # Copy this file to inventory.yml, and edit to suit 2 | 3 | # The benchmark group is for servers that will run benchmarks 4 | # The controller group is for servers that will manage the benchmark servers 5 | 6 | # If separate driver machines are to be used, add them to the "driver" group 7 | # and then add a var to the benchmark host called "driver" with a value 8 | # corresponding to the name of the driver host. Don't use the same driver for 9 | # multiple hosts!! 10 | # 11 | # In the example below, server1 will be driven by server6, and server2 by 12 | # server7. server3 and server4 will run HammerDB locally. 13 | 14 | all: 15 | vars: 16 | ansible_timeout: 180 17 | children: 18 | benchmark: 19 | hosts: 20 | server1.example.com: 21 | driver: server6.example.com 22 | server2.example.com: 23 | driver: server7.example.com 24 | server3.example.com: 25 | server4.example.com: 26 | driver: 27 | hosts: 28 | server6.example.com: 29 | server7.example.com: 30 | controller: 31 | hosts: 32 | server5.example.com: -------------------------------------------------------------------------------- /playbooks/clean-postgres.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 3 | - benchmark 4 | gather_facts: no 5 | 6 | roles: 7 | - common 8 | 9 | tasks: 10 | - include_tasks: tools/clean-postgres.yml 11 | -------------------------------------------------------------------------------- /playbooks/clean.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: clean-postgres.yml 3 | 4 | - hosts: 5 | - benchmark 6 | roles: 7 | - common 8 | 9 | tasks: 10 | - name: Determine if local tasks exist 11 | local_action: stat path=../../ansible-local/hooks/clean.yml 12 | register: local_clean 13 | 14 | - name: Calling clean hook 15 | debug: 16 | msg: "{{ 'Loading additional tasks from ../../ansible-local/hooks/clean.yml' if local_clean.stat.exists else 'Local clean not found.' }}" 17 | 18 | - include_tasks: ../../ansible-local/hooks/clean.yml 19 | when: local_clean.stat.exists -------------------------------------------------------------------------------- /playbooks/config-system.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 3 | - all 4 | roles: 5 | - common 6 | 7 | tasks: 8 | - name: Update the DNF cache 9 | command: dnf makecache 10 | become: yes 11 | 12 | - name: Ensure the pgdg10 repo is disabled 13 | command: dnf config-manager --set-disabled pgdg10 14 | become: yes 15 | 16 | - name: Enable the Code Ready Builder repo 17 | shell: crb enable 18 | become: yes 19 | 20 | - name: Ensure the system is fully updated 21 | dnf: 22 | name: "*" 23 | state: latest 24 | become: yes 25 | 26 | - name: Setup EPEL 27 | dnf: 28 | name: epel-release 29 | state: present 30 | become: yes 31 | 32 | - name: Import the PostgreSQL package signing key 33 | rpm_key: 34 | state: present 35 | key: https://download.postgresql.org/pub/repos/yum/RPM-GPG-KEY-PGDG 36 | become: yes 37 | 38 | - name: Setup the PostgreSQL repo 39 | dnf: 40 | name: "https://download.postgresql.org/pub/repos/yum/reporpms/EL-{{ ansible_facts['distribution_major_version'] }}-x86_64/pgdg-redhat-repo-latest.noarch.rpm" 41 | state: present 42 | become: yes 43 | 44 | - name: Disable the built-in PostgreSQL module 45 | command: dnf -qy module disable postgresql 46 | become: yes 47 | 48 | - name: Enable the PostgreSQL debuginfo repo 49 | command: dnf config-manager --set-enabled pgdg14-debuginfo 50 | become: yes 51 | 52 | - name: Setup the EDB repo 53 | dnf: 54 | name: https://yum.enterprisedb.com/edbrepos/edb-repo-latest.noarch.rpm 55 | state: present 56 | disable_gpg_check: yes 57 | become: yes 58 | when: EDB_REPO_USER is defined and EDB_REPO_USER 59 | 60 | - name: Add EDB repo credentials 61 | replace: 62 | path: /etc/yum.repos.d/edb.repo 63 | regexp: ":" 64 | replace: "{{ EDB_REPO_USER }}:{{ EDB_REPO_PW }}" 65 | backup: yes 66 | become: yes 67 | when: EDB_REPO_USER is defined and EDB_REPO_USER 68 | 69 | - name: Force a dnf cache update to ensure keys are installed 70 | command: dnf -y makecache 71 | become: yes 72 | 73 | - name: Ensure required packages are installed 74 | dnf: 75 | name: 76 | - bison 77 | - bzip2 78 | - chrony 79 | - clang 80 | - dbt2-common 81 | - dbt2-pg{{ POSTGRES_DB_VERSION }}-extensions 82 | - firewalld 83 | - flex 84 | - gcc 85 | - git 86 | - krb5-devel 87 | - libicu-devel 88 | - libpq 89 | - libuuid-devel 90 | - libxml2-devel 91 | - libxslt-devel 92 | - lvm2 93 | - llvm-devel 94 | - make 95 | - mdadm 96 | - nano 97 | - net-tools 98 | - numactl 99 | - openldap-devel 100 | - openssl-devel 101 | - pam-devel 102 | - perf 103 | - perl-devel 104 | - perl-ExtUtils-Embed 105 | - postgresql{{ POSTGRES_DB_VERSION }}-contrib 106 | - postgresql{{ POSTGRES_DB_VERSION }}-devel 107 | - postgresql{{ POSTGRES_DB_VERSION }}-server 108 | - postgresql{{ POSTGRES_DB_VERSION }}-contrib-debuginfo 109 | - postgresql{{ POSTGRES_DB_VERSION }}-devel-debuginfo 110 | - postgresql{{ POSTGRES_DB_VERSION }}-server-debuginfo 111 | - psmisc 112 | - python3-devel 113 | - python3-firewall 114 | - R-core 115 | - readline-devel 116 | - sysstat 117 | - systemd-devel 118 | - tar 119 | - tcl-devel 120 | - tmux 121 | - tuned 122 | - zlib-devel 123 | state: latest 124 | update_cache: yes 125 | become: yes 126 | 127 | - name: Ensure required packages are installed (EDB) 128 | dnf: 129 | name: 130 | - edb-as{{ POSTGRES_DB_VERSION }}-server 131 | - edb-as{{ POSTGRES_DB_VERSION }}-server-devel 132 | - edb-as{{ POSTGRES_DB_VERSION }}-server-contrib 133 | state: latest 134 | update_cache: yes 135 | become: yes 136 | when: EDB_REPO_USER is defined and EDB_REPO_USER 137 | 138 | - name: Start chronyd 139 | service: 140 | name: chronyd 141 | enabled: yes 142 | state: started 143 | become: yes 144 | 145 | - name: Create sysstat timer override directory 146 | file: 147 | path: /etc/systemd/system/sysstat-collect.timer.d 148 | state: directory 149 | become: yes 150 | 151 | - name: Configure sysstat to run every minute 152 | copy: 153 | dest: /etc/systemd/system/sysstat-collect.timer.d/override.conf 154 | content: | 155 | [Timer] 156 | OnCalendar= # Clear previous definition 157 | OnCalendar=*:*:00 158 | become: yes 159 | 160 | - name: Start sysstat for sar data 161 | service: 162 | name: sysstat 163 | enabled: yes 164 | daemon_reload: yes 165 | state: started 166 | become: yes 167 | 168 | - name: Install HammerDB 169 | unarchive: 170 | src: https://github.com/TPC-Council/HammerDB/releases/download/v4.3/HammerDB-4.3-Linux.tar.gz 171 | dest: /usr/local/ 172 | owner: root 173 | group: root 174 | remote_src: yes 175 | become: yes 176 | 177 | - name: Create data dump directory 178 | file: 179 | path: ~/pgsql/dump 180 | state: directory 181 | 182 | - hosts: 183 | - all 184 | 185 | roles: 186 | - role: geerlingguy.node_exporter 187 | node_exporter_options: --collector.vmstat.fields='.*' 188 | become: yes 189 | 190 | tasks: 191 | - name: Open the node_exporter port 192 | firewalld: 193 | zone: public 194 | port: 9100/tcp 195 | permanent: yes 196 | immediate: yes 197 | state: enabled 198 | become: yes 199 | ignore_errors: yes 200 | 201 | - hosts: 202 | - benchmark 203 | roles: 204 | - common 205 | 206 | tasks: 207 | - name: Open the PostgreSQL port 208 | firewalld: 209 | zone: public 210 | port: 5432/tcp 211 | permanent: yes 212 | immediate: yes 213 | state: enabled 214 | become: yes 215 | ignore_errors: yes 216 | 217 | - name: Open the EPAS port 218 | firewalld: 219 | zone: public 220 | port: 5444/tcp 221 | permanent: yes 222 | immediate: yes 223 | state: enabled 224 | become: yes 225 | ignore_errors: yes 226 | when: EDB_REPO_USER is defined and EDB_REPO_USER 227 | 228 | - name: Create tuned profile directory 229 | file: 230 | path: /etc/tuned/postgres 231 | owner: root 232 | group: root 233 | mode: '0755' 234 | state: directory 235 | become: yes 236 | notify: Restart server 237 | 238 | - name: Create tuned profile 239 | copy: 240 | dest: /etc/tuned/postgres/tuned.conf 241 | content: | 242 | [main] 243 | summary=Tuned profile for PostgreSQL Instances 244 | 245 | [bootloader] 246 | cmdline=transparent_hugepage=never 247 | 248 | [cpu] 249 | governor=performance 250 | energy_perf_bias=performance 251 | min_perf_pct=100 252 | 253 | [sysctl] 254 | vm.swappiness = 10 255 | vm.dirty_expire_centisecs = 500 256 | vm.dirty_writeback_centisecs = 250 257 | vm.dirty_ratio = 10 258 | vm.dirty_background_ratio = 3 259 | vm.overcommit_memory=2 260 | vm.overcommit_kbytes={{ ansible_memtotal_mb * 1024 }} 261 | net.ipv4.tcp_timestamps=0 262 | 263 | [vm] 264 | transparent_hugepages=never 265 | become: yes 266 | notify: Restart server 267 | 268 | - name: Start tuned 269 | service: 270 | name: tuned 271 | enabled: yes 272 | state: started 273 | become: yes 274 | notify: Restart server 275 | 276 | - name: Enable postgres tuned profile 277 | shell: tuned-adm profile postgres && touch /etc/tuned/.postgres-profile 278 | args: 279 | creates: /etc/tuned/.postgres-profile 280 | become: yes 281 | notify: Restart server 282 | 283 | - name: Determine if local tasks exist 284 | local_action: stat path=../../ansible-local/hooks/config-system.yml 285 | register: local_config_system 286 | 287 | - name: Calling config_system hook 288 | debug: 289 | msg: "{{ 'Loading additional tasks from ../../ansible-local/hooks/config_system.yml' if local_config_system.stat.exists else 'Local config_system not found.' }}" 290 | 291 | - include_tasks: ../../ansible-local/hooks/config-system.yml 292 | when: local_config_system.stat.exists 293 | 294 | handlers: 295 | - name: Restart server 296 | reboot: 297 | become: yes 298 | -------------------------------------------------------------------------------- /playbooks/init-dbt2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: 4 | - benchmark 5 | 6 | roles: 7 | - common 8 | 9 | tasks: 10 | 11 | - include_tasks: tools/start-postgres.yml 12 | 13 | - name: Generate a database ID 14 | set_fact: 15 | db_id: "dbt2-s{{ DBT2_WORKLOAD_NUMBER_OF_WAREHOUSES }}" 16 | 17 | - name: "Check the status of the {{ db_id }} backup" 18 | stat: 19 | path: "~/pgsql/dump/{{ db_id }}.tar.gz" 20 | register: dump_file 21 | 22 | - name: Ensure dbt2 of proper scale exists 23 | block: 24 | - name: Drop any existing dbt2 database 25 | command: "{{ postgres_bin }}/dropdb --if-exists -h /tmp dbt2" 26 | 27 | - name: Create dbt2 profile 28 | copy: 29 | dest: "~/dbt2_profile.conf" 30 | content: | 31 | # PostgreSQL variables 32 | PGUSER={{ ansible_user_id }}; export PGUSER 33 | PGPORT={{ postgres_port }}; export PGPORT 34 | PGPASSWORD={{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}; export PGPASSWORD 35 | PGHOST={{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }}; export PGHOST 36 | 37 | # dbt2 variables 38 | DBT2DBNAME=dbt2; export DBT2DBNAME 39 | DBT2PORT={{ postgres_port }}; export DBT2PORT 40 | DBT2PGDATA=~/pgsql/data; export DBT2PGDATA 41 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 42 | 43 | - name: Create dbt2 database 44 | command: "{{ postgres_bin }}/createdb -h /tmp dbt2" 45 | 46 | - name: Create dbt2 schema 47 | shell: | 48 | echo "Creating dbt2..." 49 | source ~/dbt2_profile.conf; PRIVILEGED=0 PATH={{ postgres_bin }}/:$PATH; dbt2-pgsql-build-db -u -w {{ DBT2_WORKLOAD_NUMBER_OF_WAREHOUSES }} -r 50 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 51 | environment: 52 | PGPASSWORD: "{{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}" 53 | 54 | - include_tasks: tools/backup-postgres.yml 55 | 56 | when: not dump_file.stat.exists 57 | 58 | - include_tasks: tools/restore-postgres.yml 59 | when: dump_file.stat.exists 60 | 61 | - name: Create extensions 62 | include_role: 63 | name: create-extensions 64 | vars: 65 | database: dbt2 66 | -------------------------------------------------------------------------------- /playbooks/init-pgbench.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: 4 | - benchmark 5 | 6 | roles: 7 | - common 8 | 9 | tasks: 10 | 11 | - include_tasks: tools/start-postgres.yml 12 | 13 | - name: Generate a database ID 14 | set_fact: 15 | db_id: "pgbench-s{{ PGBENCH_SCALE_FACTOR }}" 16 | 17 | - name: "Check the status of the {{ db_id }} backup" 18 | stat: 19 | path: "~/pgsql/dump/{{ db_id }}.tar.gz" 20 | register: dump_file 21 | 22 | - name: Ensure pgbench of proper scale exists 23 | block: 24 | - name: Drop any existing pgbench database 25 | command: "{{ postgres_bin }}/dropdb --if-exists -h /tmp pgbench" 26 | 27 | - name: Create pgbench database 28 | command: "{{ postgres_bin }}/createdb -h /tmp pgbench" 29 | 30 | - name: Create pgbench schema 31 | shell: | 32 | echo "Creating schema using pgbench..." 33 | {{ postgres_bin }}/pgbench -h {{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }} -i -s {{ PGBENCH_SCALE_FACTOR }} pgbench 34 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 35 | environment: 36 | PGPASSWORD: "{{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}" 37 | 38 | - include_tasks: tools/backup-postgres.yml 39 | 40 | when: not dump_file.stat.exists 41 | 42 | - include_tasks: tools/restore-postgres.yml 43 | when: dump_file.stat.exists 44 | 45 | - name: Create extensions 46 | include_role: 47 | name: create-extensions 48 | vars: 49 | database: pgbench 50 | -------------------------------------------------------------------------------- /playbooks/init-postgres.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: driver 3 | name: Gather facts from drivers 4 | tasks: [ ] 5 | 6 | - hosts: 7 | - benchmark 8 | roles: 9 | - common 10 | 11 | tasks: 12 | - name: Run initdb 13 | command: "{{ postgres_bin }}/initdb -D ~/pgsql/data" 14 | args: 15 | creates: ~/pgsql/data/PG_VERSION 16 | 17 | - name: Set the socket directory 18 | shell: | 19 | echo "unix_socket_directories = '/tmp'" >> ~/pgsql/data/postgresql.conf 20 | touch ~/pgsql/data/.postgres-socket 21 | args: 22 | creates: ~/pgsql/data/.postgres-socket 23 | 24 | - name: Enable TCP/IP connections if we're using a separate driver 25 | shell: | 26 | echo "listen_addresses = '*'" >> ~/pgsql/data/postgresql.conf 27 | touch ~/pgsql/data/.postgres-tcpip 28 | args: 29 | creates: ~/pgsql/data/.postgres-tcpip 30 | when: hostvars[inventory_hostname].driver is defined 31 | 32 | - name: Allow access to the benchmark machine from the driver if required 33 | shell: | 34 | echo "host all all {{ hostvars[hostvars[inventory_hostname].driver].ansible_default_ipv4.address }}/32 scram-sha-256" >> ~/pgsql/data/pg_hba.conf 35 | touch ~/pgsql/data/.postgres-pghba 36 | args: 37 | creates: ~/pgsql/data/.postgres-pghba 38 | when: hostvars[inventory_hostname].driver is defined 39 | 40 | - name: Determine if local tasks exist 41 | local_action: stat path=../../ansible-local/hooks/init-postgres.yml 42 | register: local_init_postgres 43 | 44 | - name: Calling init_postgres hook 45 | debug: 46 | msg: "{{ 'Loading additional tasks from ../../ansible-local/hooks/init_postgres.yml' if local_init_postgres.stat.exists else 'Local init_postgres not found.' }}" 47 | 48 | - include_tasks: ../../ansible-local/hooks/init-postgres.yml 49 | when: local_init_postgres.stat.exists 50 | 51 | - include_tasks: tools/start-postgres.yml 52 | 53 | - name: Set the {{ ansible_user_id }} role password 54 | shell: | 55 | {{ postgres_bin }}/psql -h /tmp -c "ALTER ROLE {{ ansible_user_id }} PASSWORD '{{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}' ;" postgres 56 | when: hostvars[inventory_hostname].driver is defined 57 | 58 | - include_tasks: tools/stop-postgres.yml -------------------------------------------------------------------------------- /playbooks/init-tprocc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: 4 | - benchmark 5 | roles: 6 | - common 7 | 8 | tasks: 9 | - include_tasks: tools/start-postgres.yml 10 | 11 | - name: Generate a database ID 12 | set_fact: 13 | db_id: "tprocc-w{{ TPROCC_WAREHOUSES }}-p{{ TPROCC_PARTITION }}-d{{ TPROCC_DRITA_SNAPS }}-o{{ TPROCC_ORACLE_COMPAT }}-s{{ TPROCC_STORED_PROCS }}" 14 | 15 | - name: "Check the status of the {{ db_id }} backup" 16 | stat: 17 | path: "~/pgsql/dump/{{ db_id }}.tar.gz" 18 | register: dump_file 19 | 20 | - name: Ensure tprocc of proper scale exists 21 | block: 22 | - name: Drop any existing tprocc database 23 | command: "{{ postgres_bin }}/dropdb --if-exists -h /tmp tprocc" 24 | 25 | - name: Create schema build script 26 | copy: 27 | dest: "~/tprocc-schema.tcl" 28 | content: | 29 | dbset db pg 30 | dbset bm TPC-C 31 | 32 | dgset vu {{ ansible_processor_cores }} 33 | 34 | diset connection pg_host {{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }} 35 | diset connection pg_port {{ postgres_port }} 36 | diset tpcc pg_superuser {{ ansible_user_id }} 37 | diset tpcc pg_superuserpass {{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }} 38 | diset tpcc pg_defaultdbase postgres 39 | diset tpcc pg_user {{ ansible_user_id }} 40 | diset tpcc pg_pass {{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }} 41 | diset tpcc pg_dbase tprocc 42 | 43 | diset tpcc pg_count_ware {{ TPROCC_WAREHOUSES }} 44 | diset tpcc pg_num_vu {{ TPROCC_SCHEMA_USERS }} 45 | diset tpcc pg_partition {{ TPROCC_PARTITION }} 46 | diset tpcc pg_oracompat {{ TPROCC_ORACLE_COMPAT }} 47 | diset tpcc pg_storedprocs {{ TPROCC_STORED_PROCS }} 48 | 49 | print dict 50 | buildschema 51 | waittocomplete 52 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 53 | 54 | - name: Create tprocc database and schema 55 | shell: | 56 | echo "Creating schema using HammerDB..." 57 | ./hammerdbcli auto ~/tprocc-schema.tcl 58 | args: 59 | chdir: /usr/local/HammerDB-4.3 60 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 61 | 62 | - name: Create pg_prewarm extension 63 | command: | 64 | {{ postgres_bin }}/psql -h /tmp -c "CREATE EXTENSION IF NOT EXISTS pg_prewarm;" tprocc 65 | 66 | - include_tasks: tools/backup-postgres.yml 67 | 68 | when: not dump_file.stat.exists 69 | 70 | - include_tasks: tools/restore-postgres.yml 71 | when: dump_file.stat.exists 72 | 73 | - name: Create extensions 74 | include_role: 75 | name: create-extensions 76 | vars: 77 | database: tprocc 78 | -------------------------------------------------------------------------------- /playbooks/init-tproch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: 4 | - benchmark 5 | roles: 6 | - common 7 | 8 | tasks: 9 | - include_tasks: tools/start-postgres.yml 10 | 11 | - name: Generate a database ID 12 | set_fact: 13 | db_id: "tproch-s{{ TPROCH_SCALE_FACTOR }}" 14 | 15 | - name: "Check the status of the {{ db_id }} backup" 16 | stat: 17 | path: "~/pgsql/dump/{{ db_id }}.tar.gz" 18 | register: dump_file 19 | 20 | - name: Ensure tproch of proper scale exists 21 | block: 22 | - name: Drop any existing tproch database 23 | command: "{{ postgres_bin }}/dropdb --if-exists -h /tmp tproch" 24 | 25 | - name: Create schema build script 26 | copy: 27 | dest: "~/tproch-schema.tcl" 28 | content: | 29 | dbset db pg 30 | dbset bm TPC-H 31 | 32 | diset connection pg_host {{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }} 33 | diset connection pg_port {{ postgres_port }} 34 | diset tpch pg_tpch_superuser {{ ansible_user_id }} 35 | diset tpch pg_tpch_superuserpass {{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }} 36 | diset tpch pg_tpch_defaultdbase postgres 37 | diset tpch pg_tpch_user {{ ansible_user_id }} 38 | diset tpch pg_tpch_pass {{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }} 39 | diset tpch pg_tpch_dbase tproch 40 | 41 | diset tpch pg_scale_fact {{ TPROCH_SCALE_FACTOR }} 42 | diset tpch pg_num_tpch_threads {{ TPROCH_THREADS }} 43 | 44 | print dict 45 | buildschema 46 | waittocomplete 47 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 48 | 49 | - name: Create tproch database and schema 50 | shell: | 51 | echo "Creating schema using HammerDB..." 52 | ./hammerdbcli auto ~/tproch-schema.tcl 53 | args: 54 | chdir: /usr/local/HammerDB-4.3 55 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 56 | 57 | - include_tasks: tools/backup-postgres.yml 58 | 59 | when: not dump_file.stat.exists 60 | 61 | - include_tasks: tools/restore-postgres.yml 62 | when: dump_file.stat.exists 63 | 64 | - name: Create extensions 65 | include_role: 66 | name: create-extensions 67 | vars: 68 | database: tproch -------------------------------------------------------------------------------- /playbooks/roles/common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Set Variables for Postgres DB Type 4 | set_fact: 5 | postgres_port: 5432 6 | postgres_user: postgres 7 | postgres_bin: "/usr/pgsql-{{ POSTGRES_DB_VERSION }}/bin" 8 | when: POSTGRES_DB_TYPE == 'postgres' 9 | 10 | - name: Set Variables for EPAS DB Type 11 | set_fact: 12 | postgres_port: 5444 13 | postgres_user: enterprisedb 14 | postgres_bin: "/usr/edb/as{{ POSTGRES_DB_VERSION }}/bin" 15 | when: POSTGRES_DB_TYPE == 'epas' 16 | 17 | - name: Determine if local config exists 18 | local_action: stat path=../../ansible-local/hooks/config.yml 19 | register: local_config 20 | 21 | - name: Calling config hook 22 | debug: 23 | msg: "{{ 'Loading additional config from ../../ansible-local/hooks/config.yml' if local_config.stat.exists else 'Local config not found.' }}" 24 | 25 | - include_vars: ../../ansible-local/hooks/config.yml 26 | when: local_config.stat.exists 27 | -------------------------------------------------------------------------------- /playbooks/roles/common/vars/main.yml: -------------------------------------------------------------------------------- 1 | ../../../../config.yml -------------------------------------------------------------------------------- /playbooks/roles/create-extensions/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create pg_prewarm extension 3 | shell: | 4 | {{ postgres_bin }}/psql -h /tmp -c "CREATE EXTENSION IF NOT EXISTS pg_prewarm;" {{ database }} 5 | 6 | - name: Determine if local tasks exist 7 | local_action: stat path=../../ansible-local/hooks/create-extensions.yml 8 | register: local_create_extensions 9 | 10 | - name: Calling create_extensions hook 11 | debug: 12 | msg: "{{ 'Loading additional tasks from ../../ansible-local/hooks/create_extensions.yml' if local_create_extensions.stat.exists else 'Local create_extensions not found.' }}" 13 | 14 | - include_tasks: ../../ansible-local/hooks/create-extensions.yml 15 | when: local_create_extensions.stat.exists 16 | -------------------------------------------------------------------------------- /playbooks/roles/log-stats/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Record the server stats 4 | shell: | 5 | echo "" >> {{ log_file }} 6 | echo "PostgreSQL config" >> {{ log_file }} 7 | echo "================================================================================" >> {{ log_file }} 8 | echo "" >> {{ log_file }} 9 | 10 | {{ postgres_bin }}/psql -h {{ host }} -c "SHOW ALL;" {{ database }} >> {{ log_file }} 11 | 12 | echo "" >> {{ log_file }} 13 | echo "Database info" >> {{ log_file }} 14 | echo "================================================================================" >> {{ log_file }} 15 | echo "" >> {{ log_file }} 16 | 17 | {{ postgres_bin }}/psql -h {{ host }} -c "SELECT oid, datname, pg_size_pretty(pg_database_size(oid)) as size FROM pg_database;" {{ database }} >> {{ log_file }} 18 | 19 | echo "" >> {{ log_file }} 20 | echo "Table info" >> {{ log_file }} 21 | echo "================================================================================" >> {{ log_file }} 22 | echo "" >> {{ log_file }} 23 | 24 | {{ postgres_bin }}/psql -h {{ host }} -c "SELECT c.oid, nspname AS namespace, relname AS tblname, pg_size_pretty(pg_table_size(c.oid)) as size FROM pg_class c, pg_namespace n WHERE c.relnamespace = n.oid AND relkind = 'r' AND nspname != 'pg_catalog' AND nspname != 'pg_toast' AND nspname != 'information_schema';" {{ database }} >> {{ log_file }} 25 | 26 | echo "" >> {{ log_file }} 27 | echo "Index info" >> {{ log_file }} 28 | echo "================================================================================" >> {{ log_file }} 29 | echo "" >> {{ log_file }} 30 | 31 | {{ postgres_bin }}/psql -h {{ host }} -c "SELECT c.oid, nspname AS namespace, relname AS tblname, pg_size_pretty(pg_table_size(c.oid)) as size FROM pg_class c, pg_namespace n WHERE c.relnamespace = n.oid AND relkind = 'i' AND nspname != 'pg_catalog' AND nspname != 'pg_toast' AND nspname != 'information_schema';" {{ database }} >> {{ log_file }} 32 | 33 | echo "" >> {{ log_file }} 34 | echo "pg_stat_database" >> {{ log_file }} 35 | echo "================================================================================" >> {{ log_file }} 36 | echo "" >> {{ log_file }} 37 | 38 | {{ postgres_bin }}/psql -h {{ host }} -c "SELECT * FROM pg_stat_database;" {{ database }} >> {{ log_file }} 39 | 40 | echo "" >> {{ log_file }} 41 | echo "pg_stat_user_tables" >> {{ log_file }} 42 | echo "================================================================================" >> {{ log_file }} 43 | echo "" >> {{ log_file }} 44 | 45 | {{ postgres_bin }}/psql -h {{ host }} -c "SELECT * FROM pg_stat_user_tables;" {{ database }} >> {{ log_file }} 46 | 47 | echo "" >> {{ log_file }} 48 | echo "pg_stat_user_indexes" >> {{ log_file }} 49 | echo "================================================================================" >> {{ log_file }} 50 | echo "" >> {{ log_file }} 51 | 52 | {{ postgres_bin }}/psql -h {{ host }} -c "SELECT * FROM pg_stat_user_indexes;" {{ database }} >> {{ log_file }} 53 | 54 | echo "" >> {{ log_file }} 55 | echo "pg_statio_user_tables" >> {{ log_file }} 56 | echo "================================================================================" >> {{ log_file }} 57 | echo "" >> {{ log_file }} 58 | 59 | {{ postgres_bin }}/psql -h {{ host }} -c "SELECT * FROM pg_statio_user_tables;" {{ database }} >> {{ log_file }} 60 | 61 | echo "" >> {{ log_file }} 62 | echo "pg_statio_user_indexes" >> {{ log_file }} 63 | echo "================================================================================" >> {{ log_file }} 64 | echo "" >> {{ log_file }} 65 | 66 | {{ postgres_bin }}/psql -h {{ host }} -c "SELECT * FROM pg_statio_user_indexes;" {{ database }} >> {{ log_file }} 67 | 68 | echo "" >> {{ log_file }} 69 | echo "pg_stat_bgwriter" >> {{ log_file }} 70 | echo "================================================================================" >> {{ log_file }} 71 | echo "" >> {{ log_file }} 72 | 73 | {{ postgres_bin }}/psql -h {{ host }} -c "SELECT * FROM pg_stat_bgwriter;" {{ database }} >> {{ log_file }} 74 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 75 | environment: 76 | PGPASSWORD: "{{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}" 77 | 78 | - name: Determine if local tasks exist 79 | local_action: stat path=../../ansible-local/hooks/log-stats.yml 80 | register: local_log_stats 81 | 82 | - name: Calling log_stats hook 83 | debug: 84 | msg: "{{ 'Loading additional tasks from ../../ansible-local/hooks/log-stats.yml' if local_log_stats.stat.exists else 'Local log-stats not found.' }}" 85 | 86 | - include_tasks: ../../ansible-local/hooks/log-stats.yml 87 | when: local_log_stats.stat.exists 88 | -------------------------------------------------------------------------------- /playbooks/run-dbt2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 3 | - benchmark 4 | gather_facts: no 5 | 6 | roles: 7 | - common 8 | 9 | tasks: 10 | - include_tasks: tools/stop-postgres.yml 11 | when: DBT2_CLEAR_CACHE_AND_PREWARM 12 | 13 | - name: Clear kernel cache and swap 14 | shell: | 15 | sync 16 | echo 3 > /proc/sys/vm/drop_caches 17 | swapoff -a 18 | swapon -a 19 | become: yes 20 | when: DBT2_CLEAR_CACHE_AND_PREWARM 21 | 22 | - hosts: 23 | - benchmark 24 | 25 | roles: 26 | - common 27 | 28 | tasks: 29 | 30 | - include_tasks: tools/start-postgres.yml 31 | 32 | - name: Generate the run log name 33 | set_fact: 34 | run_log: "~/pgsql/data/dbt2-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-d{{ DBT2_WORKLOAD_TEST_DURATION }}-w{{ DBT2_WORKLOAD_NUMBER_OF_WAREHOUSES }}.log" 35 | 36 | - name: Run log names 37 | debug: 38 | msg: "{{ run_log }}" 39 | 40 | - name: Make sure we have a directory for the log file if using a driver machine 41 | file: 42 | path: ~/pgsql/data/ 43 | state: directory 44 | when: hostvars[inventory_hostname].driver is defined 45 | delegate_to: "{{ hostvars[inventory_hostname].driver }}" 46 | 47 | - name: Clear out any old files that may be present on drivers 48 | shell: rm -f ~/pgsql/data/* 49 | when: hostvars[inventory_hostname].driver is defined 50 | delegate_to: "{{ hostvars[inventory_hostname].driver }}" 51 | 52 | - name: Record the config 53 | shell: | 54 | echo "################################################################################" >> {{ run_log }} 55 | echo "Run started: $(date)" >> {{ run_log }} 56 | echo "################################################################################" >> {{ run_log }} 57 | echo "" >> {{ run_log }} 58 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 59 | 60 | - name: Log pre-run stats 61 | include_role: 62 | name: log-stats 63 | vars: 64 | log_file: "{{ run_log }}" 65 | database: dbt2 66 | host: "{{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else 'localhost' }}" 67 | 68 | - name: Generate the buffercache log name 69 | set_fact: 70 | buffercache_log: "~/pgsql/data/dbt2-buffercache-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-d{{ DBT2_WORKLOAD_TEST_DURATION }}-w{{ DBT2_WORKLOAD_NUMBER_OF_WAREHOUSES }}.csv" 71 | when: MONITOR_PG_BUFFERCACHE 72 | 73 | - name: Start monitoring pg_buffercache 74 | include_tasks: tools/start-buffercache-monitor.yml 75 | when: MONITOR_PG_BUFFERCACHE 76 | 77 | - name: Generate the pg_stat_database log name 78 | set_fact: 79 | pgstatdb_log: "~/pgsql/data/dbt2-pgstatdb-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-d{{ DBT2_WORKLOAD_TEST_DURATION }}-w{{ DBT2_WORKLOAD_NUMBER_OF_WAREHOUSES }}.csv" 80 | when: MONITOR_PG_STAT_DATABASE 81 | 82 | - name: Start monitoring pg_stat_database 83 | include_tasks: tools/start-pgstatdb-monitor.yml 84 | when: MONITOR_PG_STAT_DATABASE 85 | 86 | - name: Log prewarm start time 87 | shell: | 88 | echo "################################################################################" >> {{ run_log }} 89 | echo "Pre-warm started: $(date)" >> {{ run_log }} 90 | echo "################################################################################" >> {{ run_log }} 91 | echo "" >> {{ run_log }} 92 | when: DBT2_CLEAR_CACHE_AND_PREWARM 93 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 94 | 95 | - name: Prewarm the database 96 | command: | 97 | {{ postgres_bin }}/psql -h localhost -c "SELECT relname, pg_prewarm(c.oid::regclass) FROM pg_class c WHERE relname LIKE 'dbt2_%' AND (c.relkind = 'r' OR c.relkind = 'i');" dbt2 98 | when: DBT2_CLEAR_CACHE_AND_PREWARM 99 | 100 | - name: Log benchmark start time 101 | shell: | 102 | echo "################################################################################" >> {{ run_log }} 103 | echo "Benchmark started: $(date)" >> {{ run_log }} 104 | echo "################################################################################" >> {{ run_log }} 105 | echo "" >> {{ run_log }} 106 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 107 | 108 | - name: Run the dbt2 driver 109 | shell: "time (dbt2-driver3 -a pgsql -b dbt2 -d {{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }} -l {{ DBT2_WORKLOAD_TEST_DURATION }} -wmin 1 -wmax {{ DBT2_WORKLOAD_NUMBER_OF_WAREHOUSES }} -w {{ DBT2_WORKLOAD_NUMBER_OF_WAREHOUSES }} -outdir ~/pgsql/data -altered 1 -ktd 0 -ktn 0 -kto 0 -ktp 0 -kts 0 -ttd 0 -ttn 0 -tto 0 -ttp 0 -tts 0 > /dev/null) >> {{ run_log }} 2>&1" 110 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 111 | environment: 112 | PGPASSWORD: "{{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}" 113 | 114 | - name: Post-process the DBT2 results 115 | shell: echo "" >> {{ run_log }} && bash -c 'dbt2-post-process $(find ~/pgsql/data/ -maxdepth 1 -name mix*.log -size +0 -print) >> {{ run_log }}' 116 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 117 | 118 | - name: Record the stats 119 | shell: | 120 | echo "" >> {{ run_log }} 121 | echo "################################################################################" >> {{ run_log }} 122 | echo "Benchmark completed: $(date)" >> {{ run_log }} 123 | echo "################################################################################" >> {{ run_log }} 124 | echo "" >> {{ run_log }} 125 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 126 | 127 | - name: Stop monitoring pg_buffercache 128 | include_tasks: tools/stop-buffercache-monitor.yml 129 | when: MONITOR_PG_BUFFERCACHE 130 | 131 | - name: Stop monitoring pg_stat_database 132 | include_tasks: tools/stop-pgstatdb-monitor.yml 133 | when: MONITOR_PG_STAT_DATABASE 134 | 135 | - name: Log post-run stats 136 | include_role: 137 | name: log-stats 138 | vars: 139 | log_file: "{{ run_log }}" 140 | database: dbt2 141 | host: "{{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else 'localhost' }}" 142 | 143 | - name: Download results 144 | fetch: 145 | src: "{{ run_log }}" 146 | dest: ../results/ 147 | flat: yes 148 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 149 | -------------------------------------------------------------------------------- /playbooks/run-pgbench.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 3 | - benchmark 4 | gather_facts: no 5 | 6 | roles: 7 | - common 8 | 9 | tasks: 10 | - include_tasks: tools/stop-postgres.yml 11 | when: PGBENCH_CLEAR_CACHE_AND_PREWARM 12 | 13 | - name: Clear kernel cache and swap 14 | shell: | 15 | sync 16 | echo 3 > /proc/sys/vm/drop_caches 17 | swapoff -a 18 | swapon -a 19 | become: yes 20 | when: PGBENCH_CLEAR_CACHE_AND_PREWARM 21 | 22 | - hosts: 23 | - benchmark 24 | 25 | roles: 26 | - common 27 | 28 | tasks: 29 | 30 | - include_tasks: tools/start-postgres.yml 31 | 32 | - name: Generate the run log name 33 | set_fact: 34 | run_log: "~/pgsql/data/pgbench-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-s{{ PGBENCH_SCALE_FACTOR }}-c{{ PGBENCH_CLIENTS }}-T{{ PGBENCH_RUN_TIME }}.log" 35 | 36 | - name: Run log names 37 | debug: 38 | msg: "{{ run_log }}" 39 | 40 | - name: Make sure we have a directory for the log file if using a driver machine 41 | file: 42 | path: ~/pgsql/data/ 43 | state: directory 44 | when: hostvars[inventory_hostname].driver is defined 45 | delegate_to: "{{ hostvars[inventory_hostname].driver }}" 46 | 47 | - name: Clear out any old files that may be present on drivers 48 | shell: rm -f ~/pgsql/data/* 49 | when: hostvars[inventory_hostname].driver is defined 50 | delegate_to: "{{ hostvars[inventory_hostname].driver }}" 51 | 52 | - name: Record the config 53 | shell: | 54 | echo "################################################################################" >> {{ run_log }} 55 | echo "Run started: $(date)" >> {{ run_log }} 56 | echo "################################################################################" >> {{ run_log }} 57 | echo "" >> {{ run_log }} 58 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 59 | 60 | - name: Log pre-run stats 61 | include_role: 62 | name: log-stats 63 | vars: 64 | log_file: "{{ run_log }}" 65 | database: pgbench 66 | host: "{{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }}" 67 | 68 | - name: Generate the buffercache log name 69 | set_fact: 70 | buffercache_log: "~/pgsql/data/pgbench-buffercache-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-s{{ PGBENCH_SCALE_FACTOR }}-c{{ PGBENCH_CLIENTS }}-T{{ PGBENCH_RUN_TIME }}.csv" 71 | when: MONITOR_PG_BUFFERCACHE 72 | 73 | - name: Start monitoring pg_buffercache 74 | include_tasks: tools/start-buffercache-monitor.yml 75 | when: MONITOR_PG_BUFFERCACHE 76 | 77 | - name: Generate the pg_stat_database log name 78 | set_fact: 79 | pgstatdb_log: "~/pgsql/data/pgbench-pgstatdb-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-s{{ PGBENCH_SCALE_FACTOR }}-c{{ PGBENCH_CLIENTS }}-T{{ PGBENCH_RUN_TIME }}.csv" 80 | when: MONITOR_PG_STAT_DATABASE 81 | 82 | - name: Start monitoring pg_stat_database 83 | include_tasks: tools/start-pgstatdb-monitor.yml 84 | when: MONITOR_PG_STAT_DATABASE 85 | 86 | - name: Log prewarm start time 87 | shell: | 88 | echo "################################################################################" >> {{ run_log }} 89 | echo "Pre-warm started: $(date)" >> {{ run_log }} 90 | echo "################################################################################" >> {{ run_log }} 91 | echo "" >> {{ run_log }} 92 | when: PGBENCH_CLEAR_CACHE_AND_PREWARM 93 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 94 | 95 | - name: Prewarm the database 96 | command: | 97 | {{ postgres_bin }}/psql -h /tmp -c "SELECT relname, pg_prewarm(c.oid::regclass) FROM pg_class c WHERE relname LIKE 'pgbench_%' AND (c.relkind = 'r' OR c.relkind = 'i');" pgbench 98 | when: PGBENCH_CLEAR_CACHE_AND_PREWARM 99 | 100 | - name: Log benchmark start time 101 | shell: | 102 | echo "################################################################################" >> {{ run_log }} 103 | echo "Benchmark started: $(date)" >> {{ run_log }} 104 | echo "################################################################################" >> {{ run_log }} 105 | echo "" >> {{ run_log }} 106 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 107 | 108 | - name: Run pgbench 109 | shell: "time ({{ postgres_bin }}/pgbench -h {{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }} -c {{ PGBENCH_CLIENTS }} -T {{ PGBENCH_RUN_TIME }} pgbench >> {{ run_log }}) >> {{ run_log }} 2>&1" 110 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 111 | environment: 112 | PGPASSWORD: "{{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}" 113 | 114 | - name: Record the stats 115 | shell: | 116 | echo "" >> {{ run_log }} 117 | echo "################################################################################" >> {{ run_log }} 118 | echo "Benchmark completed: $(date)" >> {{ run_log }} 119 | echo "################################################################################" >> {{ run_log }} 120 | echo "" >> {{ run_log }} 121 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 122 | 123 | - name: Stop monitoring pg_buffercache 124 | include_tasks: tools/stop-buffercache-monitor.yml 125 | when: MONITOR_PG_BUFFERCACHE 126 | 127 | - name: Stop monitoring pg_stat_database 128 | include_tasks: tools/stop-pgstatdb-monitor.yml 129 | when: MONITOR_PG_STAT_DATABASE 130 | 131 | - name: Log post-run stats 132 | include_role: 133 | name: log-stats 134 | vars: 135 | log_file: "{{ run_log }}" 136 | database: pgbench 137 | host: "{{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }}" 138 | 139 | - name: Download results 140 | fetch: 141 | src: "{{ run_log }}" 142 | dest: ../results/ 143 | flat: yes 144 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 145 | -------------------------------------------------------------------------------- /playbooks/run-tprocc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 3 | - benchmark 4 | gather_facts: no 5 | 6 | roles: 7 | - common 8 | 9 | tasks: 10 | - include_tasks: tools/stop-postgres.yml 11 | when: TPROCC_CLEAR_CACHE_AND_PREWARM 12 | 13 | - name: Clear kernel cache and swap 14 | shell: | 15 | sync 16 | echo 3 > /proc/sys/vm/drop_caches 17 | swapoff -a 18 | swapon -a 19 | become: yes 20 | when: TPROCC_CLEAR_CACHE_AND_PREWARM 21 | 22 | - hosts: 23 | - benchmark 24 | 25 | roles: 26 | - common 27 | 28 | tasks: 29 | - include_tasks: tools/start-postgres.yml 30 | 31 | - name: Create run script 32 | copy: 33 | dest: ~/tprocc-run.tcl 34 | content: | 35 | dbset db pg 36 | dbset bm TPC-C 37 | 38 | diset connection pg_host {{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }} 39 | diset connection pg_port {{ postgres_port }} 40 | diset tpcc pg_superuser {{ ansible_user_id }} 41 | diset tpcc pg_superuserpass {{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }} 42 | diset tpcc pg_defaultdbase postgres 43 | diset tpcc pg_user {{ ansible_user_id }} 44 | diset tpcc pg_pass {{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }} 45 | diset tpcc pg_dbase tprocc 46 | 47 | diset tpcc pg_driver timed 48 | diset tpcc pg_rampup {{ TPROCC_RAMPUP_TIME }} 49 | diset tpcc pg_duration {{ TPROCC_RUN_TIME }} 50 | diset tpcc pg_vacuum {{ TPROCC_VACUUM }} 51 | diset tpcc pg_dritasnap {{ TPROCC_DRITA_SNAPS }} 52 | diset tpcc pg_oracompat {{ TPROCC_ORACLE_COMPAT }} 53 | diset tpcc pg_storedprocs {{ TPROCC_STORED_PROCS }} 54 | diset tpcc pg_keyandthink {{ TPROCC_KEY_AND_THINK }} 55 | 56 | loadscript 57 | print dict 58 | 59 | vuset logtotemp 0 60 | vuset vu {{ TPROCC_VIRTUAL_USERS }} 61 | vucreate 62 | vurun 63 | waittocomplete 64 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 65 | 66 | - name: Generate the run log name 67 | set_fact: 68 | run_log: "~/pgsql/data/tprocc-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-w{{ TPROCC_WAREHOUSES }}-u{{ TPROCC_VIRTUAL_USERS }}.log" 69 | 70 | - name: Run log names 71 | debug: 72 | msg: "{{ run_log }}" 73 | 74 | - name: Make sure we have a directory for the log file if using a driver machine 75 | file: 76 | path: ~/pgsql/data/ 77 | state: directory 78 | when: hostvars[inventory_hostname].driver is defined 79 | delegate_to: "{{ hostvars[inventory_hostname].driver }}" 80 | 81 | - name: Clear out any old files that may be present on drivers 82 | shell: rm -f ~/pgsql/data/* 83 | when: hostvars[inventory_hostname].driver is defined 84 | delegate_to: "{{ hostvars[inventory_hostname].driver }}" 85 | 86 | - name: Record the config 87 | shell: | 88 | echo "################################################################################" >> {{ run_log }} 89 | echo "Run started: $(date)" >> {{ run_log }} 90 | echo "################################################################################" >> {{ run_log }} 91 | echo "" >> {{ run_log }} 92 | 93 | echo "Schema" >> {{ run_log }} 94 | echo "================================================================================" >> {{ run_log }} 95 | echo "" >> {{ run_log }} 96 | 97 | cat ~/tprocc-schema.tcl >> {{ run_log }} 98 | 99 | echo "Benchmark" >> {{ run_log }} 100 | echo "================================================================================" >> {{ run_log }} 101 | echo "" >> {{ run_log }} 102 | 103 | cat ~/tprocc-run.tcl >> {{ run_log }} 104 | echo "" >> {{ run_log }} 105 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 106 | 107 | - name: Log pre-run stats 108 | include_role: 109 | name: log-stats 110 | vars: 111 | log_file: "{{ run_log }}" 112 | database: tprocc 113 | host: "{{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }}" 114 | 115 | - name: Generate the buffercache log name 116 | set_fact: 117 | buffercache_log: "~/pgsql/data/tprocc-buffercache-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-w{{ TPROCC_WAREHOUSES }}-u{{ TPROCC_VIRTUAL_USERS }}.csv" 118 | when: MONITOR_PG_BUFFERCACHE 119 | 120 | - name: Start monitoring pg_buffercache 121 | include_tasks: tools/start-buffercache-monitor.yml 122 | when: MONITOR_PG_BUFFERCACHE 123 | 124 | - name: Generate the pg_stat_database log name 125 | set_fact: 126 | pgstatdb_log: "~/pgsql/data/tprocc-pgstatdb-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-w{{ TPROCC_WAREHOUSES }}-u{{ TPROCC_VIRTUAL_USERS }}.csv" 127 | when: MONITOR_PG_STAT_DATABASE 128 | 129 | - name: Start monitoring pg_stat_database 130 | include_tasks: tools/start-pgstatdb-monitor.yml 131 | when: MONITOR_PG_STAT_DATABASE 132 | 133 | - name: Log prewarm start time 134 | shell: | 135 | echo "################################################################################" >> {{ run_log }} 136 | echo "Pre-warm started: $(date)" >> {{ run_log }} 137 | echo "################################################################################" >> {{ run_log }} 138 | echo "" >> {{ run_log }} 139 | when: PGBENCH_CLEAR_CACHE_AND_PREWARM 140 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 141 | 142 | - name: Prewarm the database 143 | command: | 144 | {{ postgres_bin }}/psql -h /tmp -c "SELECT relname, pg_prewarm(c.oid::regclass) FROM pg_class c, pg_namespace n WHERE c.relnamespace = n.oid AND n.nspname = 'public' AND (c.relkind = 'r' OR c.relkind = 'i');" tprocc 145 | when: TPROCC_CLEAR_CACHE_AND_PREWARM 146 | 147 | - name: Log benchmark start time 148 | shell: | 149 | echo "################################################################################" >> {{ run_log }} 150 | echo "Benchmark started: $(date)" >> {{ run_log }} 151 | echo "################################################################################" >> {{ run_log }} 152 | echo "" >> {{ run_log }} 153 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 154 | 155 | - name: Run HammerDB (TPROC-C) 156 | shell: time (./hammerdbcli auto ~/tprocc-run.tcl >> {{ run_log }}) >> {{ run_log }} 2>&1 157 | args: 158 | chdir: /usr/local/HammerDB-4.3 159 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 160 | 161 | - name: Record the stats 162 | shell: | 163 | echo "" >> {{ run_log }} 164 | echo "################################################################################" >> {{ run_log }} 165 | echo "Benchmark completed: $(date)" >> {{ run_log }} 166 | echo "################################################################################" >> {{ run_log }} 167 | echo "" >> {{ run_log }} 168 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 169 | 170 | - name: Stop monitoring pg_buffercache 171 | include_tasks: tools/stop-buffercache-monitor.yml 172 | when: MONITOR_PG_BUFFERCACHE 173 | 174 | - name: Stop monitoring pg_stat_database 175 | include_tasks: tools/stop-pgstatdb-monitor.yml 176 | when: MONITOR_PG_STAT_DATABASE 177 | 178 | - name: Log post-run stats 179 | include_role: 180 | name: log-stats 181 | vars: 182 | log_file: "{{ run_log }}" 183 | database: tprocc 184 | host: "{{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }}" 185 | 186 | - name: Download results 187 | fetch: 188 | src: "{{ run_log }}" 189 | dest: ../results/ 190 | flat: yes 191 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 192 | -------------------------------------------------------------------------------- /playbooks/run-tproch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 3 | - benchmark 4 | gather_facts: no 5 | 6 | roles: 7 | - common 8 | 9 | tasks: 10 | - include_tasks: tools/stop-postgres.yml 11 | when: TPROCH_CLEAR_CACHE_AND_PREWARM 12 | 13 | - name: Clear kernel cache and swap 14 | shell: | 15 | sync 16 | echo 3 > /proc/sys/vm/drop_caches 17 | swapoff -a 18 | swapon -a 19 | become: yes 20 | when: TPROCH_CLEAR_CACHE_AND_PREWARM 21 | 22 | - hosts: 23 | - benchmark 24 | 25 | roles: 26 | - common 27 | 28 | tasks: 29 | - include_tasks: tools/start-postgres.yml 30 | 31 | - name: Create run script 32 | copy: 33 | dest: ~/tproch-run.tcl 34 | content: | 35 | dbset db pg 36 | dbset bm TPC-H 37 | 38 | diset connection pg_host {{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }} 39 | diset connection pg_port {{ postgres_port }} 40 | diset tpch pg_tpch_superuser {{ ansible_user_id }} 41 | diset tpch pg_tpch_superuserpass {{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }} 42 | diset tpch pg_tpch_defaultdbase postgres 43 | diset tpch pg_tpch_user {{ ansible_user_id }} 44 | diset tpch pg_tpch_pass {{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }} 45 | diset tpch pg_tpch_dbase tproch 46 | 47 | diset tpch pg_scale_fact {{ TPROCH_SCALE_FACTOR }} 48 | diset tpch pg_total_querysets {{ TPROCH_TOTAL_QUERYSETS }} 49 | diset tpch pg_refresh_on {{ TPROCH_REFRESH_ON }} 50 | diset tpch pg_degree_of_parallel {{ TPROCH_DEGREE_OF_PARALLEL }} 51 | diset tpch pg_update_sets {{ TPROCH_UPDATE_SETS }} 52 | diset tpch pg_trickle_refresh {{ TPROCH_TRICKLE_REFRESH }} 53 | 54 | loadscript 55 | print dict 56 | 57 | vuset logtotemp 0 58 | vuset vu {{ TPROCH_VIRTUAL_USERS }} 59 | vucreate 60 | vurun 61 | waittocomplete 62 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 63 | 64 | - name: Generate the run log name 65 | set_fact: 66 | run_log: "~/pgsql/data/tproch-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-s{{ TPROCH_SCALE_FACTOR }}-u{{ TPROCH_VIRTUAL_USERS }}.log" 67 | 68 | - name: Run log names 69 | debug: 70 | msg: "{{ run_log }}" 71 | 72 | - name: Make sure we have a directory for the log file if using a driver machine 73 | file: 74 | path: ~/pgsql/data/ 75 | state: directory 76 | when: hostvars[inventory_hostname].driver is defined 77 | delegate_to: "{{ hostvars[inventory_hostname].driver }}" 78 | 79 | - name: Clear out any old files that may be present on drivers 80 | shell: rm -f ~/pgsql/data/* 81 | when: hostvars[inventory_hostname].driver is defined 82 | delegate_to: "{{ hostvars[inventory_hostname].driver }}" 83 | 84 | - name: Record the config 85 | shell: | 86 | echo "################################################################################" >> {{ run_log }} 87 | echo "Run started: $(date)" >> {{ run_log }} 88 | echo "################################################################################" >> {{ run_log }} 89 | echo "" >> {{ run_log }} 90 | 91 | echo "Schema" >> {{ run_log }} 92 | echo "================================================================================" >> {{ run_log }} 93 | echo "" >> {{ run_log }} 94 | 95 | cat ~/tproch-schema.tcl >> {{ run_log }} 96 | 97 | echo "Benchmark" >> {{ run_log }} 98 | echo "================================================================================" >> {{ run_log }} 99 | echo "" >> {{ run_log }} 100 | 101 | cat ~/tproch-run.tcl >> {{ run_log }} 102 | echo "" >> {{ run_log }} 103 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 104 | 105 | - name: Log pre-run stats 106 | include_role: 107 | name: log-stats 108 | vars: 109 | log_file: "{{ run_log }}" 110 | database: tproch 111 | host: "{{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }}" 112 | 113 | - name: Generate the buffercache log name 114 | set_fact: 115 | buffercache_log: "~/pgsql/data/tproch-buffercache-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-s{{ TPROCH_SCALE_FACTOR }}-u{{ TPROCH_VIRTUAL_USERS }}.csv" 116 | when: MONITOR_PG_BUFFERCACHE 117 | 118 | - name: Start monitoring pg_buffercache 119 | include_tasks: tools/start-buffercache-monitor.yml 120 | when: MONITOR_PG_BUFFERCACHE 121 | 122 | - name: Generate the pg_stat_database log name 123 | set_fact: 124 | pgstatdb_log: "~/pgsql/data/tproch-pgstatdb-{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}-{{ inventory_hostname_short }}-run{{ RUN_NUM }}-s{{ TPROCH_SCALE_FACTOR }}-u{{ TPROCH_VIRTUAL_USERS }}.csv" 125 | when: MONITOR_PG_STAT_DATABASE 126 | 127 | - name: Start monitoring pg_stat_database 128 | include_tasks: tools/start-pgstatdb-monitor.yml 129 | when: MONITOR_PG_STAT_DATABASE 130 | 131 | - name: Log prewarm start time 132 | shell: | 133 | echo "################################################################################" >> {{ run_log }} 134 | echo "Pre-warm started: $(date)" >> {{ run_log }} 135 | echo "################################################################################" >> {{ run_log }} 136 | echo "" >> {{ run_log }} 137 | when: PGBENCH_CLEAR_CACHE_AND_PREWARM 138 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 139 | 140 | - name: Prewarm the database 141 | command: | 142 | {{ postgres_bin }}/psql -h /tmp -c "SELECT relname, pg_prewarm(c.oid::regclass) FROM pg_class c, pg_namespace n WHERE c.relnamespace = n.oid AND n.nspname = 'public' AND (c.relkind = 'r' OR c.relkind = 'i');" tproch 143 | when: TPROCH_CLEAR_CACHE_AND_PREWARM 144 | 145 | - name: Log benchmark start time 146 | shell: | 147 | echo "################################################################################" >> {{ run_log }} 148 | echo "Benchmark started: $(date)" >> {{ run_log }} 149 | echo "################################################################################" >> {{ run_log }} 150 | echo "" >> {{ run_log }} 151 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 152 | 153 | - name: Run HammerDB (TPROC-H) 154 | shell: time (./hammerdbcli auto ~/tproch-run.tcl >> {{ run_log }}) >> {{ run_log }} 2>&1 155 | args: 156 | chdir: /usr/local/HammerDB-4.3 157 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 158 | 159 | - name: Record the stats 160 | shell: | 161 | echo "" >> {{ run_log }} 162 | echo "################################################################################" >> {{ run_log }} 163 | echo "Benchmark completed: $(date)" >> {{ run_log }} 164 | echo "################################################################################" >> {{ run_log }} 165 | echo "" >> {{ run_log }} 166 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 167 | 168 | - name: Stop monitoring pg_buffercache 169 | include_tasks: tools/stop-buffercache-monitor.yml 170 | when: MONITOR_PG_BUFFERCACHE 171 | 172 | - name: Stop monitoring pg_stat_database 173 | include_tasks: tools/stop-pgstatdb-monitor.yml 174 | when: MONITOR_PG_STAT_DATABASE 175 | 176 | - name: Log post-run stats 177 | include_role: 178 | name: log-stats 179 | vars: 180 | log_file: "{{ run_log }}" 181 | database: tproch 182 | host: "{{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }}" 183 | 184 | - name: Download results 185 | fetch: 186 | src: "{{ run_log }}" 187 | dest: ../results/ 188 | flat: yes 189 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 190 | -------------------------------------------------------------------------------- /playbooks/scratch-run-dbt2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: clean-postgres.yml 3 | - import_playbook: tune-sysctls.yml 4 | - import_playbook: init-postgres.yml 5 | 6 | - name: Tune Postgres for OLTP 7 | import_playbook: tune-postgres.yml 8 | vars: 9 | BENCHMARK: dbt2 10 | 11 | - import_playbook: init-dbt2.yml 12 | - import_playbook: run-dbt2.yml 13 | -------------------------------------------------------------------------------- /playbooks/scratch-run-pgbench.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: clean-postgres.yml 3 | - import_playbook: tune-sysctls.yml 4 | - import_playbook: init-postgres.yml 5 | 6 | - name: Tune Postgres for OLTP 7 | import_playbook: tune-postgres.yml 8 | vars: 9 | BENCHMARK: pgbench 10 | 11 | - import_playbook: init-pgbench.yml 12 | - import_playbook: run-pgbench.yml -------------------------------------------------------------------------------- /playbooks/scratch-run-tprocc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: clean-postgres.yml 3 | - import_playbook: tune-sysctls.yml 4 | - import_playbook: init-postgres.yml 5 | 6 | - name: Tune Postgres for OLTP 7 | import_playbook: tune-postgres.yml 8 | vars: 9 | BENCHMARK: tprocc 10 | 11 | - import_playbook: init-tprocc.yml 12 | - import_playbook: run-tprocc.yml -------------------------------------------------------------------------------- /playbooks/scratch-run-tproch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: clean-postgres.yml 3 | - import_playbook: tune-sysctls.yml 4 | - import_playbook: init-postgres.yml 5 | 6 | - name: Tune Postgres for OLAP 7 | import_playbook: tune-postgres.yml 8 | vars: 9 | BENCHMARK: tproch 10 | 11 | - import_playbook: init-tproch.yml 12 | - import_playbook: run-tproch.yml -------------------------------------------------------------------------------- /playbooks/start-postgres.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 3 | - benchmark 4 | gather_facts: no 5 | 6 | roles: 7 | - common 8 | 9 | tasks: 10 | - include_tasks: tools/start-postgres.yml 11 | -------------------------------------------------------------------------------- /playbooks/stop-postgres.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 3 | - benchmark 4 | gather_facts: no 5 | 6 | roles: 7 | - common 8 | 9 | tasks: 10 | - include_tasks: tools/stop-postgres.yml 11 | -------------------------------------------------------------------------------- /playbooks/tools/backup-postgres.yml: -------------------------------------------------------------------------------- 1 | # Creates a backup of a Postgres instance using parallel compression 2 | # 3 | # For simplicity, we also stop postgres before creating the backup. The 4 | # instance will be restarted afterwards so we leave things the way we found 5 | # them. 6 | # 7 | # Variables: 8 | # - db_id: Unique identifier that marks this backup. 9 | 10 | - include_tasks: tools/stop-postgres.yml 11 | 12 | - name: Ensure the dump directory exists 13 | file: 14 | path: ~/pgsql/dump 15 | state: directory 16 | 17 | - name: Back up newly initialized benchmark contents 18 | shell: "tar -C ~/pgsql -cf - data | pigz > ~/pgsql/dump/{{ db_id }}.tar.gz" 19 | args: 20 | warn: false 21 | 22 | - include_tasks: tools/start-postgres.yml 23 | -------------------------------------------------------------------------------- /playbooks/tools/clean-postgres.yml: -------------------------------------------------------------------------------- 1 | - include_tasks: tools/stop-postgres.yml 2 | 3 | - name: Remove old PostgreSQL data 4 | file: 5 | path: ~/pgsql/data 6 | state: absent 7 | -------------------------------------------------------------------------------- /playbooks/tools/restore-postgres.yml: -------------------------------------------------------------------------------- 1 | # Restores a backup of a Postgres instance using parallel decompression 2 | # 3 | # This process includes saving the existing config so we don't lose any tuning 4 | # clobbered by the restore process, restoring the backup and saved config, and 5 | # finally restarting Postgres so everything is running. 6 | # 7 | # Variables: 8 | # - db_id: Unique identifier for the backup we should restore. 9 | 10 | - name: Preserve existing server config 11 | shell: "cp ~/pgsql/data/postgresql.conf ~/pgsql" 12 | 13 | - name: Ensure a tuning config is present even if empty 14 | shell: "touch ~/pgsql/data/postgresql.auto.conf" 15 | 16 | - name: Preserve existing tuning config 17 | shell: "cp ~/pgsql/data/postgresql.auto.conf ~/pgsql" 18 | 19 | - name: Preserve existing hba config 20 | shell: "cp ~/pgsql/data/pg_hba.conf ~/pgsql" 21 | 22 | - include_tasks: tools/clean-postgres.yml 23 | 24 | - name: "Restore {{ db_id }} backup" 25 | shell: "pigz -cd ~/pgsql/dump/{{ db_id }}.tar.gz | tar -C ~/pgsql -x" 26 | 27 | - name: Restore existing server config 28 | shell: "cp ~/pgsql/postgresql.conf ~/pgsql/data" 29 | 30 | - name: Restore existing tuning config 31 | shell: "cp ~/pgsql/postgresql.auto.conf ~/pgsql/data" 32 | 33 | - name: Restore existing hba config 34 | shell: "cp ~/pgsql/pg_hba.conf ~/pgsql/data" 35 | 36 | - include_tasks: tools/start-postgres.yml 37 | -------------------------------------------------------------------------------- /playbooks/tools/start-buffercache-monitor.yml: -------------------------------------------------------------------------------- 1 | # Start monitoring pg_buffercache 2 | 3 | --- 4 | - name: Create the pg_buffercache extension 5 | shell: | 6 | {{ postgres_bin }}/psql -h {{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }} -c "CREATE EXTENSION IF NOT EXISTS pg_buffercache;" postgres 7 | environment: 8 | PGPASSWORD: "{{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}" 9 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 10 | 11 | - name: Create the buffer cache monitoring script 12 | copy: 13 | dest: "buffercache_monitor.sh" 14 | mode: 0755 15 | content: | 16 | #!/bin/sh 17 | 18 | echo "timestamp,usagecount_0,usagecount_1,usagecount_2,usagecount_3,usagecount_4,usagecount_5" > {{ buffercache_log }} 19 | 20 | while true 21 | do 22 | {{ postgres_bin }}/psql --csv -q -t -h {{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }} -c "SELECT now(), count(*) FILTER (WHERE usagecount IS NULL), count(*) FILTER (WHERE usagecount = 1), count(*) FILTER (WHERE usagecount = 2), count(*) FILTER (WHERE usagecount = 3), count(*) FILTER (WHERE usagecount = 4), count(*) FILTER (WHERE usagecount = 5) FROM pg_buffercache;" postgres 23 | sleep 10 24 | done 25 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 26 | 27 | - name: Start buffer cache monitoring 28 | shell: | 29 | nohup ./buffercache_monitor.sh >> {{ buffercache_log }} & 30 | environment: 31 | PGPASSWORD: "{{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}" 32 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" -------------------------------------------------------------------------------- /playbooks/tools/start-pgstatdb-monitor.yml: -------------------------------------------------------------------------------- 1 | # Start monitoring pg_stat_database 2 | 3 | --- 4 | - name: Create the pg_stat_database monitoring script 5 | copy: 6 | dest: "pgstatdb_monitor.sh" 7 | mode: 0755 8 | content: | 9 | #!/bin/bash 10 | 11 | echo "timestamp,blks_read,blks_hit" 12 | 13 | PREV_READ=0 14 | PREV_HIT=0 15 | 16 | while true 17 | do 18 | DATA=$({{ postgres_bin }}/psql --csv -q -t -h {{ hostvars[inventory_hostname].ansible_default_ipv4.address if hostvars[inventory_hostname].driver is defined else '/tmp' }} -c "SELECT now(), sum(blks_read), sum(blks_hit) FROM pg_stat_database;" postgres) 19 | 20 | TS=$(echo $DATA | awk -F, '{ print $1 }') 21 | READ=$(echo $DATA | awk -F, '{ print $2 }') 22 | HIT=$(echo $DATA | awk -F, '{ print $3 }') 23 | 24 | echo $TS,$(($READ-$PREV_READ)),$(($HIT-$PREV_HIT)) 25 | 26 | PREV_READ=$READ 27 | PREV_HIT=$HIT 28 | 29 | sleep 10 30 | done 31 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 32 | 33 | - name: Start pg_stat_database monitoring 34 | shell: | 35 | nohup ./pgstatdb_monitor.sh >> {{ pgstatdb_log }} & 36 | environment: 37 | PGPASSWORD: "{{ lookup('password', '{{ playbook_dir }}/../credentials/{{ ansible_user_id }}.txt') }}" 38 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" -------------------------------------------------------------------------------- /playbooks/tools/start-postgres.yml: -------------------------------------------------------------------------------- 1 | - name: Start PostgreSQL 2 | command: "{{ postgres_bin }}/pg_ctl -D ~/pgsql/data start" 3 | args: 4 | creates: ~/pgsql/data/postmaster.pid 5 | -------------------------------------------------------------------------------- /playbooks/tools/stop-buffercache-monitor.yml: -------------------------------------------------------------------------------- 1 | # Stop pg_buffercache monitoring 2 | 3 | - name: Stop buffer cache monitoring 4 | shell: | 5 | kill $(ps -ef | grep buffercache_monitor.sh | grep -v grep | awk '{ print $2 }') 6 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 7 | ignore_errors: true 8 | 9 | - name: Download buffer cache log 10 | fetch: 11 | src: "{{ buffercache_log }}" 12 | dest: ../results/ 13 | flat: yes 14 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 15 | -------------------------------------------------------------------------------- /playbooks/tools/stop-pgstatdb-monitor.yml: -------------------------------------------------------------------------------- 1 | # Stop pg_stat_database monitoring 2 | 3 | - name: Stop pg_stat_database monitoring 4 | shell: | 5 | kill $(ps -ef | grep pgstatdb_monitor.sh | grep -v grep | awk '{ print $2 }') 6 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 7 | ignore_errors: true 8 | 9 | - name: Download pg_stat_database log 10 | fetch: 11 | src: "{{ pgstatdb_log }}" 12 | dest: ../results/ 13 | flat: yes 14 | delegate_to: "{{ hostvars[inventory_hostname].driver if hostvars[inventory_hostname].driver is defined else omit }}" 15 | -------------------------------------------------------------------------------- /playbooks/tools/stop-postgres.yml: -------------------------------------------------------------------------------- 1 | - name: Run a checkpoint 2 | command: "{{ postgres_bin }}/psql -h /tmp -c 'CHECKPOINT' postgres" 3 | ignore_errors: true 4 | 5 | 6 | - name: Stop PostgreSQL 7 | command: "{{ postgres_bin }}/pg_ctl -D ~/pgsql/data stop -m fast" 8 | args: 9 | removes: ~/pgsql/data/postmaster.pid 10 | ignore_errors: true -------------------------------------------------------------------------------- /playbooks/tune-postgres.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: 4 | - benchmark 5 | gather_facts: no 6 | 7 | roles: 8 | - common 9 | 10 | tasks: 11 | 12 | - include_tasks: tools/start-postgres.yml 13 | 14 | - name: Remove existing configuration 15 | file: 16 | path: ~/pgsql/data/postgresql.auto.conf 17 | state: absent 18 | 19 | - name: Create extensions 20 | include_role: 21 | name: create-extensions 22 | vars: 23 | database: postgres 24 | 25 | - name: Configure override GUCs 26 | shell: | 27 | {{ postgres_bin }}/psql -h /tmp -c "ALTER SYSTEM SET {{ item.name }} TO '{{ item.value }}';" postgres 28 | with_items: "{{ OVERRIDE_GUCS }}" 29 | when: OVERRIDE_GUCS is defined 30 | 31 | - name: Determine if local tasks exist 32 | local_action: stat path=../../ansible-local/hooks/tune-postgres.yml 33 | register: local_tune_postgres 34 | 35 | - name: Calling tune_postgres hook 36 | debug: 37 | msg: "{{ 'Loading additional tasks from ../../ansible-local/hooks/tune_postgres.yml' if local_tune_postgres.stat.exists else 'Local tune_postgres not found.' }}" 38 | 39 | - include_tasks: ../../ansible-local/hooks/tune-postgres.yml 40 | when: local_tune_postgres.stat.exists 41 | 42 | - include_tasks: tools/stop-postgres.yml 43 | -------------------------------------------------------------------------------- /playbooks/tune-sysctls.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: 4 | - benchmark 5 | gather_facts: no 6 | 7 | roles: 8 | - common 9 | 10 | tasks: 11 | - name: Set sysctls 12 | ansible.posix.sysctl: 13 | name: "{{ item.name }}" 14 | value: "{{ item.value }}" 15 | state: present 16 | sysctl_set: yes 17 | reload: yes 18 | with_items: "{{ SYSCTLS }}" 19 | become: yes -------------------------------------------------------------------------------- /plot-csv.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import dateutil.parser 3 | import pandas as pd 4 | import matplotlib.pyplot as plt 5 | import matplotlib.dates as mdates 6 | 7 | from pathlib import Path 8 | 9 | def read_command_line(): 10 | """Read the command line arguments. 11 | Returns: 12 | ArgumentParser: The parsed arguments object 13 | """ 14 | parser = argparse.ArgumentParser( 15 | description='Plot a graph from a CSV file.') 16 | 17 | parser.add_argument('input', 18 | help='the CSV file to plot') 19 | 20 | parser.add_argument('--style', '-s', 21 | default='line', 22 | choices=['line', 'area'], 23 | help='type of chart to create') 24 | 25 | parser.add_argument('--width', 26 | default=10, 27 | type=int, 28 | help='plot width in inches (default: 10)') 29 | 30 | parser.add_argument('--height', 31 | default=6, 32 | type=int, 33 | help='plot height in inches (default: 6)') 34 | 35 | parser.add_argument('--title', '-t', 36 | help='plot title (defaults to the input filename ' 37 | 'without extension)') 38 | 39 | parser.add_argument('--percent', '-p', 40 | default=False, action='store_true', 41 | help='scale to 100%%, rather than printing absolute values') 42 | 43 | parser.add_argument('--colormap', '-c', 44 | default='plasma', 45 | help='matplotlib colormap to use when rendering ' 46 | '(default: plasma)') 47 | 48 | parser.add_argument('--xlabel', 49 | help='label to display on the X axis') 50 | 51 | parser.add_argument('--ylabel', 52 | help='label to display on the Y axis') 53 | 54 | try: 55 | args = parser.parse_args() 56 | except: 57 | exit(1) 58 | 59 | return args 60 | 61 | args = read_command_line() 62 | 63 | # Create the dataframe 64 | df = pd.read_csv(args.input, index_col=0, parse_dates=[0], date_parser=dateutil.parser.isoparse) 65 | 66 | title = Path(args.input).stem 67 | if args.title is not None: 68 | title = args.title 69 | 70 | if args.percent: 71 | df = df.apply(lambda x: x*100/sum(x), axis=1) 72 | 73 | fig, ax = plt.subplots(figsize=(args.width, args.height), 74 | tight_layout=True) 75 | 76 | if args.style == 'line': 77 | df.plot.line(title=title, colormap=args.colormap, ax=ax) 78 | elif args.style == 'area': 79 | df.plot.area(title=title, colormap=args.colormap, ax=ax) 80 | 81 | # Date formatting 82 | ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d\n%H:%M:%S')) 83 | 84 | # Titles 85 | ax.xaxis.set_label_text(args.xlabel) 86 | ax.yaxis.set_label_text(args.ylabel) 87 | 88 | # Figure out the output file name 89 | output = Path(args.input).with_suffix('.png') 90 | plt.savefig(output) 91 | print('Wrote {}'.format(output)) 92 | -------------------------------------------------------------------------------- /requirements.yml: -------------------------------------------------------------------------------- 1 | roles: 2 | - name: geerlingguy.node_exporter 3 | 4 | collections: 5 | - name: ansible.posix -------------------------------------------------------------------------------- /run-benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | usage () { 4 | echo "Usage: $0 dbt2|pgbench|tprocc|tproch [] []" 5 | echo 6 | echo "Run a benchmark of the specified type, optionally specifying the number of runs and the first run number." 7 | exit 1 8 | } 9 | 10 | if [ $# -lt 1 ]; then 11 | usage 12 | fi 13 | 14 | if [ $1 != "dbt2" -a $1 != "pgbench" -a $1 != "tprocc" -a $1 != "tproch" ]; then 15 | usage 16 | fi 17 | 18 | BENCHMARK=$1 19 | NUM_RUNS=${2:-6} 20 | FIRST_RUN=${3:-1} 21 | LAST_RUN=$((${NUM_RUNS} + ${FIRST_RUN} - 1)) 22 | 23 | for RUN in $(seq ${FIRST_RUN} ${LAST_RUN}) 24 | do 25 | echo "Executing ${BENCHMARK} run ${RUN}" 26 | ansible-playbook -i inventory.yml --extra-vars "RUN_NUM=${RUN}" playbooks/scratch-run-${BENCHMARK}.yml 27 | RESULT=$? 28 | 29 | if [[ ${RESULT} > 0 ]]; then 30 | echo "Series run ${RUN}} returned non-zero exit status: ${RESULT}" 31 | echo "Check the ansible log and benchmark log for more info." 32 | exit ${RESULT} 33 | fi 34 | done 35 | --------------------------------------------------------------------------------