nppexec icon indicating copy to clipboard operation
nppexec copied to clipboard

CAnyRichEdit::AddStr() is very slow and should be optimized

Open d0vgan opened this issue 2 years ago • 1 comments

When NppExec performs a lot of actions within a script (for example, by running some loop) and NppExec's internal messages are enabled, most of the time of the script execution is taken by not NppExec's ScriptEngine itself, but by CNppExecConsole::PrintMessage that callsCAnyRichEdit::AddStr that, in its turn, has the following implementation:

SendMessage(hRichEdit, EM_EXGETSEL, 0, (LPARAM) &cr);
SendMessage(hRichEdit, WM_SETREDRAW, FALSE, 0);
SendMessage(hRichEdit, EM_EXSETSEL, 0, (LPARAM) &CHARRANGE{-1, -1});
SendMessage(hRichEdit, EM_SETCHARFORMAT, (WPARAM) dwOptions, (LPARAM) &cf);
SendMessage(hRichEdit, EM_REPLACESEL, FALSE, (LPARAM) cszText);
SendMessage(hRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
SendMessage(hRichEdit, EM_SCROLLCARET, 0, 0);
SendMessage(hRichEdit, WM_SETREDRAW, TRUE, 0);
if (InvalidateRect(hRichEdit, NULL, TRUE))
    UpdateWindow(hRichEdit);

And when I'm talking about most of the time of the script execution, here is what I mean:

  • a script with a silent loop of 10000 iterations takes around 1 second to complete when the internal messages are disabled.
  • the very same script takes around 2 minutes and 30 seconds when the internal messages are enabled (i.e. when each command prints something to NppExec's Console, thus calling CAnyRichEdit::AddStr).

This is the difference I'm talking about: 1 second vs. 2 minutes and 30 seconds. Definitely, something needs to be improved here. But once I change something in the implementation of CAnyRichEdit::AddStr - for example, if I remove SendMessage(hRichEdit, WM_SETREDRAW, FALSE, 0), SendMessage(hRichEdit, WM_SETREDRAW, TRUE, 0), InvalidateRect(hRichEdit, NULL, TRUE) and UpdateWindow(hRichEdit) - it takes even more time than before (I got the results of 3 minutes and 30 seconds)! If anyone has ideas/suggestions of how it can be improved, please let me know.

d0vgan avatar Aug 19 '23 20:08 d0vgan

Here is a test script. In its current form it takes around 1 second to complete, but once you change the very first line to npe_console local -- m+, it will take around 2 minutes and 30 seconds:

npe_console local -- m-
set local N = 20
set local i = 0

:1
set local i ~ $(i) + 1
if $(i) >= 8400 goto 3
if~ $(i) % 100 != 0 goto 1
set local k ~ ord a
set local kk = 0
:2
set local c ~ chr $(k)
set local v ~ strupper $(c)
set local $($(c)_) = $($(c)_)$(v)
set local k ~ $(k) + 1
set local kk ~ $(kk) + 1
if $(kk) < $(N) goto 2
goto 1

:3
set local k ~ ord a
set local kk = 0
:4
set local c ~ chr $(k)
echo $($(c)_)
set local k ~ $(k) + 1
set local kk ~ $(kk) + 1
if $(kk) < $(N) goto 4

d0vgan avatar Aug 19 '23 20:08 d0vgan