Created
August 19, 2023 17:18
-
-
Save qqii/7c24d3f825193885688d0f8838fa3a0a to your computer and use it in GitHub Desktop.
Disk torture test by repeatedly running the default CrystalDiskMark benchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Repeatedly runs the default CrystalDiskMark benchmark: | |
# | |
# Random Data, 1GiB | |
# Test Count 5 | |
# Interval 5s, Measure 5s, Read then Write | |
# SEQ1M Q8T1 | |
# SEQ1M Q1T1 | |
# RND4K Q32T1 | |
# RND4K Q1T1 | |
# | |
# CrystalDiskMark is a wrapper DiskSpd, this script calls DiskSpd directly. | |
# Instructions: | |
# 1. Download DiskSpd (https://github.com/microsoft/diskspd/releases) | |
# 2. Extract DiskSpd/amd64/diskspd.exe into the same folder as this script | |
# 3. Run this script in an elevated PowerShell session. The first argument | |
# should be an non-existent file path in the drive you want to test. | |
# | |
# Leave the script running for as long as you want to test the drive. Press | |
# CTRL+C to stop the script. | |
# TODO: | |
# - Automatically download and extract DiskSpd | |
# - Automatically run as admin | |
# - Parse DiskSpd output and save to CSV | |
# - Parse DiskSpd and display results in a GUI | |
Param( | |
[Parameter(Mandatory = $true)] | |
[string]$TestFilePath, | |
[Parameter()] | |
[ValidateRange(1, [int]::MaxValue)] | |
[int]$N = [int]::MaxValue, # How many times to run the torture test | |
[Parameter()] | |
[ValidateRange(1, [int]::MaxValue)] | |
[int]$TestCount = 5, # How many times each test is run in a row | |
[Parameter()] | |
[ValidateRange(1, [int]::MaxValue)] | |
[int]$TestDataSize = 1GB, | |
[Parameter()] | |
[TimeSpan]$TestDuration = (New-TimeSpan -Seconds 5), | |
[Parameter()] | |
[TimeSpan]$IntervalDelay = (New-TimeSpan -Seconds 5) | |
) | |
# Check administartor rights | |
$IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) | |
if (-not $IsAdmin) { | |
Write-Error "This script must be run as an administrator." | |
return | |
} | |
# Check DiskSpd exists | |
$DiskSpdPath = Get-Command -Name "diskspd.exe" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source | |
if (-not $DiskSpdPath) { | |
$ScriptFolder = Split-Path -Parent $MyInvocation.MyCommand.Path | |
$DiskSpdPath = Join-Path $ScriptFolder "diskspd.exe" | |
if (-not (Test-Path $DiskSpdPath -PathType Leaf)) { | |
Write-Error "diskspd.exe not found in system path or script folder." | |
return | |
} | |
} | |
# Check if file exists | |
if (Test-Path $TestFilePath -PathType Leaf) { | |
Write-Error "File already exists at $TestFilePath." | |
$DeleteFile = Read-Host "Type 'delete this file' to delete the file and continue, or any other key to exit" | |
if ($DeleteFile -eq "delete this file") { | |
Write-Output "Deleting..." | |
Remove-Item -Force $TestFilePath | |
} | |
else { | |
return | |
} | |
} | |
# Generate random file | |
Write-Output "Generating File..." | |
New-Item -Force -ItemType File -Path $TestFilePath > $null | |
$RandomData = New-Object byte[] $TestDataSize | |
(New-Object Random).NextBytes($RandomData) | |
[IO.File]::WriteAllBytes($TestFilePath, $RandomData) | |
if (-not (Test-Path $TestFilePath -PathType Leaf)) { | |
Write-Error "Failed to create file at $TestFilePath" | |
return | |
} | |
$FileSize = (Get-Item $TestFilePath).Length | |
if ($FileSize -ne $TestDataSize) { | |
Write-Error "Failed to fill file with random data." | |
return | |
} | |
function Start-SleepWithProgress { | |
param ( | |
[int]$DurationSeconds, | |
[int]$ParentId = 1, | |
[int]$Id = 1 | |
) | |
for ($i = 1; $i -le $DurationSeconds; $i++) { | |
$Status = "$($i)s / $($DurationSeconds)s" | |
$Pct = $i / $DurationSeconds * 100 | |
$Rem = $DurationSeconds - $i | |
Write-Progress -ParentId $ParentId -Id $Id -Activity "Sleeping for $($DurationSeconds)s" -Status $Status -PercentComplete $Pct -SecondsRemaining $Rem | |
Start-Sleep -Seconds 1 | |
} | |
Write-Progress -ParentId $ParentId -Id $Id -Activity "Sleeping for $($DurationSeconds)s" -Completed | |
} | |
function Invoke-DiskSpdTest { | |
param ( | |
[int]$Id, | |
[string]$TestName, | |
[string]$TestArgs | |
) | |
$SplitArgs = $TestArgs -split " " | |
for ($j = 1; $j -le $TestCount; $j++) { | |
$TestStatus = "$j / $TestCount" | |
$TestPct = $j / $TestCount * 100 | |
$Rem = $TestDuration.TotalSeconds * ($TestCount - $j) | |
# There's a bug preventing this from | |
Write-Progress -ParentId 1 -Id $Id -Activity $TestName -Status $TestStatus -PercentComplete $TestPct -SecondsRemaining $Rem | |
# -Z use random data of size | |
# -W0 no warmup | |
# -S disable software caching | |
# -ag group affinity | |
# -d duration in seconds | |
& $DiskSpdPath "-Z$($TestDataSize)" @SplitArgs -W0 -S -ag "-d$($TestDuration.TotalSeconds)" $TestFilePath > $null | |
} | |
Write-Progress -ParentId 1 -Id $Id -Activity $TestName -Status "Done" -PercentComplete 100 | |
Start-SleepWithProgress -DurationSeconds $IntervalDelay.TotalSeconds -ParentId $Id -Id 10 | |
} | |
Write-Host "Running tests..." | |
for ($i = 1; $i -le $N; $i++) { | |
$Status = "$i / $N" | |
$Pct = $i / $N * 100 | |
Write-Progress -Id 1 -Activity "Torture Test" -Status $Status -PercentComplete $Pct | |
Invoke-DiskSpdTest -Id 2 -TestName "Read: SEQ1M Q8T1" -TestArgs "-b1M -o8 -t1 -w0" | |
Invoke-DiskSpdTest -Id 3 -TestName "Read: SEQ1M Q1T1" -TestArgs "-b1M -o1 -t1 -w0" | |
Invoke-DiskSpdTest -Id 4 -TestName "Read: RND4K Q32T1" -TestArgs "-b4K -o32 -t1 -w0 -r" | |
Invoke-DiskSpdTest -Id 5 -TestName "Read: RND4K Q1T1" -TestArgs "-b4K -o1 -t1 -w0 -r" | |
Invoke-DiskSpdTest -Id 6 -TestName "Write: SEQ1M Q8T1" -TestArgs "-b1M -o8 -t1 -w100" | |
Invoke-DiskSpdTest -Id 7 -TestName "Write: SEQ1M Q1T1" -TestArgs "-b1M -o1 -t1 -w100" | |
Invoke-DiskSpdTest -Id 8 -TestName "Write: RND4K Q32T1" -TestArgs "-b4K -o32 -t1 -w100 -r" | |
Invoke-DiskSpdTest -Id 9 -TestName "Write: RND4K Q1T1" -TestArgs "-b4K -o1 -t1 -w100 -r" | |
} | |
Write-Host "Done! Deleting file..." | |
Remove-Item -Force $TestFilePath |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment