PixelSearch faster than Gdip on benchmarks?

Get help with using AutoHotkey and its commands and hotkeys
User avatar
WAZAAAAA
Posts: 75
Joined: 13 Jan 2015, 19:48

PixelSearch faster than Gdip on benchmarks?

13 Jan 2015, 22:02

So I was doing some benchmarks to find out what is the fastest way to make AHK continuously monitor a single pixel and do an action when a specific color is detected.

My weird results so far, in order of speed from the fastest to the slowest, are the following:
(time elapsed for doing the same action looped for 1 million times)
PixelSearch - 8.16
PixelGetColor - 14.87
GDI+ code by Linear Spoon - 20.24
PixelGetColor Alt - 29.32
PixelGetColor Slow - 36.30
PixelSearch Fast - 46.89
GDI+ by me - more than 15 minutes...
(no differences detected between RGB and BGR PixelSearch options, PixelGetColor was untested)

Pretty much everyone says that the Gdip library is 3 times faster than the default PixelSearch so I must be doing something terrible in my code...

Here are the benchmark codes I have used for:
(please note, Continue should be used WHEN POSSIBLE instead of Sleep -1, benchmarks are done faster that way)

PixelGetColor test

Code: Select all

#NoEnv
#KeyHistory 0
#MaxThreads 255
#MaxMem 4095
#MaxThreadsBuffer On
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
ListLines Off
Process, Priority, , R
SetTitleMatchMode fast
SetBatchLines, -1
SetKeyDelay, -1, -1, -1
SetMouseDelay, -1
SetWinDelay, -1
SetControlDelay, -1
SetDefaultMouseSpeed, 0
QPC()
{
    Static QPCLAST, QPCNOW, QPCFREQ

    if not QPCFREQ
        if not DllCall("QueryPerformanceFrequency", "Int64 *", QPCFREQ)
            return "Fail QPF"

    QPCLAST=%QPCNOW%
    if not DllCall("QueryPerformanceCounter", "Int64 *", QPCNOW)
        return "Fail QPC"

    return (QPCNOW-QPCLAST)/QPCFREQ
}

LastTickCount=%A_TickCount%
QPC()
loop 1000000
{
pixelgetcolor, test, 100, 100
if (test=0xFFFFFF)
sleep -1
}
msgbox, % "TickCount`n" A_TickCount-LastTickCount "`n`nQueryPerformanceCounter`n" QPC()
PixelSearch test

Code: Select all

#NoEnv
#KeyHistory 0
#MaxThreads 255
#MaxMem 4095
#MaxThreadsBuffer On
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
ListLines Off
Process, Priority, , R
SetTitleMatchMode fast
SetBatchLines, -1
SetKeyDelay, -1, -1, -1
SetMouseDelay, -1
SetWinDelay, -1
SetControlDelay, -1
SetDefaultMouseSpeed, 0
QPC()
{
    Static QPCLAST, QPCNOW, QPCFREQ

    if not QPCFREQ
        if not DllCall("QueryPerformanceFrequency", "Int64 *", QPCFREQ)
            return "Fail QPF"

    QPCLAST=%QPCNOW%
    if not DllCall("QueryPerformanceCounter", "Int64 *", QPCNOW)
        return "Fail QPC"

    return (QPCNOW-QPCLAST)/QPCFREQ
}

LastTickCount=%A_TickCount%
QPC()
loop 1000000
{
pixelsearch, , , 100, 100, 100, 100, 0xFFFFFF
if errorlevel = 0
sleep -1
}
msgbox, % "TickCount`n" A_TickCount-LastTickCount "`n`nQueryPerformanceCounter`n" QPC()
Gdip test

Code: Select all

#include gdip.ahk
PixelSearch(x, y, color)
{ 
    pToken := GDIP_StartUp()
    pBitMap := GDIP_BitmapFromScreen()
    ARGB := GDIP_GetPixel(pBitMap, x, y)
    Gdip_DisposeImage(pBitmap)
    Gdip_Shutdown(pToken)
    If (ARGB = color)
        Return true
    Else
        Return false
}
#NoEnv
#KeyHistory 0
#MaxThreads 255
#MaxMem 4095
#MaxThreadsBuffer On
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
ListLines Off
Process, Priority, , R
SetTitleMatchMode fast
SetBatchLines, -1
SetKeyDelay, -1, -1, -1
SetMouseDelay, -1
SetWinDelay, -1
SetControlDelay, -1
SetDefaultMouseSpeed, 0
QPC()
{ 
    Static QPCLAST, QPCNOW, QPCFREQ

    if not QPCFREQ 
        if not DllCall("QueryPerformanceFrequency", "Int64 *", QPCFREQ)
            return "Fail QPF"

    QPCLAST=%QPCNOW%
    if not DllCall("QueryPerformanceCounter", "Int64 *", QPCNOW)
        return "Fail QPC"

    return (QPCNOW-QPCLAST)/QPCFREQ
}

LastTickCount=%A_TickCount%
QPC()
loop 1000000
{
If PixelSearch(100,100,4294967295)
sleep -1
}
msgbox, % "TickCount`n" A_TickCount-LastTickCount "`n`nQueryPerformanceCounter`n" QPC()

My request is: can anyone help me to create a responsive code using the Gdip library?



EDIT:
Spoiler
Last edited by WAZAAAAA on 27 Oct 2016, 05:59, edited 4 times in total.
YOU'RE NOT ALEXANDER
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: PixelSearch faster than Gdip on benchmarks?

14 Jan 2015, 00:01

There is a lot of overhead in the GDIP_BitmapFromScreen call. It uses GDI to copy the screen into a bitmap, then converts that into a format usable by GDIP (which is GDI "plus").

If your only goal is to read a single pixel off the screen repeatedly, you don't even need GDIP. You can and should stick with plain GDI. On my machine this performs about as well as PixelGetColor. It has the extra advantage of not needing to load and unload gdiplus.dll each loop iteration, as the dll for GDI is already loaded by AHK. Unfortunately I can't explain why PixelSearch is fastest for you, it is about the same speed as PixelGetColor for me.

Code: Select all

#include gdip.ahk

;Note color should be 0x00BBGGRR to match the return value of GetPixel
PixelSearch(x, y, color)
{ 
  ScreenDC := GetDC()
  point := DllCall("GetPixel", "ptr", ScreenDC, "int", x, "int", y)
  ReleaseDC(ScreenDC)
  return (point = color)
}
#NoEnv
#KeyHistory 0
#MaxThreads 255
#MaxMem 4095
#MaxThreadsBuffer On
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
ListLines Off
Process, Priority, , R
SetTitleMatchMode fast
SetBatchLines, -1
SetKeyDelay, -1, -1, -1
SetMouseDelay, -1
SetWinDelay, -1
SetControlDelay, -1
SetDefaultMouseSpeed, 0
QPC()
{ 
    Static QPCLAST, QPCNOW, QPCFREQ

    if not QPCFREQ 
        if not DllCall("QueryPerformanceFrequency", "Int64 *", QPCFREQ)
            return "Fail QPF"

    QPCLAST=%QPCNOW%
    if not DllCall("QueryPerformanceCounter", "Int64 *", QPCNOW)
        return "Fail QPC"

    return (QPCNOW-QPCLAST)/QPCFREQ
}

LastTickCount=%A_TickCount%
QPC()
loop 1000000
{
If PixelSearch(100,100,0xFFFFFF)
  continue  ;Changed from sleep, -1 (tested the others with the same modification)
}
msgbox, % "TickCount`n" A_TickCount-LastTickCount "`n`nQueryPerformanceCounter`n" QPC()
If you look at AHK's source for PixelGetColor, you'll see it uses almost the same code.

Code: Select all

HDC hdc = use_alt_mode ? CreateDC(_T("DISPLAY"), NULL, NULL, NULL) : GetDC(NULL);
	if (!hdc)
		return SetErrorLevelOrThrow();

	COLORREF color = GetPixel(hdc, aX, aY);
	if (use_alt_mode)
		DeleteDC(hdc);
	else
		ReleaseDC(NULL, hdc);
I have only heard of GDIP being faster than ImageSearch, and even that requires a special mcode function.
User avatar
WAZAAAAA
Posts: 75
Joined: 13 Jan 2015, 19:48

Re: PixelSearch faster than Gdip on benchmarks?

19 Jan 2015, 22:40

Thanks for "Continue"... I totally forgot about its existence
Thanks for the code too, I benchmarked that and put it on the first post. Gdip is now usable but still ends up being slower than PixelSearch like you've pointed out.

But I wonder if Gdip's PixelSearch can end up having an edge speed wise compared to the default when searching for a range of colors (pretty much like with the Variation option of the default PixelSearch), or when it searches for a larger X Y screen area (monitoring more than one pixel)? How to test those two with your code?
YOU'RE NOT ALEXANDER

Return to “Ask For Help”

Who is online

Users browsing this forum: boiler, Odlanir, pn4265 and 246 guests