├── local.txt ├── prime.txt ├── README.md ├── LICENSE ├── ReadMe.txt └── p95_core_cycle.ps1 /local.txt: -------------------------------------------------------------------------------- 1 | NumCPUs=1 2 | CpuNumHyperthreads=1 3 | CpuSupportsAVX=0 4 | CpuSupportsAVX2=0 5 | CpuSupportsAVX512F=0 -------------------------------------------------------------------------------- /prime.txt: -------------------------------------------------------------------------------- 1 | StressTester=1 2 | UsePrimenet=0 3 | MinTortureFFT=84 4 | MaxTortureFFT=84 5 | TortureMem=8 6 | TortureTime=3 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # per-core-stability-test-script 2 | Test script developed for for easier testing of Zen 3 curve offsets 3 | Requires Windows Powershell 4 | See readme.txt for more details 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 jasonpoly 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ReadMe.txt: -------------------------------------------------------------------------------- 1 | # Windows Powershell Script 2 | # Will extract, configure and run a single thread on prime 95, 3 | # using $process.ProcessorAffinity to assign to each cpu core for the specified time 4 | # Assumes SMT is enabled, so one core means two threads and the process is assigned to two threads at a time 5 | # Provided as-is and for use at your own risk. 6 | 7 | Requires Windows10 Powershell. 8 | 9 | WARNING: This script is provided as a convenience and use is entirely at your own risk 10 | WARNING: On Ryzen CPUs a single thread can boost to high voltages, potentially degrading a CPU over time 11 | WARNING: Do not use if you have never run Prime95 12 | WARNING: Check for safe temperature and voltage on each core 13 | WARNING: After completing your testing, check that prime95 is not still running in the background 14 | 15 | Download p95v307b9.win64.zip from https://www.mersenne.org/download/ and place into this folder 16 | 17 | [Optional] Open p95_core_cycle.ps1 in a text editor and edit the top few lines in case you want to change anything from the defaults: 18 | 19 | # Edit filename to use a different version of p95 20 | $p95path="p95v307b9.win64.zip"; # path to p95 .zip you want to extract and use 21 | 22 | # adjust the following to customize length of time to run 23 | $loops=3; # Default=3. Number of times to loop arount all cores. 24 | $cycle_time=180; # Default=180. Approx time in s to run on each core. 25 | $cooldown=15; # Default=15. Time in s to cool down between testing each core. 26 | 27 | # adjust next two values to limit testing to a specific range of cores 28 | $first_core=0; # First core to test in each loop. Default=0. Any cores lower than this number will not be tested. 29 | $last_core=31; # Last core to test in each loop. Any cores (that exist) higher than this number will not be tested. 30 | 31 | [Optional] Edit the contents of prime.txt and local.txt to change those values 32 | 33 | Right click on p95_core_cycle.ps1 and select "Run with PowerShell" -------------------------------------------------------------------------------- /p95_core_cycle.ps1: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2021 jasonpoly 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | # Windows Powershell Script 25 | # Will extract, configure and run a single thread on prime 95, 26 | # using $process.ProcessorAffinity to assign to each cpu core for the specified time 27 | 28 | $p95path="p95v307b9.win64.zip"; # path to p95 .zip you want to extract and use 29 | 30 | # adjust the following to customize length of time to run 31 | $core_loop_test=$true; # Default=$true. Basic test to loop around all cores. Set to $falue to disable. 32 | $loops=3; # Default=3. Number of times to loop around all cores. 33 | $cycle_time=180; # Default=180. Approx time in s to run on each core. 34 | $cooldown=15; # Default=15. Time in s to cool down between testing each core. 35 | 36 | $core_jumping_test=$true; # Default=$true. Test to move process from core to core. Set to $falue to disable. 37 | $core_jumping_loops=5; # Default=5. Number of loops to run. 38 | $core_jumping_cycle_time=10; # Default=10. Approx time in s to run on each core. 39 | 40 | # adjust next two values to limit testing to a specific range of cores 41 | $first_core=0; # First core to test in each loop. Default=0. Any cores lower than this number will not be tested. 42 | $last_core=31; # Last core to test in each loop. Any cores (that exist) higher than this number will not be tested. 43 | # Will automaticlly get adjusted down to the actual number of detected cores. 44 | # Default and MAX value=31. Cores 32 or higher will result in an Error: "Arithmetic operation resulted in an overflow." 45 | 46 | # additional settings 47 | $stop_on_error=$false; # Default=$false. $true will stop if an error is found, otherwise skip to the next core. 48 | $timestep=1; # Minimum time to run stress test. Will check for errors every this many seconds. 49 | $use_smt=$true; # Default=$true. $false will only enable one thread on each physical core even if SMT (Hyperthreading) is enabled on the system. 50 | 51 | $fatal_error=$false; # Default=$false. Script sets this to true if there is an unrecoverable error. Any subsequent tests will then be skipped. 52 | 53 | # After extracting, we will add the following lines to local.txt for single thread, non-AVX test 54 | # NumCPUs=1 55 | # CpuNumHyperthreads=1 56 | # CpuSupportsAVX=0 57 | # CpuSupportsAVX2=0 58 | # CpuSupportsAVX512F=0 59 | # Add the following lines to prime.txt for stress test with FFT size of 84 60 | # StressTester=1 61 | # UsePrimenet=0 62 | # MinTortureFFT=84 63 | # MaxTortureFFT=84 64 | # TortureMem=8 65 | # TortureTime=3 66 | 67 | filter timestamp {"$(Get-Date -Format G): $_"} 68 | 69 | if ($PSScriptRoot) 70 | { 71 | $work_dir="$PSScriptRoot" 72 | } 73 | else 74 | { 75 | $work_dir="." 76 | } 77 | 78 | 79 | ################################################################### 80 | # Functions 81 | ################################################################### 82 | 83 | function Write-Log ($msg) 84 | { 85 | Write-Output $msg | timestamp 86 | $msg | timestamp >> "$work_dir\cycle.log" 87 | } 88 | 89 | function Clean-p95-Results ($test) 90 | { 91 | Write-Log "Moving any previous results into ${test}.prev.results\" 92 | if (Test-Path "$work_dir\${test}.core*failure.txt") 93 | { 94 | mkdir "$work_dir\${test}.prev.results" -ErrorAction SilentlyContinue 95 | mv -Force "$work_dir\${test}.core*_failure.txt" "$work_dir\${test}.prev.results" 96 | } 97 | if (Test-Path "$work_dir\p95\results.txt") 98 | { 99 | mv -Force "$work_dir\p95\results.txt" "$work_dir\p95\prev.results.txt" 100 | } 101 | } 102 | 103 | function Set-Affinity 104 | { 105 | param ( 106 | [Parameter(Mandatory=$true)]$CPUCore, 107 | [Parameter(Mandatory=$true)]$ProcessName 108 | ) 109 | 110 | $time_out=10 111 | 112 | $starttime=(GET-DATE) 113 | $runtime=0 114 | 115 | while ( ($runtime -lt $time_out) -and (Get-Process -Name $ProcessName -ErrorAction SilentlyContinue).Count -eq 0 ) 116 | { 117 | Start-Sleep -Milliseconds 100 118 | $runtime = (NEW-TIMESPAN -Start $starttime -End (GET-DATE)).TotalSeconds 119 | } 120 | 121 | if ($runtime -ge $time_out) 122 | { 123 | Write-Log "!!!! =================================================== !!!!" 124 | Write-Log "!!!! ERROR Timed out waiting for $ProcessName to start !!!!" 125 | Write-Log "!!!! =================================================== !!!!" 126 | Write-Output 0 127 | } 128 | else 129 | { 130 | if ($smt_enabled) 131 | { 132 | if ($use_smt) 133 | { 134 | [Int64]$affinity=[Math]::Pow(2, $CPUCore*2) + [Math]::Pow(2, $CPUCore*2+1) 135 | } 136 | else 137 | { 138 | [Int64]$affinity=[Math]::Pow(2, $CPUCore*2) 139 | } 140 | } 141 | else 142 | { 143 | [Int64]$affinity=[Math]::Pow(2, $CPUCore) 144 | } 145 | 146 | $process=Get-Process prime95 147 | $process.ProcessorAffinity=[System.IntPtr]$affinity 148 | Write-Output $process 149 | } 150 | } 151 | 152 | function p95-Error 153 | { 154 | param ( 155 | [Parameter()]$p95result, 156 | [Parameter(Mandatory=$true)]$process, 157 | [Parameter(Mandatory=$true)]$CPUCore, 158 | [Parameter(Mandatory=$true)]$Loop 159 | ) 160 | 161 | if ($p95result) 162 | { 163 | Write-Log "!!!! ============================================= !!!!" 164 | Write-Log "!!!! Test FAILED on core $CPUCore. !!!!" 165 | Write-Log "!!!! Check core${CPUCore}_loop${Loop}_failure.txt !!!!" 166 | Write-Log "!!!! ============================================= !!!!" 167 | Write-Log "$p95result" 168 | mv "$work_dir\p95\results.txt" "$work_dir\${test}.core${CPUCore}_loop${Loop}_failure.txt" 169 | if ($stop_on_error) 170 | { 171 | Stop-Process -InputObject $process 172 | Wait-Process -Id $Process.Id -ErrorAction SilentlyContinue 173 | } 174 | } 175 | elseif ($process.HasExited -ne $false) 176 | { 177 | Write-Log "!!!! ============================================= !!!!" 178 | Write-Log "!!!! Prime95 process closed unexpectedly !!!!" 179 | Write-Log "!!!! Test FAILED on core $CPUCore. !!!!" 180 | Write-Log "!!!! Check core${CPUCore}_loop${Loop}_failure.txt !!!!" 181 | Write-Log "!!!! ============================================= !!!!" 182 | Write-Log "$p95result" 183 | if (Test-Path "$work_dir\p95\results.txt") 184 | { 185 | mv "$work_dir\p95\results.txt" "$work_dir\${test}.core${CPUCore}_loop${Loop}_failure.txt" 186 | } 187 | else 188 | { 189 | "Prime95 process closed unexpectedly" >> "$work_dir\${test}.core${CPUCore}_loop${Loop}_failure.txt" 190 | } 191 | if ($stop_on_error) 192 | { 193 | Stop-Process -InputObject $process 194 | Wait-Process -Id $Process.Id -ErrorAction SilentlyContinue 195 | } 196 | } 197 | } 198 | 199 | 200 | function Wait-prime95 201 | { 202 | param ( 203 | [Parameter(Mandatory=$true)]$CPUCore, 204 | [Parameter(Mandatory=$true)]$WaitTime, 205 | [Parameter(Mandatory=$true)]$Loop 206 | ) 207 | 208 | # wait for p95 to run for $cycle_time, as long as there is no error, and no failure in a previous loop 209 | $runtime=0 210 | $p95result="" 211 | $starttime=(GET-DATE) 212 | while ( ($runtime -lt $WaitTime) -and (-not($p95result)) -and ((Test-Path "$work_dir\core${CPUCore}_loop*_failure.txt") -eq $false) -and ($process.HasExited -eq $false) ) 213 | { 214 | Start-Sleep -Seconds $timestep 215 | $p95result = if (Test-Path "$work_dir\p95\results.txt") {Select-String "$work_dir\p95\results.txt" -Pattern ERROR} 216 | $runtime = (NEW-TIMESPAN -Start $starttime -End (GET-DATE)).TotalSeconds 217 | } 218 | 219 | if ($p95result) 220 | { 221 | p95-Error -p95result $p95result.Line -process $process -CPUCore $CPUCore -Loop $Loop 222 | } 223 | elseif ($process.HasExited -ne $false) 224 | { 225 | p95-Error -p95result $p95result.Line -process $process -CPUCore $CPUCore -Loop $Loop 226 | } 227 | else 228 | { 229 | Write-Log "Test passed on core $CPUCore." 230 | } 231 | } 232 | 233 | 234 | function Exit-Process 235 | { 236 | param ( 237 | [Parameter(Mandatory=$true)]$Process, 238 | [Parameter(Mandatory=$true)]$ProcessName 239 | ) 240 | 241 | if ( ($Process -ne 0) -and ($Process.HasExited -eq $false) ) 242 | { 243 | Write-Log "Waiting for $ProcessName to close" 244 | Stop-Process -InputObject $process 245 | Wait-Process -Id $Process.Id -ErrorAction SilentlyContinue 246 | } 247 | } 248 | 249 | ################################################################### 250 | # Main Script 251 | ################################################################### 252 | 253 | Write-Log "Writing log to $work_dir\cycle.log" 254 | 255 | if (Test-Path "$work_dir\$p95path") 256 | { 257 | if (!(Test-Path "$work_dir\p95")) 258 | { 259 | Write-Log "Extracting prime95 from $p95path" 260 | Expand-Archive -LiteralPath "$p95path" -DestinationPath p95 -ErrorAction SilentlyContinue 261 | } 262 | else 263 | { 264 | Write-Log "Using previously extracted p95 found in $work_dir\p95" 265 | } 266 | } 267 | else 268 | { 269 | Write-Log "!!!! ============================================= !!!!" 270 | Write-Log "!!!! $work_dir\$p95path not found " 271 | Write-Log "!!!! Download and copy this into $work_dir" 272 | Write-Log "!!!! ============================================= !!!!" 273 | Wait-Event 274 | exit 275 | } 276 | 277 | Write-Log "Configuring prime95 for single core, non-AVX torture test" 278 | cp "$work_dir\local.txt" "$work_dir\p95\" 279 | cp "$work_dir\prime.txt" "$work_dir\p95\" 280 | 281 | # Figure out how many cores we have an if SMT (Hyperthreading) is enabled or disabled 282 | # We will then stress one core at a time, but use both threads on that core if SMT is enabled 283 | $NumberOfLogicalProcessors = Get-WmiObject Win32_Processor | Measure -Property NumberOfLogicalProcessors -Sum 284 | $NumberOfCores = Get-WmiObject Win32_Processor | Measure -Property NumberOfCores -Sum 285 | if ( ($NumberOfCores.Sum * 2) -eq $NumberOfLogicalProcessors.Sum ) 286 | { 287 | Write-Log "Detected $($NumberOfCores.Sum) cores and $($NumberOfLogicalProcessors.Sum) threads. SMT is enabled" 288 | if ($use_smt -eq $true) 289 | { 290 | Write-Log " use_smt=$true Using 2 threads per core" 291 | } 292 | else 293 | { 294 | Write-Log " use_smt=$fales Using 1 thread per core" 295 | } 296 | 297 | $smt_enabled=$true 298 | } 299 | elseif ( $NumberOfCores.Sum -eq $NumberOfLogicalProcessors.Sum ) 300 | { 301 | Write-Log "Detected $($NumberOfCores.Sum) cores and $($NumberOfLogicalProcessors.Sum) threads. SMT is disabled" 302 | $smt_enabled=$false 303 | } 304 | else 305 | { 306 | Write-Log "!!!! =========================================================================== !!!!" 307 | Write-Log "!!!! ERROR detected $NumberOfCores cores and $NumberOfLogicalProcessors threads. !!!!" 308 | Write-Log "!!!! This script only supports 1 or 2 threads per core !!!!" 309 | Write-Log "!!!! =========================================================================== !!!!" 310 | $fatal_error=$true 311 | } 312 | 313 | if ($last_core -ge $NumberOfCores.Sum) 314 | { 315 | $last_core = $NumberOfCores.Sum-1 316 | } 317 | 318 | if ((Get-Process -Name prime95 -ErrorAction SilentlyContinue).Count -gt 0) 319 | { 320 | Write-Log "!!!! ============================================= !!!!" 321 | Write-Log "!!!! ERROR Prime95 is already running !!!!" 322 | Write-Log "!!!! ============================================= !!!!" 323 | $fatal_error=$true 324 | } 325 | 326 | if ( ($fatal_error -eq $false) -and ($core_loop_test -eq $true) ) 327 | { 328 | $test="core_loop_test" 329 | Write-Log "Starting loop test on cores $first_core through $last_core" 330 | 331 | Clean-p95-Results ($test) 332 | 333 | Write-Log "Looping $loops times around all cores" 334 | 335 | $first_run=1 336 | 337 | for ($i=1; $i -le $loops; $i++) 338 | { 339 | Write-Log "Loop $i out of $loops" 340 | for ($core=$first_core; $core -le $last_core; $core++) 341 | { 342 | # skip testing if this core already failied in an earlier loop 343 | if (Test-Path "$work_dir\*.core${core}_loop*_failure.txt") 344 | { 345 | Write-Log "!!!! ============================================= !!!!" 346 | Write-Log "!!!! Skipping core ${core} due to previous failure !!!!" 347 | Write-Log "!!!! ============================================= !!!!" 348 | } 349 | else 350 | { 351 | $timer=0 352 | $p95result="" 353 | 354 | # Don't cool down before the first test 355 | if ($first_run -eq 1) 356 | { 357 | $first_run= 0 358 | } 359 | else 360 | { 361 | Write-Log "Cooling down for $cooldown seconds" 362 | Start-Sleep -Seconds $cooldown 363 | } 364 | 365 | Write-Log "Starting $cycle_time second torture test on core $core" 366 | 367 | # Start stress test 368 | Start-Process -FilePath "$work_dir\p95\prime95.exe" -ArgumentList "-T" -WindowStyle Minimized 369 | 370 | $process=Set-Affinity -CPUCore $core -ProcessName "prime95" 371 | 372 | Wait-prime95 -CPUCore $core -WaitTime $cycle_time -Loop $i 373 | 374 | Exit-Process -Process $process -ProcessName "prime95" 375 | } 376 | } 377 | } 378 | } 379 | 380 | if ( ($fatal_error -eq $false) -and ($core_jumping_test -eq $true) ) 381 | { 382 | $test="core_jumping_test" 383 | $loops=$core_jumping_loops 384 | $cycle_time=$core_jumping_cycle_time 385 | [int]$prev_core=-1 386 | [int]$core=-1 387 | 388 | Write-Log "Starting core jumping test on cores $first_core through $last_core" 389 | 390 | Clean-p95-Results ($test) 391 | 392 | for ($i=1; $i -le $loops; $i++) 393 | { 394 | Write-Log "Loop $i out of $loops" 395 | 396 | for ($j=$first_core; $j -le $last_core; $j++) 397 | { 398 | # randomly pick a new core to start or move to 399 | while ($core -eq $prev_core) { $core=Get-Random -Minimum $first_core -Maximum $last_core } 400 | 401 | # skip testing if this core already failied in an earlier loop 402 | if (Test-Path "$work_dir\*.core${core}_loop*_failure.txt") 403 | { 404 | Write-Log "!!!! ============================================= !!!!" 405 | Write-Log "!!!! Skipping core ${core} due to previous failure !!!!" 406 | Write-Log "!!!! ============================================= !!!!" 407 | } 408 | else 409 | { 410 | $timer=0 411 | $p95result="" 412 | 413 | Write-Log "Starting $cycle_time second torture test on core $core" 414 | 415 | # Start or re-start stress test 416 | if ( (Get-Process -Name prime95 -ErrorAction SilentlyContinue).Count -eq 0 ) 417 | { 418 | Start-Process -FilePath "$work_dir\p95\prime95.exe" -ArgumentList "-T" -WindowStyle Minimized 419 | } 420 | 421 | $process=Set-Affinity -CPUCore $core -ProcessName "prime95" 422 | 423 | Start-Sleep -Milliseconds 100 424 | $p95result = if (Test-Path "$work_dir\p95\results.txt") {Select-String "$work_dir\p95\results.txt" -Pattern ERROR} 425 | if ($p95result) 426 | { 427 | if ($prev_core -gt -1) 428 | { 429 | Write-Log "!!!! ================================================================================== !!!!" 430 | Write-Log "!!!! Warning, test failed within 100 ms. Previous core $prev_core might not be stable !!!!" 431 | Write-Log "!!!! ================================================================================== !!!!" 432 | } 433 | p95-Error -p95result $p95result.Line -process $process -CPUCore $core -Loop $i 434 | Exit-Process -Process $process -ProcessName "prime95" 435 | } 436 | elseif ($process.HasExited -ne $false) 437 | { 438 | if ($prev_core -gt -1) 439 | { 440 | Write-Log "!!!! ================================================================================== !!!!" 441 | Write-Log "!!!! Warning, test failed within 100 ms. Previous core $prev_core might not be stable !!!!" 442 | Write-Log "!!!! ================================================================================== !!!!" 443 | } 444 | p95-Error -p95result $p95result.Line -process $process -CPUCore $core -Loop $i 445 | } 446 | else 447 | { 448 | Wait-prime95 -CPUCore $core -WaitTime $cycle_time -Loop $i 449 | } 450 | } 451 | $prev_core=$core 452 | } 453 | } 454 | 455 | Exit-Process -Process $process -ProcessName "prime95" 456 | } 457 | 458 | 459 | if ( $fatal_error -eq $true) 460 | { 461 | Write-Log "" 462 | Write-Log "Script encountered an error. Resolve and retry" 463 | } 464 | else 465 | { 466 | Write-Log "" 467 | Write-Log "Testing complete." 468 | Write-Log "Check log at $work_dir\cycle.log for any failures" 469 | } 470 | Wait-Event 471 | 472 | --------------------------------------------------------------------------------