Skip to content

Instantly share code, notes, and snippets.

@ubidefeo
Created January 19, 2025 16:44
Show Gist options
  • Save ubidefeo/ef890794efaa235f8f1cee34207804c3 to your computer and use it in GitHub Desktop.
Save ubidefeo/ef890794efaa235f8f1cee34207804c3 to your computer and use it in GitHub Desktop.
Benchmark Block Devices (SD cards, USB sticks, drives etc)
#!/bin/bash
if [ "$#" -lt 3 ]; then
echo "Usage: $0 mode device block_size1 [block_size2 ...]"
echo "Example: $0 read /dev/rdisk2 1m 4m 8m 16m"
exit 1
fi
# Request sudo upfront
if ! sudo -v; then
echo "This script requires sudo privileges"
exit 1
fi
mode=$1
if [ "$mode" != "read" ] && [ "$mode" != "write" ]; then
echo "Invalid mode. Please use either 'read' or 'write'"
exit 1
fi
device=$2
if [ ! -b "$device" ]; then
echo "Invalid input device"
exit 1
fi
shift 2
# Function to convert block size to bytes
get_bytes() {
local size=$1
local number=${size%[cwbkKmMgG]}
local suffix=${size#"$number"}
case $suffix in
c) echo $((number * 1));;
w) echo $((number * 2));;
b) echo $((number * 512));;
k) echo $((number * 1024));;
K) echo $((number * 1000));;
m) echo $((number * 1024 * 1024));;
M) echo $((number * 1000 * 1000));;
g) echo $((number * 1024 * 1024 * 1024));;
G) echo $((number * 1000 * 1000 * 1000));;
*) echo $number;; # Assume bytes if no suffix
esac
}
# Function to format bytes to human readable
format_bytes() {
local bytes=$1
if [ $bytes -ge $((1024 * 1024 * 1024)) ]; then
echo "$(echo "scale=2; $bytes/1024/1024/1024" | bc)GB"
elif [ $bytes -ge $((1024 * 1024)) ]; then
echo "$(echo "scale=2; $bytes/1024/1024" | bc)MB"
elif [ $bytes -ge 1024 ]; then
echo "$(echo "scale=2; $bytes/1024" | bc)KB"
else
echo "${bytes}B"
fi
}
# Store results in a file for easier sorting
results_file=$(mktemp)
for bs in "$@"; do
# Convert block size to bytes
bs_bytes=$(get_bytes "$bs")
# Calculate number of blocks to transfer approximately 1GB
target_bytes=$((1024 * 1024 * 1024))
blocks=$((target_bytes / bs_bytes))
total_bytes=$((blocks * bs_bytes))
formatted_size=$(format_bytes $total_bytes)
echo "Testing ${bs} blocks | data transfer: ${formatted_size}"
sudo purge
echo "----------------"
start_time=$(date +%s)
if [ "$mode" == "read" ]; then
sudo dd if=$device of=/dev/null bs=$bs count=$blocks status=progress
else
sudo dd if=/dev/zero of=$device bs=$bs count=$blocks status=progress
fi
end_time=$(date +%s)
duration=$((end_time - start_time))
# Store each result as: duration block_size transfer_size
echo "$duration $bs ${formatted_size}" >> "$results_file"
echo "----------------"
sleep 5
done
echo ""
echo "--------------------------------"
echo "Results from fastest to slowest:"
echo "--------------------------------"
sort -n "$results_file" | while read -r duration bs transfer; do
echo "Block size: ${bs} | Transfer: ${transfer} | Time: ${duration}s"
done
rm "$results_file"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment