Page 1 of 1

[V2] ComboBox.add() Huge retardation

Posted: 19 Jun 2021, 22:30
by arcticir
On my computer, the add() for this example uses ~400 milliseconds. Is this normal?

Code: Select all

	MyGui := Gui()
	box:=MyGui.Add("ComboBox")

	r:=[]
	loop 100
		r.push(a_index)
	box.Delete()

	DllCall('QueryPerformanceCounter', 'Int64P', &a:=0)
	box.add(r) 
	DllCall('QueryPerformanceCounter', 'Int64P', &b:=0)
	MsgBox   Round((b - a) / 10000000, 6)

	box.Choose(44)
	MyGui.show()

Re: [V2] ComboBox.add() Huge retardation

Posted: 20 Jun 2021, 01:58
by swagfag

Code: Select all

#Requires AutoHotkey v2.0-a136

MyGui := Gui()
box:=MyGui.Add("ComboBox")

r:=[]
loop 100
	r.push(a_index)
box.Delete()

DllCall('QueryPerformanceCounter', 'Int64P', &a:=0)
box.add(r) 
DllCall('QueryPerformanceCounter', 'Int64P', &b:=0)
box.Choose(44)
MyGui.show()
MsgBox   Round((b - a) / 10000000, 6) ; 0.038695
ExitApp

Code: Select all

#Requires AutoHotkey v1.1.33.09
#NoEnv
#SingleInstance Force
SetBatchLines -1

Gui Add, ComboBox, HwndhCB

Loop 100
	r .= A_Index "|"

DllCall("QueryPerformanceCounter", "Int64P", a:=0)
GuiControl, , % hCB, % r
DllCall("QueryPerformanceCounter", "Int64P", b:=0)
Gui Show
MsgBox % Round((b - a) / 10000000, 6) ; 0.037114
ExitApp
both of these take anywhere between 35-50ms on my computer and cranking the number of elements makes them scale identically

Re: [V2] ComboBox.add() Huge retardation

Posted: 20 Jun 2021, 05:43
by just me
The v1 version needs about 80 ms on my 9 years old laptop (Intel i3-2310M, 2 cores at 2.10 GHz, 4 GB RAM, Win 10 64-bit, AHK U64). The v2 (a137) version is a bit faster.

Re: [V2] ComboBox.add() Huge retardation

Posted: 20 Jun 2021, 06:22
by just me
:arrow: Acquiring high-resolution time stamps

Code: Select all

	DllCall('QueryPerformanceFrequency', 'Int64P', &f:=0)
	MyGui := Gui()
	box:=MyGui.Add("ComboBox")

	r:=[]
	loop 100
		r.push(a_index)
	box.Delete()

	DllCall('QueryPerformanceCounter', 'Int64P', &a:=0)
	box.add(r)
	DllCall('QueryPerformanceCounter', 'Int64P', &b:=0)

	MsgBox   Round((b - a) * 1000 / f, 6) ; milliseconds

	box.Choose(44)
	MyGui.show()
Any difference?

Re: [V2] ComboBox.add() Huge retardation

Posted: 20 Jun 2021, 17:07
by arcticir
@just me
There is no difference. But I think I found the reason.
When I quit all the other AutoHotkey processes, the elapsed time reaches a reasonable ~30 ms or so.
And the ahk process that was affecting it loaded thousands of CreateWindowEx(), which uses WINAPI to customize the GUI.
Is this interference reasonable?

Re: [V2] ComboBox.add() Huge retardation

Posted: 20 Jun 2021, 18:30
by swagfag
can u not post code, so we dont have to waste time needlessly guessing??

Re: [V2] ComboBox.add() Huge retardation

Posted: 20 Jun 2021, 18:57
by arcticir
@swagfag
I pretend to understand what you're saying. That WINAPI-GUI code is so large and complex to use that I think it would be rude to release it lightly.

Re: [V2] ComboBox.add() Huge retardation

Posted: 21 Jun 2021, 10:21
by swagfag
if u run this script, which bypasses ahk and creates GUIs using CreateWindowEx(), ull see that the more u create, the longer it takes for windows to create them. on my computer, the first GUI takes 2ms and the 10000th - about 80ms
if u run ur ComboBox benchmark at any point during, ull also see that it takes variably longer to add the items
why is that? can windows not keep up with updating its internal window tracking structures? is it because there are too many windowProcs to call into? who knows.
its not like it matters anyway

Code: Select all

#Requires AutoHotkey v2.0-a137

Stats := Gui('+AlwaysOnTop')

Stats.Add('Text', , 'A_Index:')
Index := Stats.Add('Text', 'w100 yp')

Stats.Add('Text', 'xm', 'Total:')
Total := Stats.Add('Text', 'w100 yp')

Stats.Add('Text', 'xm', 'Per Window:')
PerWindow := Stats.Add('Text', 'w100 yp')

Stats.Show()

DllCall('QueryPerformanceFrequency', 'Int64*', &frequency := 0)
GUIs := []
DllCall('QueryPerformanceCounter', 'Int64*', &t0 := 0)
Loop 10000
{
	DllCall('QueryPerformanceCounter', 'Int64*', &t1 := 0)
	hwnd := makeGui()
	DllCall('QueryPerformanceCounter', 'Int64*', &t2 := 0)
	
	Index.Text := A_Index
	Total.Text := toMs(t0, t2)
	PerWindow.Text := toMs(t1, t2)

	GUIs.Push(hwnd) ; play with these
	; DllCall('DestroyWindow', 'Ptr', hwnd) ; play with these
}

MsgBox 'script has finished. OK to exit'

toMs(start, end) => Round(((end - start) * 1000) / frequency)  ' ms'

makeGui() {
	static wc
	if !IsSet(wc)
	{
		; typedef struct tagWNDCLASSW {
		;     0 UINT      style; 
		;     8 WNDPROC   lpfnWndProc; 
		;    16 int       cbClsExtra; 
		;    20 int       cbWndExtra; 
		;    24 HINSTANCE hInstance; 
		;    32 HICON     hIcon; 
		;    40 HCURSOR   hCursor; 
		;    48 HBRUSH    hbrBackground; 
		;    56 LPWSTR    lpszMenuName; 
		;    64 LPWSTR    lpszClassName; 
		; }
		wc := Buffer(72, 0)
		
		wndProc(hwnd, msg, wparam, lparam) => true
		static lpfnWndProc := CallbackCreate(wndProc)
		NumPut('Ptr', lpfnWndProc, wc, 8) ; lpfnWndProc

		static hInstance := DllCall('GetModuleHandle', 'Ptr', 0, 'Ptr')
		NumPut('Ptr', hInstance, wc, 24) ; hInstance

		static className := 'randomgui'
		NumPut('Ptr', StrPtr(className), wc, 64) ; lpszClassName

		DllCall('RegisterClass', 'Ptr', wc)
	}

	static WS_POPUP := 0x80000000
	static WS_CAPTION := 0xC00000
	static WS_SYSMENU := 0x80000
	static WS_MINIMIZEBOX := 0x20000
	static styles := WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX

	return DllCall('CreateWindowEx', 
		'UInt', 0, ; dwExStyle
		'Str', className, ; lpClassName
		'Str', 'random title', ; lpWindowName
		'UInt', styles, ; dwStyle
		'Int', 0, ; X
		'Int', 0, ; Y
		'Int', 100, ; nWidth
		'Int', 100, ; nHeight
		'Ptr', 0, ; hWndParent
		'Ptr', 0, ; hMenu
		'Ptr', hInstance, ; hInstance
		'Ptr', 0) ; lpParam
}