Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?

Just starting out? Need help? Post your questions and find answers here.
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?

Post 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.)
The PureBASIC Archives: FOSS Resources:
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage

Post 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.
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage

Post 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.
The PureBASIC Archives: FOSS Resources:
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage

Post 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.
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage

Post 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
The PureBASIC Archives: FOSS Resources:
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage

Post 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.
The PureBASIC Archives: FOSS Resources:
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage

Post 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.
The PureBASIC Archives: FOSS Resources:
Barbarossa
User
User
Posts: 47
Joined: Fri Oct 12, 2012 8:50 am

Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?

Post 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
AZJIO
Addict
Addict
Posts: 2143
Joined: Sun May 14, 2017 1:48 am

Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?

Post by AZJIO »

Barbarossa
User
User
Posts: 47
Joined: Fri Oct 12, 2012 8:50 am

Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?

Post 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
AZJIO
Addict
Addict
Posts: 2143
Joined: Sun May 14, 2017 1:48 am

Re: Scintilla: SCI_GETDIRECTFUNCTION or ScintillaSendMessage()?

Post 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)
Post Reply