mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 19:06:14 +01:00 
			
		
		
		
	 5357110556
			
		
	
	
	5357110556
	
	
	
		
			
			In commit f5ca4077, an the "--log" option was added but it was implemented by
invoking a sub-shell. Any errors in the sub-shell would not be propagated and
thus cause mini-benchmark to suppress errors.
The fix here is to propagate the exit status of the sub-shell.
All new code of the whole pull request, including one or several files that are
either new files or modified ones, are contributed under the BSD-new license. I
am contributing on behalf of my employer Amazon Web Services, Inc.
		
	
			
		
			
				
	
	
		
			313 lines
		
	
	
	
		
			9.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			313 lines
		
	
	
	
		
			9.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
| #!/bin/bash
 | |
| # Abort on errors
 | |
| set -ex
 | |
| 
 | |
| display_help() {
 | |
|   echo "Usage: $(basename "$0") [-h] [--perf] [--perf-flamegraph]"
 | |
|   echo
 | |
|   echo "This is a very small and naive benchmark script designed to be suitable"
 | |
|   echo "for running in a CI system on every commit to detect severe performance"
 | |
|   echo "regressions."
 | |
|   echo
 | |
|   echo "optional arguments:"
 | |
|   echo "  --name STRING      identifier for the benchmark, added to the "
 | |
|   echo "                     folder name and (if --log is set) the log file "
 | |
|   echo "  --threads \"STRING\" quoted string of space-separated integers "
 | |
|   echo "                     representing the threads to run."
 | |
|   echo "                     example: --threads \"1 32 64 128\""
 | |
|   echo "                     default: \"1 2 4 8 16\""
 | |
|   echo "  --duration INTEGER duration of each thread run in seconds"
 | |
|   echo "                     default: 60"
 | |
|   echo "  --workload STRING  sysbench workload to execute"
 | |
|   echo "                     default: oltp_read_write"
 | |
|   echo "  --log              logs the mini-benchmark stdout/stderr into the"
 | |
|   echo "                     benchmark folder."
 | |
|   echo "  --perf             measure CPU cycles and instruction count in for "
 | |
|   echo "                     sysbench runs"
 | |
|   echo "  --perf-flamegraph  record performance counters in perf.data.* and"
 | |
|   echo "                     generate flamegraphs automatically"
 | |
|   echo "  --cpu-limit        upper limit on the number of CPU cycles (in billions) used for the benchmark"
 | |
|   echo "                     default: 750"
 | |
|   echo "  -h, --help         display this help and exit"
 | |
| }
 | |
| 
 | |
| # Default parameters
 | |
| BENCHMARK_NAME='mini-benchmark'
 | |
| THREADS='1 2 4 8 16'
 | |
| DURATION=60
 | |
| WORKLOAD='oltp_read_write'
 | |
| 
 | |
| while :
 | |
| do
 | |
|   case "$1" in
 | |
|     -h | --help)
 | |
|       display_help
 | |
|       exit 0
 | |
|       ;;
 | |
|     --version)
 | |
|       display_version
 | |
|       exit 0
 | |
|       ;;
 | |
|     --name)
 | |
|       shift
 | |
|       BENCHMARK_NAME+='-'
 | |
|       BENCHMARK_NAME+=$1
 | |
|       shift
 | |
|       ;;
 | |
|     --threads)
 | |
|       shift
 | |
|       THREADS=$1
 | |
|       shift
 | |
|       ;;
 | |
|     --duration)
 | |
|       shift
 | |
|       DURATION=$1
 | |
|       shift
 | |
|       ;;
 | |
|     --workload)
 | |
|       shift
 | |
|       WORKLOAD=$1
 | |
|       shift
 | |
|       ;;
 | |
|     --log)
 | |
|       LOG=true
 | |
|       shift
 | |
|       ;;
 | |
|     --perf)
 | |
|       PERF=true
 | |
|       shift
 | |
|       ;;
 | |
|     --perf-flamegraph)
 | |
|       PERF_RECORD=true
 | |
|       shift
 | |
|       ;;
 | |
|     --cpu-limit)
 | |
|       shift
 | |
|       CPU_CYCLE_LIMIT=$1
 | |
|       shift
 | |
|       ;;
 | |
|     -*)
 | |
|       echo "Error: Unknown option: $1" >&2
 | |
|       ## or call function display_help
 | |
|       exit 1
 | |
|       ;;
 | |
|     *)  # No more options
 | |
|       break
 | |
|       ;;
 | |
|   esac
 | |
| done
 | |
| 
 | |
| # Save results of this run in a subdirectory so that they are not overwritten by
 | |
| # the next run
 | |
| TIMESTAMP="$(date -Iseconds)"
 | |
| mkdir "$BENCHMARK_NAME-$TIMESTAMP"
 | |
| cd "$BENCHMARK_NAME-$TIMESTAMP" || exit 1
 | |
| 
 | |
| (
 | |
| # Check that the dependencies of this script are available
 | |
| if [ ! -e /usr/bin/pgrep ]
 | |
| then
 | |
|   echo "ERROR: Command 'pgrep' missing, please install package 'psproc'"
 | |
|   exit 1
 | |
| fi
 | |
| 
 | |
| if [ ! -e /usr/bin/sysbench ]
 | |
| then
 | |
|   echo "ERROR: Command 'sysbench' missing, please install package 'sysbench'"
 | |
|   exit 1
 | |
| fi
 | |
| 
 | |
| # If there are multiple processes, assume the last one is the actual server and
 | |
| # any potential other ones were just part of the service wrapper chain
 | |
| # shellcheck disable=SC2005
 | |
| MARIADB_SERVER_PID="$(echo "$(pgrep -f mariadbd || pgrep -f mysqld)" | tail -n 1)"
 | |
| 
 | |
| if [ -z "$MARIADB_SERVER_PID" ]
 | |
| then
 | |
|   echo "ERROR: Server 'mariadbd' or 'mysqld' is not running, please start the service"
 | |
|   exit 1
 | |
| fi
 | |
| 
 | |
| if [ "$PERF" == true ] && [ "$PERF_RECORD" == true ]
 | |
| then
 | |
|   echo "ERROR: Cannot select both --perf and --perf-flamegraph options simultaneously. Please choose one or the other."
 | |
|   exit 1
 | |
| fi
 | |
| 
 | |
| if [ "$PERF" == true ] || [ "$PERF_RECORD" == true ]
 | |
| then
 | |
|   if [ ! -e /usr/bin/perf ]
 | |
|   then
 | |
|     echo "ERROR: Command 'perf' missing, please install package 'perf'"
 | |
|     exit 1
 | |
|   fi
 | |
| fi
 | |
| 
 | |
| if [ "$PERF_RECORD" == true ]
 | |
| then
 | |
|   if [ ! -e /usr/bin/flamegraph.pl ]
 | |
|   then
 | |
|     echo "ERROR: Command 'flamegraph.pl' missing, please install package 'flamegraph'"
 | |
|     exit 1
 | |
|   fi
 | |
| 
 | |
|   if [ ! -e /usr/bin/stackcollapse-perf.pl ]
 | |
|   then
 | |
|     echo "ERROR: Command 'stackcollapse-perf.pl' missing, please install package 'flamegraph-stackcollapse-perf'"
 | |
|     exit 1
 | |
|   fi
 | |
| 
 | |
|   if [ ! -e /usr/bin/debuginfo-install ]
 | |
|   then
 | |
|     echo "ERROR: Command 'debuginfo-install' missing, please install package 'dnf-utils'"
 | |
|     exit 1
 | |
|   fi
 | |
| 
 | |
|   echo "Ensure the MariaDB Server debug symbols are installed"
 | |
|   for x in $(ldd /usr/sbin/mariadbd | grep -oE " /.* ")
 | |
|   do
 | |
|     rpm -q --whatprovides --qf '%{name}' "$x" | cut -d : -f 1
 | |
|   done | sort -u > mariadbd-dependencies.txt
 | |
|   # shellcheck disable=SC2046
 | |
|   debuginfo-install -y mariadb-server $(cat mariadbd-dependencies.txt)
 | |
| 
 | |
|   if ! (perf record echo "testing perf") > /dev/null 2>&1
 | |
|   then
 | |
|     echo "perf does not have permission to run on this system. Skipping."
 | |
|     PERF_COMMAND=""
 | |
|   else
 | |
|     echo "Using 'perf' to record performance counters in perf.data files"
 | |
|     PERF_COMMAND="perf record -g --freq=99 --output=perf.data --timestamp-filename --pid=$MARIADB_SERVER_PID --"
 | |
|   fi
 | |
| 
 | |
| elif [ "$PERF" == true ]
 | |
| then
 | |
|   # If flamegraphs were not requested, log normal perf counters if possible
 | |
| 
 | |
|   if ! (perf stat echo "testing perf") > /dev/null 2>&1
 | |
|   then
 | |
|     echo "perf does not have permission to run on this system. Skipping."
 | |
|     PERF_COMMAND=""
 | |
|   else
 | |
|     echo "Using 'perf' to log basic performance counters for benchmark"
 | |
|     PERF_COMMAND="perf stat -p $MARIADB_SERVER_PID --"
 | |
|   fi
 | |
| fi
 | |
| 
 | |
| # Run sysbench on another CPU if system has more than one available
 | |
| if [ "$(nproc)" -gt 1 ]
 | |
| then
 | |
|   TASKSET_SYSBENCH='taskset -c 1'
 | |
| else
 | |
|   TASKSET_SYSBENCH=''
 | |
| fi
 | |
| 
 | |
| echo "System hardware information:"
 | |
| lscpu
 | |
| free -m
 | |
| df -h .
 | |
| uname -a
 | |
| echo
 | |
| 
 | |
| echo "Set highest priority for MariaDB Server process ID $MARIADB_SERVER_PID"
 | |
| renice --priority -20 --pid "$MARIADB_SERVER_PID" || echo "renice failed. Not setting priority."
 | |
| 
 | |
| echo "Set CPU affinity 0 for MariaDB Server process ID $MARIADB_SERVER_PID"
 | |
| taskset -cp 0 "$MARIADB_SERVER_PID" || echo "taskset failed. Not setting cpu affinity."
 | |
| 
 | |
| mariadb -e "
 | |
|   CREATE DATABASE IF NOT EXISTS sbtest;
 | |
|   CREATE USER IF NOT EXISTS sbtest@localhost;
 | |
|   GRANT ALL PRIVILEGES ON sbtest.* TO sbtest@localhost"
 | |
| 
 | |
| sysbench "$WORKLOAD" prepare --tables=20 --table-size=100000 | tee sysbench-prepare.log
 | |
| sync && sleep 1 # Ensure writes were propagated to disk
 | |
| 
 | |
| # Run benchmark with increasing thread counts. The MariaDB Server will be using
 | |
| # around 300 MB of RAM and mostly reading and writing in RAM, so I/O usage is
 | |
| # also low. The benchmark will most likely be CPU bound to due to the load
 | |
| # profile, and also guaranteed to be CPU bound because of being limited to a
 | |
| # single CPU with 'tasksel'.
 | |
| for t in $THREADS
 | |
| do
 | |
|   # Prepend command with perf if defined
 | |
|   # Output stderr to stdout as perf outputs everything in stderr
 | |
|   # shellcheck disable=SC2086
 | |
|   $PERF_COMMAND $TASKSET_SYSBENCH sysbench "$WORKLOAD" run --threads=$t --time=$DURATION --report-interval=10 2>&1 | tee sysbench-run-$t.log
 | |
| done
 | |
| 
 | |
| sysbench "$WORKLOAD" cleanup --tables=20 | tee sysbench-cleanup.log
 | |
| 
 | |
| # Store results from 4 thread run in a Gitlab-CI compatible metrics file
 | |
| grep -oE '[a-z]+:[ ]+[0-9.]+' sysbench-run-4.log | sed -r 's/\s+/ /g' | tail -n 15 > metrics.txt
 | |
| 
 | |
| echo # Newline improves readability
 | |
| echo "== SUMMARY =="
 | |
| 
 | |
| # Print performance counter summary if they were logged
 | |
| if grep --quiet cycles sysbench-run-*.log
 | |
| then
 | |
|   grep -e cycles sysbench-run-*.log | sort -k 2
 | |
|   echo "Total: $(grep -h -e cycles sysbench-run-*.log | sort -k 1 | awk '{s+=$1}END{print s}')"
 | |
|   echo # Newline improves readability
 | |
|   grep -e instructions sysbench-run-*.log | sort -k 2
 | |
|   echo "Total: $(grep -h -e instructions sysbench-run-*.log | sort -k 1 | awk '{s+=$1}END{print s}')"
 | |
|   echo # Newline improves readability
 | |
| 
 | |
|   if [ -z "$CPU_CYCLE_LIMIT" ]
 | |
|   then 
 | |
|      # 04-04-2024: We found this to be an appropriate default limit after running a few benchmarks
 | |
|      # Configure the limit with --cpu-limit if needed
 | |
|     CPU_CYCLE_LIMIT=750
 | |
|   fi
 | |
|   CPU_CYCLE_LIMIT_LONG="${CPU_CYCLE_LIMIT}000000000"
 | |
| 
 | |
|   # Final verdict based on cpu cycle count
 | |
|   RESULT="$(grep -h -e cycles sysbench-run-*.log | sort -k 1 | awk '{s+=$1}END{print s}')"
 | |
|   if [ "$RESULT" -gt "$CPU_CYCLE_LIMIT_LONG" ]
 | |
|   then
 | |
|     echo # Newline improves readability
 | |
|     echo "Benchmark exceeded the allowed limit of ${CPU_CYCLE_LIMIT} billion CPU cycles"
 | |
|     echo "Performance most likely regressed!"
 | |
|     exit 1
 | |
|   fi
 | |
| fi
 | |
| 
 | |
| # List all sysbench status lines at once
 | |
| grep -h thds sysbench-run-*.log | sort -k 5 -h
 | |
| 
 | |
| echo # Newline improves readability
 | |
| echo "Highest count for queries per second:"
 | |
| sort -k 9 -h sysbench-run-*.log | tail -n 1
 | |
| 
 | |
| if [ "$PERF_RECORD" == true ]
 | |
| then
 | |
|   for f in perf.data.*
 | |
|   do
 | |
|     perf script -i "$f" | stackcollapse-perf.pl | flamegraph.pl --width 1800 > "$f".svg
 | |
|   done
 | |
|   echo "Flamegraphs stored in folder $BENCHMARK_NAME-$TIMESTAMP/"
 | |
| fi
 | |
| 
 | |
| # Fallback if CPU cycle count not available: final verdict based on peak QPS
 | |
| RESULT="$(sort -k 9 -h sysbench-run-*.log | tail -n 1 | grep -oE "qps: [0-9]+" | grep -oE "[0-9]+")"
 | |
| case $RESULT in
 | |
|   ''|*[!0-9]*)
 | |
|     echo "ERROR: Benchmark result invalid, not an integer."
 | |
|     exit 1
 | |
|     ;;
 | |
| 
 | |
|   *)
 | |
|     if [ "$RESULT" -lt 13000 ]
 | |
|     then
 | |
|       echo # Newline improves readability
 | |
|       echo "Benchmark did not reach 13000+ qps, performance most likely regressed!"
 | |
|       exit 1
 | |
|     else
 | |
|       echo "Banchmark passed with $RESULT queries per second as peak value"
 | |
|     fi
 | |
|     ;;
 | |
| esac
 | |
| # Record the output into the log file, if requested
 | |
| ) 2>&1 | ($LOG && tee "$BENCHMARK_NAME"-"$TIMESTAMP".log)
 | |
| exit ${PIPESTATUS[0]} # Propagate errors in the sub-shell
 |