| #!/bin/bash |
| # SPDX-License-Identifier: MIT or GPL-2.0-only |
| |
| declare -A TEST_RUN |
| |
| declare -A FIO_TERSE_FIELDS |
| FIO_TERSE_FIELDS=( |
| # Read status |
| ["read io"]=6 |
| ["read bandwidth"]=7 |
| ["read iops"]=8 |
| ["read runtime"]=9 |
| ["read slat min"]=10 |
| ["read slat max"]=11 |
| ["read slat mean"]=12 |
| ["read slat stdev"]=13 |
| ["read clat min"]=14 |
| ["read clat max"]=15 |
| ["read clat mean"]=16 |
| ["read clat stdev"]=17 |
| # read clat percentiles are 18-37 |
| ["read lat min"]=38 |
| ["read lat max"]=39 |
| ["read lat mean"]=40 |
| ["read lat stdev"]=41 |
| ["read bandwidth min"]=42 |
| ["read bandwidth max"]=43 |
| ["read bandwidth %"]=44 |
| ["read bandwidth mean"]=45 |
| ["read bandwidth stdev"]=46 |
| |
| # Write status |
| ["write io"]=47 |
| ["write bandwidth"]=48 |
| ["write iops"]=49 |
| ["write runtime"]=50 |
| ["write slat min"]=51 |
| ["write slat max"]=52 |
| ["write slat mean"]=53 |
| ["write slat stdev"]=54 |
| ["write clat min"]=55 |
| ["write clat max"]=56 |
| ["write clat mean"]=57 |
| ["write clat stdev"]=58 |
| # write clat percentiles are 59-78 |
| ["write lat min"]=79 |
| ["write lat max"]=80 |
| ["write lat mean"]=81 |
| ["write lat stdev"]=82 |
| ["write bandwidth min"]=83 |
| ["write bandwidth max"]=84 |
| ["write bandwidth %"]=85 |
| ["write bandwidth mean"]=86 |
| ["write bandwidth stdev"]=87 |
| |
| # Trim status |
| ["trim io"]=88 |
| ["trim bandwidth"]=89 |
| ["trim iops"]=90 |
| ["trim runtime"]=91 |
| ["trim slat min"]=92 |
| ["trim slat max"]=93 |
| ["trim slat mean"]=94 |
| ["trim slat stdev"]=95 |
| ["trim clat min"]=96 |
| ["trim clat max"]=97 |
| ["trim clat mean"]=98 |
| ["trim clat stdev"]=99 |
| # trim clat percentiles are 100-119 |
| ["trim lat min"]=120 |
| ["trim lat max"]=121 |
| ["trim lat mean"]=122 |
| ["trim lat stdev"]=123 |
| ["trim bandwidth min"]=124 |
| ["trim bandwidth max"]=125 |
| ["trim bandwidth %"]=126 |
| ["trim bandwidth mean"]=127 |
| ["trim bandwidth stdev"]=128 |
| |
| # CPU usage |
| ["user cpu"]=129 |
| ["system cpu"]=130 |
| ["context switches"]=131 |
| ["major page faults"]=132 |
| ["minor page faults"]=133 |
| |
| # IO depth distribution |
| ["io depth <=1"]=134 |
| ["io depth 2"]=135 |
| ["io depth 4"]=136 |
| ["io depth 8"]=137 |
| ["io depth 16"]=138 |
| ["io depth 32"]=139 |
| ["io depth >=64"]=140 |
| |
| # IO latency distribution |
| ["io latency <=2 us"]=141 |
| ["io latency 4 us"]=142 |
| ["io latency 10 us"]=143 |
| ["io latency 20 us"]=144 |
| ["io latency 50 us"]=145 |
| ["io latency 100 us"]=146 |
| ["io latency 250 us"]=147 |
| ["io latency 500 us"]=148 |
| ["io latency 750 us"]=149 |
| ["io latency 1000 us"]=150 |
| ["io latency <=2 ms"]=151 |
| ["io latency 4 ms"]=152 |
| ["io latency 10 ms"]=153 |
| ["io latency 20 ms"]=154 |
| ["io latency 50 ms"]=155 |
| ["io latency 100 ms"]=156 |
| ["io latency 250 ms"]=157 |
| ["io latency 500 ms"]=158 |
| ["io latency 750 ms"]=159 |
| ["io latency 1000 ms"]=160 |
| ["io latency 2000 ms"]=161 |
| ["io latency >=2000 ms"]=162 |
| |
| # Disk utilization (11 fields per disk) |
| ) |
| |
| FIO_OUTPUT="$TEST_DIR/.fio_perf" |
| |
| _fio_perf_report() { |
| # If there is more than one group, we don't know what to report. |
| if [[ $(wc -l < "$FIO_OUTPUT") -gt 1 ]]; then |
| echo "_fio_perf: too many terse lines" >&2 |
| return |
| fi |
| |
| local name field value |
| for name in "${FIO_PERF_FIELDS[@]}"; do |
| field="${FIO_TERSE_FIELDS["$name"]}" |
| if [[ -z $field ]]; then |
| echo "_fio_perf: unknown fio terse field '$name'" >&2 |
| continue |
| fi |
| value="$(cut -d ';' -f "$field" "$FIO_OUTPUT")" |
| TEST_RUN["$FIO_PERF_PREFIX$name"]="$value" |
| done |
| } |
| |
| __run_fio_libaio() { |
| DEVS=$1 |
| BS=$2 |
| RW=$3 |
| JOBS=$4 |
| RTIME=$5 |
| |
| QD=128 |
| BATCH=16 |
| FIO=fio |
| |
| $FIO --output=$FIO_OUTPUT --output-format=terse --terse-version=4 --group_reporting=1 \ |
| --bs=$BS --ioengine=libaio \ |
| --iodepth=$QD \ |
| --iodepth_batch_submit=$BATCH \ |
| --iodepth_batch_complete_min=$BATCH \ |
| --filename=$DEVS --gtod_reduce=1 \ |
| --direct=1 --runtime=$RTIME --numjobs=$JOBS --rw=$RW \ |
| --name=test > /dev/null 2>&1 |
| } |
| |
| __ublk_loop_backing_file() { |
| eval $UBLK list > ${UBLK_TMP} |
| file=`cat ${UBLK_TMP} | grep "loop" | awk '{print $2}' | awk -F "," '{print $1}' | awk -F ":" '{print $2}'` |
| echo $file | xargs |
| } |
| |
| __ublk_dev_id() { |
| local dev=$1 |
| dev_id=`echo "$dev" | awk '{print substr($1, 11)}'` |
| echo "$dev_id" |
| } |
| |
| __ublk_get_pid() { |
| local dev=$1 |
| local dev_id=`__ublk_dev_id $dev` |
| |
| eval $UBLK list -n $dev_id > ${UBLK_TMP} |
| pid=`cat ${UBLK_TMP} | grep "pid" | awk '{print $7}'` |
| echo $pid |
| } |
| |
| __ublk_get_queue_tid() { |
| local dev=$1 |
| local qid=$2 |
| local dev_id=`__ublk_dev_id $dev` |
| |
| eval $UBLK list -n ${dev_id} > ${UBLK_TMP} |
| q_tid=`cat ${UBLK_TMP} | grep "queue ${qid}" | awk '{print $4}'` |
| echo $q_tid |
| } |
| |
| __ublk_get_dev_state() { |
| local dev=$1 |
| local dev_id=`__ublk_dev_id $dev` |
| |
| eval $UBLK list -n ${dev_id} > ${UBLK_TMP} |
| state=`cat ${UBLK_TMP} | grep "state" | awk '{print $11}'` |
| echo $state |
| } |
| |
| __run_fio_perf() { |
| __run_fio_libaio $@ |
| _fio_perf_report |
| } |
| |
| __remove_ublk_dev_return() { |
| local dev="$1" |
| if [ "$dev" == "*" ]; then |
| eval $UBLK del -a |
| else |
| dev_id=`__ublk_dev_id $dev` |
| eval $UBLK del -n "$dev_id" |
| fi |
| RES=$? |
| udevadm settle |
| echo $RES |
| } |
| |
| __remove_ublk_dev() { |
| __remove_ublk_dev_return $@ > /dev/null 2>&1 |
| } |
| |
| __find_free_ublk_id() |
| { |
| for id in `seq 0 64`; do |
| [ -c /dev/ublkc${id} ] && continue |
| echo $id |
| break |
| done |
| [ $id == "64" ] && echo "-" |
| } |
| |
| __create_ublk_dev() |
| { |
| id=`__find_free_ublk_id` |
| [ ${id} == "-" ] && echo "no free ublk device nodes" && exit -1 |
| eval $UBLK add ${T_TYPE_PARAMS} -n $id > /dev/null 2>&1 |
| udevadm settle |
| echo "/dev/ublkb${id}" |
| } |
| |
| __recover_ublk_dev() |
| { |
| local dev=$1 |
| local dev_id=`__ublk_dev_id $dev` |
| |
| eval $UBLK recover -n $dev_id |
| RES=$? |
| echo $RES |
| } |
| |
| __get_cpu_utils() |
| { |
| local user_cpu=`echo ${TEST_RUN["user cpu"]} | awk -F "." '{print $1}'` |
| local sys_cpu=`echo ${TEST_RUN["system cpu"]} | awk -F "." '{print $1}'` |
| echo "cpu_util(${user_cpu}% ${sys_cpu}%)" |
| } |
| |
| __run_dev_perf_no_create() |
| { |
| local TYPE=$1 |
| local JOBS=$2 |
| local DEV=$3 |
| local RT=$TRUNTIME |
| local BS=4k |
| local FIO_PERF_FIELDS=("read iops" "write iops" "user cpu" "system cpu") |
| |
| RW="randwrite" |
| __run_fio_perf $DEV $BS $RW $JOBS 20 |
| cpu_util=`__get_cpu_utils` |
| echo -e "\t$RW($BS): jobs $JOBS, iops ${TEST_RUN["write iops"]}, $cpu_util" |
| |
| RW="randread" |
| __run_fio_perf $DEV $BS $RW $JOBS $RT |
| cpu_util=`__get_cpu_utils` |
| echo -e "\t$RW($BS): jobs $JOBS, iops ${TEST_RUN["read iops"]}, $cpu_util" |
| |
| RW="randrw" |
| __run_fio_perf $DEV $BS $RW $JOBS $RT |
| cpu_util=`__get_cpu_utils` |
| echo -e "\t$RW($BS): jobs $JOBS, iops read ${TEST_RUN["read iops"]} write ${TEST_RUN["write iops"]}, $cpu_util" |
| |
| RW="rw" |
| BS=64k |
| __run_fio_perf $DEV $BS $RW $JOBS $RT |
| cpu_util=`__get_cpu_utils` |
| echo -e "\t$RW($BS): jobs $JOBS, iops read ${TEST_RUN["read iops"]} write ${TEST_RUN["write iops"]}, $cpu_util" |
| |
| RW="rw" |
| BS=512k |
| __run_fio_perf $DEV $BS $RW $JOBS $RT |
| cpu_util=`__get_cpu_utils` |
| echo -e "\t$RW($BS): jobs $JOBS, iops read ${TEST_RUN["read iops"]} write ${TEST_RUN["write iops"]}, $cpu_util" |
| |
| echo "" |
| } |
| |
| __run_dev_perf() |
| { |
| JOBS=$1 |
| |
| DEV=`__create_ublk_dev` |
| |
| echo -e "\tublk add ${T_TYPE_PARAMS}, fio: ($DEV libaio dio io jobs($JOBS))..." |
| __run_dev_perf_no_create "ublk" $JOBS $DEV |
| |
| __remove_ublk_dev $DEV |
| } |
| |
| _create_null_image() |
| { |
| echo "" |
| } |
| |
| _create_image() |
| { |
| local type=$1 |
| |
| shift 1 |
| |
| eval _create_${type}_image $@ |
| } |
| |
| _remove_null_image() |
| { |
| echo "nothing" > /dev/null |
| } |
| |
| _remove_image() |
| { |
| local type=$1 |
| shift 1 |
| eval _remove_${type}_image $@ |
| } |