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

Helpful script writing tricks and HowTo's
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

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

27 Oct 2016, 07:29

Code: Select all

if (IsTrue = 1):	9.594683
if (IsTrue):		7.755995    ; <- fastes

if (IsFalse = 0):	9.508504
if not (IsFalse):	8.588009
if (IsFalse <> 1):	9.613642
if !(IsFalse):	    8.520527    ; <- fastes

Code: Select all

#NoEnv
SetBatchLines -1

global IsTrue    := 1
global IsFalse   := 0

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

QPC(1)
loop 100000000
    if (IsTrue = 1)
        continue
test1 := QPC(0)

QPC(1)
loop 100000000
    if (IsTrue)
        continue
test2 := QPC(0)

QPC(1)
loop 100000000
    if (IsFalse = 0)
        continue
test3 := QPC(0)

QPC(1)
loop 100000000
    if not (IsFalse)
        continue
test4 := QPC(0)

QPC(1)
loop 100000000
    if (IsFalse <> 1)
        continue
test5 := QPC(0)

QPC(1)
loop 100000000
    if !(IsFalse)
        continue
test6 := QPC(0)


MsgBox % "if (IsTrue = 1):`t"   test1 "`n"
       . "if (IsTrue):`t`t"     test2 "`n`n"
       . "if (IsFalse = 0):`t"  test3 "`n"
       . "if not (IsFalse):`t"  test4 "`n"
	   . "if (IsFalse <> 1):`t" test5 "`n"
       . "if !(IsFalse):`t"     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) 
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
SvenBent
Posts: 266
Joined: 09 Aug 2015, 01:34

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

27 Oct 2016, 12:16

nice work.

if (IsTrue): 7.755995 ; <- fastes
We got the same results here

if !(IsFalse): 8.520527 ; <- fastes
I dont think i did testing with ! but i'm unsure

if not (IsFalse): 8.588009
hmm i got this to be slower than <>1

maybe an achitecture difference ?
Gonna check up in next time i try to optimize some code


I have a question abotu optimize arithmics.
i was under the assumption that + is faster than - and that Paranthes would hurt performance
so i tried to optimize this:

test := ((newKrnlTime-oldKrnlTime) + (newUserTime-oldUserTime)) // (newTickCount - oldTickCount) // 800

to
test := ((newKrnlTime+newUserTime - (oldKrnlTime+oldUserTime)) // (newTickCount - oldTickCount) // 800

Which made one - into a + and removed a parenthesis pair bit it came out slightly slower

can i assumed multiplications are faster than interger division ?
would it help to change

// (newTickCount - oldTickCount) // 800

to

// ((newTickCount - oldTickCount) * 800)


I've always though the order of cost in operators would be
+ Fastest
-
*
/ slowest (Why we try to use bit sift operations instead)
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

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

28 Oct 2016, 01:00

100.000.000 Loops

Code: Select all

A + B   7.822086
A - B   7.793425

A + 1   7.647965
A - 1   7.629782

A++     6.906725
A--     6.837371

++A     7.220017
--A	    7.273083
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

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

28 Oct 2016, 01:23

Calc with 'power of 2' numbers
262144 / 1024 -> 256 (100.000.000 Loops)

Code: Select all

┌──────────────────┬──────────────┬────────────┐
│                  │  Return      │  Time      │
├──────────────────┼──────────────┼────────────┤
│ A / 1024         │  256.000000  │   7.596106 │
│ Floor(A / 1024)  │  256         │   9.746309 │
│ Round(A / 1024)  │  256         │   9.663673 │
│ A // 1024        │  256         │   8.199030 │
│ A >> 10          │  256         │   7.652976 │
└──────────────────┴──────────────┴────────────┘

256 * 1024 -> 262144 (100.000.000 Loops)

Code: Select all

┌──────────────────┬──────────────┬────────────┐
│                  │    Return    │    Time    │
├──────────────────┼──────────────┼────────────┤
│ B * 1024         │       262144 │   7.626448 │
│ B << 10          │       262144 │   7.685819 │
└──────────────────┴──────────────┴────────────┘

Code: Select all

MsgBox %   1  <<   0    ; ->    1
MsgBox %   1  <<   1    ; ->    2
MsgBox %   1  <<   2    ; ->    4
MsgBox %   1  <<   3    ; ->    8
MsgBox %   1  <<   4    ; ->   16
MsgBox %   1  <<   5    ; ->   32
MsgBox %   1  <<   6    ; ->   64
MsgBox %   1  <<   7    ; ->  128
MsgBox %   1  <<   8    ; ->  256
MsgBox %   1  <<   9    ; ->  512
MsgBox %   1  <<  10    ; -> 1024
; ...
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
Almost_there
Posts: 404
Joined: 30 Sep 2014, 10:32

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

28 Oct 2016, 18:10

Nice thread :thumbup:

I have a couple of ideas too I would like to share, it's probably obvious.
I use a huge program running at external desktop, and the only ways to get information from the program is by reading colors (imagesearch, pixelgetcolor and pixelsearch), reading window title or window size.
Because I've made a 6k lines script to maximize effeciency, I've learn that these tips may reduce noticeable lags (when waiting for imagesearch to finnish).

1. Multiple boolean IF/OR/AND
Situation 1 - There is some functions - checkSlow(), checkFast() and checkFastest(). Those name just gives a hint about the time it takes for those functions to return a result. If testing if all of those gives true, the most efficient way is normally by putting the fastest function first, bedause if that one return 0, a multiple AND statement won't waste time calling the next function.

Good idea:
If ( checkFastest() && checkFast() && checkSlow() )
do something
If there is a multiple boolean AND operator (if I can call it so?) and each function call takes about the same time, it's a good idea to put first the function that is most likely to return 0. For multiple OR operators, inverse rules applies.


2. Multiple imagesearch
ImageSearch will be relatively slow when searching a large area of screen. If the image to match is likely to stay in same location between multiple imagesearch calls, it is a good idea to make the second imagesearch (after the first imagesearch where a match was found) to only search within the matching area that measure the same dimensions as the image file.


Also I recently found a very useful resource - PixelChecksum()
https://autohotkey.com/boards/viewtopic.php?f=6&t=4431
That seems faster than using ImageSearch. Too bad it doesn't work in 64 bit WIndows.
Sam_
Posts: 146
Joined: 20 Mar 2014, 20:24

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

22 Nov 2016, 14:39

.SetCapacity is the Array/Object equivalent of VarSetCapacity, and can significantly improve performance.

Test Script:

Code: Select all

Process, Priority, , H
SetBatchLines, -1

; worse
QPC(1)
Loop, 1000000 ; to limit memory usage
	{
	Array:=[]
	Loop, 1000
		Array.Push(A_Index)
	Array:=""
	}
toc:=QPC(0)


; better
tic:=QPC(1)
Loop, 1000000 ; to limit memory usage
	{
	Array:=[]
	Array.SetCapacity(1000)
	Loop, 1000
		Array.Push(A_Index)
	Array:=""
	}
toc2:=QPC(0)

MsgBox % toc "`r`n" toc2
Results:
---------------------------
benchmarks.ahk
---------------------------
NOT using SetCapacity: 375.618883

using SetCapacity: 147.962063
---------------------------
OK
---------------------------
Sam_
Posts: 146
Joined: 20 Mar 2014, 20:24

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

22 Nov 2016, 15:24

Some testing of different ways to assign key, value pairs in arrays:

Code: Select all

Process, Priority, , H
SetBatchLines, -1


QPC(1)
Loop, 100000 ; to limit memory usage
	{
	Array:=[]
	Array.SetCapacity(1000)
	Loop, 1000
		Array.Push(A_Index)
	Array:=""
	}
toc1:=QPC(0)


tic:=QPC(1)
Loop, 100000 ; to limit memory usage
	{
	Array:=[]
	Array.SetCapacity(1000)
	Loop, 1000
		ObjRawSet(Array,A_Index,A_Index)
	Array:=""
	}
toc2:=QPC(0)

QPC(1)
Loop, 100000 ; to limit memory usage
	{
	Array:=[]
	Array.SetCapacity(1000)
	Loop, 1000
		Array[A_Index]:=A_Index
	Array:=""
	}
toc3:=QPC(0)

QPC(1)
Loop, 100000 ; to limit memory usage
	{
	Array:=[]
	Array.SetCapacity(1000)
	Loop, 1000
		Array.Insert(A_Index)
	Array:=""
	}
toc4:=QPC(0)

QPC(1)
Loop, 100000 ; to limit memory usage
	{
	Array:=[]
	Array.SetCapacity(1000)
	Loop, 1000
		Array.InsertAt(Array.Length()+1,A_Index)
	Array:=""
	}
toc5:=QPC(0)


MsgBox % toc1 "`r`n" toc2 "`r`n" toc3 "`r`n" toc4 "`r`n" toc5
Results:

Code: Select all

---------------------------
benchmarks.ahk
---------------------------
Array.Push()		14.231856
ObjRawSet()			13.684982
Array[]:=			12.596166    ; <- fastes
Array.Insert()		16.269619
Array.InsertAt()	26.067634
---------------------------
OK   
---------------------------
Sam_
Posts: 146
Joined: 20 Mar 2014, 20:24

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

29 Nov 2016, 12:08

@V for Vendetta, Here are my results:
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   
---------------------------

String Concatenation:

Code: Select all

#MaxMem 2048

Var:=""
QPC(1)
Loop, 10000000
	Var=%var%%A_Index%-
toc1:=QPC(0)
Var:=""

Var2:=""
QPC(1)
Loop, 10000000
	Var2.=A_Index "-"
toc2:=QPC(0)
Var2:=""

Var3:=""
QPC(1)
Loop, 10000000
	Var3.=A_Index . "-"
toc3:=QPC(0)
Var3:=""

MsgBox % toc1 "`n" toc2 "`n" toc3
Results:

Code: Select all

---------------------------
benchmarks.ahk
---------------------------
173.310786
72.365218
69.749422    ; <- fastest
---------------------------
OK   
---------------------------
This would indicate that using the ".=" operator in conjunction with (when applicable) the explicit "." concatenation operator is fastest. That last bit surprises me... See Operators.
Further testing indicates this is false. See my next post.
Last edited by Sam_ on 30 Nov 2016, 10:47, edited 3 times in total.
User avatar
V for Vendetta
Posts: 105
Joined: 29 Sep 2016, 11:33

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

29 Nov 2016, 13:23

Sam_ wrote: This would indicate that using the ".=" operator in conjunction with (when applicable) the explicit "." concatenation operator is fastest. That last bit surprises me... See Operators.
From the tests I made, both seem to be the same!

loop, 1000000
text .= a_index "`r`n"

loop, 1000000
text .= a_index . "`r`n"

Result from my pc (for loop 1 000 000): both varies from 10 000 to 12 000 milliseconds!!!
User avatar
FanaticGuru
Posts: 1905
Joined: 30 Sep 2013, 22:25

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

30 Nov 2016, 00:30

Sam_ wrote: Results:

Code: Select all

---------------------------
benchmarks.ahk
---------------------------
173.310786
72.365218
69.749422    ; <- fastest
---------------------------
OK   
---------------------------
This would indicate that using the ".=" operator in conjunction with (when applicable) the explicit "." concatenation operator is fastest. That last bit surprises me... See Operators.
My results did not concur. The last two on my system were very similar in multiple test. Less than 1% deviation plus or minus with neither consistently faster.

I did add SetBatchLines -1 and Process, Priority, , H to my script to try to limit other processes on my computer stealing processor time.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
Sam_
Posts: 146
Joined: 20 Mar 2014, 20:24

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

30 Nov 2016, 10:42

@V for Vendetta, @FanaticGuru
After further testing, I have arrived at the same conclusion as you. I set the following script up and let it run for a few hours last night

Code: Select all

Process, Priority, , H
SetBatchLines, -1

#MaxMem 1024
Var:=""

While 0<1
	{
	VarSetCapacity(Var, 80000000, 0)
	QPC(1)
	Loop, 10000000
		Var.=A_Index . "-"
	toc:=QPC(0)
	FileAppend, %toc%%A_Tab%Yes`r`n, %A_ScriptDir%\benchmark.txt

	VarSetCapacity(Var, 80000000, 0)
	QPC(1)
	Loop, 10000000
		Var.=A_Index "-"
	toc:=QPC(0)
	FileAppend, %toc%%A_Tab%No`r`n, %A_ScriptDir%\benchmark.txt
	}
After 4,011 loops (of ten million concatenations using each method), no explicit "." syntax resulted in an average of 2.037523 sec. while with it had an average of 2.037380 sec. I imagine that's well within the margin of error of the test. In terms of speed, concatenation with or without the "." operator is identical.
User avatar
Almost_there
Posts: 404
Joined: 30 Sep 2014, 10:32

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

17 Dec 2016, 19:30

Hi. I'm not where I talk so much about those tiny micro seconds one operator compares to another. Instead I focus on how to improve the kind of taksk that I know takes times, and how to make it as effective as possible.

Todays examle - Say I have 4 function, each normally takes noticeable time to complete. It might be a imagesearch for each function, so if possible - the goal is to run as few as possible function calls (one function return true if it had success).
Most of explanation is to be found in comments.

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

;  ---- AlmostThere -----

; Move function call one place forward in queue each time function is called (and returns true).
; Purpose: For time consuming function calls (eg. imagesearch where several different images may be found) - we want that the function that most oftens returns true should be called first (in a list of functions).
; Weakness - if it turns out that two of the functions alternates between return true - those two might just swap place forever - without actually move to the begin of the queue.
; Possible solutions for this problem:
;  1. Always swap with first in queue (might not be most effective method when times goes by, as less often functions that is only true once in a while)
;  2. Add another table that counts when each functions returns true, and sorts by number of return-true.

OnExit("exitFunction")

table_functionsnames_sorted := Object()

; Create the ini file if it doesn't already exists (may not be neccesary as it would be created when script terminates).
IfNotExist, ahk_setting.ini
{
FileAppend,
(
[function_call_order]
function_number_1=1
function_number_2=2
function_number_3=3
function_number_4=4
), ahk_setting.ini
}


; Read from INI file. May be solved by a for loop, but avoid this in example because function names may refer to a description of a image to match (own experience)
IniRead, OutputVar, ahk_setting.ini, function_call_order, function_number_1, 1
table_functionsnames_sorted[1] := OutputVar

IniRead, OutputVar, ahk_setting.ini, function_call_order, function_number_2, 2
table_functionsnames_sorted[2] := OutputVar

IniRead, OutputVar, ahk_setting.ini, function_call_order, function_number_3, 3
table_functionsnames_sorted[3] := OutputVar

IniRead, OutputVar, ahk_setting.ini, function_call_order, function_number_4, 4
table_functionsnames_sorted[4] := OutputVar


F8::
	Loop, 4	; Same number as number of possible functions to call.
	{
		func_index := table_functionsnames_sorted[A_Index]
		function_returned_value := funksjon_%func_index%()
		If (function_returned_value == 1) {
			If (A_Index == 1)
				Break	; The first function in queue returned true, so no need to proceed nor do any sorting.
			Else {	; Function returned true moves one step forward in queue.
				outOfArray_value := table_functionsnames_sorted[A_Index]
				table_functionsnames_sorted[A_Index] := table_functionsnames_sorted[A_Index-1]
				table_functionsnames_sorted[A_Index-1] := outOfArray_value
				Break	; Do not call any more functions when one returns true.
			}
		}
	}

	; VIEW ARRAY CONTENT.
	arrayContentText(table_functionsnames_sorted)
Return	; F8


arrayContentText(arrayID) {	; Displays the contents of array
	For i , Value in arrayID
		textOut .= i . "`t-`t" . Value . "`n"
	MsgBox, %textOut%
}


; Write to INI when exit.
exitFunction() {
	Global table_functionsnames_sorted
	TrayTip, Exit script now, Writing the functions order to the INI file `n---------------`nReason for exit: %A_ExitReason%
	
	For i , Value in table_functionsnames_sorted
		IniWrite, %Value%, ahk_setting.ini, function_call_order, function_number_%i%
	
	IniWrite, %A_ExitReason%, ahk_setting.ini, function_call_order_other, exit_reason
	Sleep 3000	; only for traytip to stay long enough so user have time to read.
}


;  -----------------------  Functions that may or may not return true - dummy functions only suitable for this example.
funksjon_1() {
	MsgBox, 0x124, Funksjon 1, Would you want function number 1 to return true??, 4
	IfMsgBox Yes
		Return 1
	Return 0
}

funksjon_2() {
	MsgBox, 0x124, Funksjon 2, Would you want function number 2 to return true??, 4
	IfMsgBox Yes
		Return 1
	Return 0
}

funksjon_3() {
	MsgBox, 0x124, Funksjon 3, Would you want function number 3 to return true??, 4
	IfMsgBox Yes
		Return 1
	Return 0
}

funksjon_4() {
	MsgBox, 0x124, Funksjon 4, Would you want function number 4 to return true??, 4
	IfMsgBox Yes
		Return 1
	Return 0
}
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

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

21 Dec 2016, 14:12

Almost_there wrote:Hi. I'm not where I talk so much about those tiny micro seconds one operator compares to another. Instead I focus on how to improve the kind of taksk that I know takes times, and how to make it as effective as possible.
A sound approach! :thumbup:
User avatar
Almost_there
Posts: 404
Joined: 30 Sep 2014, 10:32

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

04 Jan 2017, 18:55

Next version is done. Now I have added a counter and a bubble-sort (slightly modified) routine so that the function that returns true the most number of times, is the function that is called first.

Most of explanation is done by comments - read well, folks :D

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

/*
  Scripted by Grobe <smiley goes here>
*/

; Writes function order to ini file, and display traytip to the user.
; Gives errormessage when trying to launch same script twice - need to fix that.
OnExit("script_terminates")

; I decided for using two separate arrays because it is easier for me (personally) to deal with.
; Later on, I may change it to use a two-dimensional array instead.
function_names_list := Object()
hitCounts := [0,0,0,0]

; Create the INI file if it doesn't already exists
IfNotExist, ahk_setting.ini
{
FileAppend,
(
[function_call_order]
rekkefolge_1=1
rekkefolge_2=2
rekkefolge_3=3
rekkefolge_4=4
number_of_functions_call=4

[function_call_order_other]

), ahk_setting.ini
}


; IniRead, OutputVar, Filename, Section, Key [, Default]
IniRead, OutputVar, ahk_setting.ini, function_call_order, rekkefolge_1, 1
function_names_list[1] := OutputVar
IniRead, OutputVar, ahk_setting.ini, function_call_order, rekkefolge_2, 2
function_names_list[2] := OutputVar
IniRead, OutputVar, ahk_setting.ini, function_call_order, rekkefolge_3, 3
function_names_list[3] := OutputVar
IniRead, OutputVar, ahk_setting.ini, function_call_order, rekkefolge_4, 4
function_names_list[4] := OutputVar
IniRead, number_of_functions_call, ahk_setting.ini, function_call_order, number_of_functions_call, -1

F8::
	mainLoop:
	Loop, %number_of_functions_call%
	{
		func_index := function_names_list[A_Index]
		function_return_value := funksjon_%func_index%()
		If (function_return_value == 1) {
			If (A_Index == 1) {
				hitCounts[1]++
				Break, mainLoop	; Function called was already first in queue and no sorting is required.
			}
			Else {
				; ACTION 1 - Poeng legges til
				hitCounts[A_Index]++
				index_last_used_last := A_Index -1	; number of iterations used in bubble-sort (performance tweak - limits iterations).
				; Here I can allow making performance tweak for bubble-sort because the counts would never increase by more than 1 between each
				; time that sorting is performed.
				
				; ACTION 2 - Sorting routine - Sorting based on hitCounts[], but the move of array elements is equal in both arrays.
				loop_search_all_decending:
				Loop, %index_last_used_last%
				{
					index_less_than_next := A_index
					If (hitCounts[A_Index+1] > hitCounts[A_Index]) {	; If one index found to have less counts than next, run bubble-sort.
						status_sorted_secondary := 0	; If value is 1, the hitCounts[] is properly sorted (highest counts first)
						loop_sort_bubble:
						While, !status_sorted_secondary
						{
							loop_backwards:
							Loop, %index_less_than_next%
							{
								status_sorted_secondary := 1
								i_backwards := index_last_used_last - A_index +1
								; Searching backwards for entries that is not sorted. That normally requires less iterations.
								
								If ( hitCounts[i_backwards+1] > hitCounts[i_backwards] ) {
									status_sorted_secondary := 0	; Resets sorting status - this makes the while loop to iterate one more time (until sorted)
									
									; TEST - display for the user that bubblesort actually works. Because of measurements that limits
									; the number of iterations for bubble-sort (we always know what index of function returns 1, and counts never increases more
									; than once per iteration of main loop) you should see this only once.
									arrayContentText1(hitCounts)
									
									; Swap number in table index in hitCounts[] with the index above.
									hitCounts_temp := hitCounts[i_backwards]
									hitCounts[i_backwards] := hitCounts[i_backwards+1]
									hitCounts[i_backwards+1] := hitCounts_temp
									
									; Swap number in table index in function_names_list[] with the index above.
									rekkefolge_temp := function_names_list[i_backwards]
									function_names_list[i_backwards] := function_names_list[i_backwards+1]
									function_names_list[i_backwards+1] := rekkefolge_temp
								}
							}
						}	; while "not sorted"
					}	; If "next indeks have a higher number of counts"
					Else {	; next one is already bigger - skip (this whole block can be deleted)
						Continue, loop_search_all_decending
					}
				}	; main sorting loop
				
				Break	; Prevents the code to call more than one function.
			}	; Check if the function called is already first in queue.
		}	; if "return of called function is 1"
	}	; Loop main - loops through a number of functions.

	; ACTION - VIEW ARRAY CONTENT.
	arrayContentText2(function_names_list, hitCounts)
	
Return	; F8


; Display the values in both arrays - that is function call order and the number of hits for each function call
arrayContentText2(arrayID, counterArray) {
	textOut := "Index`t`tfunction_id`t`tCounts`n"
	For i , Value in arrayID
		textOut .= i . "`t-`t" . Value . "`t-`t" . counterArray[i] . "`n"
	MsgBox, %textOut%
}


; Displan values in one array.
arrayContentText1(arrayID) {
	textOut := "Index`t`tVerdi`n"
	For i , Value in arrayID
		textOut .= i . "`t-`t" . Value . "`n"
	MsgBox, %textOut%
}


; ACTION 2 - Write to INI ved ahk exit.
script_terminates() {
	Global function_names_list
	Global hitCounts
	TrayTip, Script terminates shortly, Wait until sort order is saved to ini file `n---------------`nReason for script termination: %A_ExitReason%
	
	For i , Value in function_names_list
		IniWrite, %Value%, ahk_setting.ini, function_call_order, rekkefolge_%i%
	
	For i , Value in hitCounts
	{
		If (i == 1)	; for some rare reason, the IF statements fails when pharanteses is removed.
			counts := Value
		Else
			counts .= " - " . Value
	}
	
	; Writes some more information to the ini file. Not used later, just simple information.
	; Maybe add total number of counts in a later version.
	IniWrite, %counts%, ahk_setting.ini, function_call_order_other, function_call_counts_sorted
	IniWrite, %A_ExitReason%, ahk_setting.ini, function_call_order_other, exit_reason
	Sleep 3000
}



;  -----------------------  The functions that is to be called  -  main code will try to call the functions in most effective order (most used function is tried first).
funksjon_1() {
	MsgBox, 0x124, Funksjon 1, Do you want function number 1 return true?`n - - - - - - `n`nYou got 4 seconds to decide before I decide -NO- for you..., 4
	IfMsgBox Yes
		Return 1
	Return 0
}

funksjon_2() {
	MsgBox, 0x124, Funksjon 2, Do you want function number 2 return true?`n - - - - - - `n`nYou got 4 seconds to decide before I decide -NO- for you..., 4
	IfMsgBox Yes
		Return 1
	Return 0
}

funksjon_3() {
	MsgBox, 0x124, Funksjon 3, Do you want function number 3 return true?`n - - - - - - `n`nYou got 4 seconds to decide before I decide -NO- for you..., 4
	IfMsgBox Yes
		Return 1
	Return 0
}

funksjon_4() {
	MsgBox, 0x124, Funksjon 4, Do you want function number 4 return true?`n - - - - - - `n`nYou got 4 seconds to decide before I decide -NO- for you..., 4
	IfMsgBox Yes
		Return 1
	Return 0
}
serg
Posts: 56
Joined: 21 Mar 2015, 05:33

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

09 Jan 2017, 05:33

This is quite useful thread, I want to add few points:

A) Regular vars are retrieved faster than array elements (in example below ~3 times faster):

Code: Select all

ar := [1,2,3,4,5,6,7,8,9]
t1 := a_tickcount
Loop, 1000000
 q1 := ar[1]*ar[2]*ar[3]*ar[4]*ar[5]*ar[6]*ar[7]*ar[8]*ar[9]
t1 := a_tickcount - t1

ar1 := 1 , ar2 := 2 , ar3 := 3 , ar4 := 4 , ar5 := 5 , ar6 := 6  , ar7 := 7 , ar8 := 8 , ar9 := 9
t2 := a_tickcount
Loop, 1000000
 q2 := ar1*ar2*ar3*ar4*ar5*ar6*ar7*ar8*ar9
t2 := a_tickcount - t2
msgbox Test1:`nt1 = %t1%	q1 = %q1%`n`nTest2:`nt2 = %t2%	q2 = %q2%

B) "Loop, Parse" is faster than "StringSplit" - as mentioned in AHK documentation

C) To convert float to integer, Round() is ~30-35% faster than [SetFormat Float 0.0 + then set back to original]

D) Vars with many references in names (i.e. var%a%_%b%) reduce speed quite significantly (noticable in Loops)

E) Not sure about this one, but according to my testing:
when working with large data sets and need to retrieve parts of the data fast, the fastest ways are:
1) create structured file with File.Write where each field is fixed size 4 or 8... bits.
Then retrieve data using File.Read
or
2) "FileRead + InStr()/SubStr()" - in cases where possible to use SubStr() instead of Loop,Parse
These 2 methods are much faster than "Loop,Read" or "FileRead + Loop,Parse"
User avatar
Almost_there
Posts: 404
Joined: 30 Sep 2014, 10:32

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

10 Jan 2017, 20:12

moved to separate thread as advised

https://autohotkey.com/boards/viewtopic ... 42#p125442
Last edited by Almost_there on 11 Jan 2017, 11:29, edited 2 times in total.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

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

11 Jan 2017, 03:46

If you want more speed you need to change how you recognize buttons (basically stop using ImageSearch).
Also the way you wrote that script is pretty cancerous.
Rather than defining one function which let's you search for different Images at different positions you define like 8 functions and even worse rather than storing the results somewhere you let each function have them store it in static parameters.
Recommends AHK Studio
serg
Posts: 56
Joined: 21 Mar 2015, 05:33

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

11 Jan 2017, 04:19

@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
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

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

11 Jan 2017, 06:10

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.
Recommends AHK Studio

Return to “Tutorials (v1)”

Who is online

Users browsing this forum: No registered users and 30 guests