Skip to content

Instantly share code, notes, and snippets.

@tabokie
Created September 22, 2023 08:23
Show Gist options
  • Save tabokie/3a7aff4f1b3b3ed7894e626a6e4aaf91 to your computer and use it in GitHub Desktop.
Save tabokie/3a7aff4f1b3b3ed7894e626a6e4aaf91 to your computer and use it in GitHub Desktop.
#!/bin/bash
## basic spec report
function _io_test()
{
local rw="${1}"
local bs="${2}"
local sec="${3}"
local jobs="${4}"
local log="${5}"
local size="${6}"
local rm="${7}"
local fdatasync="${8:-0}"
local cmd
if [ `echo ${fdatasync} | grep "1"` ]; then
cmd="fio -direct=0 -fdatasync=1 --fallocate=posix -rw="${rw}" -size="${size}" -numjobs="${jobs}" -bs="${bs}" -runtime="${sec}" -ramp_time=15 -randseed=0 -group_reporting -name=test -time_based"
else
cmd="fio -direct=1 -fdatasync=0 -rw="${rw}" -size="${size}" -numjobs="${jobs}" -bs="${bs}" -runtime="${sec}" -ramp_time=15 -randseed=0 -group_reporting -name=test -time_based"
fi
echo "====================" >> ${log}
if [ `echo ${rm} | grep "1"` ]; then
rm -rf "*.0" || true
fi
echo ${cmd} >> ${log}
${cmd} | tee -a ${log} | { grep IOPS || test $? == 1; } | awk -F ': ' '{print $2}'
}
function _io_standard()
{
local threads="${1}"
local log="${2}"
local sec="${3}"
local size="${4}"
local bs="${5}"
local rm="${6}"
local wl_w=`_io_test 'write' "${bs}" "${sec}" "${threads}" "${log}" "${size}" "${rm}"`
local wl_sync=`_io_test 'write' "${bs}" "${sec}" "${threads}" "${log}" "${size}" "${rm}" "1"`
local wl_r=`_io_test 'read' "${bs}" "${sec}" "${threads}" "${log}" "${size}" "${rm}"`
local wl_iops_w=`echo "${wl_w}" | awk -F ',' '{print $1}'`
local wl_iops_sync=`echo "${wl_sync}" | awk -F ',' '{print $1}'`
local wl_iops_r=`echo "${wl_r}" | awk -F ',' '{print $1}'`
local wl_iotp_w=`echo "${wl_w}" | awk '{print $2}'`
local wl_iotp_sync=`echo "${wl_sync}" | awk '{print $2}'`
local wl_iotp_r=`echo "${wl_r}" | awk '{print $2}'`
echo "${bs}, ${threads} threads: Write: ${wl_iops_w} ${wl_iotp_w}, WriteSync: ${wl_iops_sync} ${wl_iotp_sync}, Read: ${wl_iops_r} ${wl_iotp_r}"
}
function io_report()
{
if [ -z "${4+x}" ]; then
echo "usage error" >&2
return 1
fi
local log="${1}"
local sec="${2}"
local size="${3}"
local rm="${4}"
t_arr=("1" "2" "4" "8" "16")
bs_arr=("4k" "16k" "64k" "256k" "1m")
for t in ${t_arr[@]}
do
for bs in ${bs_arr[@]}
do
_io_standard "${t}" "${log}" "${sec}" "${size}" "${bs}" "${rm}"
done
done
}
export -f io_report
## latency report
function _lat_workload()
{
local run_sec="${1}"
local threads="${2}"
local bs="${3}"
local rw="${4}"
local fsize="${5}"
local iops="${6}"
local log="${7}"
local fdatasync="${8:-0}"
local rate_iops=`expr ${iops} / ${threads}`
local cmd
if [ `echo ${fdatasync} | grep "1"` ]; then
cmd="fio -direct=0 -fdatasync=1 -numjobs="${threads}" -size="${fsize}" -bs="${bs}" -rw="rand${rw}" -rate_iops="${rate_iops}" \
-name=test -group_reporting -runtime="${run_sec}" -ramp_time=15 -randseed=0 -time_based"
else
cmd="fio -direct=1 -fdatasync=0 -numjobs="${threads}" -size="${fsize}" -bs="${bs}" -rw="rand${rw}" -rate_iops="${rate_iops}" \
-name=test -group_reporting -runtime="${run_sec}" -ramp_time=15 -randseed=0 -time_based"
fi
echo "====================" >> ${log}
rm -rf "*.0" || true
echo ${cmd} >> ${log}
local output=`${cmd} | tee -a ${log}`
local out=`echo "${output}" | { grep IOPS || test $? == 1; } | awk -F ': ' '{print $2}'`
local iops=`echo "${out}" | awk -F ',' '{print $1}'`
local iotp=`echo "${out}" | awk '{print $2}'`
local lats=`echo "${output}" | grep "lat (usec): " | awk -F ', ' '{print $2 " "$3}'`
local clat=`echo "${lats}" | awk 'NR==1{print}'`
local lat=`echo "${lats}" | awk 'NR==2{print}'`
local lat_99=`echo "${output}" | grep "99.99th=" | sed 's/ *//' | sed 's/|//' | sed 's/ //' | sed 's/ //'`
echo "${iops} ${iotp}"
echo "clat (usec): ${clat}"
echo "lat (usec): ${lat}"
echo "${lat_99}"
}
function mixed_workload()
{
local log="${1}"
threads_write_1m_seq=("0" "1" "2" "4" "8")
threads_write_64k_seq=("1" "2" "4")
for t1 in ${threads_write_1m_seq[@]}
do
for t2 in ${threads_write_64k_seq[@]}
do
rm -rf "*.0" || true
_exec_mixed_workload "300s" "8G" "${log}" "${t1}" "${t2}"
done
done
}
function _exec_mixed_workload()
{
local sec="${1}"
local size="${2}"
local log="${3}"
local jobs_1m="${4}"
local jobs_64k="${5}"
local cmd="fio -size="${size}" -ramp_time=10 -randseed=0 -time_based -group_reporting -runtime=${sec} \
-new_group -name=write_64k_seq -rw=write -bs=64k -fdatasync=1 -fallocate=posix -numjobs=${jobs_64k}"
local cmd_1="-new_group -name=write_1m_seq -rw=write -bs=1m -fallocate=posix -numjobs=${jobs_1m} \
-new_group -name=read_4k_rand -rw=randread -bs=4k -numjobs=${jobs_1m}"
if [ "${jobs_1m}" != "0" ]; then
cmd=""${cmd}" "${cmd_1}""
fi
echo "====================" >> ${log}
rm -rf "*.0" || true
echo ${cmd} >> ${log}
local output=`${cmd} | tee -a ${log} | { grep IOPS || test $? == 1; } | awk -F ': ' '{print $2}'`
local iops=`echo "${output}" | awk -F ',' '{print $1}'`
local iotp=`echo "${output}" | awk '{print $2}'`
echo "[mixed workload, write_1m_seq_jobs:${jobs_1m}, read_4k_rand_jobs:${jobs_1m}, write_64k_seq_jobs:${jobs_64k}]"
echo "Jobs: write_64k_seq, write_1m_seq, read_4k_rand"
echo "${iops}"
echo "${iotp}"
}
function io_lat_report()
{
if [ -z "${4+x}" ]; then
echo "[func io_report] usage: <func> test_file disk_name each_test_sec bw_threads iops_threads file_size" >&2
return 1
fi
local disk="${1}"
local run_sec="${2}"
local fsize="${3}"
local log="${4}"
t_arr=("1" "8")
bs_arr=("4k" "64k" "256k" "1m")
iops_arr=("1000" "2000" "3000" "4000" "5000")
for t in ${t_arr[@]}
do
for bs in ${bs_arr[@]}
do
for iops in ${iops_arr[@]}
do
echo "[write_${t}t_${bs}bs_${iops}iops]"
_lat_workload "${run_sec}" "${t}" "${bs}" "write" "${fsize}" "${iops}" "${log}"
wait
echo "[read_${t}t_${bs}bs_${iops}iops]"
_lat_workload "${run_sec}" "${t}" "${bs}" "read" "${fsize}" "${iops}" "${log}"
wait
echo "[write_sync_${t}t_${bs}bs_${iops}iops]"
_lat_workload "${run_sec}" "${t}" "${bs}" "write" "${fsize}" "${iops}" "${log}" "1"
wait
done
done
done
}
export -f io_lat_report
## some tools
function get_device()
{
local fs=$(df -k "${1}" | tail -1)
local device=''
local last=''
local cached_mnt=''
local cached_device=''
local mnt=$(echo "${fs}" | awk '{ print $6 }')
if [ "${cached_mnt}" != "${mnt}" ]; then
local cached_mnt="${mnt}"
local mnts=$(mount)
local new_mnt="${mnt}"
while [ -n "${new_mnt}" ]; do
local new_mnt=$(echo "${mnts}" | grep " on ${mnt} " | awk '{ print $1 }')
[ "${new_mnt}" = "${mnt}" ] && break
if [ -n "${new_mnt}" ]; then
local device="${new_mnt}"
local mnt=$(df "${new_mnt}" 2> /dev/null | tail -1 | awk '{print $6 }')
[ "${mnt}" = "${device}" -o "${mnt}" = "${last}" ] && break
local last="${mnt}"
fi
done
local cached_device="${device}"
else
local device="${cached_device}"
fi
echo "${device}"
}
function check_all_installed()
{
local info=`fio --help 2>&1 | grep '--version'`
if [ -z "${info}" ]; then
echo "fio is not installed" >&2
return 1
fi
}
function generate_disk_info()
{
local log="disk.info.log"
echo "==========smartctl==========" >> ${log}
local info=`smartctl -i ${1}`
echo "${info}" >> ${log}
echo "==========fdisk==========" >> ${log}
local info=`fdisk -l`
echo "${info}" >> ${log}
}
## main entry
function io_trait()
{
local dir="${1}"
mkdir -p "${dir}"
cd "${dir}"
local disk=`get_device "."`
check_all_installed
generate_disk_info ${disk}
local log="./io-report.`hostname`.`basename ${disk}`.log"
echo "IO trait report created by [io-report.sh]" > "${log}"
echo " host: `hostname`" >> "${log}"
echo " disk: ${disk}" >> "${log}"
echo " os: `uname -a`" >> "${log}"
echo " date: `date +%D-%T`" >> "${log}"
echo "" >> "${log}"
echo "Get involved:" >> "${log}"
echo " https://github.com/hunterlxt/io-report" >> "${log}"
echo "Forked:" >> "${log}"
echo " https://github.com/innerr/io-report" >> "${log}"
echo "" >> "${log}"
echo "==> [basic io spec report] (size=10G, runtime=60s)" >> "${log}"
io_report "fio.basic.log" "60" "10G" "1" >> "${log}"
echo "" >> "${log}"
echo "==> [cache detecting report] (size=10G, runtime=60s)" >> "${log}"
io_report "fio.cache.log" "60" "10G" "0" >> "${log}"
echo "" >> "${log}"
echo "==> [latency report]" >> "${log}"
io_lat_report "${disk}" "60" "10G" "fio.lat.log" >> "${log}"
echo "" >> "${log}"
echo "==> [mixed workload report]" >> "${log}"
mixed_workload "fio.mixed.log" >> "${log}"
}
export -f io_trait
## user interface
set -eu
if [ "$#" != 1 ]; then
echo "usage: <bin> test_dir" >&2
exit 1
fi
io_trait "${1}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment