The #develop teamblog
#  Thursday, 27 September 2007

Yesterday I wrote about how I made compiling 30% faster by using multi-threading to let my dual-core CPU work with both cores. A problem was that I had to use serialize build events to send them back to the host process.

MSBuild provides these events to loggers (number of occurrences during the test shown in parenthesis):
MessageRaised   (21156)
ErrorRaised      (0)
WarningRaised   (18)
BuildStarted      (47)
BuildFinished     (47)
ProjectStarted  (449)
ProjectFinished (449)
TargetStarted (2910)
TargetFinished (2910)
TaskStarted (4308)
TaskFinished (4308)
CustomEventRaised (0)

All these events must be send to the SharpDevelop process, where logger AddIns can process them. Each one is serialized separately, and includes information about the full name of the project file being build and some other highly redundant information. Each event is about 1 KB in serialized form. Half of the events occurred in the worker running in the SharpDevelop process, but the other half occurred in the worker that ran in its own process; so half of the events had to be transferred, so we tranferred a total of 18 MB during the 25-second build. Remember the main cost is the serialization (.NET BinaryFormatter), not the data transfer itself.

Obviously, most of these events are not interesting for SharpDevelop, and the best way to improve performance is to ignore uninteresting events in the worker instead of ignoring them in the host.
So which events does SharpDevelop need? Potentially all, since AddIns can add loggers; but if those AddIns tell SharpDevelop which
events are required before the build starts, we can optimize for the common case that all AddIns are only interested in specific events - usually only in errors and warnings. Events that SharpDevelop currently does not use anywhere are MessageRaised, TargetStarted and TargetFinished - all are called quite frequently.
To our benchmark results from yesterday, I added an entry "Less events" where MessageRaised, TargetStarted and TargetFinished are deactivated:

Core Duo Notebook, 1 GB RAM, Vista Home Premium, Aero disabled:
   One worker:  35.2, 34.9, 35.2, 35.0, 34.3 : Average 35.1 seconds
   Two workers: 25.6, 23.9, 24.2, 23.5, 23.8 : Average 24.2 seconds
   Less events: 23.7, 23.5, 23.0, 22.4, 21.2 : Average 22.8 seconds

 Build (no changes):
   One worker:  7.4, 7.1, 7.2, 7.8, 7.1 : Average 7.3 seconds
   Two workers: 6.9, 6.8, 6.7, 6.6, 6.2 : Average 6.6 seconds
   Less events: 5.1, 5.0, 6.2, 5.6, 5.1 : Average 5.4 seconds

More than 1 second saved! (see yesterdays' post for details about the benchmark)

Now why does SharpDevelop need TaskStarted and TaskFinished? Take a look at the code:
void OnTaskStarted(object sender, TaskStartedEventArgs e)
  activeTaskName = e.TaskName;
  if (MSBuildEngine.CompileTaskNames.Contains(e.TaskName.ToLowerInvariant())) {
    AppendText("${res:MainWindow.CompilerMessages.CompileVerb} " + Path.GetFileNameWithoutExtension(e.ProjectFile));

TaskStarted is just there to let the user know that building a project resulted in a recompilation - when doing a Rebuild, SharpDevelop
shows "Compiling ProjectName" for each project, whereas for a Build (no changes), no such lines are shown in the Output view.
But in fact, all consumers of TaskStarted probably look for specific task names. And all consumers of TaskFinished are also listening to TaskStarted and are also only interested in some specific types of tasks.
If we pass the build worker a list of task names we are interested in, it can send us only those events and we don't spend time serializing the tons of events about the tasks <Copy>, <Message> etc.
Together with the "Less events" changes, this decreases the event count from over 36000 to less than 1000.

I implemented this in revision 2696.

Now let's extend our benchmark:
Core Duo Notebook, 1 GB RAM, Vista Home Premium, Aero disabled, two workers, new event handling:
 Rebuild: 20.3, 20.9, 19.9, 20.2, 20.0 : Average 20.3 seconds
 Build (no changes): 4.3, 4.6, 5.0, 4.4, 4.2 : Average 4.5 seconds

That's better than "Less events" because we're sending even less events now, but logger AddIns can tell SharpDevelop that they need to receive additional events, so AddIns did not lose any functionality (but if you install such an AddIn, of course you would lose the performance benefits).
So we're now down from formerly 35.1 seconds (using only one core) to 20.3 seconds - that's 43% faster.
For "Build (no changes)", the reduction of the event count now makes using two workers efficient; from originally 7.3 seconds to 4.5 seconds is a 39% decrease in build time.

Categories: Daniel
Thursday, 27 September 2007 14:31:07 (GMT Daylight Time, UTC+01:00)  #    Comments [0]


#  Wednesday, 26 September 2007

[Warning: long post. Short version: Building in SharpDevelop goes multi-threaded, scroll down for benchmark results]

SharpDevelop contains a rewritten build system. It has some new features that might be interesting for AddIn developers, but one new feature is directly useful for users, or more specifically, users with multi-core CPUs.

Here a quick history on build systems in SharpDevelop:
SharpDevelop 2.0 (the first version to use MSBuild), compiled solutions by telling MSBuild to build the .sln file.
SharpDevelop 2.1 and 2.2 compile solutions by telling MSBuild to build the projects individually.

When writing the build engine for SharpDevelop 2.1, I tried to make it multi-threaded so that two projects that are not dependent on each other can be built in parallel. However, this did not work: MSBuild makes use Environment.CurrentDirectory; and if two MSBuild instances run in the same process at the same time, they overwrite the CurrentDirectory and cause the other instance to search files in the wrong location.

Now I solved this problem by moving the build into worker processes. However, this means that all MSBuild events are serialized and remoted to the host process, where SharpDevelop AddIns need to have access to them - e.g. the CodeAnalysis AddIn registers itself as MSBuild logger, waits for the TaskStarted, ErrorRaised, WarningRaised and TaskFinished events and fixes certain FxCop error messages (some FxCop errors are not associated with a line number, but with a class/member name). Other SharpDevelop AddIns might decide that certain MSBuild events should be displayed in some form, e.g. in the output window. The only way to give AddIns access to all MSBuild events like they had before is to serialize all events and send them to the SharpDevelop process. When doing a build where there's relatively few work but lots of events (e.g. "Clean solution"), the worker is sending up to 1 MB/s of serialized events to the host.

This had a noticeable impact on performance, so I've kept the first worker in the SharpDevelop process, and only additional workers get their own process. So if you use only one worker, you won't see any worker process and should get the same build performance as SharpDevelop 2.x.

So even though building a project has multiple parts, of which some are waiting for the disk and others are waiting for the CPU; the overhead of using a worker process will cause the build to get slower. (MSBuild has to check if input files changed, start the compiler; the compiler will load input files, actually compile, write the output assembly; and some other stuff happens in the obj\ directory that you probably don't want to hear about)

But if you have a dual core processor, the CPU overhead doesn't hurt: a little overhead for one core is better than not using that core at all (this is assuming the compiler you use is not multithreaded).

But enough talking, let's get some benchmark results:

I used SharpDevelop to compile the source code for SharpDevelop 2.2.1:
AMD 3500+ (single core), 2 GB RAM, Vista Ultimate (32 bit), Areo enabled:
   One worker: 34.3, 34.1, 34.6, 34.7, 34.3 : Average 34.4 seconds
   Two workers: 39.6, 38.7, 38.1, 37.0, 36.6 : Average 38.0 seconds

 Build (no changes, so it's not compiling, but just checking everything for changes):
   One worker:  8.5,  8.0,  8.3,  8.0,  8.0 : Average  8.2 seconds
   Two workers: 13.4, 13.9, 14.0, 12.8, 13.1 : Average 13.4 seconds

The number of MSBuild events (Target started, Task started, Log Message...) is not much different between Rebuild and Build (no changes), so we get a constant overhead of about 5 seconds for the SharpDevelop solution on my desktop computer with a single core processor.

Here finally is the interesting part: Test results from my dual core notebook:

Core Duo T2300, 1 GB RAM, Vista Home Premium (32 bit), Aero disabled:
   One worker: 35.2, 34.9, 35.2, 35.0, 34.3 : Average 35.1 seconds
   Two workers: 25.6, 23.9, 24.2, 23.5, 23.8 : Average 24.2 seconds

 Build (no changes):
   One worker: 7.4, 7.1, 7.2, 7.8, 7.1 : Average 7.3 seconds
   Two workers: 6.9, 6.8, 6.7, 6.6, 6.2 : Average 6.6 seconds

For build (no changes), the overhead plays a big role, but using two workers still made the build a little faster.

But for the real job when there's something to compile, using two workers really rocks: My build is now 30% faster.

SharpDevelop 3.0 allows you to set the number of workers under Tools > Options > Project and solution > Number of projects to build in parallel. The default value for single-core processors is 1, for other processors it's 2. I don't know if going above 2 will have benefits for quad-core users as the overhead (both CPU for sending events to the host and memory because of the additional processes) increases with the number of workers.

Please leave a comment here with your test results - I'm looking for feedback from other multi-core users.

And if you're doing your own benchmark, some notes on how I did my benchmark:
- make sure enough RAM is free so that not only the system does not swap, but Windows has enough room to keep the files you are compiling in memory (this is generally a good idea if you want your system to be fast)
- don't count the first test run as the files are not yet in memory there
- reuse the same SharpDevelop instance for all test runs
- if you leave less than 60 seconds between test runs, SharpDevelop will re-use the worker process, otherwise it is shut down and has to be restarted. I did my tests re-using a single worker process. It might be interesting to see if the overhead of restarting the worker process is worth keeping it longer than 60 seconds.

Categories: Daniel
Wednesday, 26 September 2007 21:05:40 (GMT Daylight Time, UTC+01:00)  #    Comments [0]


#  Sunday, 26 August 2007

Today I retired the initial Wiki (which only remained online for the book errata; we are now actually at Wiki #3), as well as the initial forum. Both resources [/heyhey/wiki/ and /opensource/sd/forums/] were available read-only anyways. The old URLs now redirect to our new and active installations.

The main reason for the complete removal is security. Both were old, unmaintained ASP solutions.

Categories: Chris
Sunday, 26 August 2007 14:59:49 (GMT Daylight Time, UTC+01:00)  #    Comments [0]


#  Friday, 10 August 2007

When you double-click a file in SharpDevelop 2.x, it will get opened inside SharpDevelop. AddIns can add display bindings opening for opening file types (e.g. ResourceEditor for .resx files), but this has the effect of disabling the other display bindings for that file type - In SharpDevelop 2.x, you cannot open a .resx file inside the text editor (except if you disable the ResourceEditor AddIn).

In SharpDevelop 3.0, you can now right-click a file in the project browser and select "Open With...". A dialog will show the list of display bindings that can handle the file type. There also is the entry "Use the default Windows application for this file" which will open the file as if you double-clicked it in Windows Explorer.

You can add new programs to the "Open With" list. SharpDevelop will store the list programs for each file extension in the SharpDevelop settings.

Here is a screenshot of the "Open With"/"Add program" dialog:

A very useful feature of the "Open With" dialog is the "Set as Default" button. This will mark an entry as the default program for opening files with the same extension in SharpDevelop. Double-clicks in the project browser will run the chosen default program. ("Set as Default" does not have any effect on double-clicks in Windows Explorer)

For example, SharpDevelop does not have a built-in image viewer/editor, so if you don't want the text editor, which is the fall-back for unknown file types, to open images, you can "Open With" a .png file in your project, enter your favorite image editor and set it as default program for .png.

Categories: Daniel
Friday, 10 August 2007 07:55:23 (GMT Daylight Time, UTC+01:00)  #    Comments [0]


#  Thursday, 09 August 2007

A small but highly visible bug went unnoticed for the official 2.2.1 release: When creating a new project, ${USER} ${DATE} in the standard header etc. was not replaced with values. Thus we decided to release an 2.2.1a version that contains a fix for this templates-related issue.

Categories: Chris
Thursday, 09 August 2007 07:02:24 (GMT Daylight Time, UTC+01:00)  #    Comments [4]


#  Wednesday, 08 August 2007

Today, we released SharpDevelop 2.2.1. This is a bug fix release with two updated external software packages: NUnit 2.4.2 and SharpDevelop Reports It is recommend that you upgrade to this point release.

Categories: Chris
Wednesday, 08 August 2007 14:59:50 (GMT Daylight Time, UTC+01:00)  #    Comments [0]


#  Sunday, 24 June 2007

In revision 2583, I added the XamlBinding and WPF Designer to the setup of SharpDevelop 3.0.

XamlBinding is a language binding that integrates .xaml files into SharpDevelop's code-completion infrastructure.
Here is an example of SharpDevelop showing a tool tip for a property in a .xaml file:

A window in .xaml is a partial class: one part is generated from the .xaml file, the other is the user code. If the xaml file specifies a name for an element, the compiler will generate a field that can be used by the user code. XamlBinding adds code-completion support for such fields:

As you can see in the "Search Results" window, "Find references" now searches for references in .xaml files. The "rename" refactoring will update both the XAML and C# code.

Finally, the WPF designer that I wrote earlier this year is now integrated in SharpDevelop. Here is a screen shot:

The designer replaces SharpDevelop's property grid with its own, WPF-based property grid. This property grid will provide support for editing attached properties and data binding in the future.

Unlike the Windows Forms designer, which is included in the .NET Framework and merely hosted by SharpDevelop (which isn't as easy as it sounds); the WPF designer is written from scratch. Thankfully WPF makes this a lot easier than writing a Windows Forms designer from scratch would be.

The WPF designer is still missing lots of features; I would welcome any help.

You can download preview builds of SharpDevelop 3.0 from our build server.

Categories: Daniel
Sunday, 24 June 2007 16:23:00 (GMT Daylight Time, UTC+01:00)  #    Comments [5]


#  Wednesday, 13 June 2007

The current episode of .NET Rocks! has me talking about SharpDevelop, its history, the challenges, its goals and where we are headed. I wrote about the show in my personal blog too, so please check there for more information.

Categories: Chris
Wednesday, 13 June 2007 11:40:57 (GMT Daylight Time, UTC+01:00)  #    Comments [0]


#  Thursday, 24 May 2007

Another new addition to our Web offerings: the online code formatter. It is based on the syntax highlighter of SharpDevelop's text editor, and thus supports quite a few formats out of the box: SP/XHTML, BAT, Boo, Coco, C++.NET, C#, HTML, Java, JavaScript, Patch, PHP, TeX, VBNET, XML. In addition the Web form, I also added a Web service that can be used in your application to perform code conversion, a sample is available.

Noteworthy: the Web offerings are built upon the sample you can find in the source download (revisions 2522 upwards) - \Samples\HtmlSyntaxColorizer.

Categories: Chris
Thursday, 24 May 2007 20:56:35 (GMT Daylight Time, UTC+01:00)  #    Comments [0]


Our online code converter has been extended with the SnippetParser that Daniel wrote about on this blog. Now you can convert entire classes, or just code snippets. Please note that snippet conversion is only available for C# and VB.NET.

Categories: Chris
Thursday, 24 May 2007 10:21:45 (GMT Daylight Time, UTC+01:00)  #    Comments [0]


© Copyright 2016 SharpDevelop Core Team

Subscribe to this weblog's RSS feed with SharpReader, Radio Userland, NewsGator or any other aggregator listening on port 5335 by clicking this button.   RSS 2.0|Atom 1.0  Send mail to the author(s)


Copyright ©2000-2009 IC#Code. All rights reserved. Projects sponsored by AlphaSierraPapa.