Facade Functional Programming Suite

Post your working scripts, libraries and tools for AHK v1.1 and older
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Optimizing AutoHotkey Code

30 Aug 2021, 16:24

AutoHotkey performs no optimization.

That means choosing good data structures and algorithms is very important. If your code is slow, improving those is likely to result in a greater improvement than anything I mention below.

The manual foolishly encourages programmers to write as much code as possible on one line, using , to join expressions, to gain an up to 35% speed increase. In my tests, realistic uses (Facade's code) caused an about 6% improvement.

You can avoid wrecking the maintainability of your code by putting , at the beginning of the line to be joined to the previous. It will result in exactly the same performance. I dub this "sawtoothing" due to the appearance it causes. The technique needs a name and to be spread, at least until AutoHotkey spends the nickle I gave it to buy a real parser. No other programming language I know of has this problem.

One thing I was very surprised by was AutoHotkey's preallocation trap. There are APIs to preallocate space for strings and elements in Objects (that's {} Objects, not other kinds). In every case I tested, doing this slows execution. These APIs should be removed since they only add complexity and act as a trap. If the string API is to be used as part of the FFI, there should at least be a warning that code using it can cause significant slowdown.

Procedure calls in AutoHotkey cause significant slowdown (which may explain why using preallocation is not an optimization). In my tests, each procedure call in realistic code caused an about 11% increase in execution time (i.e. each call made things 11% slower). This is much, much more serious than not using the 'comma trick'!

I tried to measure the time goto consumes, and it was so small that I could not measure it. Whatever is wrong has to do with call stack management.

One of the best ways to significantly improve the time efficiency of AutoHotkey code without ruining its maintainability is to perform manual common subexpression elimination because it can eliminate those expensive procedure calls. If that sounds scary, it just means storing the result of a referentially transparent (no side effects like I/O or mutating globals) expression in a variable and reusing that variable wherever you would have used the expression so that the expression only needs to be executed once. You can usually put the first use of the expression you want to cache inside a larger expression and use the fact := returns the value assigned for this purpose. Augmented assignments will also work.

If an expression is a constant referentially transparent expression, you can execute it 'before run-time' in AutoHotkey by assigning it to a static variable. This is the closest thing AutoHotkey has to Lisp macros.

If someone wants to write an interpreter in AutoHotkey, I would suggest making your interpreter use bytecode and a loop with goto to dispatch to the appropriate code for each byte.

If someone wants to compile to AutoHotkey, I would suggest making your compiler use inlining (i.e. insert copies of the code where the procedure would be called) and common subexpression elimination (possibly to static variables) in (only) any code that consumes over 50% of the execution time.

Please, please do not write most of your code like the interpreter or compiler suggestions. Anyone trying to maintain it will, quite reasonably, want to kill you.

My Type Checking and Facade libraries use these techniques (except goto and inlining) should you want an example.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 70 guests