How to optimize the speed of a script as much as possible.

Helpful script writing tricks and HowTo's
User avatar
WAZAAAAA
Posts: 89
Joined: 13 Jan 2015, 19:48

How to optimize the speed of a script as much as possible.

Post by WAZAAAAA » 14 Feb 2015, 14:00

This code disables several ON-by-default "obscure" delays, unnecessary debug functions, gives a higher CPU priority to your scripts and contains a high precision Sleep function.
Please note that inside the spoiler of note #8 you can find a good benchmark script to test the speed of your scripts.



Generic optimizations
Just copy this at the beginning of any AHK script to make use of the performance optimizations:

Code: Select all

;OPTIMIZATIONS START
#NoEnv
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
#KeyHistory 0
ListLines Off
Process, Priority, , A
SetBatchLines, -1
SetKeyDelay, -1, -1
SetMouseDelay, -1
SetDefaultMouseSpeed, 0
SetWinDelay, -1
SetControlDelay, -1
SendMode Input
DllCall("ntdll\ZwSetTimerResolution","Int",5000,"Int",1,"Int*",MyCurrentTimerResolution) ;setting the Windows Timer Resolution to 0.5ms, THIS IS A GLOBAL CHANGE
;OPTIMIZATIONS END

;YOUR SCRIPT GOES HERE
DllCall("Sleep","UInt",1) ;I just slept exactly 1ms!
DllCall("ntdll\ZwDelayExecution","Int",0,"Int64*",-5000) ;you can use this to sleep in increments of 0.5ms if you need even more granularity 
^NOTES
1. #NoEnv is recommended for all scripts, it disables environment variables.
2. The default #MaxHotkeysPerInterval along with #HotkeyInterval will stop your script by showing message boxes if you have some kind of rapid autofire/turbo loop in it. Just put some insane unreachable high number to ignore this limit.
3. #KeyHistory and ListLines are functions used to "log your keys". Disable them as they're only useful for debugging purposes.
4. Setting a higher Priority to a Windows program is supposed to improve its performance. Use AboveNormal/A. If you feel like it's making things worse, comment or remove this line.
Spoiler
5. The default SetBatchLines value makes your script sleep around 10-15.6 milliseconds every line. Make it -1 to not sleep (but remember to include at least one Sleep in your loops to avoid high CPU waste!). THIS IS THE SINGLE MOST IMPORTANT LINE, and will be the default in AutoHotkey v2. Honestly you could ignore everything else in this thread and just use this line. That's how much difference it makes.
6. Even though SendInput ignores SetKeyDelay, SetMouseDelay and SetDefaultMouseSpeed, having these delays at -1 improves SendEvent's speed just in case SendInput is not available and falls back to SendEvent.
7. SetWinDelay and SetControlDelay may affect performance depending on the script.
8. SendInput is the fastest send method. SendEvent (the default one) is 2nd place, SendPlay a far 3rd place (it's the most compatible one though). SendInput does not obey to SetKeyDelay, SetMouseDelay, SetDefaultMouseSpeed; there is no delay between keystrokes in that mode.
Spoiler
9. It is well-documented that Sleep is not precise. But it can be if you change the Windows Timer Resolution first and then Sleep through a DllCall, with no CPU waste!
Spoiler
10. When using PixelSearch to scan a single pixel of a single color variation, don't use the Fast parameter. According to my benchmarks, regular PixelSearch is faster than PixelSearch Fast in that case.
11. According to the documentation, the Unicode x64bit version of AHK is faster, use it when available (this text is found in the setup file).
Spoiler


Misc optimizations
Spoiler


Previous inputs from users of the archived forum are located here: https://autohotkey.com/board/topic/94455-how-to-optimize-the-speed-of-a-script-as-much-as-possible/
For more optimizations read every page of this thread, users have performed many different tests!



AutoHotkey v2 version of this thread: viewtopic.php?p=559263
Last edited by WAZAAAAA on 04 Mar 2024, 13:10, edited 29 times in total.
YOU'RE NOT ALEXANDER

User avatar
WAZAAAAA
Posts: 89
Joined: 13 Jan 2015, 19:48

Re: How to optimize the speed of a script as much as possibl

Post by WAZAAAAA » 14 Feb 2015, 14:08

Oh my, maybe I should've posted this in the Tutorials section. Moderators what do you think?
YOU'RE NOT ALEXANDER

User avatar
joedf
Posts: 9117
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: How to optimize the speed of a script as much as possibl

Post by joedf » 14 Feb 2015, 15:26

I think it's fine here. ;)
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]

Skrell
Posts: 335
Joined: 23 Jan 2014, 12:05

Re: How to optimize the speed of a script as much as possibl

Post by Skrell » 18 Feb 2015, 13:15

I REALLY like where this thread is heading! I've always wanted to know more about speed optimizations in AHK! Please post more benchmarks/comparisons if possible on ANY functions in AHK that essentially do the same thing. For instance, i use a LOT of settimer commands in my code and would love to know if you have any thoughts on it.
Also can you please comment more on these values (what the trade off is in using them):

SetTitleMatchMode 2
SetTitleMatchMode fast
SetBatchLines, -1
SetKeyDelay, -1, -1, -1
SetMouseDelay, -1
SetWinDelay, -1
SetControlDelay, -1
SetDefaultMouseSpeed, 0

User avatar
jNizM
Posts: 3201
Joined: 30 Sep 2013, 01:33
Contact:

Re: How to optimize the speed of a script as much as possibl

Post by jNizM » 19 Feb 2015, 01:39

Speed Test (Benchmark): Define Variables
[AHK] v2.0.18 | [WIN] 11 Pro (23H2) | [GitHub] Profile

Skrell
Posts: 335
Joined: 23 Jan 2014, 12:05

Re: How to optimize the speed of a script as much as possibl

Post by Skrell » 19 Feb 2015, 08:47

jNizM wrote:Speed Test (Benchmark): Define Variables
Would you mind explaining what this is doing?
QPC(R := 0)
{
static P := 0, F := 0, Q := DllCall("QueryPerformanceFrequency", "Int64P", F)
return ! DllCall("QueryPerformanceCounter", "Int64P", Q) + (R ? (P := Q) / F : (Q - P) / F)
}

I dont understand how this function manages to measure the time it takes to assign variables by using QPC(0) and QPC(1) :(

User avatar
jNizM
Posts: 3201
Joined: 30 Sep 2013, 01:33
Contact:

Re: How to optimize the speed of a script as much as possibl

Post by jNizM » 19 Feb 2015, 08:56

Code: Select all

_QPC(Reset := 0) ; By SKAN,  http://goo.gl/nf7O4G,  CD:01/Sep/2014 | MD:02/Sep/2014
{
	static PrvQPC := 0, FRQ := 0, QPC := 0

	if !(FRQ)
		DllCall("kernel32.dll\QueryPerformanceFrequency", "Int64P", FRQ)

	DllCall("kernel32.dll\QueryPerformanceCounter", "Int64P", QPC)

	if (Reset)
	{
		PrvQPC := QPC
		return QPC / FRQ
	}
	else
	{
		return (QPC - PrvQPC) / FRQ
	}
}
[AHK] v2.0.18 | [WIN] 11 Pro (23H2) | [GitHub] Profile

Ffkwa

Re: How to optimize the speed of a script as much as possible.

Post by Ffkwa » 05 Jun 2015, 01:13

Ok, I can't edit. So here are my findings:

1. Realtime priority is bad news almost always. Don't do that. It almost never works, even if your script is written correctly. If your script is written incorrectly, then you can cause your entire system to hang.
2. High priority/above normal priority sometimes work. You can try them, but they are a very big potential source of problems. Disable them if something is going wrong.
3. Spintest sleep (sleepz) doesn't work when scripting for programs that require CPU time to process. For example, if you're trying to script for a game, then your script will hog all the processor time and the game will lag.
4. Batchlines 0 forces your script to consume CPU time even when you sleep. That absolutely kills performance in the rest of the system. Don't do it.
5. Setting batchlines to normal right before Sleep seems to not change anything at all. It still consumes huge CPU timeslices.
6. WAZAA is absolutely correct about the speed of SendMode Input and SendMode Event, but the difference is tiny compared to the variability of Sleep. I suspect that Event may still be less reliable, but I am not sure and don't have meaningful tests for reliability.

lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: How to optimize the speed of a script as much as possible.

Post by lexikos » 05 Jun 2015, 03:18

Batchlines 0 forces your script to consume CPU time even when you sleep.
No. SetBatchLines does not affect Sleep at all. It determines how often the program "rests" (sleeps for 10ms) in between execution of lines of script. If the script is not executing code (i.e. it is idle, waiting or sleeping), the setting has no effect.
That absolutely kills performance in the rest of the system. Don't do it.
On my 5yo system, a single script utilizing maximum CPU time does not noticeably affect performance at all, let alone "kill" it. Most systems have at least a dual-core CPU, and a script is only capable of tying up one core.
It still consumes huge CPU timeslices.
There's something wrong with your script, or your system. While sleeping, the program checks its message queue and then yields its CPU time slice, and repeats. There is generally no measurable CPU usage unless there is a flood of messages to process (having been sent to the script's own window(s)).

Edit:
To be clear, I am not condoning the OP's suggestions. For instance, these will not make the script run faster, and might even be undesirable:

Code: Select all

#MaxThreads 255
#MaxMem 4095
#MaxThreadsBuffer On
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
Most scripts will never need more than the default #MaxThreads (10). That means something like a hotkey starts, then is interrupted by another, and another, etc. so that there are 10 running that have not yet completed. If that happens and you hit the default limit, there's probably a problem with the design of your script.

#MaxMem: "The purpose of limiting each variable's capacity is to prevent a buggy script from consuming all available system memory. Raising or lowering the limit does not affect the performance of a script"

The default settings for #MaxHotkeysPerInterval and #HotkeyInterval enable a safe-guard against accidentally causing infinite loops with hotkeys that send keys which can trigger hotkeys. Using the settings shown above would disable this safe-guard. (However, disabling it is sometimes useful - for example, some Logitech mice have a free-spinning mouse wheel, which can easily exceed the default hotkey limit for a WheelUp/WheelDown hotkey.)

Ffkwa

Re: How to optimize the speed of a script as much as possible.

Post by Ffkwa » 05 Jun 2015, 09:13

I'm glad I posted. Thanks for the informative response!
lexikos wrote:
Batchlines 0 forces your script to consume CPU time even when you sleep.
No. SetBatchLines does not affect Sleep at all. It determines how often the program "rests" (sleeps for 10ms) in between execution of lines of script. If the script is not executing code (i.e. it is idle, waiting or sleeping), the setting has no effect.
That absolutely kills performance in the rest of the system. Don't do it.
On my 5yo system, a single script utilizing maximum CPU time does not noticeably affect performance at all, let alone "kill" it. Most systems have at least a dual-core CPU, and a script is only capable of tying up one core.
This was my mistake. This is affected by my test setup I forgot to mention. I'm on VMWare, with only one core. So anything that behaves badly causes system-wide lockdown for me.
It still consumes huge CPU timeslices.
There's something wrong with your script, or your system. While sleeping, the program checks its message queue and then yields its CPU time slice, and repeats. There is generally no measurable CPU usage unless there is a flood of messages to process (having been sent to the script's own window(s)).
You are right, my testing script had a mistake. I was testing a special sleep() function which used normal Sleep for a long duration, then a spintest Sleepz() to have fine resolution at the end. But my function calculated used "Sleep % %period% - 15.7" which meant I was just testing the high resolution timer.

Ffkwa

Re: How to optimize the speed of a script as much as possible.

Post by Ffkwa » 05 Jun 2015, 09:22

The OP and I are actually both scripting for the same game. The context is that frames take ~16ms - 22ms, and it's important that sent keys resolve on discrete frames.

I'm thinking about letting my script force Windows's built in tick from 15.6 ms to maybe 5 ms. The downside would be power consumption, and probably excessive context switches, but maybe it will improve Sleep consistency. I'm also kind of wondering how VMWare will handle this tick resolution, given that I've disabled its "backdoor" port that lets it communicate with the host system. Would my host system get the changed tick as well? And if my script crashes and forgets to reset the timer, will my system be stuck at a 5ms tick until reset?

Guest

Re: How to optimize the speed of a script as much as possible.

Post by Guest » 05 Jun 2015, 10:00

Doing some reading, I found that the timer tick rate will reset when your process terminates, which is good.

User avatar
KuroiLight
Posts: 328
Joined: 12 Apr 2015, 20:24
Contact:

Re: How to optimize the speed of a script as much as possible.

Post by KuroiLight » 06 Jun 2015, 12:13

SetBatchLines, -1 should be enough, as long as you sleep somewhere in your loops.
That absolutely kills performance in the rest of the system. Don't do it.
On my 5yo system, a single script utilizing maximum CPU time does not noticeably affect performance at all, let alone "kill" it. Most systems have at least a dual-core CPU, and a script is only capable of tying up one core.
Whether or not it kills performance really depends on the system and script, but I'd still recommend against anything non-critical running as real-time (possibly starving the process your scripting for); if you need that much of the cpus time for a script it might be better to revisit the code to see if it can be reduced.

edit*:
The default settings for #MaxHotkeysPerInterval and #HotkeyInterval enable a safe-guard against accidentally causing infinite loops with hotkeys that send keys which can trigger hotkeys. Using the settings shown above would disable this safe-guard. (However, disabling it is sometimes useful - for example, some Logitech mice have a free-spinning mouse wheel, which can easily exceed the default hotkey limit for a WheelUp/WheelDown hotkey.)
It would be nice to be able to turn of the popup you get when these limits are exceeded, and just halt the script for a time. :shifty:


just my 2cents.
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]

lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: How to optimize the speed of a script as much as possible.

Post by lexikos » 06 Jun 2015, 19:04

KuroiLight wrote:It would be nice to be able to turn of the popup you get when these limits are exceeded, and just halt the script for a time.
On the surface that seems like a good idea, but the point of the limit and the popup is that hitting the limit often indicates an error in the script which should be fixed, and the popup directs users to the solution. Suppressing the popup and instead blocking the hotkey for a time would likely result in the script being left as is, not behaving the way the user expects - either because they get an occasional flood of hotkeys (from a send-hotkey loop) that wasn't intentional, or because their rapid-fire hotkey doesn't work consistently.

If you're specifically opting to suppress the popup but keeping the limit, that basically means you expect the hotkey to fire very rapidly sometimes, but still want to limit the number of activations per interval. I don't think that would be a common case.

User avatar
KuroiLight
Posts: 328
Joined: 12 Apr 2015, 20:24
Contact:

Re: How to optimize the speed of a script as much as possible.

Post by KuroiLight » 07 Jun 2015, 19:20

lexikos wrote:
KuroiLight wrote:It would be nice to be able to turn of the popup you get when these limits are exceeded, and just halt the script for a time.
On the surface that seems like a good idea, but the point of the limit and the popup is that hitting the limit often indicates an error in the script which should be fixed, and the popup directs users to the solution. Suppressing the popup and instead blocking the hotkey for a time would likely result in the script being left as is, not behaving the way the user expects - either because they get an occasional flood of hotkeys (from a send-hotkey loop) that wasn't intentional, or because their rapid-fire hotkey doesn't work consistently.

If you're specifically opting to suppress the popup but keeping the limit, that basically means you expect the hotkey to fire very rapidly sometimes, but still want to limit the number of activations per interval. I don't think that would be a common case.
I agree, I've only encountered this once so far with my scroll script, since someones mouse wheel could potentially send 10s or 100s of events at a time. I think it would be better if after a set limit of it would end the thread, e.g.

Code: Select all

#MaxThreadsPerHotkey, 1
#InterruptMaxThread, true
allowing only 1 thread for the hotkey to exist at a time and interrupting it if its too slow, but not blocking it. ofc this has problems too.

sorry to derail the thread op, i'm done.
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]

lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: How to optimize the speed of a script as much as possible.

Post by lexikos » 07 Jun 2015, 23:31

I don't understand your suggestion

One of three things can happen if the hotkey is activated when it already has a thread running:
  • The new thread interrupts the older ones, which can be resumed some time after the new thread finishes.
  • The hotkey is running the maximum number of threads, so the event is ignored/discarded (#MaxThreadsBuffer Off).
  • The hotkey is running the maximum number of threads, so the event is buffered/postponed (#MaxThreadsBuffer On).
Maybe what you're saying is that one of the hotkey's previous threads should be terminated before starting the new thread, but that simply can't be done with the current thread design. It also has nothing to do with the problem #MaxHotkeysPerInterval is meant to detect: rapidly repeated (not simultaneous) activations of a hotkey.

User avatar
KuroiLight
Posts: 328
Joined: 12 Apr 2015, 20:24
Contact:

Re: How to optimize the speed of a script as much as possible.

Post by KuroiLight » 08 Jun 2015, 01:52

lexikos wrote:hotkey's previous threads should be terminated before starting the new thread,
yeah, this is what I meant, no big deal though, I can work around it.
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]

Sam_
Posts: 146
Joined: 20 Mar 2014, 20:24

Re: How to optimize the speed of a script as much as possible.

Post by Sam_ » 22 Jun 2015, 16:50

So, taking the above into account, following the recommendations in the documentation (generally a wise move), and rearranging a bit, we now have:

Code: Select all

#NoEnv
Process, Priority, , H
SetBatchLines, -1
ListLines Off
#KeyHistory 0
SendMode Input
SetTitleMatchMode 2
SetTitleMatchMode Fast
SetKeyDelay, -1, -1, Play
SetMouseDelay, -1
SetWinDelay, 0		; Changed to 0 upon recommendation of documentation
SetControlDelay, 0	; Changed to 0 upon recommendation of documentation
SetDefaultMouseSpeed, 0

; YOUR_SCRIPT_HERE
Edited SetKeyDelay. See next post.
Last edited by Sam_ on 22 Jun 2015, 20:27, edited 2 times in total.

lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: How to optimize the speed of a script as much as possible.

Post by lexikos » 22 Jun 2015, 19:16

SetKeyDelay, -1, -1, -1
The third parameter should be the word "Play" or nothing at all. -1 has no meaning.

Sam_
Posts: 146
Joined: 20 Mar 2014, 20:24

Re: How to optimize the speed of a script as much as possible.

Post by Sam_ » 22 Jun 2015, 20:29

lexikos wrote:
SetKeyDelay, -1, -1, -1
The third parameter should be the word "Play" or nothing at all. -1 has no meaning.
Thanks for the catch! I updated my last post.

Post Reply

Return to “Tutorials (v1)”