jeeswg's benchmark tests

Put simple Tips and Tricks that are not entire Tutorials in this forum
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

jeeswg's benchmark tests

04 Oct 2017, 17:39

I will add to this collection of benchmark tests periodically.

ASSUME ALWAYS:
The benchmark test examples work best with the following settings, and require the QPC function.

Code: Select all

#NoEnv
SetBatchLines, -1
AutoTrim, Off
ListLines, Off

;based on QPC by wolf_II
;note: this function returns milliseconds, the original function returns seconds
;Anagrams - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=19&t=34240&p=158464#p158464

QPC()
{
	static vFreq, vInit := DllCall("kernel32\QueryPerformanceFrequency", Int64P,vFreq)
	DllCall("kernel32\QueryPerformanceCounter", Int64P,vCount)
	return (vCount / vFreq) * 1000
}
I welcome any other suggestions re. conditions for a good benchmark test.

Links:
[note: I have two posts on Page 5 which are included in this thread also]
How to optimize the speed of a script as much as possible. - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=6413
How to optimize the speed of a script as much as possible. - Ask for Help - AutoHotkey Community
https://autohotkey.com/board/topic/9445 ... -possible/

==================================================

BENCHMARK TESTS

[STRINGS] 4 REGEXMATCH / REGEXREPLACE TESTS
[this post]

STRING / ARRAY - CHECK IF LIST CONTAINS ITEM
https://autohotkey.com/boards/viewtopic ... 29#p192029

[STRINGS] REPEAT STRING: LOOP V. VARSETCAPACITY
[STRINGS] PARSE LINES: LOOP WITH OMITTED CHARACTERS V. STRREPLACE
[STRINGS] INSTR: CASE SENSITIVE V. CASE INSENSITIVE
https://autohotkey.com/boards/viewtopic ... 69#p194669

[STRINGS] RTRIM V. STRREPLACE
[STRINGS] TRUNCATE STRING
https://autohotkey.com/boards/viewtopic ... 72#p194672

STRINGS: SUBSTR: CROP FIRST CHARACTER V. CROP LAST CHARACTER
https://autohotkey.com/boards/viewtopic ... 71#p195571

NUMBER: SWAP BYTES (e.g. 0x11223344 to 0x44332211)
https://autohotkey.com/boards/viewtopic ... 81#p194681

[CLIPBOARD] CLIPWAIT / DLLCALL - CHECK IF CLIPBOARD EMPTY
https://autohotkey.com/boards/viewtopic ... 78#p190278

[WINDOWS] WINGETPOS V. GETWINDOWRECT (BUILT-IN COMMANDS/FUNCTIONS V. DLLCALL)
[WINDOWS] WINGET ID: A (ACTIVE WINDOW) V. 'AHK_CLASS NOTEPAD'
[WINDOWS] TWO-WAY COMPATIBILITY FUNCTIONS: WINGETPOS COMMAND V. CUSTOM WINGETPOS FUNCTION
https://autohotkey.com/boards/viewtopic ... 62#p194662

[LOOPS] LOOPED CODE V. HARDCODED CODE
https://autohotkey.com/boards/viewtopic ... 66#p194666

==================================================

4 REGEXMATCH / REGEXREPLACE TESTS

Code: Select all

q:: ;RegExMatch - [abc] v. (a|b|c)
vNum := 10000000, vText := "_"
vText := StrReplace(Format("{:" vNum "}", ""), " ", vText) ;repeat string
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
Loop
{
	DllCall("QueryPerformanceCounter", Int64P,vQPC1)
	;RegExMatch(vText, "[abc]")
	RegExMatch(vText, "(a|b|c)")
	DllCall("QueryPerformanceCounter", Int64P,vQPC2)
	MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
}
;[abc] 228.454816 250.858284 241.224296
;(a|b|c) 609.747399 631.340479 631.166855
return

Code: Select all

q:: ;RegExMatch - [^z] v. .*?
vNum := 10000000, vText := "_"
vText := StrReplace(Format("{:" vNum "}", ""), " ", vText) "z" ;repeat string
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
Loop
{
	DllCall("QueryPerformanceCounter", Int64P,vQPC1)
	;RegExMatch(vText, "^[^z]*z")
	RegExMatch(vText, "^.*?z")
	DllCall("QueryPerformanceCounter", Int64P,vQPC2)
	MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
}
;[^z] 15.176267 31.758203 32.513851
;.*? 122.261575 143.827286 129.315580
return

;Put here requests of problems with regular expressions - Page 14 - Ask for Help - AutoHotkey Community
;https://autohotkey.com/board/topic/12375-put-here-requests-of-problems-with-regular-expressions/page-14
;Use: <([AB])\b[^>]*>(.*?)<\/\1>
;If it's a text node you can replace .*? with [^<]* for better performance.

;Put here requests of problems with regular expressions - Page 65 - Ask for Help - AutoHotkey Community
;https://autohotkey.com/board/topic/12375-put-here-requests-of-problems-with-regular-expressions/page-65
;That's because of the lazy matching of .*?. In small strings the performance hit is negligible, but in large files it obviously makes a difference. The way around it is to use a negated character class:

Code: Select all

q:: ;RegExMatch v. RegExReplace - get initial characters
vNum := 100000, vText := "_"
vText := StrReplace(Format("{:" vNum "}", ""), " ", vText) ;repeat string
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
Loop
{
	DllCall("QueryPerformanceCounter", Int64P,vQPC1)
	;Loop, 1000
	;	RegExMatch(vText, "O)^(.{" Floor(vNum/2) "})", o)
	Loop, 1000
		vText2 := RegExReplace(vText, "^.{" Floor(vNum/2) "}\K.*")
	DllCall("QueryPerformanceCounter", Int64P,vQPC2)
	MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
}
;RegExMatch 124.518258 126.705235 126.224989
;RegExReplace 246.634006 260.154431 252.441425
return

;Put here requests of problems with regular expressions - Page 24 - Ask for Help - AutoHotkey Community
;https://autohotkey.com/board/topic/12375-put-here-requests-of-problems-with-regular-expressions/page-24
;RegExReplace will be somewhat slower compared to regexmatch

Code: Select all

q:: ;replacing digits with nothing
;the StrReplace variants are roughly the same speed-wise
;using StrReplace multiple times is faster than using RegExReplace once
;the interest in the StrReplace variants was re. the conversion of integers
;to strings prior to doing a StrReplace
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
vNum := 2000
vText := ""
VarSetCapacity(vText, vNum*10*2)
Loop, % vNum
	vText .= "0123456789"

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
{
	vText2 := vText
	Loop, 10
		vText2 := StrReplace(vText2, Chr(47+A_Index))
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
;MsgBox, % StrLen(vText) " " StrLen(vText2)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
{
	vText2 := vText
	Loop, 10
		vText2 := StrReplace(vText2, A_Index-1)
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
;MsgBox, % StrLen(vText) " " StrLen(vText2)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
{
	vText2 := vText
	Loop, 10
		vText2 := StrReplace(vText2, "" (A_Index-1))
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
;MsgBox, % StrLen(vText) " " StrLen(vText2)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	vText2 := RegExReplace(vText, "\d")
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
;MsgBox, % StrLen(vText) " " StrLen(vText2)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	vText2 := RegExReplace(vText, "[\d]")
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
;MsgBox, % StrLen(vText) " " StrLen(vText2)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	vText2 := RegExReplace(vText, "[0-9]")
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
;MsgBox, % StrLen(vText) " " StrLen(vText2)
return
Last edited by jeeswg on 01 Feb 2018, 10:44, edited 11 times in total.
User avatar
jNizM
Posts: 2341
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
Contact:

Re: jeeswg's benchmark tests

05 Oct 2017, 00:47

QueryPerformanceFrequency should not be called every time in a loop. It's enough if you call it once at scripts loadtime.
global InitQPC := DllCall("QueryPerformanceFrequency", "Int64P", QPF)
[AHK] 1.1.30.01 x64 Unicode | [WIN] 10 Pro (Version 1803) x64 | [GitHub] Profile
Donations are appreciated if I could help you
User avatar
RUNIE
Posts: 281
Joined: 03 May 2014, 14:50
GitHub: Run1e

Re: jeeswg's benchmark tests

08 Oct 2017, 09:48

I use a pretty simple Timer class:

Code: Select all

	Class Timer {
		static _init := Debug.Timer.Init()
		static Timers := []
		
		Init() {
			DllCall("QueryPerformanceFrequency", "Int64P", F)
			this.Freq := F
		}
		
		Current() {
			DllCall("QueryPerformanceCounter", "Int64P", Timer)
			return Timer
		}
		
		Start(ID) {
			this.Timers[ID] := this.Current()
		}
		
		Stop(ID) {
			return ((this.Current() - this.Timers[ID]) / this.Freq), this.Timers.Delete(ID)
		}
	}
Timer.Start(id) starts a timer, Timer.Stop(id) stops a timer and returns the timers result.
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

Re: jeeswg's benchmark tests

23 Dec 2017, 11:05

CLIPWAIT / DLLCALL - CHECK IF CLIPBOARD EMPTY

Based on:
Clipboard Bug, copying a file from a compressed folder (zip) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 37#p190237

Code: Select all

q:: ;test ClipWait, minimum wait time
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
vClip := ""
;vClip := "abc"

if 0
{
	Clipboard := vClip
	;roughly 500 ms maximum if clipboard blank
	DllCall("QueryPerformanceCounter", Int64P,vQPC1)
	ClipWait, 0, 1
	DllCall("QueryPerformanceCounter", Int64P,vQPC2)
	MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
}

if 0
{
	Clipboard := vClip
	;roughly 500 ms maximum if clipboard blank
	DllCall("QueryPerformanceCounter", Int64P,vQPC1)
	ClipWait, 0.0001, 1
	DllCall("QueryPerformanceCounter", Int64P,vQPC2)
	MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
}

Clipboard := vClip
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
ClipWait, 0.001, 1
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

Clipboard := vClip
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
vRet := DllCall("user32\CountClipboardFormats")
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

Clipboard := vClip
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
vFormat := 49296
vRet := DllCall("user32\IsClipboardFormatAvailable", UInt,vFormat)
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
return
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

Re: jeeswg's benchmark tests

01 Jan 2018, 10:33

STRING / ARRAY - CHECK IF LIST CONTAINS ITEM

Regarding:
conversion logic, v1 = -> v1 := -> v2, two-way compatibility - Page 6 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... &start=100

Should ControlGetList (possibly 'ControlGetItems' in future) return an array, an LF-delimited list, or provide an option to choose. An array seems like the natural default, however, an option to return an LF-delimited list seems sensible (for faster searching).

Code: Select all

q:: ;check if an array/LF-delimited string contains an item
DllCall("QueryPerformanceFrequency", Int64P,vQPF)

;vCount := 1000
vCount := 10000

vLen := StrLen(vCount)
(oArray := {}).SetCapacity(vCount)
VarSetCapacity(vOutput, vCount*(vLen+1)*2+2)
vOutput := "`n"
Loop, % vCount
{
	;vNum := Format("{:04}", A_Index)
	vNum := Format("{:0" vLen "}", A_Index)
	;vNum := A_Index
	vOutput .= Format(vNum) "`n"
	oArray.Push(vNum)
}

;check each array item (for loop)
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
for _, vValue in oArray
	if (vValue = vCount)
		break
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*vCount)

;check each array item (loop)
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % oArray.Length()
	if (oArray[A_Index] = vCount)
		break
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*vCount)

;search string
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
vPos := InStr(vOutput, "`n" vCount "`n")
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*vCount)

;concatenate array items and search string
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
vLen := StrLen(vCount)
VarSetCapacity(vOutput, vCount*(vLen+1)*2+2)
vOutput := "`n"
for _, vValue in oArray
	vOutput .= vValue "`n"
vPos := InStr(vOutput, "`n" vCount "`n")
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*vCount)
return
iPhilip
Posts: 317
Joined: 02 Oct 2013, 12:21

Re: jeeswg's benchmark tests

02 Jan 2018, 01:31

RUNIE wrote:I use a pretty simple Timer class:

Code: Select all

	Class Timer {
		static _init := Debug.Timer.Init()
		static Timers := []
		
		Init() {
			DllCall("QueryPerformanceFrequency", "Int64P", F)
			this.Freq := F
		}
		
		Current() {
			DllCall("QueryPerformanceCounter", "Int64P", Timer)
			return Timer
		}
		
		Start(ID) {
			this.Timers[ID] := this.Current()
		}
		
		Stop(ID) {
			return ((this.Current() - this.Timers[ID]) / this.Freq), this.Timers.Delete(ID)
		}
	}
Timer.Start(id) starts a timer, Timer.Stop(id) stops a timer and returns the timers result.
There are a couple of errors in the class as posted:
  1. Debug.Timer.Init() should be Timer.Init()
  2. The variable Timer in the function Current() should be renamed to something else as it resets the class object.
The version below incorporates the above 2 changes:

Code: Select all

Class Timer {
   static _init := Timer.Init()
   static Timers := []
   
   Init() {
      DllCall("QueryPerformanceFrequency", "Int64P", F)
      this.Freq := F
   }
   
   Current() {
      DllCall("QueryPerformanceCounter", "Int64P", Count)
      return Count
   }
   
   Start(ID) {
      this.Timers[ID] := this.Current()
   }
   
   Stop(ID) {
      return (this.Current() - this.Timers.Delete(ID)) / this.Freq
   }
}
Windows 7 Pro (64 bit) - AutoHotkey v1.1+ (Unicode 32-bit)
User avatar
RUNIE
Posts: 281
Joined: 03 May 2014, 14:50
GitHub: Run1e

Re: jeeswg's benchmark tests

03 Jan 2018, 03:22

Yeah, that's an old version I barely even used. This is what I use now:

Code: Select all

Class Timer {
	__New() {
		static instance := new Timer()
		if instance
			return instance
		class := this.__Class
		%class% := this
		
		DllCall("QueryPerformanceFrequency", "Int64P", F)
		this.Freq := F
		this.Timers := {}
	}
	
	Current() {
		DllCall("QueryPerformanceCounter", "Int64P", Current)
		return Current / this.Freq
	}
	
	Start(ID) {
		this.Timers[ID] := this.Current()
	}
	
	Stop(ID) {
		return (this.Current() - this.Timers[ID]), this.Timers.Delete(ID)
	}
}
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

Re: jeeswg's benchmark tests

16 Jan 2018, 10:37

WINGETPOS V. GETWINDOWRECT (BUILT-IN COMMANDS/FUNCTIONS V. DLLCALL)

Code: Select all

q:: ;WinGetPos v. GetWindowRect
;... and checking the speed of VarSetCapacity, NumGet, calculations etc
;WinGetPos is about twice as fast
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
WinGet, hWnd, ID, A
vNum := 100000

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
{
	WinGetPos, vWinX, vWinY, vWinW, vWinH, % "ahk_id " hWnd
	;MsgBox, % Format("x{} y{} w{} h{}", vWinX, vWinY, vWinW, vWinH)
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
VarSetCapacity(RECT, 16, 0)
Loop, % vNum
	DllCall("user32\GetWindowRect", Ptr,hWnd, Ptr,&RECT)
;MsgBox, % Format("x{} y{} w{} h{}", vWinX, vWinY, vWinW, vWinH)
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
VarSetCapacity(RECT, 16, 0)
Loop, % vNum
{
	DllCall("user32\GetWindowRect", Ptr,hWnd, Ptr,&RECT)
	vWinX := NumGet(&RECT, 0, "Int"), vWinY := NumGet(&RECT, 4, "Int")
	, vWinW := NumGet(&RECT, 8, "Int")-vWinX, vWinH := NumGet(&RECT, 12, "Int")-vWinY
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
{
	VarSetCapacity(RECT, 16, 0)
	DllCall("user32\GetWindowRect", Ptr,hWnd, Ptr,&RECT)
	vWinX := NumGet(&RECT, 0, "Int"), vWinY := NumGet(&RECT, 4, "Int")
	, vWinW := NumGet(&RECT, 8, "Int")-vWinX, vWinH := NumGet(&RECT, 12, "Int")-vWinY
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	VarSetCapacity(RECT, 16, 0)
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

VarSetCapacity(RECT, 16, 0)
DllCall("user32\GetWindowRect", Ptr,hWnd, Ptr,&RECT)
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
{
	vWinX := NumGet(&RECT, 0, "Int"), vWinY := NumGet(&RECT, 4, "Int")
	, vWinW := NumGet(&RECT, 8, "Int")-vWinX, vWinH := NumGet(&RECT, 12, "Int")-vWinY
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

VarSetCapacity(RECT, 16, 0)
DllCall("user32\GetWindowRect", Ptr,hWnd, Ptr,&RECT)
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
{
	vWinX := NumGet(&RECT, 0, "Int"), vWinY := NumGet(&RECT, 4, "Int")
	, vWinR := NumGet(&RECT, 8, "Int"), vWinB := NumGet(&RECT, 12, "Int")
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

VarSetCapacity(RECT, 16, 0)
DllCall("user32\GetWindowRect", Ptr,hWnd, Ptr,&RECT)
vWinX := NumGet(&RECT, 0, "Int"), vWinY := NumGet(&RECT, 4, "Int")
, vWinR := NumGet(&RECT, 8, "Int"), vWinB := NumGet(&RECT, 12, "Int")
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	vWinW := vWinR-vWinX, vWinH := vWinB-vWinY
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
return
==================================================

WINGET ID: A (ACTIVE WINDOW) V. 'AHK_CLASS NOTEPAD'

Code: Select all

q:: ;specify active window versus 'ahk_class Notepad'
;'ahk_class Notepad' is about 26 times slower
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
vNum := 10000

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	WinGet, hWnd, ID, A
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	WinGet, hWnd, ID, ahk_class Notepad
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
return
==================================================

TWO-WAY COMPATIBILITY FUNCTIONS: WINGETPOS COMMAND V. CUSTOM WINGETPOS FUNCTION

Code: Select all

q::
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
vNum := 1000000

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	WinGetPos, vWinX, vWinY, vWinW, vWinH, A
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	WinGetPos(vWinX, vWinY, vWinW, vWinH, "A")
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
return

;commands as functions (AHK v2 functions for AHK v1) - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=37&t=29689

WinGetPos(ByRef X:="", ByRef Y:="", ByRef Width:="", ByRef Height:="", WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")
{
    WinGetPos X, Y, Width, Height, %WinTitle%, %WinText%, %ExcludeTitle%, %ExcludeText%
}
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

Re: jeeswg's benchmark tests

16 Jan 2018, 11:16

LOOPED CODE V. HARDCODED CODE

Prompted by this post:
How to genuinely compile a script? Is there any "loop" faster alternative? - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=39925

Code: Select all

;a single code line repeated (hardcoded)
;versus the same single code line looped
;seem to give roughly the same speeds
q:: ;looped lines v. hardcoded lines
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
vNum := 100000

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
{
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	vText := ""
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

;script contains this line repeated 10000 times:
;vText := ""
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
#Include %A_ScriptDir%\z repeated code line.ahk
#IncludeAgain %A_ScriptDir%\z repeated code line.ahk
#IncludeAgain %A_ScriptDir%\z repeated code line.ahk
#IncludeAgain %A_ScriptDir%\z repeated code line.ahk
#IncludeAgain %A_ScriptDir%\z repeated code line.ahk
#IncludeAgain %A_ScriptDir%\z repeated code line.ahk
#IncludeAgain %A_ScriptDir%\z repeated code line.ahk
#IncludeAgain %A_ScriptDir%\z repeated code line.ahk
#IncludeAgain %A_ScriptDir%\z repeated code line.ahk
#IncludeAgain %A_ScriptDir%\z repeated code line.ahk
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
return
just me
Posts: 5637
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: jeeswg's benchmark tests

16 Jan 2018, 11:21

Hi jeeswg,

#Include will be processed only once (see #Include / #IncludeAgain).

Edit: Sorry, must have been blind for a moment.
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

Re: jeeswg's benchmark tests

16 Jan 2018, 11:31

STRINGS

REPEAT STRING: LOOP V. VARSETCAPACITY
PARSE LINES: LOOP WITH OMITTED CHARACTERS V. STRREPLACE
INSTR: CASE SENSITIVE V. CASE INSENSITIVE
How to optimize the speed of a script as much as possible. - Page 5 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 30#p132230

REVERSE LIST: VARIABLES V. ARRAYS
How to optimize the speed of a script as much as possible. - Page 5 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 39#p140139

==================================================

@just me: Haha sorry, I fixed it, it was only incorrect momentarily.
Last edited by jeeswg on 20 Jan 2018, 14:54, edited 2 times in total.
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

Re: jeeswg's benchmark tests

16 Jan 2018, 11:49

STRING TESTS

RTRIM V. STRREPLACE

Prompted by this post:
Base64PNG_to_HICON() : Uses native PNG Decompression (requires WIN VISTA and later) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 92#p168792

Code: Select all

q:: ;RTrim v. StrReplace
;RTrim seems about 10 times faster for this task,
;this assumes that the text to be removed can only appear at the end of the string,
;clearly the functions are very different generally speaking,
;but are equivalent for this particular task
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
vNum := 10000
vText := ""
VarSetCapacity(vText, vNum*2)
Loop, % vNum/2
	vText .= "a"
Loop, % vNum/2
	vText .= "b"

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	vText2 := StrReplace(vText, "b")
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
;MsgBox, % StrLen(vText2) "`r`n" vText2

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
	vText2 := RTrim(vText, "b")
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
;MsgBox, % StrLen(vText2) "`r`n" vText2
return
==================================================

TRUNCATE STRING

Code: Select all

q:: ;truncate string
;using a custom function instead of SubStr can be 4 times faster
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
vNum := 2000
vLen := 1000000

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
{
	VarSetCapacity(vOutput, vLen*2, 1)
	;MsgBox, % StrLen(vOutput)
	vOutput := SubStr(vOutput, 1, vLen-1000)
	;MsgBox, % StrLen(vOutput)
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vNum
{
	VarSetCapacity(vOutput, vLen*2, 1)
	;MsgBox, % StrLen(vOutput)
	JEE_StrTruncate(vOutput, vLen-1000)
	;MsgBox, % StrLen(vOutput)
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
return

JEE_StrTruncate(ByRef vText, vLen)
{
	if A_IsUnicode
		NumPut(0, &vText, vLen << 1, "UShort")
	else
		NumPut(0, &vText, vLen, "UChar")
	VarSetCapacity(vText, -1)
}
Last edited by jeeswg on 17 Jan 2018, 06:53, edited 2 times in total.
User avatar
derz00
Posts: 497
Joined: 02 Feb 2016, 17:54
GitHub: derz00
Location: Middle of the round cube

Re: jeeswg's benchmark tests

16 Jan 2018, 12:06

Hi jeeswg, You might have missed this:
jNizM wrote:QueryPerformanceFrequency should not be called every time in a loop. It's enough if you call it once at scripts loadtime.
global InitQPC := DllCall("QueryPerformanceFrequency", "Int64P", QPF)
try it and see
...
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

Re: jeeswg's benchmark tests

16 Jan 2018, 12:12

- @derz00: AFAICT I've called it once in every example (and I checked again just now). There may have been an example where I used it multiple times that I since corrected. If you can spot any errors of any kind, do post them. Thanks.
- QueryPerformanceFrequency at the start of each example.
- QueryPerformanceCounter used twice for each test, to get the start/end times.
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

Re: jeeswg's benchmark tests

16 Jan 2018, 12:47

NUMBER: SWAP BYTES (e.g. 0x11223344 to 0x44332211)

Prompted by this post:
LoadPicture() from variable - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 62#p181462

Code: Select all

q:: ;swap bytes (UInt) (e.g. 0x11223344 to 0x44332211)
;using bitshifting/bitwise-and/bitwise-or is about 3 times faster than the two other methods that use NumGet/NumPut/DllCall
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
vNum := 0x11223344
vCount := 10000

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vCount
{
	vNum2 := (0xFF000000&vNum)>>24 | (0xFF0000&vNum)>>8 | (0xFF00&vNum)<<8 | (0xFF&vNum)<<24
	;MsgBox, % Format("0x{:08X}", vNum2)
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vCount
{
	VarSetCapacity(vData1, 4)
	, VarSetCapacity(vData2, 4)
	, NumPut(vNum, &vData1, 0, "UInt")
	, NumPut(NumGet(&vData1, 0, "UChar"), &vData2, 3, "UChar")
	, NumPut(NumGet(&vData1, 1, "UChar"), &vData2, 2, "UChar")
	, NumPut(NumGet(&vData1, 2, "UChar"), &vData2, 1, "UChar")
	, NumPut(NumGet(&vData1, 3, "UChar"), &vData2, 0, "UChar")
	, vNum2 := NumGet(&vData2, 0, "UInt")
	;MsgBox, % Format("0x{:08X}", vNum2)
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Loop, % vCount
{
	VarSetCapacity(vData1, 4)
	, VarSetCapacity(vData2, 4)
	, NumPut(vNum, &vData1, 0, "UInt")
	, DllCall("msvcrt.dll\_swab", "Ptr",&vData1, "Ptr",&vData2+2, "Int",2, "Cdecl")
	, DllCall("msvcrt.dll\_swab", "Ptr",&vData1+2, "Ptr",&vData2, "Int",2, "Cdecl")
	, vNum2 := NumGet(&vData2, 0, "UInt")
	;MsgBox, % Format("0x{:08X}", vNum2)
}
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
return
Helgef
Posts: 3295
Joined: 17 Jul 2016, 01:02
Contact:

Re: jeeswg's benchmark tests

17 Jan 2018, 06:48

Hello, thanks for sharing your tests :wave:.
It's enough if you call it once at scripts loadtime.
:thumbup:. Although, global InitQPC := DllCall("QueryPerformanceFrequency", "Int64P", QPF) is probably a mistake ;)
- QueryPerformanceFrequency at the start of each example.
You have it in the hotkey routine, not in the auto-exec. That is a minor offense, littering the examples with

Code: Select all

DllCall("QueryPerformanceCounter", Int64P,vQPC1)
; ...
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000)
instead of using a function is more annoying, for visual reasons, and also because you set the clipboard. And the q:: is annoying too :P. It would be convenient if you included the ASSUME ALWAYS: code.

Code: Select all

JEE_StrTruncate
Where is it?

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

Re: jeeswg's benchmark tests

17 Jan 2018, 06:59

- Re. 'assume always', what about what's convenient for me? The point is I'm trying to keep everything as uncluttered and stand-alone as possible, by keeping everything self-contained and avoiding the use of functions. Is there any problem re. *functionality*, if calling QueryPerformanceFrequency in every hotkey subroutine? (A separate but related point, why would doing Random new seed every time, cause a problem?)
- Come on, this is easy street: DllCall("QueryPerformanceCounter", Int64P,vQPC1), that doesn't need wrapping.
- This isn't too bad: MsgBox, % Clipboard := (((vQPC2-vQPC1)/vQPF)*1000).
- And q:: is cool, very cool.
- I try and make everything so you can just copy and paste to the bottom of your temporary testing script, and not need to flood your PC with individual separate scripts.
- JEE_StrTruncate has now been added above, thanks for mentioning it.
User avatar
nnnik
Posts: 3526
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: jeeswg's benchmark tests

17 Jan 2018, 07:04

I think this doesn't belong into the tutorials section as you only provide scripts and no explination or discussion as to which method is better and you don't even deliver any results of that tests.
It's like your saying "run this script and think about the results" something that is an unfairness to all the tutorials that were created through hard work.
Recommends AHK Studio
User avatar
jeeswg
Posts: 5403
Joined: 19 Dec 2016, 01:58
Location: UK

Re: jeeswg's benchmark tests

17 Jan 2018, 07:19

nnnik wrote:I think this doesn't belong into the tutorials section as you only provide scripts and no explination or discussion as to which method is better and you don't even deliver any results of that tests.
It's like your saying "run this script and think about the results" something that is an insult to all the people that try very hard to create their tutorials.
- @nnnik: This tutorial is perfectly acceptable as a tutorial. It's about explaining to people how to speed up their scripts. It is essentially an extension of this tutorial:
How to optimize the speed of a script as much as possible. - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=6413
- Some of the examples do provide results, otherwise at least a summary. Also, I may furnish some of them with more information, although I was interested in getting feedback on the examples, before publishing information in full. I like to do things thoroughly, sometimes that involves double-checking things.
- Btw re. explanations of why one method is better than another, anyone is welcome to contribute information, that I will then review and possibly incorporate. If I had more detailed behind-the-scenes information for some of these scripts, I would write an explanation. Can you help with some of these examples? Sometimes the explanation is simply: RegEx is slow, or, this approach happens to be slightly slower.
- On about half-a-dozen of my threads, you've appeared and stated that there is a problem, and not elaborated, therefore helping neither me, nor the readers. Please return to those pages and complete your posts, at present, those posts are an insult to all the people that try very hard to contribute to or learn from the forum. Btw I should warn you that your tutorials are not above criticism, there are a lot of criticisms that I could expand upon. Also, perhaps if you tried to think in a less linear way, and in a more associative way, you'd appreciate some of the things that I'm trying to do here, instead of jumping in with unwarranted criticisms. It's as though you're trying to find fault where there isn't any, instead of respecting and appreciating the author. I previously wrote to you a direct message, in a spirit of friendship, and welcome cooperating with you on projects in the future.

[EDIT:] Ah, you've toned down your post a bit, (although I don't see any Edit notification, perhaps that's an admin privilege,) to which I'll say, I looked over your GitHub scripts recently, looking to see if you'd done any nice scripts, and I enjoyed your 3D maze script, very nice.
User avatar
boiler
Posts: 2372
Joined: 21 Dec 2014, 02:44

Re: jeeswg's benchmark tests

17 Jan 2018, 08:56

jeeswg wrote:It's about explaining to people how to speed up their scripts.
I don't see it explaining anything. It's providing tools for people to use if they're interested in comparing the speed of different approaches. Even if or when it includes results, I don't see that as a tutorial.

I agree that this thread should be moved. Scripts and Functions seems to be the most appropriate destination. I am one that likes the Tutorials sub-forum to be fully "read" so it's highlighted when there is a new tutorial. Updates to this thread cause me to open it just to clear the "unread" indication for the sub-forum.

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 1 guest