Page 1 of 1
Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?
Posted: Tue Jan 03, 2017 3:36 pm
by Tristano
I have a question about usage of Scintilla gadget.
The
official documentation mentions that:
The fast way of controlling the Scintilla Edit Control is to call message handling function by yourself.
You can retrieve a pointer to the message handling function of the Scintilla Edit Control and call it directly to execute a command.
This way is much more faster than the SendMessage() way.
and then provides an example code:
Code: Select all
int (*fn)(void*,int,int,int);
void * ptr;
int canundo;
fn = (int (__cdecl *)(void *,int,int,int))SendMessage(
hwndScintilla,SCI_GETDIRECTFUNCTION,0,0);
ptr = (void *)SendMessage(hwndScintilla,SCI_GETDIRECTPOINTER,0,0);
canundo = fn(ptr,SCI_CANUNDO,0,0);
The same example has already been mentioned in another post in these forums (but the thread doesn’t discuss the advantages):
My question is:
- Is this approach “much more faster” also in PureBasic?
- Or PB’s ScintillaSendMessage() is already providing the faster interface to Scintilla component?
If I have understood correctly the original documentation, the advantage of making direct calls consists in the fact that you skip some intermediate functions. But does is really make such a big difference?
What is it that makes it “
much more faster”?
Should I then use this approach in PB code?
(I’ve seen it implemented in many examples, but so far only in old code dating back to when Scintilla was still not part of PureBasic but used via 3rd party header files; I couldn’t find a “modern” example using it.)
Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage
Posted: Tue Jan 03, 2017 4:09 pm
by Fred
You may need to do some speed test, but I don't think it's "much more faster" for real operations. The call itself is may be faster but if you spend most of the time in the function, you won't see a big difference.
Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage
Posted: Tue Jan 03, 2017 9:02 pm
by Tristano
Thanks @Fred,
It makes sense. After all, CPUs are so fast today that I doubt that it would make all that great difference — considering how slow a complex Lexer might be in comparison, if has lots of nested check with RegEx.
I think that document is actually quite old, from the early days of Scintilla — times when speed did matter much more than today.
One day I might try out some heavy duty script to benchmark a comparison of the two, just for the sake of satisfaction.
B.R.
Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage
Posted: Tue Jan 03, 2017 9:33 pm
by Tenaja
Tristano wrote:... considering how slow a complex Lexer might be in comparison, if has lots of nested check with RegEx....
If you are looking for performance improvements, get rid of RegEx, and manually roll your own parsing. RegEx is handy when you will be searching for "random" patterns within "random" strings, but with most Scintilla applications, you will be looking for specific strings.
Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage
Posted: Tue Jan 03, 2017 11:10 pm
by Tristano
Hi @Tenaja,
Tenaja wrote:RegEx is handy when you will be searching for "random" patterns within "random" strings, but with most Scintilla applications, you will be looking for specific strings.
I'm afraid for this specific project I'll have to use RegEx: Markdown parsing! Not so many though, but to catch Setex-style headers, and a few other markup syntaxes (with all their variants) they are needed. At least to start with; maybe some alternative code could be devised later on, once the whole thing is working, to match specific patterns in a less consuming way.
But hopefully it won't slow down too much the whole project.
I'll have to try and see it though, but I've seen other projects having faced the same dilemmas and having resorted to some RegEx to cover the minimum required syntaxes.
But I'll keep your advice in mind, and do some benchmarking with PB's Profiler with and without RegExs, to check how bad it gets.
Thanks!
Tristano
Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage
Posted: Wed Jan 04, 2017 12:37 pm
by Tristano
Just sharing here my tests...
I've been doing some benchmarking to compare Scintilla messaging performance using
ScintillaSendMessage() vs rirect calls with a prototype mapping to
SCI_GETDIRECTFUNCTION and even with
CallFunctionFast().
I'm using
ElapsedMilliseconds() to measure milliseconds differences in heavy For loops making message calls to Scintilla.
So far the performance differences are negligible: around 10 millisenconds for loops > 20000 — and these differences are most probably due to the OS doing other stuff in the background, because the values float from test to test. I doubt that any real case scenario would envolve more message calls than these tests.
But so fare I've only tested with
#SCI_APPENDTEXT messages. Not sure if dirrent messages can affect performance in different ways.
I was digging furture into Scintilla documentation on the issue:
http://www.scintilla.org/ScintillaDoc.html#DirectAccess
On Windows, the message-passing scheme used to communicate between the container and Scintilla is mediated by the operating system SendMessage function and can lead to bad performance when calling intensively. To avoid this overhead, Scintilla provides messages that allow you to call the Scintilla message function directly.
While faster, this direct calling will cause problems if performed from a different thread to the native thread of the Scintilla window in which case SendMessage(hSciWnd, SCI_*, wParam, lParam) should be used to synchronize with the window's thread.
This feature also works on GTK+ but has no significant impact on speed.
From version 1.47 on Windows, Scintilla exports a function called Scintilla_DirectFunction that can be used the same as the function returned by SCI_GETDIRECTFUNCTION. This saves you the call to SCI_GETDIRECTFUNCTION and the need to call Scintilla indirectly via the function pointer.
Scintilla documentation stresses in many places this overhead issue, and performance hit. Maybe on very old PCs it really does make a difference. But I can't measure any noticeable difference on my PC.
The last passage about
Scintilla_DirectFunction caught my attentions. Is this function available from PureBasic?
Can this function be imported accessed somehow?
Also, it seems that the performance issue is Windows-related only, and that direct calls are not a good idea when using threads.
So I guess that because of the latter
ScintillaSendMessage() must be mediated by MS Windows SendMessage functions, in order to work well with threads.
Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage
Posted: Wed Jan 04, 2017 2:53 pm
by Tristano
From further reading around, I seem to understand that performance issues might appear when the application hosting the Scintilla control has many windows and controls — and maybe more then one Scintilla control. In such cases, sending messages to Scintilla thorugh Windows' message might add overheard because of Windows handling messages for all other controls, while directly calling the target Scintilla control message function could be faster.
I've found and interesting project:
CScintillaCtrl, CScintillaView & CScintillaDoc, freeware MFC classes to encapsulate Scintilla:
http://www.naughter.com/scintilla.html
Among its features it offers a wrapper to Scintilla direct function calls which han an optional boolean parameter to allow multi threaded apps to fallback on Scintilla's default SendMessage:
- Uses the direct access functions provided by Scintilla to improve performance. Multi threaded code can still use SendMessage by calling the method SetCallDirect with a FALSE parameter value.
I like this approach, its transparent to the user and it would be useful to adopt it in any Scintilla libraries, so that if multi threads are used there is no need to rewrite all calls but just set to false the required parameter, while in standard use it would offer the benefit of direct calls.
I guess that direct calls are the best way to go. If the project remains small, no evident benefits might ensue, but neither it would harm. But once the project gets bigger, there might be benefits from it — and starting off with the right foot is better than rewriting all the calls.
Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?
Posted: Fri Feb 17, 2023 11:23 pm
by Barbarossa
Sorry to dig up this old thread but I am trying to implement the SCI_GETDIRECTFUNCTION in PureBasic but I cannot seem to get it to work.
Basically I need to translate the C-code from the manual to PureBasic:
Code: Select all
#include "Scintilla.h"
SciFnDirect pSciMsg = (SciFnDirect)SendMessage(hSciWnd, SCI_GETDIRECTFUNCTION, 0, 0);
sptr_t pSciWndData = (sptr_t)SendMessage(hSciWnd, SCI_GETDIRECTPOINTER, 0, 0);
// now a wrapper to call Scintilla directly
sptr_t CallScintilla(unsigned int iMessage, uptr_t wParam, sptr_t lParam){
return pSciMsg(pSciWndData, iMessage, wParam, lParam);
}
Does anyone knows how to do this?
Many thanks in advance.
John
Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?
Posted: Fri Feb 17, 2023 11:42 pm
by AZJIO
Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?
Posted: Sat Feb 18, 2023 11:18 am
by Barbarossa
Thanks, but that is not helping me at all.
It would benefit this thread if the answer was posted right here.
Surely it cannot be more than a couple of lines, right?
John
Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?
Posted: Sat Feb 18, 2023 1:51 pm
by AZJIO
I'm not sure if it will work for you, since in PureBasic the Scintilla object is built into the executable and does not require all this manipulation. I can't guess how you are going to use it. There is no universal magic tool, everything depends on the task and this task may not correspond to my ideas about your requests.
Code: Select all
OpenLibrary(0, "Scintilla.dll")
If IsLibrary(0)
pSciMsg = GetFunction(0, "Scintilla_DirectFunction")
If Not pSciMsg
MessageRequester("", "Failed to get function")
End
EndIf
Else
MessageRequester("", "library not found")
End
EndIf
Procedure CallScintilla(*point, msg, param1 = 0, param2 = 0)
If *point
ProcedureReturn pSciMsg(*point, msg, param1, param2)
Else
ProcedureReturn 0
EndIf
EndProcedure
*sciptr = SendMessage_(ScintillaHandle, #SCI_GETDIRECTPOINTER, 0, 0) ; get current Scintilla
Debug CallScintilla(*sciptr, #SCI_GETCODEPAGE)