Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Opinions wanted : Optimized DllCall()


  • Please log in to reply
92 replies to this topic
Pil
  • Members
  • 55 posts
  • Last active: Mar 25 2014 05:00 AM
  • Joined: 26 Feb 2006
What I like in AHK:
The command style is developed in a logical way so commands are easy to learn, use, and to remember. AHK is small, fast and portable. AHK has an excellent logical written and well structured detailed help file. AHK has a busy forum without just a few experts showing they know it all, discouraging others to show what they can do. On AHk’s forum everyone is participating and sharing there work and that is having fun. I can go on mentioning more positive points but what I want to say is that AHK is perfect for me, and doesn’t need any change. There is just one thing I have to complain about. And that is the speed of the DllCall. Let us be honest. You can program in C++ or Basic or Delphi etc. but when you want to do things happen exactly the way you want to, you need native programming. Using the API calls. And AHK also gives you this possibility. That is why the DllCall is so important. Single calls are no problem, but when you put the DllCall in a loop, for data transfer to ports or in converting functions and so on, things slow down terribly. I suspect it’s because variables are dimensioned in every call, so in a loop this will cost a lot of time. If this is true I would like to suggest a separation off call and dimensioning. The code below is a part of a color picker project, the same as used for instance in Photoshop, where in a rectangle with the X and Y axis the red and green values are shown and with a slider the green component (255 each) can be changed. This way you can actually move trough the RGB color cube and pick any of the 16.777.216 colors. A fast drawing is needed here to see the colors changing smoothly.
Below you see two codes drawing exactly the same picture. One written in AHK, other in VB, using the same Gdi32 dll call.
On my old MMX 233 the needed time is nine seconds for AHK code, and 0,5 second using VB You can test compiled versions downloading from here <!-- m -->https://ahknet.autoh...VB40032.DLL<!-- m -->
Please, if you have the same opinion, that an optimized DllCall is important for AHK send a comment or simply write “I agree”, to reinforce my request.
Regards
Noel


Code AHK:
SetBatchLines -1
Gui,Add,Text, vmy_text x10 y270 h60 w250, Please wait.
Gui,Show,w259 h290, ColorPicker
hDC := DllCall("GetDC", UInt, WinExist("ColorPicker")) 
x := 0
b := 0 ; blue component slider value
start_time := a_tickCount
Loop 255
{   
   x++
   y = 0
   loop 255
      {
	  y++
      color :=  (b << 16) | (y << 8) | x 
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      }
}
needed_time := (a_tickCount - start_time)/1000

GuiControl,,my_text, This drawing is done in %needed_time% seconds 
Return

GuiClose:
ExitApp

VB Code:
VERSION 4.00
Begin VB.Form ColorPicker 
   Caption         =   "Colorpicker"
   ClientHeight    =   4335
   ClientLeft      =   4680
   ClientTop       =   1995
   ClientWidth     =   3870
   Height          =   4740
   Left            =   4620
   LinkTopic       =   "Form1"
   ScaleHeight     =   289
   ScaleMode       =   3  'Pixel
   ScaleWidth      =   258
   Top             =   1650
   Width           =   3990
   Begin VB.Label Label1 
      Alignment       =   2  'Center
      Caption         =   "Please wait."
      Height          =   495
      Left            =   120
      TabIndex        =   0
      Top             =   4080
      Width           =   3615
   End
End
Attribute VB_Name = "ColorPicker"
Attribute VB_Creatable = False
Attribute VB_Exposed = False


Private Declare Function SetPixel Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal crColor As Long) As Long

Private Sub cmdClose_Click()
   Unload Me            ' Unload this form.
End Sub


Private Sub Form_Load()
 Dim X As Byte, Y As Byte, r As Integer, g  As Integer, b As Integer
     Me.AutoRedraw = True
    
start_time = Timer
    For X = 0 To 254
    r = r + 1
    g = 0
      For Y = 0 To 254
      g = g + 1
      SetPixel Me.hdc, X, Y, RGB(r, g, b)
      Next Y
    Next X
 needed_time = Timer - start_time
  
Label1.Caption = "This drawing is done in " + CStr(needed_time) + " seconds"
   
End Sub


Sivvy
  • Members
  • 726 posts
  • Last active: Apr 23 2010 02:50 PM
  • Joined: 21 Jul 2008
I think your looking for the "Wish List" Forum. Otherwise, your suggestion seems logical... But whether or not it's a priority over the current To-Do list is another story.

Pil
  • Members
  • 55 posts
  • Last active: Mar 25 2014 05:00 AM
  • Joined: 26 Feb 2006
OK
My choise was the help forum because it´s the most visited.
Thank´s for your opinion

BoBo²
  • Guests
  • Last active:
  • Joined: --

My choise was the help forum because it´s the most visited.

But posting at the "wrong" section could end up with "the most ignored" thread too. :wink:

Pil
  • Members
  • 55 posts
  • Last active: Mar 25 2014 05:00 AM
  • Joined: 26 Feb 2006
Yes, my first idea was to put it on the wish list, but when I (yes, for the first time) visited it, I didn´t see many replies and I want to know if there are more users who want to get the maximum out of AHK.
I am not asking to implement COM or such things, because I know AHK is intended to be a utility.
Yet Cris gave us the DLLCall so who wants to can try things on their own.
And that was absolutly the right decision I think.
Unfortunately in 90% of my projects I suffer with the speed Of the call, and I hate this because I am in love with AHK and I don´t want to use other languages.
Lovers mostly have a stupid behavior so you have to forgive me :)

BoBo²
  • Guests
  • Last active:
  • Joined: --

Lovers mostly have a stupid behavior so you have to forgive me

Amen. :D Don't be afraid, the 'General Chat' section is frequented quite good.
To move this thread to there, is done with a snap. Choose WrongSectionAlert only once as the threads username, and there's a 89.34% chance it'll get moved ASAP. 8)

Pil
  • Members
  • 55 posts
  • Last active: Mar 25 2014 05:00 AM
  • Joined: 26 Feb 2006

Choose WrongSectionAlert

Where?

WrongSectionAlert
  • Guests
  • Last active:
  • Joined: --
There (to the left of this line). :wink:

Moderator!!
  • Guests
  • Last active:
  • Joined: --
i usually don't move topics made by registered long-standing members, without asking them.

Pil?

Serenity
  • Members
  • 1271 posts
  • Last active:
  • Joined: 07 Nov 2004
I think your post would be more noticed in the Wish List forum where the post flow is slower, and might be more likely read by people who use DllCall intensively since this forum is mostly used by people needing help with their scripts. I would suggest adding a poll and changing the title to something more descriptive.

I appreciate your example as it demonstrates what can be done with DllCall and the limitation of using it repeatedly. (On my system it takes 2-4 seconds to complete). I haven't noticed any delay using DllCall but then I only use it once or twice in a script.

I think if DllCall were more accessible more people would use it, and probably more often. I imagine the majority of AutoHotkey users don't use DllCall that much so optimization is for a minority user base, so it's probably less of a priority.
"Anything worth doing is worth doing slowly." - Mae West
Posted Image

Pil
  • Members
  • 55 posts
  • Last active: Mar 25 2014 05:00 AM
  • Joined: 26 Feb 2006
Moderator:

i usually don't move topics made by registered long-standing members, without asking them. Pil?

Yes, please move this topic to the Wish List Forum.
Thank you.

[ Moderator!: Done! ]

Serenity:
Thank you for testing the code.
Maybe it´s interesting adding a poll about how many people use the DllCall, and I think you will have a surprise.
For me it´s one of the most important commands.
I mostly use it for accessing the hardware ports. If you have a minute you can see some of my work at the site <!-- w -->www.tiod.hpg.com.br<!-- w --> It is the only place I have something in an english version. All programs are made in AHK, because when I started I needed to send characters and didn´t know how to this in Basic. Now I know to do this with a simple api call.
I work with very slow computers because I have no financial help and have to buy them myself for the project. I don´t earn one single nickel with this. Just helping people in a country where doesn´t exist any help for them. On this moment rewriting all programs in basic would be a lot of work. All comands in AHK are optimized, why not the DllCall? Im not talking about something new, but about an existing function that could work at least as good as in other languages.

Krogdor
  • Members
  • 1391 posts
  • Last active: Jun 08 2011 05:31 AM
  • Joined: 18 Apr 2008

I am not asking to implement COM or such things, because I know AHK is intended to be a utility.


COM has been implemented through a functions which were made by Sean.



Anyway, I never use DllCall enough to notice any delay—but I suppose this suggestion makes sense, although perhaps not as high priority as many other things on the To-Do list.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
If you want to test the speed of the dll calls, it was better removing the other 2 commands from the inner loop. In my PC it sped up the drawing from 0.73s to 0.58s. Also, the loop itself has an overhead, which we can reduce (for the tests) by partial unrolling:
Loop 255 {
   x++
   y = 0
   loop 17 {
      ;y++
      ;color :=  (b << 16) | (y << 8) | x
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y,Int,color)
      }
}
It reduced the running time slightly (from 0.58s to 0.57s), proving that not the loop, but these dllcall’s are indeed very slow.

One can try making the type qualifiers literal strings:
DllCall("SetPixel","Int",hdc,"UChar",x,"UChar",y,"Int",color)
This does not bring any significant change in speed.

For keeping the functionality, you can put the assignments inside the dllcall’s, although the order of parameter evaluation is not specified in AHK, therefore it may not work in a future version. Also, a few percent speedup is possible if the dllcall’s are separated by commas, making them parts of a single expression. The inner loop is:
loop 17 {
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(b<<16)|(y<<8)|x)
   }
These bring a speedup of 14% only (0.73/0.64), by removing most overhead outside of the dllcall’s.

In this particular example another couple of percents speedup is possible with moving the unchanging part of the expression outside of the inner loop. All together 20% (0.73s-->0.61s):
Loop 255 {
   x++
   z := (b<<16)|x
   y = 0
   loop 17 {
      DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
     ,DllCall("SetPixel",Int,hdc,UChar,x,UChar,y++,Int,(y<<8)|z)
   }
}


Pil
  • Members
  • 55 posts
  • Last active: Mar 25 2014 05:00 AM
  • Joined: 26 Feb 2006

Pil wrote: I am not asking to implement COM or such things, because I know AHK is intended to be a utility.

You are right. I was not clear here. I meant to say :"I am not asking to implement COM like years ago people asked for it and the Dllcall didn´t yet exist .

COM has been implemented through a functions which were made by Sean.

Right again, and these funcions are using the DllCall that shows again how important the DllCall is.

Pil
  • Members
  • 55 posts
  • Last active: Mar 25 2014 05:00 AM
  • Joined: 26 Feb 2006
Laszlo you always surprise me by making things working somehow better. I am glad with your confirmation

proving that not the loop, but these dllcall’s are indeed very slow.

The example however was only to show the problem visually. The real problem I have, is data transfer on ports with the WinIO.dll, byte by byte. And also conversion functions. Like you can see on the site I already mentioned above http://www.tiod.hpg.com.br I am progressing and the need for speed is absolute. Or faster dllCall or rewriting everything.

When I looked up items on the wish list and then looked at the changes made in the shown in the changelog list, my hope to see something realized fell down like a stone. I don´t know if all these wishes are expected to be realized in a version 2. I just hope it won´t be an inflated AutoIt thing with al those case else bells and while i am tired stuff. I like AHK because it´s clean, just all you need. (is love). As far as I know only Chris makes changes, and that´s allright, he is the author, and he gave us the DllCall, our tool to make complements; the door to freedom with wich for instance Krogdor well said Sean implemented the COM objects. A pity that it is a straight door.
My english is poor and I need help in argumenting, that if their is only one door it has to be big enough. So the only hope I have is that all members who contributed so much extending AHK with the ONLY tool existing, join this request.

PS You must have a supermachine to do this test in ? seconds