#!/usr/bin/env zsh -e -u # This is a script that creates a disk image with slow IO (a fake, artificial disk that lives on ram resources), # and then runs the vm stress test with one single configuration on objects that are backed by files in that disk. # In the end it's going to eject the newly created volume. eject_volumes() { diskutil list | awk '/disk image/{print $1}' | tail -r | xargs -L1 diskutil eject } trap eject_volumes EXIT # Default values for the flags SIZE_MB=2048 HELP=false RAMDISK_MP="/Volumes/apfs-dmg" SLOW_DMG="slow-dmg.dmg" TYPE="ssd" IOQUEUE_DEPTH=1 ACCESS_TIME=$((1 << 18)) # in microseconds READ_THROUGHPUT=1000 # in MB/s WRITE_THROUGHPUT=1000 # in MB/s MAX_READ_CNT=$((1 << 10)) # max bytes per read (1Kb) MAX_WRITE_CNT=$((1 << 10)) # max bytes per write (1Kb) SEG_READ_CNT=$((1 << 10)) SEG_WRITE_CNT=$((1 << 10)) show_help() { echo "Usage: sudo $0 [options]" echo echo "Running this script will create a ramdisk with a disk image configured to run slower than usual, " echo "and then run the vm_stress test on a file that comes from this disk image." echo echo "Options:" echo " -h, --help Show this help message" echo " -s, --speed Set paging speed (slower, slowerer, slowest)" echo } while [[ $# -gt 0 ]]; do case "$1" in -h|--help) HELP=true shift ;; -s|--speed|-S) if [[ -z "$2" ]]; then echo "Error: --speed requires a value (slower, slowerer, slowest)." exit 1 fi case "$2" in slower) ((ACCESS_TIME = ACCESS_TIME * 2)) shift 2 ;; slowerer) ((ACCESS_TIME = ACCESS_TIME * 3)) shift 2 ;; slowest) ((ACCESS_TIME = ACCESS_TIME * 4)) shift 2 ;; *) echo "Error: Invalid speed option '$2'. Valid options are: slow, slower, slowest." exit 1 ;; esac ;; # Invalid option *) echo "Error: Invalid option '$1'. Use --help for usage." exit 1 ;; esac done # Show help if requested if $HELP; then show_help exit 0 fi echo "Selected speed: access = $ACCESS_TIME" diskutil list | awk '/disk image/{print $1}' | tail -r | xargs -L1 diskutil eject # start fresh with no extra volumes sysctl debug.didevice_queue_depth=1 ramdisk_device=$(diskutil image attach "ram://${SIZE_MB}m" | awk '{print $1}') # attach ("create, make visible and mount") disk image ("virtual disk") on RAM (just a disk with no file system) diskutil eraseDisk apfs apfs-dmg "$ramdisk_device" # put a file system on it diskutil image create blank "$RAMDISK_MP/$SLOW_DMG" -size "$((SIZE_MB / 2))m" -volumeName apfs-slow # create another (seemingly regular) disk image ("virtual disk") in the new ramdisk slow_di_device=$(diskutil image attach "$RAMDISK_MP/$SLOW_DMG" | awk 'END{print $1}') # attach it ("make it visible and mount") purge # delete all caches # configure IO to be slow on the newly created inner volume, and then apply (start): dmc configure "$RAMDISK_MP" "$TYPE" "$ACCESS_TIME" "$READ_THROUGHPUT" "$WRITE_THROUGHPUT" "$IOQUEUE_DEPTH" "$MAX_READ_CNT" "$MAX_WRITE_CNT" "$SEG_READ_CNT" "$SEG_WRITE_CNT" dmc start "$RAMDISK_MP/" # Now that the ramdisk exists, find and execute the test: SCRIPT_DIR=$(dirname "$(realpath "$0")") TEST_EXEC_DIR=$(find "$SCRIPT_DIR/../" -iname "vm_stress" -maxdepth 5 -print -quit) "$TEST_EXEC_DIR" config -- topo 6 50 5 5 1 1 -s "$TEST_EXEC_DIR" config -- over 6 50 5 5 1 1 -s "$TEST_EXEC_DIR" config -- part 6 50 5 5 1 1 -s "$TEST_EXEC_DIR" config -- one_to_many 6 50 5 5 1 1 -s "$TEST_EXEC_DIR" config -- one_to_many 6 50 5 5 0 0 -s dmc stop "$RAMDISK_MP/"