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

Helpful script writing tricks and HowTo's
serg
Posts: 35
Joined: 21 Mar 2015, 05:33

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

11 Jan 2017, 07:26

nnnik wrote:
serg wrote:@Almost_there
"Gdip_ImageSearch" by MasterFocus is much faster than native "ImageSearch", - at least it used to be. I use it for reading text from screen.
Althou your last post should probably be in a separate thread
I actually meant something completely different from ImageSearch.
Maybe a Shape search algorythm.
Seems to me, image search would be more simple solution. Just use smallest common denominator image (that is part of all search targets) + GDIP_ImageSearch func, which is exteremly fast (I use script to read text from screen - letter by letter - and it takes fraction of a second to read whole screen with GDIP_ImageSearch). This way no need to analyze shapes.
Although Im not sure what you have in mind with shape search algo, maybe it would work better in a given case
guest3456
Posts: 2464
Joined: 09 Oct 2013, 10:31

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

11 Feb 2017, 02:35

Sam_ wrote: Direct value assignment:

Code: Select all

Var:=""

QPC(1)
Loop, 1000000000
	Var=1
toc1:=QPC(0)


QPC(1)
Loop, 1000000000
	Var:=1
toc2:=QPC(0)

MsgBox % toc1 "`n" toc2
Result:

Code: Select all

---------------------------
benchmarks.ahk
---------------------------
Var=1	21.113292    ; <- faster
Var:=1	56.657990
---------------------------
OK   
---------------------------
i'm surprised that = performs that much better than := for basic integer assignment.

i am seeing similar results: ~twice as fast.

interesting.

guest3456
Posts: 2464
Joined: 09 Oct 2013, 10:31

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

11 Feb 2017, 02:53

WAZAAAAA wrote: According to the documentation (this text is found in the setup file), the Unicode x64bit version of AHK is faster, use it when available.
Spoiler
do we know WHY the Unicode x64 is faster?

guest3456
Posts: 2464
Joined: 09 Oct 2013, 10:31

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

12 Feb 2017, 23:33

Case Sensitive comparisons:

Code: Select all

SetBatchLines -1

var := "Hello World"

QPC(1)
Loop, 10000000
{
    if (var == "Hello World")
      continue
}
test1 := QPC(0)

QPC(1)
Loop, 10000000
{
    if (var = "Hello World")
      continue
}
test2 := QPC(0)

QPC(1)
Loop, 10000000
{
    if var = Hello World
      continue
}
test3 := QPC(0)

StringCaseSense, On
QPC(1)
Loop, 10000000
{
    if (var = "Hello World")   ; StringCaseSense 'On' makes expr '=' use the 'Locale' StringCaseSense method
      continue
}
test4 := QPC(0)

QPC(1)
Loop, 10000000
{
    if var = Hello World
      continue
}
test5 := QPC(0)

StringCaseSense, Locale
QPC(1)
Loop, 10000000
{
    if var = Hello World
      continue
}
test6 := QPC(0)



MsgBox % test1 "`n" test2 "`n" test3 "`n" test4 "`n" test5 "`n" test6
ExitApp


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) 
}
Results:

Code: Select all

---------------------------
New AutoHotkey Script (4).ahk
---------------------------
1.529217             ; case sensitive   Expression (if ==)
1.828639             ; case insensitive Expression (if = )
1.798214             ; case insensitive Traditional if = 
2.198342             ; case insensitive Expression (if = )  with StringCaseSene, On/Locale
1.575167             ; case sensitive   Traditional if =    with StringCaseSene, On
2.181748             ; case insensitive Traditional (if = ) with StringCaseSene, Locale
---------------------------
OK   
---------------------------
Last edited by guest3456 on 14 Feb 2017, 09:14, edited 1 time in total.

serg
Posts: 35
Joined: 21 Mar 2015, 05:33

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

14 Feb 2017, 05:46

That's interesting. I also added to the test comparison without quotes:

Code: Select all

if var = Hello World
It gave result about ~10% faster than the (case sensitive "if ==")-method - the fastest in your code above
Last edited by serg on 14 Feb 2017, 10:21, edited 1 time in total.
guest3456
Posts: 2464
Joined: 09 Oct 2013, 10:31

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

14 Feb 2017, 09:15

serg wrote: That's interesting. I also added to the test comparison without quotes:

Code: Select all

if var = Hello World
It gave result about ~10% faster than the (case sensitive "if ==")-method - the fastest in your code above
Thanks, but be careful, because Traditional if = also is affected by StringCaseSense. I didn't get the same results as you. I have updated my last post. Can you delete my quote from within your post?

serg
Posts: 35
Joined: 21 Mar 2015, 05:33

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

14 Feb 2017, 10:32

Guest3456, I ran your updated code, it gave me different results, traditional var assignments (without quotes) are the fastest :
4.884133
5.322768
4.117642
6.175888
3.612573
5.098961
So I guess PC setup makes difference here. I have Win8.1 64 with AHK 1.1.24
guest3456
Posts: 2464
Joined: 09 Oct 2013, 10:31

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

14 Feb 2017, 12:22

serg wrote:Guest3456, I ran your updated code, it gave me different results, traditional var assignments (without quotes) are the fastest :
4.884133
5.322768
4.117642
6.175888
3.612573
5.098961
So I guess PC setup makes difference here. I have Win8.1 64 with AHK 1.1.24
yep good to know. overall your numbers are significantly higher than mine

I'm on Win 10 x64, with AHK 1.1.24 x86, 3yo Core i7 laptop

i wonder if AHK x64 would change it

User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

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

15 Feb 2017, 22:00

my tests are: AHK U32 v1.1.24.05, high priority, Windows 7 x64

speed tests for generating repeated string:
'VarSetCapacity fill bytes, replace' beats 'loop append'
(repeated strings themselves are often useful for speed tests)

speed tests for parsing CRLF-delimited lines:
'parse LF ignore CR' just beats 'replace CRLF with LF, parse LF'
(out of interest 'replace CR with LF, parse LF, ignore blank lines',
also included, was essentially twice the loops, twice the time)

speed tests for InStr case sensitive/case insensitive:
case insensitive beats case sensitive
(although I might have thought case sensitive had less to check
e.g. check 'b' versus check 'B' and 'b', so would be faster)

Code: Select all

;speed tests for generating repeated string
;'VarSetCapacity fill bytes, replace' beats 'loop append'
q::
vNum := 100000000 ;10^8

;test 1 - loop append
vTickCount1 := A_TickCount
vText := ""
VarSetCapacity(vText, vNum*2)
Loop, % vNum/10
vText .= "abcdefgh`r`n"
vTickCount2 := A_TickCount
MsgBox % vTime1 := vTickCount2-vTickCount1

vText2 := vText

;test 2 - VarSetCapacity fill bytes, replace
vTickCount1 := A_TickCount
vText := ""
VarSetCapacity(vText, (vNum/10)*2, 1)
vText := StrReplace(vText, Chr(257), "abcdefgh`r`n")
vTickCount2 := A_TickCount
MsgBox % vTime2 := vTickCount2-vTickCount1

;MsgBox % (vText = vText2)
MsgBox % Clipboard := vTime1 " " vTime2 ;e.g. 1107 390, 1217 375
Return

;==================================================

;speed tests for parsing CRLF-delimited lines
;'parse LF ignore CR' just beats 'replace CRLF with LF, parse LF'
w::
vNum := 100000000 ;10^8
vText := ""
VarSetCapacity(vText, (vNum/10)*2, 1)
vText := StrReplace(vText, Chr(257), "abcdefgh`r`n")
vTextOrig := vText

;test 1 - replace CRLF with LF, parse LF
vOutput := ""
VarSetCapacity(vOutput, StrLen(vText)*2)
vTickCount1 := A_TickCount
vText := StrReplace(vText, "`r`n", "`n")
Loop, Parse, vText, `n
vOutput .= A_LoopField "`r`n"
vTickCount2 := A_TickCount
MsgBox % vTime1 := vTickCount2-vTickCount1
;MsgBox % (vTextOrig "`r`n" = vOutput)

;test 2 - parse LF ignore CR
vText := vTextOrig
vOutput := ""
VarSetCapacity(vOutput, StrLen(vText)*2)
vTickCount1 := A_TickCount
Loop, Parse, vText, `n, `r
vOutput .= A_LoopField "`r`n"
vTickCount2 := A_TickCount
MsgBox % vTime2 := vTickCount2-vTickCount1
;MsgBox % (vTextOrig "`r`n" = vOutput)

;test 3 - replace CR with LF, parse LF, ignore blank lines
vText := vTextOrig
vOutput := ""
VarSetCapacity(vOutput, StrLen(vText)*2)
vTickCount1 := A_TickCount
vText := StrReplace(vText, "`r", "`n")
Loop, Parse, vText, `n
if !(A_LoopField = "")
vOutput .= A_LoopField "`r`n"
vTickCount2 := A_TickCount
MsgBox % vTime3 := vTickCount2-vTickCount1
;MsgBox % (vTextOrig = vOutput)

MsgBox % Clipboard := vTime1 " " vTime2 " " vTime3 ;e.g. 3026 2714, 3042 2714, 3057 2730 6147, 3198 2683 6100, 3089 2699 6209
Return

;==================================================

;speed tests for InStr case sensitive/case insensitive
;case insensitive beats case sensitive
;e::
vNum := 100000000 ;10^8
vText := ""
VarSetCapacity(vText, vNum*2, 1)
vText := StrReplace(vText, Chr(257), "a") "b"

Loop, 2
{
;test 1 - case sensitive
vTickCount1 := A_TickCount
vPos := InStr(vText, "b", 1)
vTickCount2 := A_TickCount
MsgBox % vTime1 := vTickCount2-vTickCount1

;test 2 - case insensitive
vTickCount1 := A_TickCount
vPos := InStr(vText, "b", 0)
vTickCount2 := A_TickCount
MsgBox % vTime2 := vTickCount2-vTickCount1

MsgBox % Clipboard := vTime1 " " vTime2 ;125 94, 141 94
}

Return
==================================================

Comments on list comparison:

For a spellchecker or looking a up word in a list:
if there are 100 words or fewer, I use InStr, e.g.
if !InStr(vSpellListText, "`n" A_LoopField "`n")

For longer lists, if order doesn't matter:
I sort the needles list, (the haystack list is already sorted,)
and parse the 2 lists simultaneously.

For longer lists, if order does matter:
I prepend/append numbers to the needle lists,
sort the needle/haystack lists together,
possibly using a custom filter,
parse to find matches/non-matches,
(and append needle items to a new list with their match results,)
and restore the original order to the new needles results list.
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

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

30 Mar 2017, 18:08

benchmark tests: variables v. arrays, reverse a list

method 1 - split to variables then retrieve items in reverse order
method 2 - split to array then retrieve items in reverse order
method 3 - retrieve text backwards in steps, assume items of fixed length
method 4 - retrieve text backwards in steps, search for delimiter

Code: Select all

q:: ;benchmark tests: variables v. arrays
if !vIsReady
{
	vNum := 500000
	vText := ""
	VarSetCapacity(vText, vNum*10*2+2)
	Loop, % vNum
		vText .= Format("{:09}", A_Index) "`n"
	MsgBox, % SubStr(vText, 1, 200)
	vIsReady := 1
}

;METHOD 1 - split to variables then retrieve items in reverse order
vOutputX1 := ""
VarSetCapacity(vOutputX1, vNum*10*2+2)
vTickCount1 := A_TickCount
StringSplit, vOutput, vText, `n
Loop, % vOutput0
	vIndex := vOutput0+1-A_Index, vOutputX1 .= vOutput%vIndex% "`n"
vTickCount1 := A_TickCount - vTickCount1

;METHOD 2 - split to array then retrieve items in reverse order
vOutputX2 := ""
VarSetCapacity(vOutputX2, vNum*10*2+2)
vTickCount2 := A_TickCount
oOutput := StrSplit(vText, "`n")
Loop, % oOutput.MaxIndex()
	vOutputX2 .= oOutput[oOutput.MaxIndex()+1-A_Index] "`n"
vTickCount2 := A_TickCount - vTickCount2

;METHOD 3 - retrieve text backwards in steps, assume items of fixed length
vOutputX3 := ""
VarSetCapacity(vOutputX3, vNum*10*2+2)
vTickCount3 := A_TickCount
vOutputX3 .= "`n"
vNum2 := vNum*10 + 1
Loop, % vNum
	vNum2 -= 10, vOutputX3 .= SubStr(vText, vNum2, 10)
vTickCount3 := A_TickCount - vTickCount3

;METHOD 4 - retrieve text backwards in steps, search for delimiter
vOutputX4 := ""
VarSetCapacity(vOutputX4, vNum*10*2+2)
vTickCount4 := A_TickCount
vLen := StrLen(vText)
vPos2 := vLen
if vPos2
	Loop
	{
		if !vPos2 || !(vPos1 := InStr(vText, "`n", 0, vPos2-vLen))
		{
			vOutputX4 .= SubStr(vText, 1, vPos2) "`n"
			break
		}
		vOutputX4 .= SubStr(vText, vPos1+1, vPos2-vPos1) "`n"
		vPos2 := vPos1-1
	}
vTickCount4 := A_TickCount - vTickCount4

;CHECK OUTPUT
vRet := (vOutputX1 = vOutputX2) (vOutputX1 = vOutputX3) (vOutputX1 = vOutputX4)
if !(vRet = 111)
	MsgBox, % "error: not all strings match: " vRet
Loop, 3
{
	vIndex := A_Index+1
	if !(vOutputX1 = vOutputX%vIndex%)
		MsgBox, % "1 " vIndex "`n[" vOutputX1 "]`n[" vOutputX%vIndex% "]"
}

Clipboard := vTickCount1 " " vTickCount2 " " vTickCount3 " " vTickCount4
MsgBox, % Clipboard
return
Tigerlily

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

04 Oct 2018, 22:29

I tried to use the OP's code at the top and then the altered code at the bottom in one of my automation scripts that checks URLs by copying and pasting them to and from an excel spreadsheet and toggling between Chrome browser and Excel windows. It totally made my computer go haywire both times, toggling uncontrollably and not allowing me to end the script by pressing End (End is my default "stop this script immediately" key). I had to shut my VM down.

Just wondering if there is an actually useful post with code similar to this that doesn't make your script go batshit crazy?? :P

I'm pretty new to AHK so just been using really basic commands like Send, Sleep, and Click. Other than practicing and testing, where are some good resources to gain more chops at AHK? I've began implementing automation solutions with AHK at a digital marketing agency i recently started working at, which has saved them a ton of time already - however, I want to make more scalable solutions and right now my scripts sometimes do not execute 100% correctly and I don't know why. Sometimes my script will run for 10 hours straight with no hiccups, then other times it may take 1 minute and the loop misses a command.. not sure why.. how do y'all debug these kinds of issues?
User avatar
WAZAAAAA
Posts: 73
Joined: 13 Jan 2015, 19:48

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

08 Nov 2018, 17:01

Tigerlily wrote:
04 Oct 2018, 22:29
I tried to use the OP's code at the top and then the altered code at the bottom in one of my automation scripts that checks URLs by copying and pasting them to and from an excel spreadsheet and toggling between Chrome browser and Excel windows. It totally made my computer go haywire both times, toggling uncontrollably and not allowing me to end the script by pressing End (End is my default "stop this script immediately" key). I had to shut my VM down.
It sounds like your script is running too fast, you probably need to slow it down a bit by adding some Sleeps into your loops since the code on the first post got rid of the the "hidden" ones
YOU'RE NOT ALEXANDER

Return to “Tutorials”

Who is online

Users browsing this forum: No registered users and 7 guests