1# 2# This file and its contents are supplied under the terms of the 3# Common Development and Distribution License ("CDDL"), version 1.0. 4# You may only use this file in accordance with the terms of version 5# 1.0 of the CDDL. 6# 7# A full copy of the text of the CDDL should have accompanied this 8# source. A copy of the CDDL is also available via the Internet at 9# http://www.illumos.org/license/CDDL. 10# 11 12# 13# Copyright (c) 2015 by Delphix. All rights reserved. 14# 15 16. $STF_SUITE/include/libtest.shlib 17 18# If neither is specified, do a nightly run. 19[[ -z $PERF_REGRESSION_WEEKLY ]] && export PERF_REGRESSION_NIGHTLY=1 20 21# Default runtime for each type of test run. 22export PERF_RUNTIME_WEEKLY=$((30 * 60)) 23export PERF_RUNTIME_NIGHTLY=$((10 * 60)) 24 25# Default fs creation options 26export PERF_FS_OPTS=${PERF_FS_OPTS:-'-o recsize=8k -o compress=lz4' \ 27 ' -o checksum=sha256 -o redundant_metadata=most'} 28 29function get_sync_str 30{ 31 typeset sync=$1 32 typeset sync_str='' 33 34 [[ $sync -eq 0 ]] && sync_str='async' 35 [[ $sync -eq 1 ]] && sync_str='sync' 36 echo $sync_str 37} 38 39# 40# This function will run fio in a loop, according to the .fio file passed 41# in and a number of environment variables. The following variables can be 42# set before launching zfstest to override the defaults. 43# 44# PERF_RUNTIME: The time in seconds each fio invocation should run. 45# PERF_RUNTYPE: A human readable tag that appears in logs. The defaults are 46# nightly and weekly. 47# PERF_NTHREADS: A list of how many threads each fio invocation will use. 48# PERF_SYNC_TYPES: Whether to use (O_SYNC) or not. 1 is sync IO, 0 is async IO. 49# PERF_IOSIZES: A list of blocksizes in which each fio invocation will do IO. 50# PERF_COLLECT_SCRIPTS: A comma delimited list of 'command args, logfile_tag' 51# pairs that will be added to the scripts specified in each test. 52# 53function do_fio_run 54{ 55 typeset script=$1 56 typeset do_recreate=$2 57 typeset clear_cache=$3 58 typeset threads sync iosize 59 60 for threads in $PERF_NTHREADS; do 61 for sync in $PERF_SYNC_TYPES; do 62 for iosize in $PERF_IOSIZES; do 63 log_note "Running with $threads" \ 64 "$(get_sync_str $sync) threads, $iosize ios" 65 66 if $do_recreate; then 67 recreate_perfpool 68 log_must $ZFS create $PERF_FS_OPTS \ 69 $TESTFS 70 fi 71 72 if $clear_cache; then 73 # Clear the ARC 74 $ZPOOL export $PERFPOOL 75 $ZPOOL import $PERFPOOL 76 fi 77 78 export RUNTIME=$PERF_RUNTIME 79 export FILESIZE=$((TOTAL_SIZE / threads)) 80 export NUMJOBS=$threads 81 export SYNC_TYPE=$sync 82 export BLOCKSIZE=$iosize 83 $SYNC 84 85 # Start the data collection 86 do_collect_scripts $threads $sync $iosize 87 88 # Start the load 89 log_must $FIO $FIO_SCRIPTS/$script 90 done 91 done 92 done 93} 94 95# 96# This function iterates through the value pairs in $PERF_COLLECT_SCRIPTS. 97# The script at index N is launched in the background, with its output 98# redirected to a logfile containing the tag specified at index N + 1. 99# 100function do_collect_scripts 101{ 102 typeset threads=$1 103 typeset sync=$2 104 typeset iosize=$3 105 106 [[ -n $collect_scripts ]] || log_fail "No data collection scripts." 107 [[ -n $PERF_RUNTIME ]] || log_fail "No runtime specified." 108 109 # This will be part of the output filename. 110 typeset sync_str=$(get_sync_str $sync) 111 typeset suffix="$sync_str.$iosize-ios.$threads-threads" 112 113 # Add in user supplied scripts and logfiles, if any. 114 typeset oIFS=$IFS 115 IFS=',' 116 for item in $PERF_COLLECT_SCRIPTS; do 117 collect_scripts+=($($ECHO $item | $SED 's/^ *//g')) 118 done 119 IFS=$oIFS 120 121 typeset idx=0 122 while [[ $idx -lt "${#collect_scripts[@]}" ]]; do 123 typeset logbase="$(get_perf_output_dir)/$($BASENAME \ 124 $SUDO_COMMAND)" 125 typeset outfile="$logbase.${collect_scripts[$idx + 1]}.$suffix" 126 127 $TIMEOUT $PERF_RUNTIME ${collect_scripts[$idx]} >$outfile 2>&1 & 128 ((idx += 2)) 129 done 130 131 # Need to explicitly return 0 because timeout(1) will kill 132 # a child process and cause us to return non-zero. 133 return 0 134} 135 136# Find a place to deposit performance data collected while under load. 137function get_perf_output_dir 138{ 139 typeset dir="$(pwd)/perf_data" 140 [[ -d $dir ]] || $MKDIR -p $dir 141 142 $ECHO $dir 143} 144 145# 146# Destroy and create the pool used for performance tests. The 147# PERFPOOL_CREATE_CMD variable allows users to test with a custom pool 148# configuration by specifying the pool creation command in their environment. 149# If PERFPOOL_CREATE_CMD is empty, a pool using all available disks is created. 150# 151function recreate_perfpool 152{ 153 [[ -n $PERFPOOL ]] || log_fail "The \$PERFPOOL variable isn't set." 154 155 poolexists $PERFPOOL && destroy_pool $PERFPOOL 156 157 if [[ -n $PERFPOOL_CREATE_CMD ]]; then 158 log_must $PERFPOOL_CREATE_CMD 159 else 160 log_must eval "$ZPOOL create -f $PERFPOOL $DISKS" 161 fi 162} 163 164function get_max_arc_size 165{ 166 typeset -l max_arc_size=$(dtrace -qn 'BEGIN { 167 printf("%u\n", `arc_stats.arcstat_c_max.value.ui64); 168 exit(0); 169 }') 170 171 [[ $? -eq 0 ]] || log_fail "get_max_arc_size failed" 172 173 echo $max_arc_size 174} 175 176# Create a file with some information about how this system is configured. 177function get_system_config 178{ 179 typeset config=$PERF_DATA_DIR/$1 180 181 echo "{" >>$config 182 $DTRACE -qn 'BEGIN{ 183 printf(" \"ncpus\": %d,\n", `ncpus); 184 printf(" \"physmem\": %u,\n", `physmem * `_pagesize); 185 printf(" \"c_max\": %u,\n", `arc_stats.arcstat_c_max.value.ui64); 186 printf(" \"kmem_flags\": \"0x%x\",", `kmem_flags); 187 exit(0)}' >>$config 188 $ECHO " \"hostname\": \"$($UNAME -n)\"," >>$config 189 $ECHO " \"kernel version\": \"$($UNAME -v)\"," >>$config 190 $IOSTAT -En | $AWK 'BEGIN { 191 printf(" \"disks\": {\n"); first = 1} 192 /^c/ {disk = $1} 193 /^Size: [^0]/ {size = $2; 194 if (first != 1) {printf(",\n")} else {first = 0} 195 printf(" \"%s\": \"%s\"", disk, size)} 196 END {printf("\n },\n")}' >>$config 197 $SED -n 's/^set \(.*\)[ ]=[ ]\(.*\)/\1=\2/p' /etc/system | \ 198 $AWK -F= 'BEGIN {printf(" \"system\": {\n"); first = 1} 199 {if (first != 1) {printf(",\n")} else {first = 0}; 200 printf(" \"%s\": %s", $1, $2)} 201 END {printf("\n }\n")}' >>$config 202 echo "}" >>$config 203} 204 205function num_jobs_by_cpu 206{ 207 typeset ncpu=$($PSRINFO | $WC -l) 208 typeset num_jobs=$ncpu 209 210 [[ $ncpu -gt 8 ]] && num_jobs=$($ECHO "$ncpu * 3 / 4" | $BC) 211 212 $ECHO $num_jobs 213} 214 215function pool_to_lun_list 216{ 217 typeset pool=$1 218 typeset ctd ctds devname lun 219 typeset lun_list=':' 220 221 ctds=$($ZPOOL list -v $pool | $AWK '/c[0-9]*t[0-9a-fA-F]*d[0-9]*/ \ 222 {print $1}') 223 224 for ctd in $ctds; do 225 # Get the device name as it appears in /etc/path_to_inst 226 devname=$($READLINK -f /dev/dsk/${ctd}s0 | $SED -n \ 227 's/\/devices\([^:]*\):.*/\1/p') 228 # Add a string composed of the driver name and instance 229 # number to the list for comparison with dev_statname. 230 lun=$($SED 's/"//g' /etc/path_to_inst | $GREP $devname | $AWK \ 231 '{print $3$2}') 232 lun_list="$lun_list$lun:" 233 done 234 echo $lun_list 235} 236 237# Create a perf_data directory to hold performance statistics and 238# configuration information. 239export PERF_DATA_DIR=$(get_perf_output_dir) 240[[ -f $PERF_DATA_DIR/config.json ]] || get_system_config config.json 241