#!/bin/bash # Yet Another Bench Script by Mason Rowe # Initial Oct 2019; Last update Apr 2024 # Disclaimer: This project is a work in progress. Any errors or suggestions should be # relayed to me via the GitHub project page linked below. # # Purpose: The purpose of this script is to quickly gauge the performance of a Linux- # based server by benchmarking network performance via iperf3, CPU and # overall system performance via Geekbench 4/5, and random disk # performance via fio. The script is designed to not require any dependencies # - either compiled or installed - nor admin privileges to run. YABS_VERSION="v2024-04-22" echo -e '# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #' echo -e '# Yet-Another-Bench-Script #' echo -e '# '$YABS_VERSION' #' echo -e '# https://github.com/masonr/yet-another-bench-script #' echo -e '# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #' echo -e date TIME_START=$(date '+%Y%m%d-%H%M%S') YABS_START_TIME=$(date +%s) # override locale to eliminate parsing errors (i.e. using commas as delimiters rather than periods) if locale -a 2>/dev/null | grep ^C$ > /dev/null; then # locale "C" installed export LC_ALL=C else # locale "C" not installed, display warning echo -e "\nWarning: locale 'C' not detected. Test outputs may not be parsed correctly." fi # determine architecture of host ARCH=$(uname -m) if [[ $ARCH = *x86_64* ]]; then # host is running a 64-bit kernel ARCH="x64" elif [[ $ARCH = *i?86* ]]; then # host is running a 32-bit kernel ARCH="x86" elif [[ $ARCH = *aarch* || $ARCH = *arm* ]]; then KERNEL_BIT=$(getconf LONG_BIT) if [[ $KERNEL_BIT = *64* ]]; then # host is running an ARM 64-bit kernel ARCH="aarch64" else # host is running an ARM 32-bit kernel ARCH="arm" fi echo -e "\nARM compatibility is considered *experimental*" else # host is running a non-supported kernel echo -e "Architecture not supported by YABS." exit 1 fi # flags to skip certain performance tests unset PREFER_BIN SKIP_FIO SKIP_IPERF SKIP_GEEKBENCH SKIP_NET PRINT_HELP REDUCE_NET GEEKBENCH_4 GEEKBENCH_5 GEEKBENCH_6 DD_FALLBACK IPERF_DL_FAIL JSON JSON_SEND JSON_RESULT JSON_FILE GEEKBENCH_6="True" # gb6 test enabled by default # get any arguments that were passed to the script and set the associated skip flags (if applicable) while getopts 'bfdignhr4596jw:s:' flag; do case "${flag}" in b) PREFER_BIN="True" ;; f) SKIP_FIO="True" ;; d) SKIP_FIO="True" ;; i) SKIP_IPERF="True" ;; g) SKIP_GEEKBENCH="True" ;; n) SKIP_NET="True" ;; h) PRINT_HELP="True" ;; r) REDUCE_NET="True" ;; 4) GEEKBENCH_4="True" && unset GEEKBENCH_6 ;; 5) GEEKBENCH_5="True" && unset GEEKBENCH_6 ;; 9) GEEKBENCH_4="True" && GEEKBENCH_5="True" && unset GEEKBENCH_6 ;; 6) GEEKBENCH_6="True" ;; j) JSON+="j" ;; w) JSON+="w" && JSON_FILE=${OPTARG} ;; s) JSON+="s" && JSON_SEND=${OPTARG} ;; *) exit 1 ;; esac done # check for local fio/iperf installs command -v fio >/dev/null 2>&1 && LOCAL_FIO=true || unset LOCAL_FIO command -v iperf3 >/dev/null 2>&1 && LOCAL_IPERF=true || unset LOCAL_IPERF # check for ping command -v ping >/dev/null 2>&1 && LOCAL_PING=true || unset LOCAL_PING # check for curl/wget command -v curl >/dev/null 2>&1 && LOCAL_CURL=true || unset LOCAL_CURL # test if the host has IPv4/IPv6 connectivity [[ ! -z $LOCAL_CURL ]] && IP_CHECK_CMD="curl -s -m 4" || IP_CHECK_CMD="wget -qO- -T 4" IPV4_CHECK=$( (ping -4 -c 1 -W 4 ipv4.google.com >/dev/null 2>&1 && echo true) || $IP_CHECK_CMD -4 icanhazip.com 2> /dev/null) IPV6_CHECK=$( (ping -6 -c 1 -W 4 ipv6.google.com >/dev/null 2>&1 && echo true) || $IP_CHECK_CMD -6 icanhazip.com 2> /dev/null) if [[ -z "$IPV4_CHECK" && -z "$IPV6_CHECK" ]]; then echo -e echo -e "Warning: Both IPv4 AND IPv6 connectivity were not detected. Check for DNS issues..." fi # print help and exit script, if help flag was passed if [ ! -z "$PRINT_HELP" ]; then echo -e echo -e "Usage: ./yabs.sh [-flags]" echo -e " curl -sL yabs.sh | bash" echo -e " curl -sL yabs.sh | bash -s -- -flags" echo -e " wget -qO- yabs.sh | bash" echo -e " wget -qO- yabs.sh | bash -s -- -flags" echo -e echo -e "Flags:" echo -e " -b : prefer pre-compiled binaries from repo over local packages" echo -e " -f/d : skips the fio disk benchmark test" echo -e " -i : skips the iperf network test" echo -e " -g : skips the geekbench performance test" echo -e " -n : skips the network information lookup and print out" echo -e " -h : prints this lovely message, shows any flags you passed," echo -e " shows if fio/iperf3 local packages have been detected," echo -e " then exits" echo -e " -r : reduce number of iperf3 network locations (to only three)" echo -e " to lessen bandwidth usage" echo -e " -4 : use geekbench 4 instead of geekbench 6" echo -e " -5 : use geekbench 5 instead of geekbench 6" echo -e " -9 : use both geekbench 4 AND geekbench 5 instead of geekbench 6" echo -e " -6 : user geekbench 6 in addition to 4 and/or 5 (only needed if -4, -5, or -9 are set; -6 must come last)" echo -e " -j : print jsonified YABS results at conclusion of test" echo -e " -w : write jsonified YABS results to disk using file name provided" echo -e " -s : send jsonified YABS results to URL" echo -e echo -e "Detected Arch: $ARCH" echo -e echo -e "Detected Flags:" [[ ! -z $PREFER_BIN ]] && echo -e " -b, force using precompiled binaries from repo" [[ ! -z $SKIP_FIO ]] && echo -e " -f/d, skipping fio disk benchmark test" [[ ! -z $SKIP_IPERF ]] && echo -e " -i, skipping iperf network test" [[ ! -z $SKIP_GEEKBENCH ]] && echo -e " -g, skipping geekbench test" [[ ! -z $SKIP_NET ]] && echo -e " -n, skipping network info lookup and print out" [[ ! -z $REDUCE_NET ]] && echo -e " -r, using reduced (3) iperf3 locations" [[ ! -z $GEEKBENCH_4 ]] && echo -e " running geekbench 4" [[ ! -z $GEEKBENCH_5 ]] && echo -e " running geekbench 5" [[ ! -z $GEEKBENCH_6 ]] && echo -e " running geekbench 6" echo -e echo -e "Local Binary Check:" [[ -z $LOCAL_FIO ]] && echo -e " fio not detected, will download precompiled binary" || [[ -z $PREFER_BIN ]] && echo -e " fio detected, using local package" || echo -e " fio detected, but using precompiled binary instead" [[ -z $LOCAL_IPERF ]] && echo -e " iperf3 not detected, will download precompiled binary" || [[ -z $PREFER_BIN ]] && echo -e " iperf3 detected, using local package" || echo -e " iperf3 detected, but using precompiled binary instead" echo -e echo -e "Detected Connectivity:" [[ ! -z $IPV4_CHECK ]] && echo -e " IPv4 connected" || echo -e " IPv4 not connected" [[ ! -z $IPV6_CHECK ]] && echo -e " IPv6 connected" || echo -e " IPv6 not connected" echo -e echo -e "JSON Options:" [[ -z $JSON ]] && echo -e " none" [[ $JSON = *j* ]] && echo -e " printing json to screen after test" [[ $JSON = *w* ]] && echo -e " writing json to file ($JSON_FILE) after test" [[ $JSON = *s* ]] && echo -e " sharing json YABS results to $JSON_SEND" echo -e echo -e "Exiting..." exit 0 fi # format_size # Purpose: Formats raw disk and memory sizes from kibibytes (KiB) to largest unit # Parameters: # 1. RAW - the raw memory size (RAM/Swap) in kibibytes # Returns: # Formatted memory size in KiB, MiB, GiB, or TiB function format_size { RAW=$1 # mem size in KiB RESULT=$RAW local DENOM=1 local UNIT="KiB" # ensure the raw value is a number, otherwise return blank re='^[0-9]+$' if ! [[ $RAW =~ $re ]] ; then echo "" return 0 fi if [ "$RAW" -ge 1073741824 ]; then DENOM=1073741824 UNIT="TiB" elif [ "$RAW" -ge 1048576 ]; then DENOM=1048576 UNIT="GiB" elif [ "$RAW" -ge 1024 ]; then DENOM=1024 UNIT="MiB" fi # divide the raw result to get the corresponding formatted result (based on determined unit) RESULT=$(awk -v a="$RESULT" -v b="$DENOM" 'BEGIN { print a / b }') # shorten the formatted result to two decimal places (i.e. x.x) RESULT=$(echo $RESULT | awk -F. '{ printf "%0.1f",$1"."substr($2,1,2) }') # concat formatted result value with units and return result RESULT="$RESULT $UNIT" echo $RESULT } # gather basic system information (inc. CPU, AES-NI/virt status, RAM + swap + disk size) echo -e echo -e "Basic System Information:" echo -e "---------------------------------" UPTIME=$(uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes"}') echo -e "Uptime : $UPTIME" # check for local lscpu installs command -v lscpu >/dev/null 2>&1 && LOCAL_LSCPU=true || unset LOCAL_LSCPU if [[ $ARCH = *aarch64* || $ARCH = *arm* ]] && [[ ! -z $LOCAL_LSCPU ]]; then CPU_PROC=$(lscpu | grep "Model name" | sed 's/Model name: *//g') else CPU_PROC=$(awk -F: '/model name/ {name=$2} END {print name}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//') fi echo -e "Processor : $CPU_PROC" if [[ $ARCH = *aarch64* || $ARCH = *arm* ]] && [[ ! -z $LOCAL_LSCPU ]]; then CPU_CORES=$(lscpu | grep "^[[:blank:]]*CPU(s):" | sed 's/CPU(s): *//g') CPU_FREQ=$(lscpu | grep "CPU max MHz" | sed 's/CPU max MHz: *//g') [[ -z "$CPU_FREQ" ]] && CPU_FREQ="???" CPU_FREQ="${CPU_FREQ} MHz" else CPU_CORES=$(awk -F: '/model name/ {core++} END {print core}' /proc/cpuinfo) CPU_FREQ=$(awk -F: ' /cpu MHz/ {freq=$2} END {print freq " MHz"}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//') fi echo -e "CPU cores : $CPU_CORES @ $CPU_FREQ" CPU_AES=$(cat /proc/cpuinfo | grep aes) [[ -z "$CPU_AES" ]] && CPU_AES="\xE2\x9D\x8C Disabled" || CPU_AES="\xE2\x9C\x94 Enabled" echo -e "AES-NI : $CPU_AES" CPU_VIRT=$(cat /proc/cpuinfo | grep 'vmx\|svm') [[ -z "$CPU_VIRT" ]] && CPU_VIRT="\xE2\x9D\x8C Disabled" || CPU_VIRT="\xE2\x9C\x94 Enabled" echo -e "VM-x/AMD-V : $CPU_VIRT" TOTAL_RAM_RAW=$(free | awk 'NR==2 {print $2}') TOTAL_RAM=$(format_size $TOTAL_RAM_RAW) echo -e "RAM : $TOTAL_RAM" TOTAL_SWAP_RAW=$(free | grep Swap | awk '{ print $2 }') TOTAL_SWAP=$(format_size $TOTAL_SWAP_RAW) echo -e "Swap : $TOTAL_SWAP" # total disk size is calculated by adding all partitions of the types listed below (after the -t flags) TOTAL_DISK_RAW=$(df -t simfs -t ext2 -t ext3 -t ext4 -t btrfs -t xfs -t vfat -t ntfs -t swap --total 2>/dev/null | grep total | awk '{ print $2 }') TOTAL_DISK=$(format_size $TOTAL_DISK_RAW) echo -e "Disk : $TOTAL_DISK" DISTRO=$(grep 'PRETTY_NAME' /etc/os-release | cut -d '"' -f 2 ) echo -e "Distro : $DISTRO" KERNEL=$(uname -r) echo -e "Kernel : $KERNEL" VIRT=$(systemd-detect-virt 2>/dev/null) VIRT=${VIRT^^} || VIRT="UNKNOWN" echo -e "VM Type : $VIRT" [[ -z "$IPV4_CHECK" ]] && ONLINE="\xE2\x9D\x8C Offline / " || ONLINE="\xE2\x9C\x94 Online / " [[ -z "$IPV6_CHECK" ]] && ONLINE+="\xE2\x9D\x8C Offline" || ONLINE+="\xE2\x9C\x94 Online" echo -e "IPv4/IPv6 : $ONLINE" # Function to get information from IP Address using ip-api.com free API function ip_info() { # check for curl vs wget [[ ! -z $LOCAL_CURL ]] && DL_CMD="curl -s" || DL_CMD="wget -qO-" local ip6me_resp="$($DL_CMD http://ip6.me/api/)" local net_type="$(echo $ip6me_resp | cut -d, -f1)" local net_ip="$(echo $ip6me_resp | cut -d, -f2)" local response=$($DL_CMD http://ip-api.com/json/$net_ip) # if no response, skip output if [[ -z $response ]]; then return fi local country=$(echo "$response" | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^country/ {print $2}' | head -1 | sed 's/^"\(.*\)"$/\1/') local region=$(echo "$response" | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^regionName/ {print $2}' | sed 's/^"\(.*\)"$/\1/') local region_code=$(echo "$response" | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^region/ {print $2}' | head -1 | sed 's/^"\(.*\)"$/\1/') local city=$(echo "$response" | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^city/ {print $2}' | sed 's/^"\(.*\)"$/\1/') local isp=$(echo "$response" | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^isp/ {print $2}' | sed 's/^"\(.*\)"$/\1/') local org=$(echo "$response" | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^org/ {print $2}' | sed 's/^"\(.*\)"$/\1/') local as=$(echo "$response" | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^as/ {print $2}' | sed 's/^"\(.*\)"$/\1/') echo echo "$net_type Network Information:" echo "---------------------------------" if [[ -n "$isp" ]]; then echo "ISP : $isp" else echo "ISP : Unknown" fi if [[ -n "$as" ]]; then echo "ASN : $as" else echo "ASN : Unknown" fi if [[ -n "$org" ]]; then echo "Host : $org" fi if [[ -n "$city" && -n "$region" ]]; then echo "Location : $city, $region ($region_code)" fi if [[ -n "$country" ]]; then echo "Country : $country" fi [[ ! -z $JSON ]] && JSON_RESULT+=',"ip_info":{"protocol":"'$net_type'","isp":"'$isp'","asn":"'$as'","org":"'$org'","city":"'$city'","region":"'$region'","region_code":"'$region_code'","country":"'$country'"}' } if [ ! -z $JSON ]; then UPTIME_S=$(awk '{print $1}' /proc/uptime) IPV4=$([ ! -z $IPV4_CHECK ] && echo "true" || echo "false") IPV6=$([ ! -z $IPV6_CHECK ] && echo "true" || echo "false") AES=$([[ "$CPU_AES" = *Enabled* ]] && echo "true" || echo "false") CPU_VIRT_BOOL=$([[ "$CPU_VIRT" = *Enabled* ]] && echo "true" || echo "false") JSON_RESULT='{"version":"'$YABS_VERSION'","time":"'$TIME_START'","os":{"arch":"'$ARCH'","distro":"'$DISTRO'","kernel":"'$KERNEL'",' JSON_RESULT+='"uptime":'$UPTIME_S',"vm":"'$VIRT'"},"net":{"ipv4":'$IPV4',"ipv6":'$IPV6'},"cpu":{"model":"'$CPU_PROC'","cores":'$CPU_CORES',' JSON_RESULT+='"freq":"'$CPU_FREQ'","aes":'$AES',"virt":'$CPU_VIRT_BOOL'},"mem":{"ram":'$TOTAL_RAM_RAW',"ram_units":"KiB","swap":'$TOTAL_SWAP_RAW',"swap_units":"KiB","disk":'$TOTAL_DISK_RAW',"disk_units":"KB"}' fi if [ -z $SKIP_NET ]; then ip_info fi # create a directory in the same location that the script is being run to temporarily store YABS-related files DATE=$(date -Iseconds | sed -e "s/:/_/g") YABS_PATH=./$DATE touch "$DATE.test" 2> /dev/null # test if the user has write permissions in the current directory and exit if not if [ ! -f "$DATE.test" ]; then echo -e echo -e "You do not have write permission in this directory. Switch to an owned directory and re-run the script.\nExiting..." exit 1 fi rm "$DATE.test" mkdir -p "$YABS_PATH" # trap CTRL+C signals to exit script cleanly trap catch_abort INT # catch_abort # Purpose: This method will catch CTRL+C signals in order to exit the script cleanly and remove # yabs-related files. function catch_abort() { echo -e "\n** Aborting YABS. Cleaning up files...\n" rm -rf "$YABS_PATH" unset LC_ALL exit 0 } # format_speed # Purpose: This method is a convenience function to format the output of the fio disk tests which # always returns a result in KB/s. If result is >= 1 GB/s, use GB/s. If result is < 1 GB/s # and >= 1 MB/s, then use MB/s. Otherwise, use KB/s. # Parameters: # 1. RAW - the raw disk speed result (in KB/s) # Returns: # Formatted disk speed in GB/s, MB/s, or KB/s function format_speed { RAW=$1 # disk speed in KB/s RESULT=$RAW local DENOM=1 local UNIT="KB/s" # ensure raw value is not null, if it is, return blank if [ -z "$RAW" ]; then echo "" return 0 fi # check if disk speed >= 1 GB/s if [ "$RAW" -ge 1000000 ]; then DENOM=1000000 UNIT="GB/s" # check if disk speed < 1 GB/s && >= 1 MB/s elif [ "$RAW" -ge 1000 ]; then DENOM=1000 UNIT="MB/s" fi # divide the raw result to get the corresponding formatted result (based on determined unit) RESULT=$(awk -v a="$RESULT" -v b="$DENOM" 'BEGIN { print a / b }') # shorten the formatted result to two decimal places (i.e. x.xx) RESULT=$(echo $RESULT | awk -F. '{ printf "%0.2f",$1"."substr($2,1,2) }') # concat formatted result value with units and return result RESULT="$RESULT $UNIT" echo $RESULT } # format_iops # Purpose: This method is a convenience function to format the output of the raw IOPS result # Parameters: # 1. RAW - the raw IOPS result # Returns: # Formatted IOPS (i.e. 8, 123, 1.7k, 275.9k, etc.) function format_iops { RAW=$1 # iops RESULT=$RAW # ensure raw value is not null, if it is, return blank if [ -z "$RAW" ]; then echo "" return 0 fi # check if IOPS speed > 1k if [ "$RAW" -ge 1000 ]; then # divide the raw result by 1k RESULT=$(awk -v a="$RESULT" 'BEGIN { print a / 1000 }') # shorten the formatted result to one decimal place (i.e. x.x) RESULT=$(echo $RESULT | awk -F. '{ printf "%0.1f",$1"."substr($2,1,1) }') RESULT="$RESULT"k fi echo $RESULT } # disk_test # Purpose: This method is designed to test the disk performance of the host using the partition that the # script is being run from using fio random read/write speed tests. # Parameters: # - (none) function disk_test { if [[ "$ARCH" = "aarch64" || "$ARCH" = "arm" ]]; then FIO_SIZE=512M else FIO_SIZE=2G fi # run a quick test to generate the fio test file to be used by the actual tests echo -en "Generating fio test file..." $FIO_CMD --name=setup --ioengine=libaio --rw=read --bs=64k --iodepth=64 --numjobs=2 --size=$FIO_SIZE --runtime=1 --gtod_reduce=1 --filename="$DISK_PATH/test.fio" --direct=1 --minimal &> /dev/null echo -en "\r\033[0K" # get array of block sizes to evaluate BLOCK_SIZES=("$@") for BS in "${BLOCK_SIZES[@]}"; do # run rand read/write mixed fio test with block size = $BS echo -en "Running fio random mixed R+W disk test with $BS block size..." DISK_TEST=$(timeout 35 $FIO_CMD --name=rand_rw_$BS --ioengine=libaio --rw=randrw --rwmixread=50 --bs=$BS --iodepth=64 --numjobs=2 --size=$FIO_SIZE --runtime=30 --gtod_reduce=1 --direct=1 --filename="$DISK_PATH/test.fio" --group_reporting --minimal 2> /dev/null | grep rand_rw_$BS) DISK_IOPS_R=$(echo $DISK_TEST | awk -F';' '{print $8}') DISK_IOPS_W=$(echo $DISK_TEST | awk -F';' '{print $49}') DISK_IOPS=$(awk -v a="$DISK_IOPS_R" -v b="$DISK_IOPS_W" 'BEGIN { print a + b }') DISK_TEST_R=$(echo $DISK_TEST | awk -F';' '{print $7}') DISK_TEST_W=$(echo $DISK_TEST | awk -F';' '{print $48}') DISK_TEST=$(awk -v a="$DISK_TEST_R" -v b="$DISK_TEST_W" 'BEGIN { print a + b }') DISK_RESULTS_RAW+=( "$DISK_TEST" "$DISK_TEST_R" "$DISK_TEST_W" "$DISK_IOPS" "$DISK_IOPS_R" "$DISK_IOPS_W" ) DISK_IOPS=$(format_iops $DISK_IOPS) DISK_IOPS_R=$(format_iops $DISK_IOPS_R) DISK_IOPS_W=$(format_iops $DISK_IOPS_W) DISK_TEST=$(format_speed $DISK_TEST) DISK_TEST_R=$(format_speed $DISK_TEST_R) DISK_TEST_W=$(format_speed $DISK_TEST_W) DISK_RESULTS+=( "$DISK_TEST" "$DISK_TEST_R" "$DISK_TEST_W" "$DISK_IOPS" "$DISK_IOPS_R" "$DISK_IOPS_W" ) echo -en "\r\033[0K" done } # dd_test # Purpose: This method is invoked if the fio disk test failed. dd sequential speed tests are # not indiciative or real-world results, however, some form of disk speed measure # is better than nothing. # Parameters: # - (none) function dd_test { I=0 DISK_WRITE_TEST_RES=() DISK_READ_TEST_RES=() DISK_WRITE_TEST_AVG=0 DISK_READ_TEST_AVG=0 # run the disk speed tests (write and read) thrice over while [ $I -lt 3 ] do # write test using dd, "direct" flag is used to test direct I/O for data being stored to disk DISK_WRITE_TEST=$(dd if=/dev/zero of="$DISK_PATH/$DATE.test" bs=64k count=16k oflag=direct |& grep copied | awk '{ print $(NF-1) " " $(NF)}') VAL=$(echo $DISK_WRITE_TEST | cut -d " " -f 1) [[ "$DISK_WRITE_TEST" == *"GB"* ]] && VAL=$(awk -v a="$VAL" 'BEGIN { print a * 1000 }') DISK_WRITE_TEST_RES+=( "$DISK_WRITE_TEST" ) DISK_WRITE_TEST_AVG=$(awk -v a="$DISK_WRITE_TEST_AVG" -v b="$VAL" 'BEGIN { print a + b }') # read test using dd using the 1G file written during the write test DISK_READ_TEST=$(dd if="$DISK_PATH/$DATE.test" of=/dev/null bs=8k |& grep copied | awk '{ print $(NF-1) " " $(NF)}') VAL=$(echo $DISK_READ_TEST | cut -d " " -f 1) [[ "$DISK_READ_TEST" == *"GB"* ]] && VAL=$(awk -v a="$VAL" 'BEGIN { print a * 1000 }') DISK_READ_TEST_RES+=( "$DISK_READ_TEST" ) DISK_READ_TEST_AVG=$(awk -v a="$DISK_READ_TEST_AVG" -v b="$VAL" 'BEGIN { print a + b }') I=$(( $I + 1 )) done # calculate the write and read speed averages using the results from the three runs DISK_WRITE_TEST_AVG=$(awk -v a="$DISK_WRITE_TEST_AVG" 'BEGIN { print a / 3 }') DISK_READ_TEST_AVG=$(awk -v a="$DISK_READ_TEST_AVG" 'BEGIN { print a / 3 }') } # check if disk performance is being tested and the host has required space (2G) AVAIL_SPACE=$(df -k . | awk 'NR==2{print $4}') if [[ -z "$SKIP_FIO" && "$AVAIL_SPACE" -lt 2097152 && "$ARCH" != "aarch64" && "$ARCH" != "arm" ]]; then # 2GB = 2097152KB echo -e "\nLess than 2GB of space available. Skipping disk test..." elif [[ -z "$SKIP_FIO" && "$AVAIL_SPACE" -lt 524288 && ("$ARCH" = "aarch64" || "$ARCH" = "arm") ]]; then # 512MB = 524288KB echo -e "\nLess than 512MB of space available. Skipping disk test..." # if the skip disk flag was set, skip the disk performance test, otherwise test disk performance elif [ -z "$SKIP_FIO" ]; then # Perform ZFS filesystem detection and determine if we have enough free space according to spa_asize_inflation ZFSCHECK="/sys/module/zfs/parameters/spa_asize_inflation" if [[ -f "$ZFSCHECK" ]];then mul_spa=$((($(cat /sys/module/zfs/parameters/spa_asize_inflation)*2))) warning=0 poss=() for pathls in $(df -Th | awk '{print $7}' | tail -n +2) do if [[ "${PWD##$pathls}" != "${PWD}" ]]; then poss+=("$pathls") fi done long="" m=-1 for x in ${poss[@]} do if [ ${#x} -gt $m ];then m=${#x} long=$x fi done size_b=$(df -Th | grep -w $long | grep -i zfs | awk '{print $5}' | tail -c -2 | head -c 1) free_space=$(df -Th | grep -w $long | grep -i zfs | awk '{print $5}' | head -c -2) if [[ $size_b == 'T' ]]; then free_space=$(awk "BEGIN {print int($free_space * 1024)}") size_b='G' fi if [[ $(df -Th | grep -w $long) == *"zfs"* ]];then if [[ $size_b == 'G' ]]; then if ((free_space < mul_spa)); then warning=1 fi else warning=1 fi fi if [[ $warning -eq 1 ]];then echo -en "\nWarning! You are running YABS on a ZFS Filesystem and your disk space is too low for the fio test. Your test results will be inaccurate. You need at least $mul_spa GB free in order to complete this test accurately. For more information, please see https://github.com/masonr/yet-another-bench-script/issues/13\n" fi fi echo -en "\nPreparing system for disk tests..." # create temp directory to store disk write/read test files DISK_PATH=$YABS_PATH/disk mkdir -p "$DISK_PATH" if [[ -z "$PREFER_BIN" && ! -z "$LOCAL_FIO" ]]; then # local fio has been detected, use instead of pre-compiled binary FIO_CMD=fio else # download fio binary if [[ ! -z $LOCAL_CURL ]]; then curl -s --connect-timeout 5 --retry 5 --retry-delay 0 https://raw.githubusercontent.com/masonr/yet-another-bench-script/master/bin/fio/fio_$ARCH -o "$DISK_PATH/fio" else wget -q -T 5 -t 5 -w 0 https://raw.githubusercontent.com/masonr/yet-another-bench-script/master/bin/fio/fio_$ARCH -O "$DISK_PATH/fio" fi if [ ! -f "$DISK_PATH/fio" ]; then # ensure fio binary download successfully echo -en "\r\033[0K" echo -e "Fio binary download failed. Running dd test as fallback...." DD_FALLBACK=True else chmod +x "$DISK_PATH/fio" FIO_CMD=$DISK_PATH/fio fi fi if [ -z "$DD_FALLBACK" ]; then # if not falling back on dd tests, run fio test echo -en "\r\033[0K" # init global array to store disk performance values declare -a DISK_RESULTS DISK_RESULTS_RAW # disk block sizes to evaluate BLOCK_SIZES=( "4k" "64k" "512k" "1m" ) # execute disk performance test disk_test "${BLOCK_SIZES[@]}" fi if [[ ! -z "$DD_FALLBACK" || ${#DISK_RESULTS[@]} -eq 0 ]]; then # fio download failed or test was killed or returned an error, run dd test instead if [ -z "$DD_FALLBACK" ]; then # print error notice if ended up here due to fio error echo -e "fio disk speed tests failed. Run manually to determine cause.\nRunning dd test as fallback..." fi dd_test # format the speed averages by converting to GB/s if > 1000 MB/s if [ $(echo $DISK_WRITE_TEST_AVG | cut -d "." -f 1) -ge 1000 ]; then DISK_WRITE_TEST_AVG=$(awk -v a="$DISK_WRITE_TEST_AVG" 'BEGIN { print a / 1000 }') DISK_WRITE_TEST_UNIT="GB/s" else DISK_WRITE_TEST_UNIT="MB/s" fi if [ $(echo $DISK_READ_TEST_AVG | cut -d "." -f 1) -ge 1000 ]; then DISK_READ_TEST_AVG=$(awk -v a="$DISK_READ_TEST_AVG" 'BEGIN { print a / 1000 }') DISK_READ_TEST_UNIT="GB/s" else DISK_READ_TEST_UNIT="MB/s" fi # print dd sequential disk speed test results echo -e echo -e "dd Sequential Disk Speed Tests:" echo -e "---------------------------------" printf "%-6s | %-6s %-4s | %-6s %-4s | %-6s %-4s | %-6s %-4s\n" "" "Test 1" "" "Test 2" "" "Test 3" "" "Avg" "" printf "%-6s | %-6s %-4s | %-6s %-4s | %-6s %-4s | %-6s %-4s\n" printf "%-6s | %-11s | %-11s | %-11s | %-6.2f %-4s\n" "Write" "${DISK_WRITE_TEST_RES[0]}" "${DISK_WRITE_TEST_RES[1]}" "${DISK_WRITE_TEST_RES[2]}" "${DISK_WRITE_TEST_AVG}" "${DISK_WRITE_TEST_UNIT}" printf "%-6s | %-11s | %-11s | %-11s | %-6.2f %-4s\n" "Read" "${DISK_READ_TEST_RES[0]}" "${DISK_READ_TEST_RES[1]}" "${DISK_READ_TEST_RES[2]}" "${DISK_READ_TEST_AVG}" "${DISK_READ_TEST_UNIT}" else # fio tests completed successfully, print results CURRENT_PARTITION=$(df -P . 2>/dev/null | tail -1 | cut -d' ' -f 1) [[ ! -z $JSON ]] && JSON_RESULT+=',"partition":"'$CURRENT_PARTITION'","fio":[' DISK_RESULTS_NUM=$(expr ${#DISK_RESULTS[@]} / 6) DISK_COUNT=0 # print disk speed test results echo -e "fio Disk Speed Tests (Mixed R/W 50/50) (Partition $CURRENT_PARTITION):" echo -e "---------------------------------" while [ $DISK_COUNT -lt $DISK_RESULTS_NUM ] ; do if [ $DISK_COUNT -gt 0 ]; then printf "%-10s | %-20s | %-20s\n"; fi printf "%-10s | %-11s %8s | %-11s %8s\n" "Block Size" "${BLOCK_SIZES[DISK_COUNT]}" "(IOPS)" "${BLOCK_SIZES[DISK_COUNT+1]}" "(IOPS)" printf "%-10s | %-11s %8s | %-11s %8s\n" " ------" "---" "---- " "----" "---- " printf "%-10s | %-11s %8s | %-11s %8s\n" "Read" "${DISK_RESULTS[DISK_COUNT*6+1]}" "(${DISK_RESULTS[DISK_COUNT*6+4]})" "${DISK_RESULTS[(DISK_COUNT+1)*6+1]}" "(${DISK_RESULTS[(DISK_COUNT+1)*6+4]})" printf "%-10s | %-11s %8s | %-11s %8s\n" "Write" "${DISK_RESULTS[DISK_COUNT*6+2]}" "(${DISK_RESULTS[DISK_COUNT*6+5]})" "${DISK_RESULTS[(DISK_COUNT+1)*6+2]}" "(${DISK_RESULTS[(DISK_COUNT+1)*6+5]})" printf "%-10s | %-11s %8s | %-11s %8s\n" "Total" "${DISK_RESULTS[DISK_COUNT*6]}" "(${DISK_RESULTS[DISK_COUNT*6+3]})" "${DISK_RESULTS[(DISK_COUNT+1)*6]}" "(${DISK_RESULTS[(DISK_COUNT+1)*6+3]})" if [ ! -z $JSON ]; then JSON_RESULT+='{"bs":"'${BLOCK_SIZES[DISK_COUNT]}'","speed_r":'${DISK_RESULTS_RAW[DISK_COUNT*6+1]}',"iops_r":'${DISK_RESULTS_RAW[DISK_COUNT*6+4]} JSON_RESULT+=',"speed_w":'${DISK_RESULTS_RAW[DISK_COUNT*6+2]}',"iops_w":'${DISK_RESULTS_RAW[DISK_COUNT*6+5]}',"speed_rw":'${DISK_RESULTS_RAW[DISK_COUNT*6]} JSON_RESULT+=',"iops_rw":'${DISK_RESULTS_RAW[DISK_COUNT*6+3]}',"speed_units":"KBps"},' JSON_RESULT+='{"bs":"'${BLOCK_SIZES[DISK_COUNT+1]}'","speed_r":'${DISK_RESULTS_RAW[(DISK_COUNT+1)*6+1]}',"iops_r":'${DISK_RESULTS_RAW[(DISK_COUNT+1)*6+4]} JSON_RESULT+=',"speed_w":'${DISK_RESULTS_RAW[(DISK_COUNT+1)*6+2]}',"iops_w":'${DISK_RESULTS_RAW[(DISK_COUNT+1)*6+5]}',"speed_rw":'${DISK_RESULTS_RAW[(DISK_COUNT+1)*6]} JSON_RESULT+=',"iops_rw":'${DISK_RESULTS_RAW[(DISK_COUNT+1)*6+3]}',"speed_units":"KBps"},' fi DISK_COUNT=$(expr $DISK_COUNT + 2) done [[ ! -z $JSON ]] && JSON_RESULT=${JSON_RESULT::${#JSON_RESULT}-1} && JSON_RESULT+=']' fi fi # iperf_test # Purpose: This method is designed to test the network performance of the host by executing an # iperf3 test to/from the public iperf server passed to the function. Both directions # (send and receive) are tested. # Parameters: # 1. URL - URL/domain name of the iperf server # 2. PORTS - the range of ports on which the iperf server operates # 3. HOST - the friendly name of the iperf server host/owner # 4. FLAGS - any flags that should be passed to the iperf command function iperf_test { URL=$1 PORTS=$2 HOST=$3 FLAGS=$4 # attempt the iperf send test 3 times, allowing for a slot to become available on the # server or to throw out any bad/error results I=1 while [ $I -le 3 ] do echo -en "Performing $MODE iperf3 send test to $HOST (Attempt #$I of 3)..." # select a random iperf port from the range provided PORT=$(shuf -i $PORTS -n 1) # run the iperf test sending data from the host to the iperf server; includes # a timeout of 15s in case the iperf server is not responding; uses 8 parallel # threads for the network test IPERF_RUN_SEND="$(timeout 15 $IPERF_CMD $FLAGS -c "$URL" -p $PORT -P 8 2> /dev/null)" # check if iperf exited cleanly and did not return an error if [[ "$IPERF_RUN_SEND" == *"receiver"* && "$IPERF_RUN_SEND" != *"error"* ]]; then # test did not result in an error, parse speed result SPEED=$(echo "${IPERF_RUN_SEND}" | grep SUM | grep receiver | awk '{ print $6 }') # if speed result is blank or bad (0.00), rerun, otherwise set counter to exit loop [[ -z $SPEED || "$SPEED" == "0.00" ]] && I=$(( $I + 1 )) || I=11 else # if iperf server is not responding, set counter to exit, otherwise increment, sleep, and rerun [[ "$IPERF_RUN_SEND" == *"unable to connect"* ]] && I=11 || I=$(( $I + 1 )) && sleep 2 fi echo -en "\r\033[0K" done # small sleep necessary to give iperf server a breather to get ready for a new test sleep 1 # attempt the iperf receive test 3 times, allowing for a slot to become available on # the server or to throw out any bad/error results J=1 while [ $J -le 3 ] do echo -n "Performing $MODE iperf3 recv test from $HOST (Attempt #$J of 3)..." # select a random iperf port from the range provided PORT=$(shuf -i $PORTS -n 1) # run the iperf test receiving data from the iperf server to the host; includes # a timeout of 15s in case the iperf server is not responding; uses 8 parallel # threads for the network test IPERF_RUN_RECV="$(timeout 15 $IPERF_CMD $FLAGS -c "$URL" -p $PORT -P 8 -R 2> /dev/null)" # check if iperf exited cleanly and did not return an error if [[ "$IPERF_RUN_RECV" == *"receiver"* && "$IPERF_RUN_RECV" != *"error"* ]]; then # test did not result in an error, parse speed result SPEED=$(echo "${IPERF_RUN_RECV}" | grep SUM | grep receiver | awk '{ print $6 }') # if speed result is blank or bad (0.00), rerun, otherwise set counter to exit loop [[ -z $SPEED || "$SPEED" == "0.00" ]] && J=$(( $J + 1 )) || J=11 else # if iperf server is not responding, set counter to exit, otherwise increment, sleep, and rerun [[ "$IPERF_RUN_RECV" == *"unable to connect"* ]] && J=11 || J=$(( $J + 1 )) && sleep 2 fi echo -en "\r\033[0K" done # Run a latency test via ping -c1 command -> will return "xx.x ms" [[ ! -z $LOCAL_PING ]] && LATENCY_RUN="$(ping -c1 $URL 2>/dev/null | grep -o 'time=.*' | sed s/'time='//)" [[ -z $LATENCY_RUN ]] && LATENCY_RUN="--" # parse the resulting send and receive speed results IPERF_SENDRESULT="$(echo "${IPERF_RUN_SEND}" | grep SUM | grep receiver)" IPERF_RECVRESULT="$(echo "${IPERF_RUN_RECV}" | grep SUM | grep receiver)" LATENCY_RESULT="$(echo "${LATENCY_RUN}")" } # launch_iperf # Purpose: This method is designed to facilitate the execution of iperf network speed tests to # each public iperf server in the iperf server locations array. # Parameters: # 1. MODE - indicates the type of iperf tests to run (IPv4 or IPv6) function launch_iperf { MODE=$1 [[ "$MODE" == *"IPv6"* ]] && IPERF_FLAGS="-6" || IPERF_FLAGS="-4" # print iperf3 network speed results as they are completed echo -e echo -e "iperf3 Network Speed Tests ($MODE):" echo -e "---------------------------------" printf "%-15s | %-25s | %-15s | %-15s | %-15s\n" "Provider" "Location (Link)" "Send Speed" "Recv Speed" "Ping" printf "%-15s | %-25s | %-15s | %-15s | %-15s\n" "-----" "-----" "----" "----" "----" # loop through iperf locations array to run iperf test using each public iperf server for (( i = 0; i < IPERF_LOCS_NUM; i++ )); do # test if the current iperf location supports the network mode being tested (IPv4/IPv6) if [[ "${IPERF_LOCS[i*5+4]}" == *"$MODE"* ]]; then # call the iperf_test function passing the required parameters iperf_test "${IPERF_LOCS[i*5]}" "${IPERF_LOCS[i*5+1]}" "${IPERF_LOCS[i*5+2]}" "$IPERF_FLAGS" # parse the send and receive speed results IPERF_SENDRESULT_VAL=$(echo $IPERF_SENDRESULT | awk '{ print $6 }') IPERF_SENDRESULT_UNIT=$(echo $IPERF_SENDRESULT | awk '{ print $7 }') IPERF_RECVRESULT_VAL=$(echo $IPERF_RECVRESULT | awk '{ print $6 }') IPERF_RECVRESULT_UNIT=$(echo $IPERF_RECVRESULT | awk '{ print $7 }') LATENCY_VAL=$(echo $LATENCY_RESULT) # if the results are blank, then the server is "busy" and being overutilized [[ -z $IPERF_SENDRESULT_VAL || "$IPERF_SENDRESULT_VAL" == *"0.00"* ]] && IPERF_SENDRESULT_VAL="busy" && IPERF_SENDRESULT_UNIT="" [[ -z $IPERF_RECVRESULT_VAL || "$IPERF_RECVRESULT_VAL" == *"0.00"* ]] && IPERF_RECVRESULT_VAL="busy" && IPERF_RECVRESULT_UNIT="" # print the speed results for the iperf location currently being evaluated printf "%-15s | %-25s | %-15s | %-15s | %-15s\n" "${IPERF_LOCS[i*5+2]}" "${IPERF_LOCS[i*5+3]}" "$IPERF_SENDRESULT_VAL $IPERF_SENDRESULT_UNIT" "$IPERF_RECVRESULT_VAL $IPERF_RECVRESULT_UNIT" "$LATENCY_VAL" if [ ! -z $JSON ]; then JSON_RESULT+='{"mode":"'$MODE'","provider":"'${IPERF_LOCS[i*5+2]}'","loc":"'${IPERF_LOCS[i*5+3]} JSON_RESULT+='","send":"'$IPERF_SENDRESULT_VAL' '$IPERF_SENDRESULT_UNIT'","recv":"'$IPERF_RECVRESULT_VAL' '$IPERF_RECVRESULT_UNIT'","latency":"'$LATENCY_VAL'"},' fi fi done } # if the skip iperf flag was set, skip the network performance test, otherwise test network performance if [ -z "$SKIP_IPERF" ]; then if [[ -z "$PREFER_BIN" && ! -z "$LOCAL_IPERF" ]]; then # local iperf has been detected, use instead of pre-compiled binary IPERF_CMD=iperf3 else # create a temp directory to house the required iperf binary and library IPERF_PATH=$YABS_PATH/iperf mkdir -p "$IPERF_PATH" # download iperf3 binary if [[ ! -z $LOCAL_CURL ]]; then curl -s --connect-timeout 5 --retry 5 --retry-delay 0 https://raw.githubusercontent.com/masonr/yet-another-bench-script/master/bin/iperf/iperf3_$ARCH -o "$IPERF_PATH/iperf3" else wget -q -T 5 -t 5 -w 0 https://raw.githubusercontent.com/masonr/yet-another-bench-script/master/bin/iperf/iperf3_$ARCH -O "$IPERF_PATH/iperf3" fi if [ ! -f "$IPERF_PATH/iperf3" ]; then # ensure iperf3 binary downloaded successfully IPERF_DL_FAIL=True else chmod +x "$IPERF_PATH/iperf3" IPERF_CMD=$IPERF_PATH/iperf3 fi fi # array containing all currently available iperf3 public servers to use for the network test # format: "1" "2" "3" "4" "5" \ # 1. domain name of the iperf server # 2. range of ports that the iperf server is running on (lowest-highest) # 3. friendly name of the host/owner of the iperf server # 4. location and advertised speed link of the iperf server # 5. network modes supported by the iperf server (IPv4 = IPv4-only, IPv4|IPv6 = IPv4 + IPv6, etc.) IPERF_LOCS=( \ "lon.speedtest.clouvider.net" "5200-5209" "Clouvider" "London, UK (10G)" "IPv4|IPv6" \ "iperf-ams-nl.eranium.net" "5201-5210" "Eranium" "Amsterdam, NL (100G)" "IPv4|IPv6" \ "speedtest.extra.telia.fi" "5201-5208" "Telia" "Helsinki, FI (10G)" "IPv4" \ # AFR placeholder "speedtest.uztelecom.uz" "5200-5209" "Uztelecom" "Tashkent, UZ (10G)" "IPv4|IPv6" \ "speedtest.sin1.sg.leaseweb.net" "5201-5210" "Leaseweb" "Singapore, SG (10G)" "IPv4|IPv6" \ "la.speedtest.clouvider.net" "5200-5209" "Clouvider" "Los Angeles, CA, US (10G)" "IPv4|IPv6" \ "speedtest.nyc1.us.leaseweb.net" "5201-5210" "Leaseweb" "NYC, NY, US (10G)" "IPv4|IPv6" \ "speedtest.sao1.edgoo.net" "9204-9240" "Edgoo" "Sao Paulo, BR (1G)" "IPv4|IPv6" ) # if the "REDUCE_NET" flag is activated, then do a shorter iperf test with only three locations # (Clouvider London, Clouvider NYC, and Online.net France) if [ ! -z "$REDUCE_NET" ]; then IPERF_LOCS=( \ "lon.speedtest.clouvider.net" "5200-5209" "Clouvider" "London, UK (10G)" "IPv4|IPv6" \ "speedtest.sin1.sg.leaseweb.net" "5201-5210" "Leaseweb" "Singapore, SG (10G)" "IPv4|IPv6" \ "speedtest.nyc1.us.leaseweb.net" "5201-5210" "Leaseweb" "NYC, NY, US (10G)" "IPv4|IPv6" \ ) fi # get the total number of iperf locations (total array size divided by 5 since each location has 5 elements) IPERF_LOCS_NUM=${#IPERF_LOCS[@]} IPERF_LOCS_NUM=$((IPERF_LOCS_NUM / 5)) if [ -z "$IPERF_DL_FAIL" ]; then [[ ! -z $JSON ]] && JSON_RESULT+=',"iperf":[' # check if the host has IPv4 connectivity, if so, run iperf3 IPv4 tests [ ! -z "$IPV4_CHECK" ] && launch_iperf "IPv4" # check if the host has IPv6 connectivity, if so, run iperf3 IPv6 tests [ ! -z "$IPV6_CHECK" ] && launch_iperf "IPv6" [[ ! -z $JSON ]] && JSON_RESULT=${JSON_RESULT::${#JSON_RESULT}-1} && JSON_RESULT+=']' else echo -e "\niperf3 binary download failed. Skipping iperf network tests..." fi fi # launch_geekbench # Purpose: This method is designed to run the Primate Labs' Geekbench 4/5 Cross-Platform Benchmark utility # Parameters: # 1. VERSION - indicates which Geekbench version to run function launch_geekbench { VERSION=$1 # create a temp directory to house all geekbench files GEEKBENCH_PATH=$YABS_PATH/geekbench_$VERSION mkdir -p "$GEEKBENCH_PATH" GB_URL="" GB_CMD="" GB_RUN="" # check for curl vs wget [[ ! -z $LOCAL_CURL ]] && DL_CMD="curl -s" || DL_CMD="wget -qO-" if [[ $VERSION == *4* && ($ARCH = *aarch64* || $ARCH = *arm*) ]]; then echo -e "\nARM architecture not supported by Geekbench 4, use Geekbench 5 or 6." elif [[ $VERSION == *4* && $ARCH != *aarch64* && $ARCH != *arm* ]]; then # Geekbench v4 GB_URL="https://cdn.geekbench.com/Geekbench-4.4.4-Linux.tar.gz" [[ "$ARCH" == *"x86"* ]] && GB_CMD="geekbench_x86_32" || GB_CMD="geekbench4" GB_RUN="True" elif [[ $VERSION == *5* || $VERSION == *6* ]]; then # Geekbench v5/6 if [[ $ARCH = *x86* && $GEEKBENCH_4 == *False* ]]; then # don't run Geekbench 5 if on 32-bit arch echo -e "\nGeekbench $VERSION cannot run on 32-bit architectures. Re-run with -4 flag to use" echo -e "Geekbench 4, which can support 32-bit architectures. Skipping Geekbench $VERSION." elif [[ $ARCH = *x86* && $GEEKBENCH_4 == *True* ]]; then echo -e "\nGeekbench $VERSION cannot run on 32-bit architectures. Skipping test." else if [[ $VERSION == *5* ]]; then # Geekbench v5 [[ $ARCH = *aarch64* || $ARCH = *arm* ]] && GB_URL="https://cdn.geekbench.com/Geekbench-5.5.1-LinuxARMPreview.tar.gz" \ || GB_URL="https://cdn.geekbench.com/Geekbench-5.5.1-Linux.tar.gz" GB_CMD="geekbench5" else # Geekbench v6 [[ $ARCH = *aarch64* || $ARCH = *arm* ]] && GB_URL="https://cdn.geekbench.com/Geekbench-6.3.0-LinuxARMPreview.tar.gz" \ || GB_URL="https://cdn.geekbench.com/Geekbench-6.3.0-Linux.tar.gz" GB_CMD="geekbench6" fi GB_RUN="True" fi fi if [[ $GB_RUN == *True* ]]; then # run GB test echo -en "\nRunning GB$VERSION benchmark test... *cue elevator music*" # check for local geekbench installed if command -v "$GB_CMD" &>/dev/null; then GEEKBENCH_PATH=$(dirname "$(command -v "$GB_CMD")") else # download the desired Geekbench tarball and extract to geekbench temp directory $DL_CMD $GB_URL | tar xz --strip-components=1 -C "$GEEKBENCH_PATH" &>/dev/null fi # unlock if license file detected test -f "geekbench.license" && "$GEEKBENCH_PATH/$GB_CMD" --unlock $(cat geekbench.license) > /dev/null 2>&1 # run the Geekbench test and grep the test results URL given at the end of the test GEEKBENCH_TEST=$("$GEEKBENCH_PATH/$GB_CMD" --upload 2>/dev/null | grep "https://browser") # ensure the test ran successfully if [ -z "$GEEKBENCH_TEST" ]; then # detect if CentOS 7 and print a more helpful error message if grep -q "CentOS Linux 7" /etc/os-release; then echo -e "\r\033[0K CentOS 7 and Geekbench have known issues relating to glibc (see issue #71 for details)" fi if [[ -z "$IPV4_CHECK" ]]; then # Geekbench test failed to download because host lacks IPv4 (cdn.geekbench.com = IPv4 only) echo -e "\r\033[0KGeekbench releases can only be downloaded over IPv4. FTP the Geekbench files and run manually." elif [[ $VERSION != *4* && $TOTAL_RAM_RAW -le 1048576 ]]; then # Geekbench 5/6 test failed with low memory (<=1GB) echo -e "\r\033[0KGeekbench test failed and low memory was detected. Add at least 1GB of SWAP or use GB4 instead (higher compatibility with low memory systems)." elif [[ $ARCH != *x86* ]]; then # if the Geekbench test failed for any other reason, exit cleanly and print error message echo -e "\r\033[0KGeekbench $VERSION test failed. Run manually to determine cause." fi else # if the Geekbench test succeeded, parse the test results URL GEEKBENCH_URL=$(echo -e $GEEKBENCH_TEST | head -1) GEEKBENCH_URL_CLAIM=$(echo $GEEKBENCH_URL | awk '{ print $2 }') GEEKBENCH_URL=$(echo $GEEKBENCH_URL | awk '{ print $1 }') # sleep a bit to wait for results to be made available on the geekbench website sleep 10 # parse the public results page for the single and multi core geekbench scores [[ $VERSION == *4* ]] && GEEKBENCH_SCORES=$($DL_CMD $GEEKBENCH_URL | grep "span class='score'") || \ GEEKBENCH_SCORES=$($DL_CMD $GEEKBENCH_URL | grep "div class='score'") GEEKBENCH_SCORES_SINGLE=$(echo $GEEKBENCH_SCORES | awk -v FS="(>|<)" '{ print $3 }') GEEKBENCH_SCORES_MULTI=$(echo $GEEKBENCH_SCORES | awk -v FS="(>|<)" '{ print $7 }') # print the Geekbench results echo -en "\r\033[0K" echo -e "Geekbench $VERSION Benchmark Test:" echo -e "---------------------------------" printf "%-15s | %-30s\n" "Test" "Value" printf "%-15s | %-30s\n" printf "%-15s | %-30s\n" "Single Core" "$GEEKBENCH_SCORES_SINGLE" printf "%-15s | %-30s\n" "Multi Core" "$GEEKBENCH_SCORES_MULTI" printf "%-15s | %-30s\n" "Full Test" "$GEEKBENCH_URL" if [ ! -z $JSON ]; then JSON_RESULT+='{"version":'$VERSION',"single":'$GEEKBENCH_SCORES_SINGLE',"multi":'$GEEKBENCH_SCORES_MULTI JSON_RESULT+=',"url":"'$GEEKBENCH_URL'"},' fi # write the geekbench claim URL to a file so the user can add the results to their profile (if desired) [ ! -z "$GEEKBENCH_URL_CLAIM" ] && echo -e "$GEEKBENCH_URL_CLAIM" >> geekbench_claim.url 2> /dev/null fi fi } # if the skip geekbench flag was set, skip the system performance test, otherwise test system performance if [ -z "$SKIP_GEEKBENCH" ]; then [[ ! -z $JSON ]] && JSON_RESULT+=',"geekbench":[' if [[ $GEEKBENCH_4 == *True* ]]; then launch_geekbench 4 fi if [[ $GEEKBENCH_5 == *True* ]]; then launch_geekbench 5 fi if [[ $GEEKBENCH_6 == *True* ]]; then launch_geekbench 6 fi [[ ! -z $JSON ]] && [[ $(echo -n $JSON_RESULT | tail -c 1) == ',' ]] && JSON_RESULT=${JSON_RESULT::${#JSON_RESULT}-1} [[ ! -z $JSON ]] && JSON_RESULT+=']' fi # finished all tests, clean up all YABS files and exit echo -e rm -rf "$YABS_PATH" YABS_END_TIME=$(date +%s) # calculate_time_taken # Purpose: This method is designed to find the time taken for the completion of a YABS run. # Parameters: # 1. YABS_END_TIME - time when GB has completed and all files are removed # 2. YABS_START_TIME - time when YABS is started function calculate_time_taken() { end_time=$1 start_time=$2 time_taken=$(( ${end_time} - ${start_time} )) if [ ${time_taken} -gt 60 ]; then min=$(expr $time_taken / 60) sec=$(expr $time_taken % 60) echo "YABS completed in ${min} min ${sec} sec" else echo "YABS completed in ${time_taken} sec" fi [[ ! -z $JSON ]] && JSON_RESULT+=',"runtime":{"start":'$start_time',"end":'$end_time',"elapsed":'$time_taken'}' } calculate_time_taken $YABS_END_TIME $YABS_START_TIME if [[ ! -z $JSON ]]; then JSON_RESULT+='}' # write json results to file if [[ $JSON = *w* ]]; then echo $JSON_RESULT > "$JSON_FILE" fi # send json results if [[ $JSON = *s* ]]; then IFS=',' read -r -a JSON_SITES <<< "$JSON_SEND" for JSON_SITE in "${JSON_SITES[@]}" do if [[ ! -z $LOCAL_CURL ]]; then curl -s -H "Content-Type:application/json" -X POST --data ''"$JSON_RESULT"'' $JSON_SITE else wget -qO- --post-data=''"$JSON_RESULT"'' --header='Content-Type:application/json' $JSON_SITE fi done fi # print json result to screen if [[ $JSON = *j* ]]; then echo -e echo $JSON_RESULT fi fi # reset locale settings unset LC_ALL