Tuesday, July 2, 2024

The impact of PGO for MySQL

This post explains the benefit from PGO (profile guided optimization) on MySQL. A previous post showed that LTO (link time optimization) reduces CPU (improves throughput) by about 5% for CPU-bound sysbench.

The goals here are:

  • Determine the impact of PGO
  • Determine the impact of PGO + LTO
  • Determine whether PGO binary that used sysbench to generate the profile is useful when running other benchmarks (in short, yes, but the longer answer waits for another blog post).
  • Determine whether PGO helps MySQL 8.0 more than 5.6 and 5.7. A hypothesis is that the many perf regressions in MySQL 8.0 are from code bloat. Perhaps PGO helps more with more-bloated code than it does with less-bloated code.
  • Determine the impact from -Os vs -O2. A hypothesis is that -Os will undo some code bloat. Note that -Os includes the -O2 optimizations except the ones that increase code size.
  • Document the 5.6->5.7 and 5.7->8.0 regressions
  • Determine whether the regressions at low-concurrency are offset by improvements at high-concurrency
Just saw this great post on using BOLT with Postgres from Tomas Vondra.

tl;dr
  • PGO is good, PGO + LTO is better
  • PGO helps MySQL 8.0 more than 5.6
  • PGO does not undo the perf regressions that are new in 8.0
  • PGO improves results on the small servers more than on the medium server
  • Regressions from 5.7 to 8.0 are larger than from 5.6 to 5.7
  • Performance is worse with -Os compared to -O2
Updates:
  • I retracted the results for PGO+LTO because mistakes were made and I will redo that work. The updated results are here for a laptop-class CPU and pending for a server-class CPU.

Builds

I used InnoDB from MySQL 5.6.35, 5.6.51, 5.7.44 and 8.0.37. The compiler was gcc 11.4.0.
  • I used -fprofile-generate to get binaries that create PGO profiles
  • I used -fprofile-use -fprofile-correction to get binaries that used PGO profiles
  • I used -Os or -O2 (see CMake command lines here)
I also did one test with MyRocks from FB MySQL 8.0.32 but my focus is upstream MySQL.

To get PGO for clang
  • compile with -fprofile-generate
  • start mysqld with LLVM_PROFILE_FILE=$PWD/code-%p.profraw <mysqld command line>. If you don't use an absolute path then things won't work because mysqld calls chdir($data-dir) at startup and that confuses the clang profiling code

Hardware

I tested on three servers:
  • SER4 - Beelink SER 4700u (see here) with 8 cores and a Ryzen 7 4700u CPU 
  • PN53 - ASUS ExpertCenter PN53 (see here) with 8 cores and an AMD Ryzen 7 7735HS CPU. The CPU on the PN53 is newer than the CPU on the SER4.
  • C2D - a c2d-highcpu-32 instance type on GCP (c2d high-CPU) with 32 vCPU and SMT disabled so there are 16 cores
All servers use Ubuntu 22.04 with ext4. 

Benchmark

I used sysbench and my usage is explained here. There are 42 microbenchmarks and most test only 1 type of SQL statement. The database is cached by MyRocks and InnoDB.

The benchmark is run with:
  • SER4, PN53 - 1 thread, 1 table and 30M rows
  • C2D - 12 threads, 8 tables and 10M rows per table
  • each microbenchmark runs for 300 seconds if read-only and 600 seconds otherwise
  • prepared statements were enabled
The command lines for my helper scripts were:
# PN53, SER4
bash r.sh 1 30000000 300 600 nvme0n1 1 1 1
# C2D
bash r.sh 8 10000000 300 600 md0 1 1 12

Results

For the results below I split the 42 microbenchmarks into 5 groups -- 2 for point queries, 2 for range queries, 1 for writes. For the range query microbenchmarks, part 1 has queries that don't do aggregation while part 2 has queries that do aggregation. The spreadsheets with all data are here for SER4, PN53 and C2D. For each microbenchmark group there is a table with summary statistics. 

The numbers in the spreadsheets are the relative QPS which is (QPS for my version) / (QPS for base case). When the relative throughput is > 1 then that version is faster than the base case.

Results: without PGO

I use summary statistics per microbenchmark group rather than charts because there would be too many charts. The numbers are the relative QPS. MySQL 5.6.35 is the base case. MySQL 5.7.44 or 8.0.37 are slower than 5.6.35 when the relative QPS is less than 1. I focus on the median value per microbenchmark group.

Results from SER4 (older small server, low concurrency)
  • 5.7.44 is ~15% slower than 5.6.35 for most reads and ~15% slower for writes
  • 8.0.37 is ~30% slower than 5.6.35 for most reads and ~40% slower for writes
  • Regressions from 5.7->8.0 and 5.6->5.7 are similar
5.7.44minmaxavgmedian
point-10.850.890.860.85
point-20.780.990.880.85
range-10.800.930.820.81
range-20.851.211.010.96
writes0.741.290.900.85

8.0.37minmaxavgmedian
point-10.650.780.700.69
point-20.610.800.700.69
range-10.640.690.660.66
range-20.650.960.790.75
writes0.471.020.620.59

Results from PN53 (newer small server, low concurrency)
  • 5.7.44 is ~12% slower than 5.6.35 for most reads and ~11% slower for writes
  • 8.0.37 is ~30% slower than 5.6.35 for most reads and ~34% slower for writes
  • Regressions from 5.7->8.0 are larger than from 5.6->5.7
5.7.44minmaxavgmedian
point-10.860.920.890.88
point-20.861.020.920.88
range-10.830.900.860.84
range-20.901.231.040.99
writes0.821.170.920.89

8.0.37minmaxavgmedian
point-10.660.780.710.70
point-20.700.830.750.71
range-10.670.710.690.69
range-20.740.980.850.82
writes0.570.970.690.66

Results from C2D (medium server/concurrency)
  • 5.7.44 is slower and faster on reads and much faster on writes vs 5.6.35
  • 8.0.37 is up to 29% slower on reads and much faster on writes vs 5.6.35
  • There are large regressions from 5.7 to 8.0
5.7.44minmaxavgmedian
point-10.861.441.030.94
point-20.911.291.111.13
range-10.851.000.880.86
range-21.151.261.201.20
writes1.453.962.462.49

8.0.37minmaxavgmedian
point-10.711.100.830.75
point-20.731.040.880.89
range-10.670.790.710.71
range-20.931.050.990.99
writes1.253.061.911.91

Results: with PGO

I use summary statistics per microbenchmark group rather than charts because there would be too many charts. The numbers are the relative QPS. MySQL 5.6.35 is the base case. MySQL 5.7.44 or 8.0.37 are slower than 5.6.35 when the relative QPS is less than 1. I focus on the median value per microbenchmark group.

Results from SER4 (older small server, low concurrency)
  • 5.7.44 is ~11% slower than 5.6.35 for most reads and ~6% slower for writes
  • 8.0.37 is ~25% slower than 5.6.35 for most reads and ~34% slower for writes
  • Regressions from 5.7->8.0 are larger than 5.6->5.7
  • PGO helps 8.0 more than 5.6
5.7.44minmaxavgmedian
point-10.871.020.910.89
point-20.861.030.930.89
range-10.740.890.850.87
range-20.971.251.081.02
writes0.841.130.960.94

8.0.37minmaxavgmedian
point-10.640.880.770.76
point-20.700.860.770.74
range-10.510.740.690.72
range-20.801.000.880.85
writes0.551.020.700.66

Results from PN53 (newer small server, low concurrency)
  • 5.7.44 is ~10% slower than 5.6.35 for most reads and ~4% slower for writes
  • 8.0.37 is ~25% slower than 5.6.35 for most reads and ~26% slower for writes
  • Regressions from 5.7->8.0 are larger than 5.6->5.7
  • PGO helps 8.0 more than 5.6
5.7.44minmaxavgmedian
point-10.880.920.900.90
point-20.891.020.930.90
range-10.810.890.870.88
range-20.931.311.101.04
writes0.851.231.000.96

8.0.37minmaxavgmedian
point-10.670.820.760.75
point-20.750.870.790.75
range-10.580.740.710.73
range-20.801.020.910.90
writes0.611.020.760.74

Results from C2D (medium server/concurrency)
  • 5.7.44 is slower and faster on reads and much faster on writes vs 5.6.35
  • 8.0.37 is slower and faster on reads and much faster on writes vs 5.6.35
  • There are large regressions from 5.7 to 8.0
  • PGO helps 8.0 more than 5.6
5.7.44minmaxavgmedian
point-10.861.731.141.04
point-20.971.441.241.30
range-10.840.890.870.88
range-21.251.331.291.29
writes1.384.292.682.72

8.0.37minmaxavgmedian
point-10.751.360.960.87
point-20.821.231.041.09
range-10.600.760.720.72
range-21.051.091.071.07
writes1.273.092.142.14

Results: PGO + LTO

I retracted these results because mistakes were made and will redo the work.

Results: gcc -Os

I use summary statistics per microbenchmark group rather than charts because there would be too many charts. The numbers are the relative QPS. MySQL 8.0.37 with -O2 and that is compared to 8.0.37 with -Os When the relative QPS is less than 1 then the base case is faster. I focus on the median value per microbenchmark group.

Results from SER4 (older small server, low concurrency)
  • Performance is worse with -Os compared to -O2
-Osminmaxavgmedian
point-10.720.790.770.78
point-20.770.800.790.79
range-10.520.770.700.72
range-20.680.740.720.73
writes0.490.800.750.78

Results from PN53 (newer small server, low concurrency)
  • Performance is worse with -Os compared to -O2
-Osminmaxavgmedian
point-10.770.870.830.84
point-20.810.850.840.85
range-10.640.840.760.75
range-20.780.810.800.81
writes0.680.820.800.81

Results from C2D (medium server/concurrency)
  • Performance is worse with -Os compared to -O2
-Osminmaxavgmedian
point-10.800.840.820.83
point-20.820.830.830.83
range-10.610.840.760.77
range-20.670.830.770.81
writes0.800.900.860.87




No comments:

Post a Comment

Fixing some of the InnoDB scan perf regressions in a MySQL fork

I recently learned of Advanced MySQL , a MySQL fork, and ran my sysbench benchmarks for it. It fixed some, but not all, of the regressions f...