diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/Makefile.am | 14 | ||||
-rw-r--r-- | scripts/common.sh.in | 5 | ||||
-rwxr-xr-x | scripts/zpios-profile/zpios-profile-disk.sh | 129 | ||||
-rwxr-xr-x | scripts/zpios-profile/zpios-profile-pids.sh | 131 | ||||
-rwxr-xr-x | scripts/zpios-profile/zpios-profile-post.sh | 129 | ||||
-rwxr-xr-x | scripts/zpios-profile/zpios-profile-pre.sh | 184 | ||||
-rwxr-xr-x | scripts/zpios-profile/zpios-profile.sh | 226 | ||||
-rwxr-xr-x | scripts/zpios-sanity.sh | 158 | ||||
-rwxr-xr-x | scripts/zpios-survey.sh | 215 | ||||
-rwxr-xr-x | scripts/zpios-test/16th-8192rc-4rs-1cs-4off.sh | 65 | ||||
-rwxr-xr-x | scripts/zpios-test/1th-16rc-4rs-1cs-4off.sh | 66 | ||||
-rwxr-xr-x | scripts/zpios-test/1x256th-65536rc-4rs-1cs-4off.sh | 65 | ||||
-rwxr-xr-x | scripts/zpios-test/256th-65536rc-4rs-1cs-4off.sh | 65 | ||||
-rwxr-xr-x | scripts/zpios-test/4th-1024rc-4rs-1cs-4off.sh | 65 | ||||
l--------- | scripts/zpios-test/large-thread-survey.sh | 1 | ||||
l--------- | scripts/zpios-test/large.sh | 1 | ||||
l--------- | scripts/zpios-test/medium.sh | 1 | ||||
l--------- | scripts/zpios-test/small.sh | 1 | ||||
l--------- | scripts/zpios-test/tiny.sh | 1 | ||||
-rwxr-xr-x | scripts/zpios.sh | 272 |
20 files changed, 1794 insertions, 0 deletions
diff --git a/scripts/Makefile.am b/scripts/Makefile.am index a1dfc3871..ed6e5028f 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -4,11 +4,17 @@ nobase_pkglibexec_SCRIPTS += zconfig.sh nobase_pkglibexec_SCRIPTS += zfs.sh nobase_pkglibexec_SCRIPTS += zpool-create.sh nobase_pkglibexec_SCRIPTS += zpool-config/* +nobase_pkglibexec_SCRIPTS += zpios.sh +nobase_pkglibexec_SCRIPTS += zpios-sanity.sh +nobase_pkglibexec_SCRIPTS += zpios-survey.sh +nobase_pkglibexec_SCRIPTS += zpios-test/* +nobase_pkglibexec_SCRIPTS += zpios-profile/* EXTRA_DIST = zfs-update.sh $(nobase_pkglibexec_SCRIPTS) ZFS=${top_srcdir}/scripts/zfs.sh ZCONFIG=${top_srcdir}/scripts/zconfig.sh ZTEST=${top_builddir}/cmd/ztest/ztest +ZPIOS_SANITY=${top_srcdir}/scripts/zpios-sanity.sh check: @echo @@ -27,3 +33,11 @@ check: @echo @$(ZCONFIG) @echo + @echo -n "====================================" + @echo -n " ZPIOS " + @echo "====================================" + @echo + @$(ZFS) + @$(ZPIOS_SANITY) + @$(ZFS) -u + @echo diff --git a/scripts/common.sh.in b/scripts/common.sh.in index 0a8399f18..102952fdb 100644 --- a/scripts/common.sh.in +++ b/scripts/common.sh.in @@ -39,6 +39,8 @@ sbindir=@sbindir@ ETCDIR=${ETCDIR:-/etc} DEVDIR=${DEVDIR:-/dev/disk/zpool} ZPOOLDIR=${ZPOOLDIR:-${pkglibexecdir}/zpool-config} +ZPIOSDIR=${ZPIOSDIR:-${pkglibexecdir}/zpios-test} +ZPIOSPROFILEDIR=${ZPIOSPROFILEDIR:-${pkglibexecdir}/zpios-profile} ZDB=${ZDB:-${sbindir}/zdb} ZFS=${ZFS:-${sbindir}/zfs} @@ -46,10 +48,13 @@ ZINJECT=${ZINJECT:-${sbindir}/zinject} ZPOOL=${ZPOOL:-${sbindir}/zpool} ZPOOL_ID=${ZPOOL_ID:-${bindir}/zpool_id} ZTEST=${ZTEST:-${sbindir}/ztest} +ZPIOS=${ZPIOS:-${sbindir}/zpios} COMMON_SH=${COMMON_SH:-${pkglibexecdir}/common.sh} ZFS_SH=${ZFS_SH:-${pkglibexecdir}/zfs.sh} ZPOOL_CREATE_SH=${ZPOOL_CREATE_SH:-${pkglibexecdir}/zpool-create.sh} +ZPIOS_SH=${ZPIOS_SH:-${pkglibexecdir}/zpios.sh} +ZPIOS_SURVEY_SH=${ZPIOS_SURVEY_SH:-${pkglibexecdir}/zpios-survey.sh} LDMOD=${LDMOD:-/sbin/modprobe} LSMOD=${LSMOD:-/sbin/lsmod} diff --git a/scripts/zpios-profile/zpios-profile-disk.sh b/scripts/zpios-profile/zpios-profile-disk.sh new file mode 100755 index 000000000..b56ee1ee4 --- /dev/null +++ b/scripts/zpios-profile/zpios-profile-disk.sh @@ -0,0 +1,129 @@ +#!/bin/bash +# +# /proc/diskinfo <after skipping major/minor> +# Field 1 -- device name +# Field 2 -- # of reads issued +# Field 3 -- # of reads merged +# Field 4 -- # of sectors read +# Field 5 -- # of milliseconds spent reading +# Field 6 -- # of writes completed +# Field 7 -- # of writes merged +# Field 8 -- # of sectors written +# Field 9 -- # of milliseconds spent writing +# Field 10 -- # of I/Os currently in progress +# Field 11 -- # of milliseconds spent doing I/Os +# Field 12 -- weighted # of milliseconds spent doing I/Os + +PROG=zpios-profile-disk.sh + +RUN_PIDS=${0} +RUN_LOG_DIR=${1} +RUN_ID=${2} + +create_table() { + local FIELD=$1 + local ROW_M=() + local ROW_N=() + local HEADER=1 + local STEP=1 + + for DISK_FILE in `ls -r --sort=time --time=ctime ${RUN_LOG_DIR}/${RUN_ID}/disk-[0-9]*`; do + ROW_M=( ${ROW_N[@]} ) + ROW_N=( `cat ${DISK_FILE} | grep sd | cut -c11- | cut -f${FIELD} -d' ' | tr "\n" "\t"` ) + + if [ $HEADER -eq 1 ]; then + echo -n "step, " + cat ${DISK_FILE} | grep sd | cut -c11- | cut -f1 -d' ' | tr "\n" ", " + echo "total" + HEADER=0 + fi + + if [ ${#ROW_M[@]} -eq 0 ]; then + continue + fi + + if [ ${#ROW_M[@]} -ne ${#ROW_N[@]} ]; then + echo "Badly formatted profile data in ${DISK_FILE}" + break + fi + + TOTAL=0 + echo -n "${STEP}, " + for (( i=0; i<${#ROW_N[@]}; i++ )); do + DELTA=`echo "${ROW_N[${i}]}-${ROW_M[${i}]}" | bc` + let TOTAL=${TOTAL}+${DELTA} + echo -n "${DELTA}, " + done + echo "${TOTAL}, " + + let STEP=${STEP}+1 + done +} + +create_table_mbs() { + local FIELD=$1 + local TIME=$2 + local ROW_M=() + local ROW_N=() + local HEADER=1 + local STEP=1 + + for DISK_FILE in `ls -r --sort=time --time=ctime ${RUN_LOG_DIR}/${RUN_ID}/disk-[0-9]*`; do + ROW_M=( ${ROW_N[@]} ) + ROW_N=( `cat ${DISK_FILE} | grep sd | cut -c11- | cut -f${FIELD} -d' ' | tr "\n" "\t"` ) + + if [ $HEADER -eq 1 ]; then + echo -n "step, " + cat ${DISK_FILE} | grep sd | cut -c11- | cut -f1 -d' ' | tr "\n" ", " + echo "total" + HEADER=0 + fi + + if [ ${#ROW_M[@]} -eq 0 ]; then + continue + fi + + if [ ${#ROW_M[@]} -ne ${#ROW_N[@]} ]; then + echo "Badly formatted profile data in ${DISK_FILE}" + break + fi + + TOTAL=0 + echo -n "${STEP}, " + for (( i=0; i<${#ROW_N[@]}; i++ )); do + DELTA=`echo "${ROW_N[${i}]}-${ROW_M[${i}]}" | bc` + MBS=`echo "scale=2; ((${DELTA}*512)/${TIME})/(1024*1024)" | bc` + TOTAL=`echo "scale=2; ${TOTAL}+${MBS}" | bc` + echo -n "${MBS}, " + done + echo "${TOTAL}, " + + let STEP=${STEP}+1 + done +} + +echo +echo "Reads issued per device" +create_table 2 +echo +echo "Reads merged per device" +create_table 3 +echo +echo "Sectors read per device" +create_table 4 +echo "MB/s per device" +create_table_mbs 4 3 + +echo +echo "Writes issued per device" +create_table 6 +echo +echo "Writes merged per device" +create_table 7 +echo +echo "Sectors written per device" +create_table 8 +echo "MB/s per device" +create_table_mbs 8 3 + +exit 0 diff --git a/scripts/zpios-profile/zpios-profile-pids.sh b/scripts/zpios-profile/zpios-profile-pids.sh new file mode 100755 index 000000000..3514b38e2 --- /dev/null +++ b/scripts/zpios-profile/zpios-profile-pids.sh @@ -0,0 +1,131 @@ +#!/bin/bash + +PROG=zpios-profile-pids.sh + +RUN_PIDS=${0} +RUN_LOG_DIR=${1} +RUN_ID=${2} + +ROW_M=() +ROW_N=() +ROW_N_SCHED=() +ROW_N_WAIT=() + +HEADER=1 +STEP=1 + +for PID_FILE in `ls -r --sort=time --time=ctime ${RUN_LOG_DIR}/${RUN_ID}/pids-[0-9]*`; do + ROW_M=( ${ROW_N[@]} ) + ROW_N=( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ROW_N_SCHED=( `cat ${PID_FILE} | cut -f15 -d' ' | tr "\n" "\t"` ) + ROW_N_WAIT=( `cat ${PID_FILE} | cut -f17 -d' ' | tr "\n" "\t"` ) + ROW_N_NAMES=( `cat ${PID_FILE} | cut -f2 -d' ' | cut -f2 -d'(' | + cut -f1 -d')' | cut -f1 -d'/' | tr "\n" "\t"` ) + + for (( i=0; i<${#ROW_N_SCHED[@]}; i++ )); do + SUM=`echo "${ROW_N_WAIT[${i}]}+${ROW_N_SCHED[${i}]}" | bc` + + case ${ROW_N_NAMES[${i}]} in + zio_taskq) IDX=0;; + zio_req_nul) IDX=1;; + zio_irq_nul) IDX=2;; + zio_req_rd) IDX=3;; + zio_irq_rd) IDX=4;; + zio_req_wr) IDX=5;; + zio_irq_wr) IDX=6;; + zio_req_fr) IDX=7;; + zio_irq_fr) IDX=8;; + zio_req_cm) IDX=9;; + zio_irq_cm) IDX=10;; + zio_req_ctl) IDX=11;; + zio_irq_ctl) IDX=12;; + txg_quiesce) IDX=13;; + txg_sync) IDX=14;; + txg_timelimit) IDX=15;; + arc_reclaim) IDX=16;; + l2arc_feed) IDX=17;; + zpios_io) IDX=18;; + *) continue;; + esac + + let ROW_N[${IDX}]=${ROW_N[${IDX}]}+${SUM} + done + + if [ $HEADER -eq 1 ]; then + echo "step, zio_taskq, zio_req_nul, zio_irq_nul, " \ + "zio_req_rd, zio_irq_rd, zio_req_wr, zio_irq_wr, " \ + "zio_req_fr, zio_irq_fr, zio_req_cm, zio_irq_cm, " \ + "zio_req_ctl, zio_irq_ctl, txg_quiesce, txg_sync, " \ + "txg_timelimit, arc_reclaim, l2arc_feed, zpios_io, " \ + "idle" + HEADER=0 + fi + + if [ ${#ROW_M[@]} -eq 0 ]; then + continue + fi + + if [ ${#ROW_M[@]} -ne ${#ROW_N[@]} ]; then + echo "Badly formatted profile data in ${PID_FILE}" + break + fi + + # Original values are in jiffies and we expect HZ to be 1000 + # on most 2.6 systems thus we divide by 10 to get a percentage. + IDLE=1000 + echo -n "${STEP}, " + for (( i=0; i<${#ROW_N[@]}; i++ )); do + DELTA=`echo "${ROW_N[${i}]}-${ROW_M[${i}]}" | bc` + DELTA_PERCENT=`echo "scale=1; ${DELTA}/10" | bc` + let IDLE=${IDLE}-${DELTA} + echo -n "${DELTA_PERCENT}, " + done + ILDE_PERCENT=`echo "scale=1; ${IDLE}/10" | bc` + echo "${ILDE_PERCENT}" + + let STEP=${STEP}+1 +done + +exit + +echo +echo "Percent of total system time per pid" +for PID_FILE in `ls -r --sort=time --time=ctime ${RUN_LOG_DIR}/${RUN_ID}/pids-[0-9]*`; do + ROW_M=( ${ROW_N[@]} ) + ROW_N_SCHED=( `cat ${PID_FILE} | cut -f15 -d' ' | tr "\n" "\t"` ) + ROW_N_WAIT=( `cat ${PID_FILE} | cut -f17 -d' ' | tr "\n" "\t"` ) + + for (( i=0; i<${#ROW_N_SCHED[@]}; i++ )); do + ROW_N[${i}]=`echo "${ROW_N_WAIT[${i}]}+${ROW_N_SCHED[${i}]}" | bc` + done + + if [ $HEADER -eq 1 ]; then + echo -n "step, " + cat ${PID_FILE} | cut -f2 -d' ' | tr "\n" ", " + echo + HEADER=0 + fi + + if [ ${#ROW_M[@]} -eq 0 ]; then + continue + fi + + if [ ${#ROW_M[@]} -ne ${#ROW_N[@]} ]; then + echo "Badly formatted profile data in ${PID_FILE}" + break + fi + + # Original values are in jiffies and we expect HZ to be 1000 + # on most 2.6 systems thus we divide by 10 to get a percentage. + echo -n "${STEP}, " + for (( i=0; i<${#ROW_N[@]}; i++ )); do + DELTA=`echo "scale=1; (${ROW_N[${i}]}-${ROW_M[${i}]})/10" | bc` + echo -n "${DELTA}, " + done + + echo + let STEP=${STEP}+1 +done + + +exit 0 diff --git a/scripts/zpios-profile/zpios-profile-post.sh b/scripts/zpios-profile/zpios-profile-post.sh new file mode 100755 index 000000000..3a454ba04 --- /dev/null +++ b/scripts/zpios-profile/zpios-profile-post.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +PROG=zpios-profile-post.sh + +RUN_POST=${0} +RUN_PHASE=${1} +RUN_DIR=${2} +RUN_ID=${3} +RUN_POOL=${4} +RUN_CHUNK_SIZE=${5} +RUN_REGION_SIZE=${6} +RUN_THRD_COUNT=${7} +RUN_REGION_COUNT=${8} +RUN_OFFSET=${9} +RUN_REGION_NOISE=${10} +RUN_CHUNK_NOISE=${11} +RUN_THRD_DELAY=${12} +RUN_FLAGS=${13} +RUN_RESULT=${14} + +# Summarize system time per process +zpios_profile_post_pids() { + ${PROFILE_PIDS} ${PROFILE_RUN_CR_PIDS_LOG} >${PROFILE_RUN_CR_PIDS_CSV} + ${PROFILE_PIDS} ${PROFILE_RUN_WR_PIDS_LOG} >${PROFILE_RUN_WR_PIDS_CSV} + ${PROFILE_PIDS} ${PROFILE_RUN_RD_PIDS_LOG} >${PROFILE_RUN_RD_PIDS_CSV} + ${PROFILE_PIDS} ${PROFILE_RUN_RM_PIDS_LOG} >${PROFILE_RUN_RM_PIDS_CSV} +} + +zpios_profile_post_disk() { + ${PROFILE_DISK} ${PROFILE_RUN_CR_DISK_LOG} >${PROFILE_RUN_CR_DISK_CSV} + ${PROFILE_DISK} ${PROFILE_RUN_WR_DISK_LOG} >${PROFILE_RUN_WR_DISK_CSV} + ${PROFILE_DISK} ${PROFILE_RUN_RD_DISK_LOG} >${PROFILE_RUN_RD_DISK_CSV} + ${PROFILE_DISK} ${PROFILE_RUN_RM_DISK_LOG} >${PROFILE_RUN_RM_DISK_CSV} +} + +# Summarize per device performance + +# Stop a user defined profiling script which is gathering additional data +zpios_profile_post_stop() { + local PROFILE_PID=$1 + + kill -s SIGHUP `cat ${PROFILE_PID}` + + + # Sleep waiting for profile script to exit + while [ -f ${PROFILE_PID} ]; do + sleep 0.01 + done +} + +zpios_profile_post_proc_stop() { + local PROC_DIR=$1 + + if [ -f ${PROFILE_ARC_PROC} ]; then + cat ${PROFILE_ARC_PROC} >${PROC_DIR}/arcstats.txt + fi + + if [ -f ${PROFILE_VDEV_CACHE_PROC} ]; then + cat ${PROFILE_VDEV_CACHE_PROC} >${PROC_DIR}/vdev_cache_stats.txt + fi +} + +zpios_profile_post_oprofile_stop() { + local OPROFILE_LOG=$1 + local OPROFILE_ARGS="-a -g -l -p ${OPROFILE_KERNEL_DIR},${OPROFILE_SPL_DIR},${OPROFILE_ZFS_DIR}" + + /usr/bin/opcontrol --stop >>${OPROFILE_LOG} 2>&1 + /usr/bin/opcontrol --dump >>${OPROFILE_LOG} 2>&1 + /usr/bin/opreport ${OPROFILE_ARGS} >${OPROFILE_LOG} 2>&1 + /usr/bin/oparchive +} + +zpios_profile_post_create() { + zpios_profile_post_oprofile_stop ${PROFILE_RUN_CR_OPROFILE_LOG} + zpios_profile_post_proc_stop ${PROFILE_RUN_CR_DIR} + zpios_profile_post_stop ${PROFILE_RUN_CR_PID} +} + +zpios_profile_post_write() { + zpios_profile_post_oprofile_stop ${PROFILE_RUN_WR_OPROFILE_LOG} + zpios_profile_post_proc_stop ${PROFILE_RUN_WR_DIR} + zpios_profile_post_stop ${PROFILE_RUN_WR_PID} +} + +zpios_profile_post_read() { + zpios_profile_post_oprofile_stop ${PROFILE_RUN_CR_RD_LOG} + zpios_profile_post_proc_stop ${PROFILE_RUN_RD_DIR} + zpios_profile_post_stop ${PROFILE_RUN_RD_PID} +} + +zpios_profile_post_remove() { + zpios_profile_post_oprofile_stop ${PROFILE_RUN_RM_OPROFILE_LOG} + zpios_profile_post_proc_stop ${PROFILE_RUN_RM_DIR} + zpios_profile_post_stop ${PROFILE_RUN_RM_PID} +} + +# Source global zpios test configuration +if [ -f ${RUN_DIR}/zpios-config.sh ]; then + . ${RUN_DIR}/zpios-config.sh +fi + +# Source global per-run test configuration +if [ -f ${RUN_DIR}/${RUN_ID}/zpios-config-run.sh ]; then + . ${RUN_DIR}/${RUN_ID}/zpios-config-run.sh +fi + +case "${RUN_PHASE}" in + post-run) + zpios_profile_post_pids + zpios_profile_post_disk + ;; + post-create) + zpios_profile_post_create + ;; + post-write) + zpios_profile_post_write + ;; + post-read) + zpios_profile_post_read + ;; + post-remove) + zpios_profile_post_remove + ;; + *) + echo "Usage: ${PROG} {post-run|post-create|post-write|post-read|post-remove}" + exit 1 +esac + +exit 0 diff --git a/scripts/zpios-profile/zpios-profile-pre.sh b/scripts/zpios-profile/zpios-profile-pre.sh new file mode 100755 index 000000000..a2a885798 --- /dev/null +++ b/scripts/zpios-profile/zpios-profile-pre.sh @@ -0,0 +1,184 @@ +#!/bin/bash + +PROG=zpios-profile-pre.sh + +PROFILE_RDY=0 +trap "PROFILE_RDY=1" SIGHUP + +RUN_PRE=${0} +RUN_PHASE=${1} +RUN_DIR=${2} +RUN_ID=${3} +RUN_POOL=${4} +RUN_CHUNK_SIZE=${5} +RUN_REGION_SIZE=${6} +RUN_THRD_COUNT=${7} +RUN_REGION_COUNT=${8} +RUN_OFFSET=${9} +RUN_REGION_NOISE=${10} +RUN_CHUNK_NOISE=${11} +RUN_THRD_DELAY=${12} +RUN_FLAGS=${13} +RUN_RESULT=${14} + +zpios_profile_pre_run_cfg() { +cat > ${RUN_DIR}/${RUN_ID}/zpios-config-run.sh << EOF +# +# Zpios Profiling Configuration for Run ${RUN_ID} +# + +PROFILE_RUN_DIR=${RUN_DIR}/${RUN_ID} + +PROFILE_RUN_CR_DIR=${RUN_DIR}/${RUN_ID}/create +PROFILE_RUN_CR_PID=${RUN_DIR}/${RUN_ID}/create/profile.pid +PROFILE_RUN_CR_OPROFILE_LOG=${RUN_DIR}/${RUN_ID}/create/oprofile.txt +PROFILE_RUN_CR_PIDS_LOG=${RUN_DIR}/${RUN_ID}/create/pids.txt +PROFILE_RUN_CR_PIDS_CSV=${RUN_DIR}/${RUN_ID}/create/pids.csv +PROFILE_RUN_CR_DISK_LOG=${RUN_DIR}/${RUN_ID}/create/disk.txt +PROFILE_RUN_CR_DISK_CSV=${RUN_DIR}/${RUN_ID}/create/disk.csv + +PROFILE_RUN_WR_DIR=${RUN_DIR}/${RUN_ID}/write +PROFILE_RUN_WR_PID=${RUN_DIR}/${RUN_ID}/write/profile.pid +PROFILE_RUN_WR_OPROFILE_LOG=${RUN_DIR}/${RUN_ID}/write/oprofile.txt +PROFILE_RUN_WR_PIDS_LOG=${RUN_DIR}/${RUN_ID}/write/pids.txt +PROFILE_RUN_WR_PIDS_CSV=${RUN_DIR}/${RUN_ID}/write/pids.csv +PROFILE_RUN_WR_DISK_LOG=${RUN_DIR}/${RUN_ID}/write/disk.txt +PROFILE_RUN_WR_DISK_CSV=${RUN_DIR}/${RUN_ID}/write/disk.csv + +PROFILE_RUN_RD_DIR=${RUN_DIR}/${RUN_ID}/read +PROFILE_RUN_RD_PID=${RUN_DIR}/${RUN_ID}/read/profile.pid +PROFILE_RUN_RD_OPROFILE_LOG=${RUN_DIR}/${RUN_ID}/read/oprofile.txt +PROFILE_RUN_RD_PIDS_LOG=${RUN_DIR}/${RUN_ID}/read/pids.txt +PROFILE_RUN_RD_PIDS_CSV=${RUN_DIR}/${RUN_ID}/read/pids.csv +PROFILE_RUN_RD_DISK_LOG=${RUN_DIR}/${RUN_ID}/read/disk.txt +PROFILE_RUN_RD_DISK_CSV=${RUN_DIR}/${RUN_ID}/read/disk.csv + +PROFILE_RUN_RM_DIR=${RUN_DIR}/${RUN_ID}/remove +PROFILE_RUN_RM_PID=${RUN_DIR}/${RUN_ID}/remove/profile.pid +PROFILE_RUN_RM_OPROFILE_LOG=${RUN_DIR}/${RUN_ID}/remove/oprofile.txt +PROFILE_RUN_RM_PIDS_LOG=${RUN_DIR}/${RUN_ID}/remove/pids.txt +PROFILE_RUN_RM_PIDS_CSV=${RUN_DIR}/${RUN_ID}/remove/pids.csv +PROFILE_RUN_RM_DISK_LOG=${RUN_DIR}/${RUN_ID}/remove/disk.txt +PROFILE_RUN_RM_DISK_CSV=${RUN_DIR}/${RUN_ID}/remove/disk.csv + +# PROFILE_PIDS_LOG=${RUN_DIR}/${RUN_ID}/pids-summary.csv +# PROFILE_DISK_LOG=${RUN_DIR}/${RUN_ID}/disk-summary.csv +EOF +} + +zpios_profile_pre_run_args() { +cat > ${RUN_DIR}/${RUN_ID}/zpios-args.txt << EOF +# +# Zpios Arguments for Run ${RUN_ID} +# + +DIR=${RUN_DIR} +ID=${RUN_ID} +POOL=${RUN_POOL} +CHUNK_SIZE=${RUN_CHUNK_SIZE} +REGION_SIZE=${RUN_REGION_SIZE} +THRD_COUNT=${RUN_THRD_COUNT} +REGION_COUNT=${RUN_REGION_COUNT} +OFFSET=${RUN_OFFSET} +REGION_NOISE=${RUN_REGION_NOISE} +CHUNK_NOISE=${RUN_CHUNK_NOISE} +THRD_DELAY=${RUN_THRD_DELAY} +FLAGS=${RUN_FLAGS} +RESULT=${RUN_RESULT} +EOF +} + +# Spawn a user defined profiling script to gather additional data +zpios_profile_pre_start() { + local PROFILE_PID=$1 + + ${PROFILE_USER} ${RUN_PHASE} ${RUN_DIR} ${RUN_ID} & + echo "$!" >${PROFILE_PID} + + # Sleep waiting for profile script to be ready, it will + # signal us via SIGHUP when it is ready to start profiling. + while [ ${PROFILE_RDY} -eq 0 ]; do + sleep 0.01 + done +} + +zpios_profile_post_proc_start() { + + if [ -f ${PROFILE_ARC_PROC} ]; then + echo 0 >${PROFILE_ARC_PROC} + fi + + if [ -f ${PROFILE_VDEV_CACHE_PROC} ]; then + echo 0 >${PROFILE_VDEV_CACHE_PROC} + fi +} + +zpios_profile_pre_oprofile_start() { + local OPROFILE_LOG=$1 + + /usr/bin/opcontrol --reset >>${OPROFILE_LOG} 2>&1 + /usr/bin/opcontrol --start >>${OPROFILE_LOG} 2>&1 +} + +zpios_profile_pre_create() { + mkdir ${PROFILE_RUN_CR_DIR} + zpios_profile_pre_start ${PROFILE_RUN_CR_PID} + zpios_profile_post_proc_start + zpios_profile_pre_oprofile_start ${PROFILE_RUN_CR_OPROFILE_LOG} +} + +zpios_profile_pre_write() { + mkdir ${PROFILE_RUN_WR_DIR} + zpios_profile_pre_start ${PROFILE_RUN_WR_PID} + zpios_profile_post_proc_start + zpios_profile_pre_oprofile_start ${PROFILE_RUN_WR_OPROFILE_LOG} +} + +zpios_profile_pre_read() { + mkdir ${PROFILE_RUN_RD_DIR} + zpios_profile_pre_start ${PROFILE_RUN_RD_PID} + zpios_profile_post_proc_start + zpios_profile_pre_oprofile_start ${PROFILE_RUN_CR_RD_LOG} +} + +zpios_profile_pre_remove() { + mkdir ${PROFILE_RUN_RM_DIR} + zpios_profile_pre_start ${PROFILE_RUN_RM_PID} + zpios_profile_post_proc_start + zpios_profile_pre_oprofile_start ${PROFILE_RUN_RM_OPROFILE_LOG} +} + +# Source global zpios test configuration +if [ -f ${RUN_DIR}/zpios-config.sh ]; then + . ${RUN_DIR}/zpios-config.sh +fi + +# Source global per-run test configuration +if [ -f ${RUN_DIR}/${RUN_ID}/zpios-config-run.sh ]; then + . ${RUN_DIR}/${RUN_ID}/zpios-config-run.sh +fi + +case "${RUN_PHASE}" in + pre-run) + mkdir -p ${RUN_DIR}/${RUN_ID}/ + zpios_profile_pre_run_cfg + zpios_profile_pre_run_args + ;; + pre-create) + zpios_profile_pre_create + ;; + pre-write) + zpios_profile_pre_write + ;; + pre-read) + zpios_profile_pre_read + ;; + pre-remove) + zpios_profile_pre_remove + ;; + *) + echo "Usage: ${PROG} {pre-run|pre-create|pre-write|pre-read|pre-remove}" + exit 1 +esac + +exit 0 diff --git a/scripts/zpios-profile/zpios-profile.sh b/scripts/zpios-profile/zpios-profile.sh new file mode 100755 index 000000000..f4f0ee97f --- /dev/null +++ b/scripts/zpios-profile/zpios-profile.sh @@ -0,0 +1,226 @@ +#!/bin/bash + + +PROG=zpios-profile.sh + +trap "RUN_DONE=1" SIGHUP + +RUN_PHASE=${1} +RUN_LOG_DIR=${2} +RUN_ID=${3} +RUN_DONE=0 + +POLL_INTERVAL=2.99 + +# Log these pids, the exact pid numbers will vary from system to system +# so I harvest pid for all the following type of processes from /proc/<pid>/ +# +# zio_taskq/# +# spa_zio_issue/# +# spa_zio_intr/# +# txg_quiesce_thr +# txg_sync_thread +# txg_timelimit_t +# arc_reclaim_thr +# l2arc_feed_thre +# zpios_io/# + +ZIO_TASKQ_PIDS=() +ZIO_REQ_NUL_PIDS=() +ZIO_IRQ_NUL_PIDS=() +ZIO_REQ_RD_PIDS=() +ZIO_IRQ_RD_PIDS=() +ZIO_REQ_WR_PIDS=() +ZIO_IRQ_WR_PIDS=() +ZIO_REQ_FR_PIDS=() +ZIO_IRQ_FR_PIDS=() +ZIO_REQ_CM_PIDS=() +ZIO_IRQ_CM_PIDS=() +ZIO_REQ_CTL_PIDS=() +ZIO_IRQ_CTL_PIDS=() + +TXG_QUIESCE_PIDS=() +TXG_SYNC_PIDS=() +TXG_TIMELIMIT_PIDS=() + +ARC_RECLAIM_PIDS=() +L2ARC_FEED_PIDS=() + +ZPIOS_IO_PIDS=() + +show_pids() { + echo "* zio_taskq: { ${ZIO_TASKQ_PIDS[@]} } = ${#ZIO_TASKQ_PIDS[@]}" + echo "* zio_req_nul: { ${ZIO_REQ_NUL_PIDS[@]} } = ${#ZIO_REQ_NUL_PIDS[@]}" + echo "* zio_irq_nul: { ${ZIO_IRQ_NUL_PIDS[@]} } = ${#ZIO_IRQ_NUL_PIDS[@]}" + echo "* zio_req_rd: { ${ZIO_REQ_RD_PIDS[@]} } = ${#ZIO_REQ_RD_PIDS[@]}" + echo "* zio_irq_rd: { ${ZIO_IRQ_RD_PIDS[@]} } = ${#ZIO_IRQ_RD_PIDS[@]}" + echo "* zio_req_wr: { ${ZIO_REQ_WR_PIDS[@]} } = ${#ZIO_REQ_WR_PIDS[@]}" + echo "* zio_irq_wr: { ${ZIO_IRQ_WR_PIDS[@]} } = ${#ZIO_IRQ_WR_PIDS[@]}" + echo "* zio_req_fr: { ${ZIO_REQ_FR_PIDS[@]} } = ${#ZIO_REQ_FR_PIDS[@]}" + echo "* zio_irq_fr: { ${ZIO_IRQ_FR_PIDS[@]} } = ${#ZIO_IRQ_FR_PIDS[@]}" + echo "* zio_req_cm: { ${ZIO_REQ_CM_PIDS[@]} } = ${#ZIO_REQ_CM_PIDS[@]}" + echo "* zio_irq_cm: { ${ZIO_IRQ_CM_PIDS[@]} } = ${#ZIO_IRQ_CM_PIDS[@]}" + echo "* zio_req_ctl: { ${ZIO_REQ_CTL_PIDS[@]} } = ${#ZIO_REQ_CTL_PIDS[@]}" + echo "* zio_irq_ctl: { ${ZIO_IRQ_CTL_PIDS[@]} } = ${#ZIO_IRQ_CTL_PIDS[@]}" + echo "* txg_quiesce: { ${TXG_QUIESCE_PIDS[@]} } = ${#TXG_QUIESCE_PIDS[@]}" + echo "* txg_sync: { ${TXG_SYNC_PIDS[@]} } = ${#TXG_SYNC_PIDS[@]}" + echo "* txg_timelimit: { ${TXG_TIMELIMIT_PIDS[@]} } = ${#TXG_TIMELIMIT_PIDS[@]}" + echo "* arc_reclaim: { ${ARC_RECLAIM_PIDS[@]} } = ${#ARC_RECLAIM_PIDS[@]}" + echo "* l2arc_feed: { ${L2ARC_FEED_PIDS[@]} } = ${#L2ARC_FEED_PIDS[@]}" + echo "* zpios_io: { ${ZPIOS_IO_PIDS[@]} } = ${#ZPIOS_IO_PIDS[@]}" +} + +check_pid() { + local PID=$1 + local NAME=$2 + local TYPE=$3 + local PIDS=( "$4" ) + local NAME_STRING=`echo ${NAME} | cut -f1 -d'/'` + local NAME_NUMBER=`echo ${NAME} | cut -f2 -d'/'` + + if [ "${NAME_STRING}" == "${TYPE}" ]; then + if [ -n "${NAME_NUMBER}" ]; then + PIDS[${NAME_NUMBER}]=${PID} + else + PIDS[${#PIDS[@]}]=${PID} + + fi + fi + + echo "${PIDS[@]}" +} + +# NOTE: This whole process is crazy slow but it will do for now +aquire_pids() { + echo "--- Aquiring ZFS pids ---" + + for PID in `ls /proc/ | grep [0-9] | sort -n -u`; do + if [ ! -e /proc/${PID}/status ]; then + continue + fi + + NAME=`cat /proc/${PID}/status | head -n1 | cut -f2` + + ZIO_TASKQ_PIDS=( `check_pid ${PID} ${NAME} "zio_taskq" \ + "$(echo "${ZIO_TASKQ_PIDS[@]}")"` ) + + ZIO_REQ_NUL_PIDS=( `check_pid ${PID} ${NAME} "zio_req_nul" \ + "$(echo "${ZIO_REQ_NUL_PIDS[@]}")"` ) + + ZIO_IRQ_NUL_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_nul" \ + "$(echo "${ZIO_IRQ_NUL_PIDS[@]}")"` ) + + ZIO_REQ_RD_PIDS=( `check_pid ${PID} ${NAME} "zio_req_rd" \ + "$(echo "${ZIO_REQ_RD_PIDS[@]}")"` ) + + ZIO_IRQ_RD_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_rd" \ + "$(echo "${ZIO_IRQ_RD_PIDS[@]}")"` ) + + ZIO_REQ_WR_PIDS=( `check_pid ${PID} ${NAME} "zio_req_wr" \ + "$(echo "${ZIO_REQ_WR_PIDS[@]}")"` ) + + ZIO_IRQ_WR_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_wr" \ + "$(echo "${ZIO_IRQ_WR_PIDS[@]}")"` ) + + ZIO_REQ_FR_PIDS=( `check_pid ${PID} ${NAME} "zio_req_fr" \ + "$(echo "${ZIO_REQ_FR_PIDS[@]}")"` ) + + ZIO_IRQ_FR_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_fr" \ + "$(echo "${ZIO_IRQ_FR_PIDS[@]}")"` ) + + ZIO_REQ_CM_PIDS=( `check_pid ${PID} ${NAME} "zio_req_cm" \ + "$(echo "${ZIO_REQ_CM_PIDS[@]}")"` ) + + ZIO_IRQ_CM_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_cm" \ + "$(echo "${ZIO_IRQ_CM_PIDS[@]}")"` ) + + ZIO_REQ_CTL_PIDS=( `check_pid ${PID} ${NAME} "zio_req_ctl" \ + "$(echo "${ZIO_REQ_CTL_PIDS[@]}")"` ) + + ZIO_IRQ_CTL_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_ctl" \ + "$(echo "${ZIO_IRQ_CTL_PIDS[@]}")"` ) + + TXG_QUIESCE_PIDS=( `check_pid ${PID} ${NAME} "txg_quiesce" \ + "$(echo "${TXG_QUIESCE_PIDS[@]}")"` ) + + TXG_SYNC_PIDS=( `check_pid ${PID} ${NAME} "txg_sync" \ + "$(echo "${TXG_SYNC_PIDS[@]}")"` ) + + TXG_TIMELIMIT_PIDS=( `check_pid ${PID} ${NAME} "txg_timelimit" \ + "$(echo "${TXG_TIMELIMIT_PIDS[@]}")"` ) + + ARC_RECLAIM_PIDS=( `check_pid ${PID} ${NAME} "arc_reclaim" \ + "$(echo "${ARC_RECLAIM_PIDS[@]}")"` ) + + L2ARC_FEED_PIDS=( `check_pid ${PID} ${NAME} "l2arc_feed" \ + "$(echo "${L2ARC_FEED_PIDS[@]}")"` ) + done + + # Wait for zpios_io threads to start + kill -s SIGHUP ${PPID} + echo "* Waiting for zpios_io threads to start" + while [ ${RUN_DONE} -eq 0 ]; do + ZPIOS_IO_PIDS=( `ps ax | grep zpios_io | grep -v grep | \ + sed 's/^ *//g' | cut -f1 -d' '` ) + if [ ${#ZPIOS_IO_PIDS[@]} -gt 0 ]; then + break; + fi + sleep 0.1 + done + + echo "`show_pids`" >${RUN_LOG_DIR}/${RUN_ID}/pids.txt +} + +log_pids() { + echo "--- Logging ZFS profile to ${RUN_LOG_DIR}/${RUN_ID}/ ---" + ALL_PIDS=( ${ZIO_TASKQ_PIDS[@]} \ + ${ZIO_REQ_NUL_PIDS[@]} \ + ${ZIO_IRQ_NUL_PIDS[@]} \ + ${ZIO_REQ_RD_PID[@]} \ + ${ZIO_IRQ_RD_PIDS[@]} \ + ${ZIO_REQ_WR_PIDS[@]} \ + ${ZIO_IRQ_WR_PIDS[@]} \ + ${ZIO_REQ_FR_PIDS[@]} \ + ${ZIO_IRQ_FR_PIDS[@]} \ + ${ZIO_REQ_CM_PIDS[@]} \ + ${ZIO_IRQ_CM_PIDS[@]} \ + ${ZIO_REQ_CTL_PIDS[@]} \ + ${ZIO_IRQ_CTL_PIDS[@]} \ + ${TXG_QUIESCE_PIDS[@]} \ + ${TXG_SYNC_PIDS[@]} \ + ${TXG_TIMELIMIT_PIDS[@]} \ + ${ARC_RECLAIM_PIDS[@]} \ + ${L2ARC_FEED_PIDS[@]} \ + ${ZPIOS_IO_PIDS[@]} ) + + while [ ${RUN_DONE} -eq 0 ]; do + NOW=`date +%s.%N` + LOG_PIDS="${RUN_LOG_DIR}/${RUN_ID}/pids-${NOW}" + LOG_DISK="${RUN_LOG_DIR}/${RUN_ID}/disk-${NOW}" + + for PID in "${ALL_PIDS[@]}"; do + if [ -z ${PID} ]; then + continue; + fi + + if [ -e /proc/${PID}/stat ]; then + cat /proc/${PID}/stat | head -n1 >>${LOG_PIDS} + else + echo "<${PID} exited>" >>${LOG_PIDS} + fi + done + + cat /proc/diskstats >${LOG_DISK} + + NOW2=`date +%s.%N` + DELTA=`echo "${POLL_INTERVAL}-(${NOW2}-${NOW})" | bc` + sleep ${DELTA} + done +} + +aquire_pids +log_pids + +# rm ${PROFILE_PID} + +exit 0 diff --git a/scripts/zpios-sanity.sh b/scripts/zpios-sanity.sh new file mode 100755 index 000000000..194ae82e2 --- /dev/null +++ b/scripts/zpios-sanity.sh @@ -0,0 +1,158 @@ +#!/bin/bash +# +# ZFS/ZPOOL configuration test script. + +basedir="$(dirname $0)" + +SCRIPT_COMMON=common.sh +if [ -f "${basedir}/${SCRIPT_COMMON}" ]; then +. "${basedir}/${SCRIPT_COMMON}" +else +echo "Missing helper script ${SCRIPT_COMMON}" && exit 1 +fi + +PROG=zpios-sanity.sh +HEADER= + +usage() { +cat << EOF +USAGE: +$0 [hvxfc] + +DESCRIPTION: + ZPIOS sanity tests + +OPTIONS: + -h Show this message + -v Verbose + -x Destructive hd/sd/md/dm/ram tests + -f Don't prompt due to -x + -c Cleanup lo+file devices at start + +EOF +} + +while getopts 'hvxfc?' OPTION; do + case $OPTION in + h) + usage + exit 1 + ;; + v) + VERBOSE=1 + ;; + x) + DANGEROUS=1 + ;; + f) + FORCE=1 + ;; + c) + CLEANUP=1 + ;; + ?) + usage + exit + ;; + esac +done + +if [ $(id -u) != 0 ]; then + die "Must run as root" +fi + +# Perform pre-cleanup is requested +if [ ${CLEANUP} ]; then + cleanup_loop_devices + rm -f /tmp/zpool.cache.* +fi + +zpios_test() { + CONFIG=$1 + TEST=$2 + LOG=`mktemp` + + ${ZPIOS_SH} -f -c ${CONFIG} -t ${TEST} &>${LOG} + if [ $? -ne 0 ]; then + if [ ${VERBOSE} ]; then + printf "FAIL: %-13s\n" ${CONFIG} + cat ${LOG} + else + if [ ! ${HEADER} ]; then + head -2 ${LOG} + HEADER=1 + fi + + printf "FAIL: %-13s" ${CONFIG} + tail -1 ${LOG} + fi + else + if [ ${VERBOSE} ]; then + cat ${LOG} + else + if [ ! ${HEADER} ]; then + head -2 ${LOG} + HEADER=1 + fi + + tail -1 ${LOG} + fi + fi + + rm -f ${LOG} +} + +if [ ${DANGEROUS} ] && [ ! ${FORCE} ]; then + cat << EOF +The -x option was passed which will result in UNRECOVERABLE DATA LOSS +on on the following block devices: + + /dev/sd[abcd] + /dev/hda + /dev/ram0 + /dev/md0 + /dev/dm-0 + +To continue please confirm by entering YES: +EOF + read CONFIRM + if [ ${CONFIRM} != "YES" ] && [ ${CONFIRM} != "yes" ]; then + exit 0; + fi +fi + +# +# These configurations are all safe and pose no risk to any data on +# the system which runs them. They will confine all their IO to a +# file in /tmp or a loopback device configured to use a file in /tmp. +# +SAFE_CONFIGS=( \ + file-raid0 file-raid10 file-raidz file-raidz2 \ + lo-raid0 lo-raid10 lo-raidz lo-raidz2 \ +) + +# +# These configurations are down right dangerous. They will attempt +# to use various real block devices on your system which may contain +# data you car about. You are STRONGLY advised not to run this unless +# you are certain there is no data on the system you care about. +# +DANGEROUS_CONFIGS=( \ + hda-raid0 \ + sda-raid0 \ + ram0-raid0 \ + md0-raid10 md0-raid5 \ + dm0-raid0 \ +) + +for CONFIG in ${SAFE_CONFIGS[*]}; do + zpios_test $CONFIG tiny +done + +if [ ${DANGEROUS} ]; then + for CONFIG in ${DANGEROUS_CONFIGS[*]}; do + zpios_test $CONFIG tiny + done +fi + +exit 0 diff --git a/scripts/zpios-survey.sh b/scripts/zpios-survey.sh new file mode 100755 index 000000000..cb751b467 --- /dev/null +++ b/scripts/zpios-survey.sh @@ -0,0 +1,215 @@ +#!/bin/bash +# +# Wrapper script for easily running a survey of zpios based tests +# + +basedir="$(dirname $0)" + +SCRIPT_COMMON=common.sh +if [ -f "${basedir}/${SCRIPT_COMMON}" ]; then +. "${basedir}/${SCRIPT_COMMON}" +else +echo "Missing helper script ${SCRIPT_COMMON}" && exit 1 +fi + +PROG=zpios-survey.sh + +usage() { +cat << EOF +USAGE: +$0 [hvp] <-c config> <-t test> + +DESCRIPTION: + Helper script for easy zpios survey benchmarking. + +OPTIONS: + -h Show this message + -v Verbose + -p Enable profiling + -c Zpool configuration + -t Zpios test + -l Zpios survey log + +EOF +} + +print_header() { +tee -a ${ZPIOS_SURVEY_LOG} << EOF + +================================================================ +Test: $1 +EOF +} + +# Baseline performance for an out of the box config with no manual tuning. +# Ideally, we want everything to be automatically tuned for your system and +# for this to perform reasonably well. +zpios_survey_base() { + TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+baseline" + print_header ${TEST_NAME} + + ${ZFS_SH} ${VERBOSE_FLAG} | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZFS_SH} -u ${VERBOSE_FLAG} | \ + tee -a ${ZPIOS_SURVEY_LOG} +} + +# Disable ZFS's prefetching. For some reason still not clear to me +# current prefetching policy is quite bad for a random workload. +# Allowing the algorithm to detect a random workload and not do +# anything may be the way to address this issue. +zpios_survey_prefetch() { + TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+prefetch" + print_header ${TEST_NAME} + + ${ZFS_SH} ${VERBOSE_FLAG} \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \ + -o "--noprefetch" | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZFS_SH} -u ${VERBOSE_FLAG} | \ + tee -a ${ZPIOS_SURVEY_LOG} +} + +# Simulating a zerocopy IO path should improve performance by freeing up +# lots of CPU which is wasted move data between buffers. +zpios_survey_zerocopy() { + TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+zerocopy" + print_header ${TEST_NAME} + + ${ZFS_SH} ${VERBOSE_FLAG} | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \ + -o "--zerocopy" | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZFS_SH} -u ${VERBOSE_FLAG} | \ + tee -a ${ZPIOS_SURVEY_LOG} +} + +# Disabling checksumming should show some (if small) improvement +# simply due to freeing up a modest amount of CPU. +zpios_survey_checksum() { + TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+checksum" + print_header ${TEST_NAME} + + ${ZFS_SH} ${VERBOSE_FLAG} | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \ + -s "set checksum=off" | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZFS_SH} -u ${VERBOSE_FLAG} | \ + tee -a ${ZPIOS_SURVEY_LOG} +} + +# Increasing the pending IO depth also seems to improve things likely +# at the expense of latency. This should be explored more because I'm +# seeing a much bigger impact there that I would have expected. There +# may be some low hanging fruit to be found here. +zpios_survey_pending() { + TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+pending" + print_header ${TEST_NAME} + + ${ZFS_SH} ${VERBOSE_FLAG} \ + zfs="zfs_vdev_max_pending=1024" | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZFS_SH} -u ${VERBOSE_FLAG} | \ + tee -a ${ZPIOS_SURVEY_LOG} +} + +# To avoid memory fragmentation issues our slab implementation can be +# based on a virtual address space. Interestingly, we take a pretty +# substantial performance penalty for this somewhere in the low level +# IO drivers. If we back the slab with kmem pages we see far better +# read performance numbers at the cost of memory fragmention and general +# system instability due to large allocations. This may be because of +# an optimization in the low level drivers due to the contigeous kmem +# based memory. This needs to be explained. The good news here is that +# with zerocopy interfaces added at the DMU layer we could gaurentee +# kmem based memory for a pool of pages. +# +# 0x100 = KMC_KMEM - Force kmem_* based slab +# 0x200 = KMC_VMEM - Force vmem_* based slab +zpios_survey_kmem() { + TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+kmem" + print_header ${TEST_NAME} + + ${ZFS_SH} ${VERBOSE_FLAG} \ + zfs="zio_bulk_flags=0x100" | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZFS_SH} -u ${VERBOSE_FLAG} | \ + tee -a ${ZPIOS_SURVEY_LOG} +} + +# Apply all possible turning concurrently to get a best case number +zpios_survey_all() { + TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+all" + print_header ${TEST_NAME} + + ${ZFS_SH} ${VERBOSE_FLAG} \ + zfs="zfs_vdev_max_pending=1024" \ + zfs="zio_bulk_flags=0x100" | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \ + -o "--noprefetch --zerocopy" \ + -s "set checksum=off" | \ + tee -a ${ZPIOS_SURVEY_LOG} + ${ZFS_SH} -u ${VERBOSE_FLAG} | \ + tee -a ${ZPIOS_SURVEY_LOG} +} + + +PROFILE= +ZPOOL_NAME=zpios-survey +ZPOOL_CONFIG=zpool-config.sh +ZPIOS_TEST=zpios-test.sh +ZPIOS_SURVEY_LOG=/dev/null + +while getopts 'hvpc:t:l:' OPTION; do + case $OPTION in + h) + usage + exit 1 + ;; + v) + VERBOSE=1 + VERBOSE_FLAG="-v" + ;; + p) + PROFILE=1 + PROFILE_FLAG="-p" + ;; + c) + ZPOOL_CONFIG=${OPTARG} + ;; + t) + ZPIOS_TEST=${OPTARG} + ;; + l) + ZPIOS_SURVEY_LOG=${OPTARG} + ;; + ?) + usage + exit + ;; + esac +done + +if [ $(id -u) != 0 ]; then + die "Must run as root" +fi + +zpios_survey_base +zpios_survey_prefetch +zpios_survey_zerocopy +zpios_survey_checksum +zpios_survey_pending +zpios_survey_kmem +zpios_survey_all + +exit 0 diff --git a/scripts/zpios-test/16th-8192rc-4rs-1cs-4off.sh b/scripts/zpios-test/16th-8192rc-4rs-1cs-4off.sh new file mode 100755 index 000000000..cbd9c697a --- /dev/null +++ b/scripts/zpios-test/16th-8192rc-4rs-1cs-4off.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# +# Usage: zpios +# --threadcount -t =values +# --threadcount_low -l =value +# --threadcount_high -h =value +# --threadcount_incr -e =value +# --regioncount -n =values +# --regioncount_low -i =value +# --regioncount_high -j =value +# --regioncount_incr -k =value +# --offset -o =values +# --offset_low -m =value +# --offset_high -q =value +# --offset_incr -r =value +# --chunksize -c =values +# --chunksize_low -a =value +# --chunksize_high -b =value +# --chunksize_incr -g =value +# --regionsize -s =values +# --regionsize_low -A =value +# --regionsize_high -B =value +# --regionsize_incr -C =value +# --load -L =dmuio|ssf|fpp +# --pool -p =pool name +# --name -M =test name +# --cleanup -x +# --prerun -P =pre-command +# --postrun -R =post-command +# --log -G =log directory +# --regionnoise -I =shift +# --chunknoise -N =bytes +# --threaddelay -T =jiffies +# --verify -V +# --zerocopy -z +# --nowait -O +# --human-readable -H +# --verbose -v =increase verbosity +# --help -? =this help + +ZPIOS_CMD="${ZPIOS} \ + --load=dmuio \ + --pool=${ZPOOL_NAME} \ + --name=${ZPOOL_CONFIG} \ + --threadcount=16 \ + --regioncount=8192 \ + --regionsize=4M \ + --chunksize=1M \ + --offset=4M \ + --cleanup \ + --human-readable \ + ${ZPIOS_OPTIONS}" + +zpios_start() { + if [ ${VERBOSE} ]; then + ZPIOS_CMD="${ZPIOS_CMD} --verbose" + echo ${ZPIOS_CMD} + fi + + ${ZPIOS_CMD} || exit 1 +} + +zpios_stop() { + [ ${VERBOSE} ] && echo +} diff --git a/scripts/zpios-test/1th-16rc-4rs-1cs-4off.sh b/scripts/zpios-test/1th-16rc-4rs-1cs-4off.sh new file mode 100755 index 000000000..cd3c50b77 --- /dev/null +++ b/scripts/zpios-test/1th-16rc-4rs-1cs-4off.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# +# Usage: zpios +# --threadcount -t =values +# --threadcount_low -l =value +# --threadcount_high -h =value +# --threadcount_incr -e =value +# --regioncount -n =values +# --regioncount_low -i =value +# --regioncount_high -j =value +# --regioncount_incr -k =value +# --offset -o =values +# --offset_low -m =value +# --offset_high -q =value +# --offset_incr -r =value +# --chunksize -c =values +# --chunksize_low -a =value +# --chunksize_high -b =value +# --chunksize_incr -g =value +# --regionsize -s =values +# --regionsize_low -A =value +# --regionsize_high -B =value +# --regionsize_incr -C =value +# --load -L =dmuio|ssf|fpp +# --pool -p =pool name +# --name -M =test name +# --cleanup -x +# --prerun -P =pre-command +# --postrun -R =post-command +# --log -G =log directory +# --regionnoise -I =shift +# --chunknoise -N =bytes +# --threaddelay -T =jiffies +# --verify -V +# --zerocopy -z +# --nowait -O +# --human-readable -H +# --verbose -v =increase verbosity +# --help -? =this help + + +ZPIOS_CMD="${ZPIOS} \ + --load=dmuio \ + --pool=${ZPOOL_NAME} \ + --name=${ZPOOL_CONFIG} \ + --threadcount=1 \ + --regioncount=16 \ + --regionsize=4M \ + --chunksize=1M \ + --offset=4M \ + --cleanup \ + --human-readable \ + ${ZPIOS_OPTIONS}" + +zpios_start() { + if [ ${VERBOSE} ]; then + ZPIOS_CMD="${ZPIOS_CMD} --verbose" + echo ${ZPIOS_CMD} + fi + + ${ZPIOS_CMD} || exit 1 +} + +zpios_stop() { + [ ${VERBOSE} ] && echo +} diff --git a/scripts/zpios-test/1x256th-65536rc-4rs-1cs-4off.sh b/scripts/zpios-test/1x256th-65536rc-4rs-1cs-4off.sh new file mode 100755 index 000000000..743e97b64 --- /dev/null +++ b/scripts/zpios-test/1x256th-65536rc-4rs-1cs-4off.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# +# Usage: zpios +# --threadcount -t =values +# --threadcount_low -l =value +# --threadcount_high -h =value +# --threadcount_incr -e =value +# --regioncount -n =values +# --regioncount_low -i =value +# --regioncount_high -j =value +# --regioncount_incr -k =value +# --offset -o =values +# --offset_low -m =value +# --offset_high -q =value +# --offset_incr -r =value +# --chunksize -c =values +# --chunksize_low -a =value +# --chunksize_high -b =value +# --chunksize_incr -g =value +# --regionsize -s =values +# --regionsize_low -A =value +# --regionsize_high -B =value +# --regionsize_incr -C =value +# --load -L =dmuio|ssf|fpp +# --pool -p =pool name +# --name -M =test name +# --cleanup -x +# --prerun -P =pre-command +# --postrun -R =post-command +# --log -G =log directory +# --regionnoise -I =shift +# --chunknoise -N =bytes +# --threaddelay -T =jiffies +# --verify -V +# --zerocopy -z +# --nowait -O +# --human-readable -H +# --verbose -v =increase verbosity +# --help -? =this help + +ZPIOS_CMD="${ZPIOS} \ + --load=dmuio \ + --pool=${ZPOOL_NAME} \ + --name=${ZPOOL_CONFIG} \ + --threadcount=1,2,4,8,16,32,64,128,256 \ + --regioncount=65536 \ + --regionsize=4M \ + --chunksize=1M \ + --offset=4M \ + --cleanup \ + --human-readable \ + ${ZPIOS_OPTIONS}" + +zpios_start() { + if [ ${VERBOSE} ]; then + ZPIOS_CMD="${ZPIOS_CMD} --verbose" + echo ${ZPIOS_CMD} + fi + + ${ZPIOS_CMD} || exit 1 +} + +zpios_stop() { + [ ${VERBOSE} ] && echo +} diff --git a/scripts/zpios-test/256th-65536rc-4rs-1cs-4off.sh b/scripts/zpios-test/256th-65536rc-4rs-1cs-4off.sh new file mode 100755 index 000000000..92a3b77b4 --- /dev/null +++ b/scripts/zpios-test/256th-65536rc-4rs-1cs-4off.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# +# Usage: zpios +# --threadcount -t =values +# --threadcount_low -l =value +# --threadcount_high -h =value +# --threadcount_incr -e =value +# --regioncount -n =values +# --regioncount_low -i =value +# --regioncount_high -j =value +# --regioncount_incr -k =value +# --offset -o =values +# --offset_low -m =value +# --offset_high -q =value +# --offset_incr -r =value +# --chunksize -c =values +# --chunksize_low -a =value +# --chunksize_high -b =value +# --chunksize_incr -g =value +# --regionsize -s =values +# --regionsize_low -A =value +# --regionsize_high -B =value +# --regionsize_incr -C =value +# --load -L =dmuio|ssf|fpp +# --pool -p =pool name +# --name -M =test name +# --cleanup -x +# --prerun -P =pre-command +# --postrun -R =post-command +# --log -G =log directory +# --regionnoise -I =shift +# --chunknoise -N =bytes +# --threaddelay -T =jiffies +# --verify -V +# --zerocopy -z +# --nowait -O +# --human-readable -H +# --verbose -v =increase verbosity +# --help -? =this help + +ZPIOS_CMD="${ZPIOS} \ + --load=dmuio \ + --pool=${ZPOOL_NAME} \ + --name=${ZPOOL_CONFIG} \ + --threadcount=256 \ + --regioncount=65536 \ + --regionsize=4M \ + --chunksize=1M \ + --offset=4M \ + --cleanup \ + --human-readable \ + ${ZPIOS_OPTIONS}" + +zpios_start() { + if [ ${VERBOSE} ]; then + ZPIOS_CMD="${ZPIOS_CMD} --verbose" + echo ${ZPIOS_CMD} + fi + + ${ZPIOS_CMD} || exit 1 +} + +zpios_stop() { + [ ${VERBOSE} ] && echo +} diff --git a/scripts/zpios-test/4th-1024rc-4rs-1cs-4off.sh b/scripts/zpios-test/4th-1024rc-4rs-1cs-4off.sh new file mode 100755 index 000000000..0db952cd6 --- /dev/null +++ b/scripts/zpios-test/4th-1024rc-4rs-1cs-4off.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# +# Usage: zpios +# --threadcount -t =values +# --threadcount_low -l =value +# --threadcount_high -h =value +# --threadcount_incr -e =value +# --regioncount -n =values +# --regioncount_low -i =value +# --regioncount_high -j =value +# --regioncount_incr -k =value +# --offset -o =values +# --offset_low -m =value +# --offset_high -q =value +# --offset_incr -r =value +# --chunksize -c =values +# --chunksize_low -a =value +# --chunksize_high -b =value +# --chunksize_incr -g =value +# --regionsize -s =values +# --regionsize_low -A =value +# --regionsize_high -B =value +# --regionsize_incr -C =value +# --load -L =dmuio|ssf|fpp +# --pool -p =pool name +# --name -M =test name +# --cleanup -x +# --prerun -P =pre-command +# --postrun -R =post-command +# --log -G =log directory +# --regionnoise -I =shift +# --chunknoise -N =bytes +# --threaddelay -T =jiffies +# --verify -V +# --zerocopy -z +# --nowait -O +# --human-readable -H +# --verbose -v =increase verbosity +# --help -? =this help + +ZPIOS_CMD="${ZPIOS} \ + --load=dmuio \ + --pool=${ZPOOL_NAME} \ + --name=${ZPOOL_CONFIG} \ + --threadcount=4 \ + --regioncount=1024 \ + --regionsize=4M \ + --chunksize=1M \ + --offset=4M \ + --cleanup \ + --human-readable \ + ${ZPIOS_OPTIONS}" + +zpios_start() { + if [ ${VERBOSE} ]; then + ZPIOS_CMD="${ZPIOS_CMD} --verbose" + echo ${ZPIOS_CMD} + fi + + ${ZPIOS_CMD} || exit 1 +} + +zpios_stop() { + [ ${VERBOSE} ] && echo +} diff --git a/scripts/zpios-test/large-thread-survey.sh b/scripts/zpios-test/large-thread-survey.sh new file mode 120000 index 000000000..90b6e3c47 --- /dev/null +++ b/scripts/zpios-test/large-thread-survey.sh @@ -0,0 +1 @@ +1x256th-65536rc-4rs-1cs-4off.sh
\ No newline at end of file diff --git a/scripts/zpios-test/large.sh b/scripts/zpios-test/large.sh new file mode 120000 index 000000000..b8e22bf54 --- /dev/null +++ b/scripts/zpios-test/large.sh @@ -0,0 +1 @@ +256th-65536rc-4rs-1cs-4off.sh
\ No newline at end of file diff --git a/scripts/zpios-test/medium.sh b/scripts/zpios-test/medium.sh new file mode 120000 index 000000000..d81027b73 --- /dev/null +++ b/scripts/zpios-test/medium.sh @@ -0,0 +1 @@ +16th-8192rc-4rs-1cs-4off.sh
\ No newline at end of file diff --git a/scripts/zpios-test/small.sh b/scripts/zpios-test/small.sh new file mode 120000 index 000000000..cbf03b5ce --- /dev/null +++ b/scripts/zpios-test/small.sh @@ -0,0 +1 @@ +4th-1024rc-4rs-1cs-4off.sh
\ No newline at end of file diff --git a/scripts/zpios-test/tiny.sh b/scripts/zpios-test/tiny.sh new file mode 120000 index 000000000..ba8b7cd0c --- /dev/null +++ b/scripts/zpios-test/tiny.sh @@ -0,0 +1 @@ +1th-16rc-4rs-1cs-4off.sh
\ No newline at end of file diff --git a/scripts/zpios.sh b/scripts/zpios.sh new file mode 100755 index 000000000..e16a58a3b --- /dev/null +++ b/scripts/zpios.sh @@ -0,0 +1,272 @@ +#!/bin/bash +# +# Wrapper script for easily running zpios based tests +# + +basedir="$(dirname $0)" + +SCRIPT_COMMON=common.sh +if [ -f "${basedir}/${SCRIPT_COMMON}" ]; then +. "${basedir}/${SCRIPT_COMMON}" +else +echo "Missing helper script ${SCRIPT_COMMON}" && exit 1 +fi + +PROG=zpios.sh +DATE=`date +%Y%m%d-%H%M%S` +if [ "${ZPIOS_MODULES}" ]; then + MODULES=(${ZPIOS_MODULES[*]}) +else + MODULES=(zpios) +fi + +usage() { +cat << EOF +USAGE: +$0 [hvp] <-c config> <-t test> + +DESCRIPTION: + Helper script for easy zpios benchmarking. + +OPTIONS: + -h Show this message + -v Verbose + -f Force everything + -p Enable profiling + -c Zpool configuration + -t Zpios test + -o Additional zpios options + -l Additional zpool options + -s Additional zfs options + +EOF +} + +print_header() { + echo --------------------- ZPIOS RESULTS ---------------------------- + echo -n "Date: "; date + echo -n "Kernel: "; uname -r + dmesg | grep "Loaded Solaris Porting Layer" | tail -n1 + dmesg | grep "Loaded ZFS Filesystem" | tail -n1 + echo +} + +print_spl_info() { + echo --------------------- SPL Tunings ------------------------------ + ${SYSCTL} -A | grep spl + + if [ -d /sys/module/spl/parameters ]; then + grep [0-9] /sys/module/spl/parameters/* + else + grep [0-9] /sys/module/spl/* + fi + + echo +} + +print_zfs_info() { + echo --------------------- ZFS Tunings ------------------------------ + ${SYSCTL} -A | grep zfs + + if [ -d /sys/module/zfs/parameters ]; then + grep [0-9] /sys/module/zfs/parameters/* + else + grep [0-9] /sys/module/zfs/* + fi + + echo +} + +print_stats() { + echo ---------------------- Statistics ------------------------------- + ${SYSCTL} -A | grep spl | grep stack_max + + if [ -d /proc/spl/kstat/ ]; then + if [ -f /proc/spl/kstat/zfs/arcstats ]; then + echo "* ARC" + cat /proc/spl/kstat/zfs/arcstats + echo + fi + + if [ -f /proc/spl/kstat/zfs/vdev_cache_stats ]; then + echo "* VDEV Cache" + cat /proc/spl/kstat/zfs/vdev_cache_stats + echo + fi + fi + + if [ -f /proc/spl/kmem/slab ]; then + echo "* SPL SLAB" + cat /proc/spl/kmem/slab + echo + fi + + echo +} + +check_test() { + + if [ ! -f ${ZPIOS_TEST} ]; then + local NAME=`basename ${ZPIOS_TEST} .sh` + ERROR="Unknown test '${NAME}', available tests are:\n" + + for TST in `ls ${ZPIOSDIR}/ | grep ".sh"`; do + local NAME=`basename ${TST} .sh` + ERROR="${ERROR}${NAME}\n" + done + + return 1 + fi + + return 0 +} + +zpios_profile_config() { +cat > ${PROFILE_DIR}/zpios-config.sh << EOF +# +# Zpios Profiling Configuration +# + +PROFILE_DIR=/tmp/zpios/${ZPOOL_CONFIG}+${ZPIOS_TEST_ARG}+${DATE} +PROFILE_PRE=${ZPIOSPROFILEDIR}/zpios-profile-pre.sh +PROFILE_POST=${ZPIOSPROFILEDIR}/zpios-profile-post.sh +PROFILE_USER=${ZPIOSPROFILEDIR}/zpios-profile.sh +PROFILE_PIDS=${ZPIOSPROFILEDIR}/zpios-profile-pids.sh +PROFILE_DISK=${ZPIOSPROFILEDIR}/zpios-profile-disk.sh +PROFILE_ARC_PROC=/proc/spl/kstat/zfs/arcstats +PROFILE_VDEV_CACHE_PROC=/proc/spl/kstat/zfs/vdev_cache_stats + +OPROFILE_KERNEL="/boot/vmlinux-`uname -r`" +OPROFILE_KERNEL_DIR="/lib/modules/`uname -r`/kernel/" +OPROFILE_SPL_DIR=${SPLBUILD}/module/ +OPROFILE_ZFS_DIR=${MODDIR} + +EOF +} + +zpios_profile_start() { + PROFILE_DIR=/tmp/zpios/${ZPOOL_CONFIG}+${ZPIOS_TEST_ARG}+${DATE} + + mkdir -p ${PROFILE_DIR} + zpios_profile_config + . ${PROFILE_DIR}/zpios-config.sh + + ZPIOS_OPTIONS="${ZPIOS_OPTIONS} --log=${PROFILE_DIR}" + ZPIOS_OPTIONS="${ZPIOS_OPTIONS} --prerun=${PROFILE_PRE}" + ZPIOS_OPTIONS="${ZPIOS_OPTIONS} --postrun=${PROFILE_POST}" + + /usr/bin/opcontrol --init + /usr/bin/opcontrol --setup --vmlinux=${OPROFILE_KERNEL} +} + +zpios_profile_stop() { + /usr/bin/opcontrol --shutdown + /usr/bin/opcontrol --deinit +} + +PROFILE= +ZPOOL_CONFIG=zpool-config.sh +ZPIOS_TEST=zpios-test.sh +ZPOOL_NAME=zpios +ZPIOS_OPTIONS= +ZPOOL_OPTIONS="" +ZFS_OPTIONS="" + +while getopts 'hvfpc:t:o:l:s:' OPTION; do + case $OPTION in + h) + usage + exit 1 + ;; + v) + VERBOSE=1 + VERBOSE_FLAG="-v" + ;; + f) + FORCE=1 + FORCE_FLAG="-f" + ;; + p) + PROFILE=1 + ;; + c) + ZPOOL_CONFIG=${OPTARG} + ;; + t) + ZPIOS_TEST_ARG=${OPTARG} + ZPIOS_TEST=${ZPIOSDIR}/${OPTARG}.sh + ;; + o) + ZPIOS_OPTIONS=${OPTARG} + ;; + l) # Passed through to zpool-create.sh + ZPOOL_OPTIONS=${OPTARG} + ;; + s) # Passed through to zpool-create.sh + ZFS_OPTIONS=${OPTARG} + ;; + ?) + usage + exit + ;; + esac +done + +if [ $(id -u) != 0 ]; then + die "Must run as root" +fi + +# Validate and source your test config +check_test || die "${ERROR}" +. ${ZPIOS_TEST} + +# Pull in the zpios test module is not loaded. If this fails it is +# likely because the full module stack was not yet loaded with zfs.sh +if check_modules; then + if ! load_modules; then + die "Run 'zfs.sh' to ensure the full module stack is loaded" + fi +fi + +# Wait for device creation +while [ ! -c /dev/zpios ]; do + sleep 1 +done + +if [ ${VERBOSE} ]; then + print_header + print_spl_info + print_zfs_info +fi + +# Create the zpool configuration +${ZPOOL_CREATE_SH} ${VERBOSE_FLAG} ${FORCE_FLAG} \ + -p ${ZPOOL_NAME} -c ${ZPOOL_CONFIG} \ + -l "${ZPOOL_OPTIONS}" -s "${ZFS_OPTIONS}" || exit 1 + +if [ ${PROFILE} ]; then + zpios_profile_start +fi + +zpios_start +zpios_stop + +if [ ${PROFILE} ]; then + zpios_profile_stop +fi + +if [ ${VERBOSE} ]; then + print_stats +fi + +# Destroy the zpool configuration +${ZPOOL_CREATE_SH} ${VERBOSE_FLAG} ${FORCE_FLAG} \ + -p ${ZPOOL_NAME} -c ${ZPOOL_CONFIG} -d || exit 1 + +# Unload the test module stack and wait for device removal +unload_modules +while [ -c /dev/zpios ]; do + sleep 1 +done + +exit 0 |