Below is an AutoIt script that allows you to perform temperature-based throttling of a process using AutoIt, Battle Encoder Shirase (mentioned earlier in this thread) and Open Hardware Monitor. There's plenty of room for improvement and I only somewhat cleaned it up for this post, but it has served me well enough 'as is' for similar tasks - the top of the script will have to do as far as documentation goes.
#cs ****************************************************************************
Process throttle control based on temperature.
Requires:
- http://openhardwaremonitor.org/ - Open Hardware Monitor (OHM)
- http://mion.faireal.net/BES/ - Battle Encoder Shirase (BES)
Instructions:
1. Install OHM and BES.
2. Run OHM, right-click on the temperature read-out you want to monitor on
the left, choose 'Rename' and add 'throttle' to its name. RESTART OHM!
3. Run your processor-intensive program.
4. Run BES, press the 'Targe' button to select the process to throttle,
press the 'Limit this' button, then press the 'Control' button.
5. Evaluate this script, or run the binary.
6. To quit, find the AutoIt icon in the tray, right-click it, choose Exit.
( Looks like a blue circle with a stylized 'A' in it. )
Explanation:
This is a basic AutoIt script that reads in the temperature control as
output via WMI by OHM. If it is higher than a desired temperature, it
moves BES' process limiting slider to the right, and if it is lower, it
moves BES' process limiting slider to the left. This should result in a
stable temperature (fluctuating around the center value).
But don't CPUs already throttle?
Yes, but they do this based on high (semi-)fixed values (e.g. 100°C) and by
playing with the clock speeds of the processor, resulting in large
temperature swings, potentially reduced performance, and temperatures you
may not be comfortable with (even though the processor itself couldn't
care less - it will hard shut down if it truly 'overheats'. )
Limitations/potential enhancements:
Only a single temperature sensor and a single process (first-listed in BES)
is supported. Ideally, multiple could be supported.
Sensor could be picked from a list instead of the 'throttle' name hack.
The slider's value could be set directly, rather than the key press hacks.
The BES 'Limit control' must remain open (can be in background).
Temperature and throttling could be logged
(was in, but removed for brevity).
OHM could be eliminated on some systems; I could not get reliable
temperature data for my machine, and OHM has been tweaked to work with
various hardware, so might as well use that.
Only minimal and dirty error checking - makes sure OHM and BES are running
on startup
CONFIGURATION:
Adjust the values in next section. Should be pretty self-explanatory,
but there are comments, just in case.
#ce ****************************************************************************
; User configuration
Local $minTemp = 86 ; Temperature (in Celsius) below which the process will be given more processor time. Should be < $maxTemp
; Note: Temperature is throttled to this value. If the temperature is already below it, no throttling is applied.
Local $maxTemp = 90 ; Temperature above which the process will be given less processor time. Should be > $minTemp
; These values together provide for a bit of hysteresis. Recommend you keep them closely 'around' the desired temperature.
; Note: If the process is throttled by 99% already, the temperature can still exceed this value due to other processes running.
Local $alertTemp = 99 ; If the temperature reaches this value, a series of three high pitch beeps will be played. Should be > $maxTemp. To disable, just set to something like 1000.
Local $alertAtLimit = True ; If BES can be throttled no further than 99%, a series of three low pitch beeps will be played. Should be True / False.
Local $alertOnError = True ; If OHM/BES/'Limit control' window aren't open, series of three decreasing pitch beeps will be played at each interval). Should be True / False.
; Internal configuration
Local $sensorTag = "throttle" ; Sensor Tag to look for.
Local $numReadings = 5 ; Number of readings to average.
; 1 results in instant adjustment, but temperature sensors are rarely stable enough for that to make sense.
; Recommend 3 <= N <= 10, as more readings could easily lead to unchecked temperature escalation
Local $interval = 1 ; Interval in seconds between readings.
; Recommend 1 <= N <= 5, as longer durations could easily lead to unchecked temperature escalation
; < 1 does not apply as OHM samples at 1s.
; ******************************************************************************
; Some basic AutoIt config, includes and internal non-config variables
Opt("WinTitleMatchMode",2)
#include
Local $objWMIService
Local $currentTemp
Local $avgTemp
Local $settled = False
; Check if everything is up and running on startup.
If (Not ProcessExists("OpenHardwareMonitor.exe")) Then
MsgBox(1,"Error - OHM not running","Open Hardware Monitor does not appear to be running.")
Exit
ElseIf (Not ProcessExists("BES.exe")) Then
MsgBox(1,"Error - BES not running","Battle Encoder Shirase does not appear to be running.")
Exit
ElseIf (Not WinExists("Limiter control","Target Sleep/Awake Cycle")) Then
MsgBox(1,"Error - BES limiter control not open","Battle Encoder Shirase 'Limiter control' window is not open.")
Exit
Else
; Set up the WMI query service for OHM
$objWMIService = ObjGet("winmgmts:\\.\root\OpenHardwareMonitor")
Local $foundTag = False
Local $colItems = $objWMIService.ExecQuery("SELECT * FROM Sensor", "WQL",0x10 + 0x20) ; wbemFlagReturnImmediately + wbemFlagForwardOnly
For $objItem in $colItems
If (StringInStr($objItem.Name,$sensorTag)) Then
$foundTag = True
$currentTemp = $objItem.Value
ExitLoop
EndIf
Next
If (Not $FoundTag) Then
MsgBox(1,"Error - Could not find OHM sensor tag","Sensor tag '" & $sensorTag & "' not found." & @CRLF & "If you -just- renamed it, you may have forgotten to restart OHM.")
Exit
EndIf
EndIf
; Initialize the temperature readings.
Local $tempArray[$numReadings]
For $i = 0 to ($numReadings - 1)
$tempArray[$i] = $currentTemp
Next
; Start BES off in the middle
Local $BESthrottle = 50
ControlSend("Limiter control", "", 1025, "{END}") ; -99% / IDLE
ControlSend("Limiter control", "", 1025, "{PGUP}{PGUP}{PGUP}{PGUP}{PGUP}{PGUP}{PGUP}{PGUP}{PGUP}{PGUP}") ; -49%
ControlSend("Limiter control", "", 1025, "{RIGHT}") ; -50%
; Convert interval in seconds to milliseconds
$interval *= 1000
; Loop forever.
While 1
If (($alertOnError) AND ((Not ProcessExists("OpenHardwareMonitor.exe")) Or (Not ProcessExists("BES.exe")) Or (Not WinExists("Limiter control","Target Sleep/Awake Cycle")))) Then
Beep(3000,250)
Beep(2500,250)
Beep(2000,250)
EndIf
; Get OHM readings
Local $colItems = $objWMIService.ExecQuery("SELECT * FROM Sensor", "WQL",0x10 + 0x20)
For $objItem in $colItems
If (StringInStr($objItem.Name,$sensorTag)) Then
$currentTemp = $objItem.Value
; Check if spot temperature is above alert temperature
If ($currentTemp >= $alertTemp) Then
; Limit process fully
ControlSend("Limiter control", "", 1025, "{END}") ; -99% / IDLE
; Alert user
Beep(3000,250)
Beep(3000,250)
Beep(3000,250)
EndIf
_ArrayPush($tempArray,$currentTemp,1)
$avgTemp = 0
For $t In $tempArray
$avgTemp += $t
Next
$avgTemp = $avgTemp / $numReadings
; Perform by-temperature throttling
$BESthrottle = ControlGetText("Limiter control","",1022)
$BESthrottle = StringReplace($BESthrottle,"%","")
$BESthrottle = StringRight($BESthrottle,2)
$BESthrottle = StringReplace($BESthrottle," ","")
If ($avgTemp > $maxTemp) Then
If (($alertAtLimit) And ($BESthrottle == 99)) Then
Beep(1500,250)
Beep(1500,250)
Beep(1500,250)
Else
ControlSend("Limiter control", "", 1025, "{RIGHT}") ; Limit by 1% more
EndIf
ElseIf ($avgTemp >= $minTemp) Then
$settled = True
If (ControlGetText("Limiter control","",1019) == "Limit #&1") Then
ControlSend("Limiter control","",1019,"1")
EndIf
ElseIf ($avgTemp < $minTemp) Then
If ((Not $settled) And (ControlGetText("Limiter control","",1019) == "Unlimit #&1")) Then
ControlSend("Limiter control","",1019,"1")
EndIf
If ($BESthrottle > 1) Then
ControlSend("Limiter control", "", 1025, "{LEFT}") ; Limit by 1% less
EndIf
EndIf
ExitLoop
EndIf
Next
Sleep($interval)
WEnd
Some pretty graphs with explanations in an imgur album:
http://imgur.com/a/wfE4w
Or just the pictures:
Note that this only works on CPU-bound processes. If you want to throttle GPU/ASIC mining, check your mining app's documentation - odds are it already has temperature-based throttling in it. If not, the above script will only work for GPU/ASIC throttling if the miner's CPU process effectively controls GPU/ASIC use as well (which generally is not the case as most of the work tends to be internal to those processes).