Skip to content

Instantly share code, notes, and snippets.

@Semmu
Created March 30, 2024 14:42
Show Gist options
  • Save Semmu/7281a1b37e77dcb06ada541338325190 to your computer and use it in GitHub Desktop.
Save Semmu/7281a1b37e77dcb06ada541338325190 to your computer and use it in GitHub Desktop.
Shell script to test block device write speed at multiple locations

this simple shell script tests the write speed of a block device.

it splits the device into $NUM_TESTS parts and writes $WRITE_SIZE_IN_MB data at each location using dd. then it does a last write test at the very end of the device.

it can be used to print the write speed of the device on its whole range instead of just the beginning, like what a typical dd would do. this is important for e.g. HDDs, where the speed usually decreases at the end, because of the constant angular velocity but varying bit "density".

the first couple of lines define the default values for some arguments, and they can be overridden by invoking the script like this:

NUM_TESTS=3 WRITE_SIZE_IN_MB=10 ./block_device_multiple_dd_write_test.sh /dev/sdX

it also has some default conv and oflag parameters passed to dd to prevent write caching to affect these numbers too much.

#!/bin/bash
set -ex
: ${NUM_TESTS:=10}
: ${WRITE_SIZE_IN_MB:=1024}
: ${IF:=/dev/zero}
: ${OFLAG:=nocache}
: ${CONV:=fsync}
: ${STATUS:=progress}
if [[ $( whoami ) != "root" ]] ; then
echo "must be run as root!"
exit 1
fi
if [[ -z $1 ]] ; then
echo "needs a block device parameter!"
exit 1
fi
DISK=$1
OPTIMAL_BLOCKSIZE=$(blockdev --getbsz $DISK)
TOTAL_SIZE_IN_512=$(blockdev --getsz $DISK)
TOTAL_SIZE_IN_BLOCKS=$(( $TOTAL_SIZE_IN_512 * 512 / $OPTIMAL_BLOCKSIZE ))
WRITE_SIZE_IN_BLOCKS=$(( $WRITE_SIZE_IN_MB * 1024 * 1024 / $OPTIMAL_BLOCKSIZE ))
for (( I = 0 ; I < $NUM_TESTS ; I++ )) ; do
echo "--- WRITE TEST #${I} / ${NUM_TESTS}"
CURRENT_SEEK=$(( $TOTAL_SIZE_IN_BLOCKS / $NUM_TESTS * $I ))
dd if=$IF of=$DISK bs=$OPTIMAL_BLOCKSIZE obs=$OPTIMAL_BLOCKSIZE seek=$CURRENT_SEEK count=$WRITE_SIZE_IN_BLOCKS oflag=$OFLAG conv=$CONV status=$STATUS
done
echo "--- WRITE TEST #END"
END_SEEK=$(( $TOTAL_SIZE_IN_BLOCKS - $WRITE_SIZE_IN_BLOCKS ))
dd if=$IF of=$DISK bs=$OPTIMAL_BLOCKSIZE obs=$OPTIMAL_BLOCKSIZE seek=$END_SEEK count=$WRITE_SIZE_IN_BLOCKS oflag=$OFLAG conv=$CONV status=$STATUS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment