基于 dd 的块设备读写性能测试

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/engrossment/article/details/97800562

概述

本文档说明测试块设备(block device)读写性能的方法。块设备包含如 SATA、USB、SD、eMMC、Nand 等。

测试技术要点

  1. 读写使用 dd 命令,基于块设备在 /dev/ 下的设备文件进行操作,不依赖文件系统。
  2. 从 /dev/urandom 获取随机数进行读写测试。
  3. 考虑硬件框图、数据流向。直接从 DDR 内存读取数据写入到待测设备,直接从待测设备读取数据然后存储到 DDR 内存。不能从待测设备读取再写入待测设备,把待测设备的读与写纠缠一起。
  4. 在 tmpfs /dev/shm/ 路径下暂存数据,即使用 DDR 内存。
  5. 清除缓存数据:echo 3 > /proc/sys/vm/drop_caches 。确保数据确实写入到、读取自待测设备,避免后续的 cmp 比较只是比较缓存中的数据。
  6. 注意 dd 的 bs 设置会影响总体测试数据。512 KB 以上会达到最快。读写模式使用 conv=sync 确保数据完成写入、读取。
  7. 注意操作系统不能从待测设备启动,避免操作系统其他数据占用待测设备的通信带宽。
  8. 统计 CPU 负载。计算不同数据量测试的平均值、方差。

测试操作方法

确认 /dev/shm、待测设备的可用空间

TARGET# df -h

配置最大测试数据量

测试程序 blk_dd_rw_diagnose.sh 的 MAX_COUNT 配置必须小于 /dev/shm 可用空间的一半,同时必须小于待测设备的可用空间,单位 MB。

执行测试

TARGET# ./blk_dd_rw_diagnose.sh -n /dev/mmcblk1p3

检查测试结果

测试将生成两个文件 write_dia.log read_dia.log,注意是否有报错读写数据不一致,留意测试的平均值、方差与 CPU 占用率。方差大说明本轮测试的多个不同数据量的测试结果波动性大。

参考代码

#! /bin/bash
# Description:
#   Diagnose data read/write speed of block device using dd command.

# NOTE: run df -h to see max size of /dev/shm, two files saving here.
readonly MAX_COUNT=200      # size = count * 1 MB. Max size is half of /dev/shm.
readonly COUNT_STEP=10      # Incresing step.
readonly BLOCK_SIZE=1048576 # 1 MB
readonly RANDOM_SRC_FILE="/dev/shm/random_file.test"
readonly READ_FILE="/dev/shm/read_file.test"
readonly WRITE_DIA_FILE='write_dia.log'
readonly READ_DIA_FILE='read_dia.log'

usage() {
cat <<-EOF >&2
    usage: ./${0##*/} [-m mount point] [-n device node]
        -h Print this usage
        e.g. ./${0##*/} -m /run/media/sda1
        e.g. ./${0##*/} -n /dev/sda1
EOF
exit 0
}

########## MAIN ##########
DEV_NODE=""
MNT_POINT=""
while getopts :n:m:h arg
do case $arg in
        n)      DEV_NODE="$OPTARG";;
        m)      MNT_POINT="$OPTARG";;
        h)      usage;;
        :)      echo "$0: Must supply an argument to -$OPTARG." >&2
                exit 1
                ;;
        \?)     echo "Invalid Option -$OPTARG ignored." >&2
                usage
                exit 1
                ;;
esac
done

if [[ ! -z ${DEV_NODE} ]];then
    DST_FILE=${DEV_NODE}
elif [[ ! -z ${MNT_POINT} ]];then
    DST_FILE="${MNT_POINT}/dst_file"
else
    echo "ERROR! Yout need to specify at least one of -n or -m."
    usage
    exit 1
fi

echo "MB  secs  MB/s  CPU" > ${WRITE_DIA_FILE}
echo "MB  secs  MB/s  CPU" > ${READ_DIA_FILE}

cnt=${COUNT_STEP}
while [[ ${cnt} -le ${MAX_COUNT} ]];do
    echo "Testing ${cnt} MB data write and read..."

    # Generate random data file.
    echo "Generating ${cnt} MB random data file with /dev/urandom ..."
    dd if=/dev/urandom of=${RANDOM_SRC_FILE} bs=${BLOCK_SIZE} count=${cnt} 2> /dev/null
    sync
    echo 3 > /proc/sys/vm/drop_caches

    # Write out data to block device.
    time -v dd if=${RANDOM_SRC_FILE} of=${DST_FILE} bs=${BLOCK_SIZE} count=${cnt} conv=sync 2> /tmp/tmp.out$$
    sync
    echo 3 > /proc/sys/vm/drop_caches
    min=$(cat /tmp/tmp.out$$ | grep Elapsed | awk '{print $8}' | awk -F 'm' '{print $1}')
    sec=$(cat /tmp/tmp.out$$ | grep Elapsed | awk '{print $9}' | awk -F 's' '{print $1}')
    cpu=$(cat /tmp/tmp.out$$ | grep CPU | awk '{print $7}')
    cos=$( echo "scale=2; ${min} * 60 + ${sec}" | bc )
    speed=$( echo "scale=2; ${cnt} / ${cos}" | bc )
    echo "Write -> size:${cnt} MB  time:${cos} seconds  speed:${speed} MB/s  CPU:${cpu}"
    echo "${cnt}  ${cos}  ${speed}  ${cpu}" >> ${WRITE_DIA_FILE}

    # Read data from block device.
    time -v dd if=${DST_FILE} of=${READ_FILE} bs=${BLOCK_SIZE} count=${cnt} conv=sync 2> /tmp/tmp.out$$
    sync
    echo 3 > /proc/sys/vm/drop_caches
    min=$(cat /tmp/tmp.out$$ | grep Elapsed | awk '{print $8}' | awk -F 'm' '{print $1}')
    sec=$(cat /tmp/tmp.out$$ | grep Elapsed | awk '{print $9}' | awk -F 's' '{print $1}')
    cpu=$(cat /tmp/tmp.out$$ | grep CPU | awk '{print $7}')
    cos=$( echo "scale=2; ${min} * 60 + ${sec}" | bc )
    speed=$( echo "scale=2; ${cnt} / ${cos}" | bc )
    echo "Read  -> size:${cnt} MB  time:${cos} seconds  speed:${speed} MB/s  CPU:${cpu}"
    echo "${cnt}  ${cos}  ${speed}  ${cpu}" >> ${READ_DIA_FILE}

    cmp ${RANDOM_SRC_FILE} ${READ_FILE}
    if [ $? -ne 0 ]; then
        err="Read data and write data are not the same!"
        echo ${err}
        sed -i "$ s/$/  ERROR! ${err}/" ${WRITE_DIA_FILE}   # Append to last line.
        sed -i "$ s/$/  ERROR! ${err}/" ${READ_DIA_FILE}
    else
        echo "The read data is the same as the write data."
    fi
    sync

    cnt=$(( ${cnt} + ${COUNT_STEP} ))
done

w_ave_sig=$(tail -n+2 ${WRITE_DIA_FILE} | awk '{a[++i]=$3;}END{for(i in a)sum+=a[i];ave=sum/NR;for(i in a)tmp+=(a[i]-ave)*(a[i]-ave);print ave,tmp/NR}')
r_ave_sig=$(tail -n+2 ${READ_DIA_FILE} | awk '{a[++i]=$3;}END{for(i in a)sum+=a[i];ave=sum/NR;for(i in a)tmp+=(a[i]-ave)*(a[i]-ave);print ave,tmp/NR}')
echo "Write speed average and sigma: ${w_ave_sig}"
echo "Read speed average and sigma : ${r_ave_sig}"
echo -e "\nWrite speed average and sigma: ${w_ave_sig}" >> ${WRITE_DIA_FILE}
echo -e "\nRead speed average and sigma : ${r_ave_sig}"  >> ${READ_DIA_FILE}

rm -f ${RANDOM_SRC_FILE}
rm -f ${READ_FILE}
if [[ ! -z ${MNT_POINT} ]];then
    rm -f ${DST_FILE}
fi
echo "Diagnose done! Please check log files: ${WRITE_DIA_FILE} ${READ_DIA_FILE}"

2019年7月31日

展开阅读全文

没有更多推荐了,返回首页