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
majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006

I'd like to hear any ideas you may have on syntax/usage.

I personaly disliike DllCall syntax a lot.
This is the one i found around that i like - its available in CInvoke, Lua, etc.. Now that AHK supports functions as values you could do it like thsi:

MsgBox = Declare( "user32", "MessageBox", "i=IAAI", "stdcall" )
%MsgBox%(....)

THird parameter describes return values and parameters and once defined function can be used as regular AHK function anywhere. This make it also easier to create library of declrations for common API things.
Posted Image

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
I'm not a fan of the abbreviated declaration. It need only be typed once, so it may as well be readable.

Now that AHK supports functions as values

You should know that is not true. Dynamic function calls work by name, so in your example, it would need to search the function list. This would likely negate any performance benefit.

This make it also easier to create library of declrations for common API things.

Do you mean to say it is somehow easier than the #DllFunction way?

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006

You should know that is not true.

Ye, I know, but from AHK programers point of view you don't consider how the thing is implemented. The consequence is that I can use functions as values, be it a hack or well thought out design.

You should know that is not true. Dynamic function calls work by name, so in your example, it would need to search the function list. This would likely negate any performance benefit.

I was talking about practical value. You asked for syntax ideas. I am sure something can be thought out to speed up the search if this way is choosen.

Do you mean to say it is somehow easier than the #DllFunction way?

I first time see now #DllFunction proposal. Its basicly the same, just the syntax is different. It may be better to use more common solution as you can copy/paste function definition from other languages that uses them. I also prefer functions over commands.
Posted Image

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

You asked for syntax ideas.

Yes, and I do appreciate your input, though I don't always show it. :)

I am sure something can be thought out to speed up the search if this way is choosen.

It will be optimised eventually. OTOH, I plan to eventually implement built-in LowLevel functionality, including the ability to call functions by pointer.

Its basicly the same, just the syntax is different.

The main benefit of #DllFunction would be performance - a built-in function is generated once, and references to the function are resolved at load-time. No matter how efficient searching for a function is, searching will take longer than not searching.

It may be better to use more common solution as you can copy/paste function definition from other languages that uses them.

I think that at least the DllCall type names should be reused, because they are familiar, consistent and already documented... Aside from that, I'd like the syntax to resemble a function declaration.

with a built-in version

?

Sorry, I hadn't noticed your post until now. I temporarily implemented SetPixel as a built-in function in a custom build of AutoHotkey (i.e. in C++). It did the very minimum of work: convert the input parameters to the required types (32-bit integers) and call gdi32\SetPixel directly.

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012

The main benefit of #DllFunction would be performance - a built-in function is generated once, and references to the function are resolved at load-time. No matter how efficient searching for a function is, searching will take longer than not searching.

IA uses tracing optimization rules for dynamic p/invokes - a method signature is created on the first DllCall() then stored in memory for subsequent calls (deferred JIT). AHKs DynaCall works in a similar way so it could be possible to cache certain objects. I oppose the idea of both DllCall() and #DllFunction, it should be one or the other.

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

I oppose the idea of both DllCall() and #DllFunction, it should be one or the other.

Everything can be done with function pointers, so why not do away with statically linked functions in C++? :roll: Even if DllCall() generates a perfectly optimized function for subsequent calls, it still needs to find that function next time to call it.

#DllFunction could generate a (script) function whose first parameter is a (native) function pointer to call, so the only remaining advantage of DllCall would be dynamic parameter/return types.

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012

why not do away with statically linked functions in C++?

Why introduce alternative syntax for something that does well on its own? That is code bloat, AutoHotkey already has many confusing quirks and inconsistencies.

Even if DllCall() generates a perfectly optimized function for subsequent calls, it still needs to find that function next time to call it.

Have you any benchmark results? Dynamic variables have to be dereferenced at runtime and that's pretty fast. I believe there is a negligible difference between tracing and compile time optimizations for DllCall() because as you said conventional type unboxing is the bottleneck. A #define macro makes more sense to me.

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

I believe there is a negligible difference between tracing and compile time optimizations for DllCall()

When you mention tracing and optimization, I think of determining where the most time is spent in order to more effectively optimize. I don't see how that could apply in this case, so I get the impression you're talking about something else. Could you please explain what you mean by a "tracing optimization"?

because as you said conventional type unboxing is the bottleneck.

Did I? I suppose it is true in the sense that it can't be avoided, but data conversion is not where a significant amount of time is spent.

(Btw, "type unboxing" does not apply to AutoHotkey. I suppose you mean conversion of strings to or from other types.)

A #define macro makes more sense to me.

I thought you were against alternative syntax? #define is nothing more than that, with no run-time benefits.

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012

Could you please explain what you mean by a "tracing optimization"?

I explained in a previous post that tracing would cache link states from DynaCall and reuse them for future calls to the same function. There are no method overloads in low level API which makes this possible.

x := DllCall("GetParent", "UInt", hwnd) ; first call to user32\GetParent - cache state from DynaCall
y := DllCall("GetParent", "UInt", hwnd2) ; dispatch to compiled link, changing only the parameter stack
; ...
DllCall("CloseHandle", "UInt", hfile) ; ... start over

data conversion is not where a significant amount of time is spent.

In this context I don't see what else it would be. Benchmarks would eliminate any guesswork.

"type unboxing" does not apply to AutoHotkey. I suppose you mean conversion of strings to or from other types.

Not everything is converted to strings, I seem to remember int, float and bool primitive types left in their form (in variables). Maybe I am thinking too much from CLR perspective.

I thought you were against alternative syntax? #define is nothing more than that, with no run-time benefits.

It is an often requested syntactic sugar with many uses beyond DllCalls. Provided your parser is written well enough #define can provide compile time benefits.

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

I explained in a previous post

I understood the concept; what I did not and still do not understand is your use of the term "tracing."

data conversion is not where a significant amount of time is spent.

In this context I don't see what else it would be. Benchmarks would eliminate any guesswork.

Did you see in one of my previous posts "After doing some more benchmarks..."? It was not a guess. I understand your scepticism, since I had also thought that way before performing the benchmarks.

There are no method overloads in low level API which makes this possible.

I know of a few instances where the same function is necessarily called with different parameter types. DllCall's type parameters would still need to be parsed in order to generate a unique "signature", so I'm not sure what exactly could be cached.

I seem to remember int, float and bool primitive types left in their form (in variables).

During expression evaluation, numeric results of operations are kept as __int64 or double, including when they are passed to built-in functions. However, they are always converted back to strings when stored in variables, including parameters of script functions. (See the first paragraph of Variables and Expressions.)

It is an often requested syntactic sugar with many uses beyond DllCalls.

I surely know that...

Provided your parser is written well enough #define can provide compile time benefits.

Define "compile time." What I meant by "run-time benefits" was increased performance or functionality. #define is purely text substitution, so does not offer that. I am not arguing against #define, but it is off-topic for this thread.

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012

I did not and still do not understand is your use of the term "tracing."

Its the name of a technique a researcher developed for Tamarin project but used in some way in many other scripting languages (Perl, PHP). You can search Adobe/mozilla blogs for details.

What I meant by "run-time benefits" was increased performance or functionality.

#DllFunction is a preprocessor feature with no benefits to the current DllCall() function everyone is used to. I went through the same thought process regarding p/invoke performance in IA and decided against innovating syntax. If you say tracing rules can't be applied to the C++ version it is unfortunate, but I have made a note to explore this at a later date.

#define is purely text substitution

It doesn't have to be. If your parser can tell the difference between "#define Add(a, B) (a + B)" and "#define Add(a, B) DllCall("test\Something", int, a, int, B)" you can bring everything #DllFunction was intended for without the added complexity on the users part.

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

#DllFunction is a preprocessor feature with no benefits to the current DllCall() function everyone is used to.

You are obviously not paying attention. #DllFunction, when implemented, will generate machine code equivalent to a built-in function.

... you can bring everything #DllFunction was intended for without the added complexity on the users part.

In other words, implement #DllFunction with different syntax. What is the difference from the user's perspective? I wasn't defending "#DllFunction" syntax, btw, but the functionality.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

You are obviously not paying attention...

Search the Forum. You will find ample evidence about the futility of arguing with Titan. Just ignore him. You can spend your time more productively.

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
Sadly, you obviously haven't yet understood how tracing or JIT works. Take some time to study them if you wish to continue this dialog.

implement #DllFunction with different syntax. What is the difference from the user's perspective?

Think about it; DllCall() has scope for improvement but you throw in #define and #DllFunction to the mix, in the end users will face a dilema akin to the := vs = problem. It's very common in the FOSS world to see many forks dying because developers believed their radical ideas would take off, not saying you have.

I wasn't defending "#DllFunction" syntax, btw, but the functionality.

I jumped in late in the discussion and all I saw was you advocating new syntax.

Laszlo its a shame you have nothing better to do than troll here. In fact its despicable you have to mention my name on the sly, if you're still holding past grudges (ones I forgot about because I actually have a life outside the interweb) you can take them up with me direct.

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

Sadly, you obviously haven't yet understood how tracing or JIT works.

What you are referring to is not tracing, but a specific technique which involves tracing. All I needed to hear was:

this blogger[/url]":16b3gf90]'Tamarin Tracing' is an implementation that uses a 'tracing jit'. This type of 'just in time compiler' traces code executing during hotspots and compiles it so when those hotspots are entered again the compiled code is run instead.

To paraphrase, it is a technique used to avoid compiling code that is not executed frequently. Now I see how this could be applied to AutoHotkey: Use the existing DllCall methods, and compile only for frequently-used calls. I am not convinced it would provide enough benefit over simply compiling every unique call.

Either way you need processing to find the relevant compiled function for each call, or to determine whether there is one. (That is not to say I won't try it, only that I expect #DllFunction to have better results.)

implement #DllFunction with different syntax. What is the difference from the user's perspective?

Think about it; DllCall() has scope for improvement but you throw in #define and #DllFunction to the mix,

I was drawing a comparison between #DllFunction and your suggestion about #define, not between #define/#DllFunction and optimising DllCall().

It's very common in the FOSS world to see many forks dying because developers believed their radical ideas would take off,

There need only be one user of AutoHotkey_L for development to continue.

I jumped in late in the discussion and all I saw was you advocating new syntax.

It would be wise to read the discussion before jumping into it.