News:

Accounts with zero posts and zero activity during the last months will be deleted periodically to fight SPAM!

Main Menu

Flood of wxEVT_SCI_MODIFIED and wxEVT_SCI_CHANGE messages

Started by ollydbg, July 18, 2013, 05:14:50 PM

Previous topic - Next topic

ollydbg

When loading a project, I see a lot of wxEVT_SCI_MODIFIED and wxEVT_SCI_CHANGE messages. (You can enable the TRACE of codecompletion.cpp to see them)

I just track down, and I see that: UpdateEditorSyntax(editor); (mostly in CodeCompletion::OnParserEnd()) will cause such message.

Can we avoid them? It's annoying.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

MortenMacFly

Quote from: ollydbg on July 18, 2013, 05:14:50 PM
Can we avoid them? It's annoying.
I think not really. It iterates (only!) across the open editors to update the syntax highlighting. If you skip the call to UpdateEditorSyntax() or avoid the event the editors won'T be highlighted correctly. IIRC this is needed for the macro and keyword stuff.

The only thing is not to have too many editors open... :-)
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: [url="https://www.codeblocks.org/docs/main_codeblocks_en.html"]https://www.codeblocks.org/docs/main_codeblocks_en.html[/url]
C::B FAQ: [url="https://wiki.codeblocks.org/index.php?title=FAQ"]https://wiki.codeblocks.org/index.php?title=FAQ[/url]

ollydbg

It looks like
void SCI_METHOD LexerCPP::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) {

call


void SetLevel(int line, int level) {
pAccess->SetLevel(line, level);
}


in a loop, so a lot of wxEVT_SCI_MODIFIED was sent. :(
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

ollydbg

Quote from: MortenMacFly on July 18, 2013, 05:28:06 PM
Quote from: ollydbg on July 18, 2013, 05:14:50 PM
Can we avoid them? It's annoying.
I think not really. It iterates (only!) across the open editors to update the syntax highlighting. If you skip the call to UpdateEditorSyntax() or avoid the event the editors won'T be highlighted correctly. IIRC this is needed for the macro and keyword stuff.

The only thing is not to have too many editors open... :-)
I have just post an analysis result, and found the source of such annoying message. (even only one editor is opened, there are still many messages sent).
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

ollydbg

I track down the source, and I see that the flood of wxEVT_SCI_MODIFIED of messages happen at two time.

1, when loading project files
cbEditor* EditorManager::Open(LoaderBase* fileLdr, const wxString& filename, int /*pos*/, ProjectFile* data)

Each line will be set a new level, and those messages will be sent for each lines
int SCI_METHOD Document::SetLevel(int line, int level) {
int prev = static_cast<LineLevels *>(perLineData[ldLevels])->SetLevel(line, level, LinesTotal());
if (prev != level) {
DocModification mh(SC_MOD_CHANGEFOLD | SC_MOD_CHANGEMARKER,
                  LineStart(line), 0, 0, 0, line);
mh.foldLevelNow = level;
mh.foldLevelPrev = prev;
NotifyModified(mh);
}
return prev;
}


2, when parser done, in void CodeCompletion::OnParserEnd(wxCommandEvent& event)
The call statement

UpdateEditorSyntax(editor);

Some code style will change, so there is also some messages of wxEVT_SCI_MODIFIED.

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

ollydbg

Ok, I got the correct answer from Scintilla's mail-list, see:
https://groups.google.com/d/msg/scintilla-interest/9Vt8FJFL3CU/aOjLveFw4oAJ
It is by design, but we can filter them(I don't think it is necessary), so leave it as it is. :)
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Alpha

Quote from: ollydbg on July 21, 2013, 05:54:48 PM
It is by design, but we can filter them(I don't think it is necessary), so leave it as it is. :)
Could filtering possibly result in a (small) performance gain?

ollydbg

Quote from: Alpha on July 21, 2013, 06:13:36 PM
Quote from: ollydbg on July 21, 2013, 05:54:48 PM
It is by design, but we can filter them(I don't think it is necessary), so leave it as it is. :)
Could filtering possibly result in a (small) performance gain?
I don't know, maybe we can temporary disable send such message when an editor is created and a file is loaded. To measure performance, there need at least a benchmark test.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

ollydbg

I still see many unwanted event sent, so I did some further debugging.
I found that C::B did try to disable the notifications when an editor was initialized, see the code

bool cbEditor::Open(bool detectEncoding)
{
   if (m_pProjectFile)
   {
       if (!wxFileExists(m_Filename))
           m_pProjectFile->SetFileState(fvsMissing);
       else if (!wxFile::Access(m_Filename.c_str(), wxFile::write)) // readonly
           m_pProjectFile->SetFileState(fvsReadOnly);
   }

   if (!wxFileExists(m_Filename))
       return false;

   // open file
   m_pControl->SetReadOnly(false);

   m_pControl->ClearAll();
   m_pControl->SetModEventMask(0);

   if (!m_pData)
       return false;

   if (!m_pData->m_pFileLoader)
       m_pData->m_pFileLoader = Manager::Get()->GetFileManager()->Load(m_Filename, false);

#ifdef fileload_measuring
   wxStopWatch sw;
#endif
   EncodingDetector enc((wxByte*)m_pData->m_pFileLoader->GetData(), m_pData->m_pFileLoader->GetLength());
   if (detectEncoding)
   {
       m_pData->m_useByteOrderMark    = enc.UsesBOM();
       m_pData->m_byteOrderMarkLength = enc.GetBOMSizeInBytes();
       m_pData->m_encoding            = enc.GetFontEncoding();

       SetEncoding(enc.GetFontEncoding());
       SetUseBom(m_pData->m_byteOrderMarkLength > 0);
   }

   ConfigManager* mgr = Manager::Get()->GetConfigManager(_T("editor"));
#ifdef fileload_measuring
   Manager::Get()->GetLogManager()->DebugLog(F(_T("cbEditor::Open() => Encoding detection and conversion took : %d ms"),(int)sw.Time()));
   sw.Start();
#endif

   m_pControl->InsertText(0, enc.GetWxStr());
   m_pControl->EmptyUndoBuffer(mgr->ReadBool(_T("/margin/use_changebar"), true));
   m_pControl->SetModEventMask(wxSCI_MODEVENTMASKALL);
...
...

It first SetModEventMask to 0 (which disable all the modify notifications), and after loading, it set its value to wxSCI_MODEVENTMASKALL, this looks OK.

But I find that when the first time an OnPaint event is received, it did the following

[debug]> bt 30
[debug]#0  LexAccessor::SetLevel (this=0x22ced4, line=20, level=67109888) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\lexlib\LexAccessor.h:202
[debug]#1  0x011b722a in LexerCPP::Fold(unsigned int, int, int, IDocument*)@20 (this=0x1a2e54a8, startPos=0, length=6655, initStyle=0, pAccess=0x1a30bb04) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\lexers\LexCPP.cxx:1217
[debug]#2  0x01243d40 in LexInterface::Colourise (this=0x1a2b27e8, start=0, end=6655) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\Document.cxx:65
[debug]#3  0x0124a527 in Document::EnsureStyledTo (this=0x1a30bb00, pos=6655) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\Document.cxx:1812
[debug]#4  0x01235de2 in Editor::StyleToPositionInView (this=0x1a2fbfb8, pos=6655) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\Editor.cxx:6833
[debug]#5  0x0122514d in Editor::Paint (this=0x1a2fbfb8, surfaceWindow=0x1a1979e8, rcArea=...) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\Editor.cxx:3515
[debug]#6  0x01195377 in ScintillaWX::DoPaint (this=0x1a2fbfb8, dc=0x22f1b0, rect=(0, 0) 968*215) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\ScintillaWX.cpp:924
[debug]#7  0x011901a0 in wxScintilla::OnPaint (this=0x1a196900) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\wxscintilla.cpp:5211
[debug]#8  0x04c11b0e in wxAppConsole::HandleEvent (this=0x10a24ba8, handler=0x1a196900, func=(void (wxEvtHandler::*)(wxEvtHandler * const, wxEvent &)) 0x119011e <wxScintilla::OnPaint(wxPaintEvent&)>, event=...) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\common\appbase.cpp:322
[debug]#9  0x04c9273d in wxEvtHandler::ProcessEventIfMatches (entry=..., handler=0x1a196900, event=...) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\common\event.cpp:1239
[debug]#10 0x04c91d53 in wxEventHashTable::HandleEvent (this=0x1518800 <cbStyledTextCtrl::sm_eventHashTable>, event=..., self=0x1a196900) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\common\event.cpp:906
[debug]#11 0x04c9293a in wxEvtHandler::ProcessEvent (this=0x1a196900, event=...) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\common\event.cpp:1301
[debug]#12 0x04cdbc20 in wxWindow::HandlePaint (this=0x1a196900) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\msw\window.cpp:4617
[debug]#13 0x04cd8830 in wxWindow::MSWWindowProc (this=0x1a196900, message=15, wParam=0, lParam=0) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\msw\window.cpp:2747
[debug]#14 0x04cd8109 in wxWndProc(HWND__*, unsigned int, unsigned int, long)@16 (hWnd=0x709c8, message=15, wParam=0, lParam=0) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\msw\window.cpp:2618
[debug]#15 0x7e418734 in USER32!GetDC () from C:\WINDOWS\system32\user32.dll
[debug]#16 0x000709c8 in ?? ()
[debug]#17 0x0000000f in ?? ()
[debug]#18 0x00000000 in ?? ()
[debug]>>>>>>cb_gdb:

This try to set the style for each line (when SetLevel() function is called). So, for a large file which contains many lines, C::B will send many wxEVT_SCI_CHANGE events.

Do we need to allow sending all such events? I don't think so.

Hint:
I just found the Codelite's editor filter some events, see:
https://github.com/eranif/codelite/blob/master/LiteEditor/cl_editor.cpp
line 355.

SetModEventMask (wxSTC_MOD_DELETETEXT | wxSTC_MOD_INSERTTEXT  | wxSTC_PERFORMED_UNDO  | wxSTC_PERFORMED_REDO | wxSTC_MOD_BEFOREDELETE | wxSTC_MOD_CHANGESTYLE);



EDIT:

Below is the backtrace of another source of events. (caused by CodeCompletion::UpdateEditorSyntax())

[debug]> bt 30
[debug]#0  LexAccessor::SetLevel (this=0x22d61c, line=192, level=67175425) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\lexlib\LexAccessor.h:202
[debug]#1  0x011b722a in LexerCPP::Fold(unsigned int, int, int, IDocument*)@20 (this=0x1a2a90d8, startPos=0, length=81090, initStyle=0, pAccess=0x1a3048bc) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\lexers\LexCPP.cxx:1217
[debug]#2  0x01243d40 in LexInterface::Colourise (this=0x1a30bf48, start=0, end=81090) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\Document.cxx:65
[debug]#3  0x0124380a in ScintillaBase::WndProc (this=0x1a30a218, iMessage=4003, wParam=0, lParam=-1) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\ScintillaBase.cxx:948
[debug]#4  0x011951aa in ScintillaWX::WndProc (this=0x1a30a218, iMessage=4003, wParam=0, lParam=-1) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\ScintillaWX.cpp:898
[debug]#5  0x01184aa9 in wxScintilla::SendMsg (this=0x1a24c918, msg=4003, wp=0, lp=-1) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\wxscintilla.cpp:271
[debug]#6  0x0118df1a in wxScintilla::Colourise (this=0x1a24c918, start=0, end=-1) at F:\cb_sf_git\trunk\src\sdk\wxscintilla\src\wxscintilla.cpp:4399
[debug]#7  0x70064b20 in CodeCompletion::UpdateEditorSyntax (this=0x1245dd78, ed=0x1a24cd38) at F:\cb_sf_git\trunk\src\plugins\codecompletion\codecompletion.cpp:3320
[debug]#8  0x700658d8 in CodeCompletion::OnEditorActivatedTimer (this=0x1245dd78, event=...) at F:\cb_sf_git\trunk\src\plugins\codecompletion\codecompletion.cpp:3495
[debug]#9  0x04c11b0e in wxAppConsole::HandleEvent (this=0x10a24ba8, handler=0x1245dd78, func=(void (wxEvtHandler::*)(wxEvtHandler * const, wxEvent &)) 0x70065638 <CodeCompletion::OnEditorActivatedTimer(wxTimerEvent&)>, event=...) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\common\appbase.cpp:322
[debug]#10 0x04c9273d in wxEvtHandler::ProcessEventIfMatches (entry=..., handler=0x1245dd78, event=...) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\common\event.cpp:1239
[debug]#11 0x04c92d91 in wxEvtHandler::SearchDynamicEventTable (this=0x1245dd78, event=...) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\common\event.cpp:1421
[debug]#12 0x04c928f4 in wxEvtHandler::ProcessEvent (this=0x1245dd78, event=...) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\common\event.cpp:1297
[debug]#13 0x04d911e2 in wxTimerBase::Notify (this=0x1245dff8) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\common\timercmn.cpp:57
[debug]#14 0x04ccedcb in wxProcessTimer (timer=...) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\msw\timer.cpp:187
[debug]#15 0x04ccee72 in wxTimerWndProc(HWND__*, unsigned int, unsigned int, long)@16 (hWnd=0x50884, message=275, wParam=11, lParam=0) at E:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\src\msw\timer.cpp:200
[debug]#16 0x7e418734 in USER32!GetDC () from C:\WINDOWS\system32\user32.dll
[debug]#17 0x00050884 in ?? ()
[debug]#18 0x00000113 in ?? ()
[debug]#19 0x0000000b in ?? ()
[debug]#20 0x00000000 in ?? ()
[debug]>>>>>>cb_gdb:



If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.