Performance for using as a log window

SyntaxEditor for Windows Forms Forum

Posted 13 years ago by Duncan Woods
Avatar
Hi,

I am using the highlighter to display log messages. It is proving useful to allow custom higlighting of different message severity and contents.

Could you please advise me on ways to ensure maximum performance since 1000s of messages can be regularly added.

For the actual actipro control traceText, I am calling the following to add x lines every 500ms. The text is halved when it reaches 5000 lines or so to keep memory usage under control:

  if (traceText.Document.Lines.Count > maxLines)
  {
    traceText.Document.Text = traceText.Document.Text.Substring(traceText.Document.Text.Length / 2);
  }

  traceText.Document.AppendText(s.ToString());
  traceText.SelectedView.GoToLine(traceText.Document.Lines.Count - 1);
  traceText.Document.UndoRedo.Clear(); 
The default higlighting config looks like the following:

<SyntaxLanguage Key="XML" LanguageDefinitionVersion="3.0" Secure="True" xmlns="http://ActiproSoftware/SyntaxEditor/3.0/LanguageDefinition">

    <!-- String Properties -->
    <Properties>
        <Property Key="Creator" Value="Duncan Woods GH" />
        <Property Key="Copyright" Value="Copyright (c) Garrad Hassan.  All rights reserved." />
    </Properties>

    <!-- Highlighting Styles -->    
    <Styles>
        <Style Key="ERROR" ForeColor="Red" BackColor="Default" Bold="True" Italic="False" Underline="False" />
        <Style Key="WARN" ForeColor="Orange" BackColor="Default" Bold="True" Italic="False" Underline="False" />
        <Style Key="INFO" ForeColor="Black" BackColor="Default" Bold="True" Italic="False" Underline="False" />
        <Style Key="DEBUG" ForeColor="Gray" BackColor="Default" Bold="True" Italic="False" Underline="False" />
        <Style Key="Logger" ForeColor="Blue" BackColor="Default" Bold="False" Italic="False" Underline="False" />
        <Style Key="Tag" ForeColor="Blue" BackColor="Default" Bold="False" Italic="False" Underline="False" />
    </Styles>

    <!-- Macros -->    
    <Macros>
        <!-- Redefine word macros to include hyphens -->
        <Macro Key="LoggerMacro" Value="[^:]" />
    </Macros>
    
    <!-- States -->
    <States>
    
    
            <State Key="DefaultState">
                <!-- Patterns Groups -->
                <PatternGroups>
                    <!-- Whitespace -->
                    <RegexPatternGroup TokenKey="WhitespaceToken" PatternValue="{WhitespaceMacro}+" IsWhitespace="True" />
                    
                    <!-- Brackets -->
                    <ExplicitPatternGroup Key="OpenParenthesisPatternGroup" TokenKey="OpenParenthesisToken" Style="Logger" PatternValue="[" EndBracket="CloseParenthesisPatternGroup" />
                    <ExplicitPatternGroup Key="CloseParenthesisPatternGroup" TokenKey="CloseParenthesisToken" Style="Logger" PatternValue="]" StartBracket="OpenParenthesisPatternGroup" />
                    
                    <ExplicitPatternGroup TokenKey="ERROR" Style="ERROR" LookAhead="{NonWordMacro}">
                        <ExplicitPatterns>ERROR</ExplicitPatterns>
                    </ExplicitPatternGroup>
                    
                    <ExplicitPatternGroup TokenKey="WARN" Style="WARN" LookAhead="{NonWordMacro}">
                        <ExplicitPatterns>WARN</ExplicitPatterns>
                    </ExplicitPatternGroup>
                    
                    <ExplicitPatternGroup TokenKey="INFO" Style="INFO" LookAhead="{NonWordMacro}">
                        <ExplicitPatterns>INFO</ExplicitPatterns>
                    </ExplicitPatternGroup>
                    
                    <ExplicitPatternGroup TokenKey="DEBUG" Style="DEBUG" LookAhead="{NonWordMacro}">
                        <ExplicitPatterns>DEBUG</ExplicitPatterns>
                    </ExplicitPatternGroup>             
                </PatternGroups>
                <ChildStates>
                    <ChildState Key="StartTagState" />
            </ChildStates>
            </State>
            
        <!-- Start Tags -->
        <State Key="StartTagState" TokenKey="StartTagDefaultToken" Style="Tag">
            <!-- Scopes -->
            <Scopes>
                <Scope>
                    <ExplicitPatternGroup Type="StartScope" TokenKey="StartTagStartToken" Style="Tag" PatternValue="[" />
                    <ExplicitPatternGroup Type="EndScope" TokenKey="StartTagStartToken" Style="Tag" PatternValue="]" />
                </Scope>
            </Scopes>            
        </State>
            
    </States>
        
</SyntaxLanguage>
Thanks,
Duncan

Comments (3)

Posted 13 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Duncan,

I have several suggestions for you...

First, never do editor.Document.Text.Length... that call is building a complete string
of the text and then taking the length of the string. Use editor.Document.Length
instead since that is a direct variable we store and will return results much faster
for large documents.

Second, on the line where you are trimming, that is a bad way to do it because it is
forcing a complete reparse of the remaining text. What you really want is to simply
chop off the start of the text. You can do this, which will cause minimal parsing
and should be much faster:
traceText.Document.DeleteText(DocumentModificationType.Delete, 0, traceText.Document.Length / 2);
That is v4.0 beta syntax. The v3.1 equivalent used an UndoableDelete method call.

Third, make your tokens as long as possible. For instance if you only care about
syntax highlighting and won't be parsing this later, make tokens incldue as much text
as possible that has the same style. I'm not sure what your logging language looks
like but I don't see anything for making tokens for words, etc. So what is going to
happen for "normal" text is that you will be making a new token for each character
that isn't assigned a pattern. This of course adds more memory.

You can use our main SDI application sample to load your language and then load some
text to show it in action. When you move the caret over a token, it tells you the
name of the token in the statusbar. If an asterisk (*) appears next to the name,
that indicates that that character is startng a new token. For a simple logging
language you want those asterisks to appear only at the start of a run of
text that has the same style, based on what I mentioned in the previous paragraph.

Hope that helps!


Actipro Software Support

Posted 13 years ago by Duncan Woods
Avatar
Thanks for the suggestions, I'll put them into action. Halving the log text does indeed take a long time so that should be interesting to see the result.

The memory usage is much higher than I expected so perhaps it is too many tokens.

The default highlighting config should just colour the words ERROR, WARN, INFO, DEBUG (case sensitive) and anything in square brackets. These can appear anywhere on a line. Can you suggest how to minimise the tokens for this?

Many thanks,
Duncan
Posted 13 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Maybe make a pattern that highlights includes everything on a line that doesn't start
with the start characters of those items, such as this regex:
[^EWID\[]+

Another thing that speeds up lexing is to write a programmatic lexical parser, which
is a feature in v4.0. It's a more advanced concept but does yield better parsing
speed. For instance the C# language implementation in the .NET Languages Add-on uses
a programmatic lexical parser and runs about 5-6 times faster than the dynamic C#
language implementation's lexical parser.

[Modified at 09/21/2006 02:01 PM]


Actipro Software Support

The latest build of this product (v2018.1 build 0341) was released 7 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.