SharpDevelop Community

Get your problems solved!
Welcome to SharpDevelop Community Sign in | Join | Help
in Search

Siegfried Pammer

  • Profiling Unit Tests Made Easy

    Although we had basic support for profiling unit tests in the RC1 of SharpDevelop 3, it was very hard to use. The reason for this was that the profiler simply attached itself to the NUnit console runner used by SharpDevelop and recorded all calls, even the initialization of NUnit. This produced a large overhead of data.

    In SharpDevelop 3.1 rev. 4863 I changed the data processor a bit. The profiler now displays all unit tests as root nodes in the "Overview" tab and all NUnit initialization calls are removed from the data.

    As you can see, it is much easier find the information you need. This also works with multiple tests selected.

    Another feature I thought it could be useful for profiling in general is "Find references". Simply right-click on a node in the tree view and select "Find references" from the context menu.

    I hope you like the changes and find it useful. If you have any questions or suggestions, please post them here.

     

    Posted Sep 02 2009, 04:20 PM by siegi44 with no comments
    Filed under:
  • API Changes explained: Language Bindings and Project Bindings

    Important note: The changes discussed in this post apply only to SharpDevelop 4.0.0.4537 and later revisions.

    Why?

    As you might have noticed, I am one of the accepted Google Summer of Code 2009 students. While working on my project, the XAML binding, I had the idea of implementing an Outline Pad for XAML. After a short discussion with my mentor, we decided to add a general solution for implementing this functionality for C#, VB .NET, Boo, Windows Forms Designer and the (upcoming) WPF Designer too.

    For instance, normal backend bindings like the C#, VB .NET and Boo binding could display a tree of the current document structure with namespaces, classes, member variables, methods properties, etc. This would allow fast physical restructuring of a file. With XAML you could easily move a part of the XAML tree to another location. Same would go for the Windows Forms and WPF Designer.

    So each language binding or display binding should be able to tell the outline pad what content it should display to the user. The existing ILanguageBinding only represented a language from the point of view of the project system, there was no support for things like code completion, formatting or highlighting. So I changed the name of the existing ILanguageBinding to "IProjectBinding".

    The New Language Binding API

    The new ILanguageBinding is not project-based, but file- or, to be more specific, ITextEditor-based. What does this mean? It simply means, that every ITextEditor instance (that is, every file opened by the default text editor in SharpDevelop), gets its own ILanguageBinding instance. Furthermore, if you use the split-view functionality present in SharpDevelop, both views get their own ILanguageBinding instance too. Please keep that in mind, when implementing your own language bindings.

    So let's move on the practical part: In fact, the "API" only consists of one interface, plus wrappers for the SharpDevelop addin system, to make it easy for backend binding addins to provide their own language-specific implementation. We will discuss its structure first:

    public interface ILanguageBinding
    {
            IFormattingStrategy FormattingStrategy {
                get;
            }
           
            LanguageProperties Properties {
                get;
            }
           
            void Attach(ITextEditor editor);
           
            void Detach();
    }

    It is not very complex, but there are a few things to keep in mind:

    Attach is called only once on every ILanguageBinding instance (before any other method calls).

    SharpDevelop will never Detach() and re-Attach() a language binding; instead, it will detach the old binding and attach a new instance. A new instance is created in the following situations:

    • an ITextEditor is created by SharpDevelop,
    • the filename, of the file being edited, has changed
    • or the user switches to split-view mode.

    You can attach additional functionality like a custom highlighter or an IOutlineContentHost, to provide content displayed in the Outline pad, as mentioned at the beginning.

    If you override Attach, you should also override Detach. It is called only once in the life-cycle of an ILanguageBinding instance:

    • when an ITextEditor is closed (disposed by SharpDevelop),
    • before a new language binding is attached, after the filename, of the file being edited, has changed. (So SharpDevelop disposes the old one before creating a new one.)
    • after switching from split-view to normal view mode, to dispose the second view, as it is not needed anymore.

    You should detach (and dispose) all services and additional functionality, added by your language binding, from the ITextEditor at this point.

    FormattingStrategy should return an instance of the IFormattingStrategy implementation for your language binding.

    Properties should return a reference to the LanguageProperties implementation for your language binding.

    Example: XamlLanguageBinding

    I pasted the Attach and Detach method from the XamlLanguageBinding as a small example. Please note that adding custom syntax highlighting (in this case: XamlColorizer) and additional services, like IOutlineContentHost, requires a reference to the TextView of the AvalonEdit.TextEditor class. So this part can only be implemented for specific text editor controls.

    public override void Attach(ITextEditor editor)
    {
        base.Attach(editor);
        
        // try to access the ICSharpCode.AvalonEdit.Rendering.TextView
        // of this ITextEditor
        this.textView = editor.GetService(typeof(TextView)) as TextView;
        
        // if editor is not an AvalonEdit.TextEditor
        // GetService returns null
        if (textView != null) {
            colorizer = new XamlColorizer(editor, textView);
            // attach the colorizer
            textView.LineTransformers.Add(colorizer);
            // add the XamlOutlineContentHost, which manages the tree view
            textView.Services.AddService(typeof(IOutlineContentHost), new XamlOutlineContentHost(editor));
        }
    }

    public override void Detach()
    {
        base.Detach();
        
        // if we added something before
        if (textView != null && colorizer != null) {
            // remove and dispose everything we added
            textView.LineTransformers.Remove(colorizer);
            textView.Services.RemoveService(typeof(IOutlineContentHost));
            colorizer.Dispose();
        }
    }

    Nice, But How Do I Register My Language Binding With SharpDevelop?

    Similar to all other parts of SharpDevelop, just add it to the addin path /SharpDevelop/Workbench/LanguageBindings like this:

    <Path name="/SharpDevelop/Workbench/LanguageBindings">
        <LanguageBinding
            id="XAML"
            class="ICSharpCode.XamlBinding.XamlLanguageBinding"
            extensions=".xaml" />
    </Path>

    short explanation:

    id: The name of the LanguageBinding, must be unique, preferably the same as your project binding or code completion binding.

    class: The fully-qualified name of your language binding class.

    extensions: A semicolon-separated list of file extensions, that are handled by your language binding. Please note that multiple LanguageBindings can handle a file extension. But only the first non-null FormattingStrategy is used or only the first non-null LanguageProperties instance is used. You can control the order of the language bindings using the insertbefore and insertafter attributes.

    Important: In the past you were able to register a formatting strategy by adding it to /AddIns/DefaultTextEditor/Formatter/, this was removed. Now the IFormattingStrategy gets set by overriding the FormattingStrategy property in the Language Binding implementation.

    How To Access The Features From AddIns?

    When dealing with text displayed inside a SharpDevelop text editor, the easiest way to do this is to use the ITextEditor interface. The active language binding can be accessed by using ITextEditor.Language property.

    Project Bindings

    I have not done any changes to the project binding API, except renaming everything. Project bindings are responsible for project management (reading project files, compilation management, etc.). XAML does not need its own project format (there is no .xamlproj ;-)), so I cannot provide an example and explain it to you, please take a look at existing project bindings such as CSharpProjectBinding, VBNetProjectBinding or BooProjectBinding.

    Conclusion

    I think the language bindings make it easier to extend ITextEditor with language specific features and also allow other AddIns to access these features. In my next post I will explain my work on the XAML binding more in detail and guide you through the features I implemented.

    If you have any questions concerning language bindings and these changes, please feel free to ask.

  • Merging of Calls – Pinpointing Interesting Methods

    As mentioned in the previous post, SharpDevelop 3.1 will contain a built-in profiler.

    Today we'll talk about what data the profiler collects, and what exactly "merging" is.

    We’ll use the following sample program for exploring the topic:

    using System;
    using System.Threading;

    namespace ICSharpCode.Profiler.Example1
    {
        class Program
        {
            static void DoCalculation(bool doLotsOfWork) {
                if (doLotsOfWork) {
                    int target = Environment.TickCount + 1000;
                    while (Environment.TickCount < target) { }
                } else
                    Thread.Sleep(100);
            }
           
            static void SomeMethod() {
                DoCalculation(true);
            }
           
            static void SomeOtherMethod() {
                for (int i = 0; i < 10; i++) {
                    DoCalculation(false);
                }
            }
           
            static void Main() {
                SomeMethod();
                SomeOtherMethod();
            }
        }
    }

    SomeMethod and SomeOtherMethod take the same amount of time, but for different reasons.

    If we simply store timing information per method, it would seem that DoCalculation spends 50% of the time in get_TickCount and 50% in Thread.Sleep.

    But a good profiler should be able to show that only the invocations of SomeMethod spend their time in get_TickCount, whereas SomeOtherMethod ends up spending time in Thread.Sleep.

    Or, assume you have a program with a textbox and a button. You click on the button, then change the text (input to the program) and then run the button code again. The other input might mean that the performance characteristics of the button method change dramatically - so ideally, we should be able to view each click separately.

    What data does the profiler have to collect to do this? The easiest solution would be to record all function calls. For each function call, store the function ID, the call start time, and the call end time.

    That way, we don't lose any data; we can reconstruct the application's stack at every point in time.
    Of course, if you are looking into a performance issue, you don't want to look at individual stack traces - you want a little more overview. Or expressed for our textbox/button example: It is nice to be able to separately view the data for each button click; but initially, you'll want to look at all data at once.

    Now we get to our data model: when you're using the SharpDevelop profiler, you're dealing with "merged" sets of individual calls. Instead of seeing a single call stack, you'll see the tree of all call stacks.

    For our example code, this looks like in the following screenshot:


     
    Note that the ten calls to DoCalculation inside SomeOtherMethod were merged into a single node in the tree view (a "merged" call). In this view, you are not able to view an individual call's timing data, only the sum of all individual times. However, the DoCalculation call inside SomeMethod and that in SomeOtherMethod are still separate, as these have different call stacks.

    If you want to view them together, select both calls and use Right Click > Merge.

    A new tree will open with all 11 calls merged together:


     
    No matter whether we're dealing with multiple calls after each other, or with calls in different positions in the tree, it's always the same operation: merging. You can even merge calls of different functions together - though unless the functions do similar things, you won't get useful results.

    For example, here you can see SomeMethod and SomeOtherMethod merged together:


     
    Note that merging functions also merges their children (grouped by function name).

    Now it's pretty clear what the timeline control above does: the profiler takes all root nodes from all stack traces in the selected time span, and merges nodes belonging to the same thread.

    However, naïvely storing every function call individually takes a lot of space - about 7 GB (!) for SharpDevelop starting and opening its own solution (SharpDevelop.sln). That's why the profiler limits you to selecting start and end positions for the time spans with a granularity of about 500ms: during profiling, the profiler hook merges the calls into data sets of about 500ms.

    We never actually create the "function start,end"-entries proposed above, but directly build a merged representation as the profiler runs. That way we dramatically reduce the size of the profiler output: only 198 MB for SharpDevelop starting and opening its own solution.

    In the next post we will give you a brief overview of all the other commands you can access in the context menu of each call and how to use them.

    Posted Apr 13 2009, 02:20 PM by siegi44 with no comments
    Filed under:
  • Introducing a New Tool in SharpDevelop – The Profiler

    Nearly one year ago, we started building a new tool for SharpDevelop: a profiler. It will make it easier to analyze and improve the performance of applications developed using SharpDevelop. In the next few weeks we are going to give you an overview of all the different aspects of the profiler, its usage and we will shed some light on its implementation and technical details.

    Using the Profiler

    To start a new profiler session just go to “Quality Tools” > “Profiler” and then you can decide whether to profile the currently opened project or you can select a program to run.


    During execution of the application, performance data is collected. On program end, SharpDevelop will automatically open up the session and display the collected data.

     

    In the “Overview” tab, all threads and all calls are listed. In the “Top 20” tab 20 methods, in which most time is spent during run time, are listed. On the right side you can see the ring diagram. The concept of the ring diagram was taken from the Ubuntu “Disk Usage Analyzer”. It can be used to easily navigate to deep levels of the call tree. Just click on a call to move there. If you want to go back to the call you had selected before, just click inside the gray circle in the middle.

    To show details on a call in the ring diagram simply move the mouse over it and a tool tip with important information will be displayed. The gray circle represents the call currently selected in the tree view. The innermost ring is a pie chart showing the children of the selected call. The size of each piece is proportional to the time spent inside that call. The other rings represent the deeper levels of the call tree.

    In the next post we will show you the “merge” feature, which allows you to view multiple parts of the call tree at once. The “merge” feature is used by the “Top 20” tab and the timeline too.

    Posted Apr 04 2009, 06:43 PM by siegi44 with no comments
    Filed under:
  • New feature: Extract method

     In the upcoming SharpDevelop 3 there's a new refactoring included: Extract method. With it you can easily split a method into two independent methods.

    If you want to use it you first have to select the piece of code you want to extract:

    Then just click on Refactor > Extract method in the main menu:

     The preview will pop up, here you can enter a name for the new method:

     After entering a name click "OK" and here you can see the new method and the inserted call:

    Of course you can undo the change, just press Ctrl+Z.

    I hope you find this refactoring useful and I would be glad to receive any comments on this.

  • The Hex Editor

    Basically the UI of the hex editor is divided into two views. On the left side you can edit/input the parts of the bytes as hexadecimal figures. On the right side you can edit/input the data as ASCII characters:

    The interface of the hex editor.

    On the left-most side and on the top you see the offsets of the bytes you look at. You can switch the way the offsets are displayed by selecting either "hexadecimal", "decimal" or "octal" in the toolbar above. The number of bytes displayed per line can be changed using the middle up-down-field.

    In the screenshot you can see that it is disabled, that's because the button on the left is switched on. If it is switched on, the number of bytes displayed per line is calculated automatically to fit the current width of the editor's window. When you resize the window, the number of bytes per line is adjusted automatically.

    Editing data in the hex editor

    You can either input data using the 0, 1, ..., 8, 9, A, ..., F keys on the left side or just change it on the right side like in a normal text editor. Text can be selected using the mouse with the left mouse button held down or using left shift and the arrow keys.

    Text can be copied, pasted and cut using Ctrl+C, Ctrl+V and Ctrl+X. Ctrl+A selects everything the editor.You can switch between the left and the right side without loosing the current selection or position using the TAB key. Using Ctrl+Up or Down arrow key you can scroll the view without moving the caret.

    Customizing the hex editor

    In the options dialog you can customize the standard behavior of the hex editor:

    The options dialog.

    You can simply change the font, style and/or color of the offsets or the data. It is recommended to use fixed-size fonts for best view (like Courier, Courier New). Furthermore you can force the editor use "automatic fitting of bytes per line" or set a standard view-mode and a standard number of bytes per line. You can tell SharpDevelop to open specific file-types with the hex editor using the last text-field.

    One important thing: You have to set ALL settings (even font, style and size and standard number of bytes per line) when you first open up the settings dialog, before this point there's no settings-file and the hex editor uses it's built-in standard settings, but when a settings file is created and there is no font selected, another standard font is used.

    I would be glad to receive tips for improvement and feature requests for the hex editor.

Powered by Community Server (Commercial Edition), by Telligent Systems
Don't contact us via this (fleischfalle@alphasierrapapa.com) email address.