Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Startup of Winforms program 10x slower under x64 relative to x86

I've created a popular Winforms program in C# which has a lot of GUI widgets, and found that when the platform target is x64, startup is around 5-10x slower than x86. Under an x64 target, it takes around 5 seconds to start up, and this negatively impacts the user experience. I'd like to make it quicker.

I also tried with another program of mine, and also found the startup time under x64 was double or triple that of x86.

So I began to wonder what was causing it. My programs use quite a lot of widgets, so to test the theory I decided to create a test project with 800 buttons! I set all of them to Visible=False so that redrawing/refresh speed doesn't muddy the waters.

Sample form with 800 buttons

To my amazement, the x64 started up a LOT slower than the x86 equivalent. I then proceeded to time the InitializeComponent(); section and sure enough, the x64 version ran in about 3.5 seconds. The x86 on the other hand took only around 0.275 seconds. That's almost 13x quicker!

.NET Framework 2.0, 3.0, and 3.5 are equally as bad. Targeting .NET 4 & 4.5 under x64 is much better at around 0.8 seconds, but that's still about 3x as slow (x86 is about as good at 0.28 seconds), and I want to use .NET 3.5 for the increased userbase.

So my question is: What's causing the x64 version to start up so slow, and how can I make it quicker so that it's comparable to the x86 version?

If anyone wants to test immediately, I have created a zip of the VS 2010 project which can be downloaded here: http://www.skytopia.com/stuff/64_vs_32bit_Startup_Speed.zip

like image 769
Dan W Avatar asked May 09 '15 09:05

Dan W


1 Answers

It's the JIT cost of your 10000 line InitializeComponent function.

  • If you measure the time between the call to InitializeComponent and the execution of its first line, that's the majority of the cost. (Just insert a line at the top of InitializeComponent for the measurement.)

  • If you use the VS Performance Analyzer, it'll show most time spent in ThePreStub, which is related to JIT.

  • The 64 bit JITter takes longer to compile code than the 32 bit JITter, but in exchange it produces better code.

    Microsoft is working on new version of the JITter, called RyuJIT. It's derived from the 32 bit JITter and has similar characteristics (fast compilation outputting worse code). It will become the standard JIT in future versions of .NET.

  • .NET 4.5 reduces cost from 2.0 seconds to 1.3 on my machine. This is probably due to JIT improvements in the 4.0 runtime.

  • An equivalent loop is much faster than your InitializeComponent function.

    That won't help you if you want to create all components in the designer, but if you have a mix of repetitive controls and components that you want to edit in the designer, you can use a loop. Just put it in Form1.cs not in Form1.designer.cs so that it won't get overwritten by the designer.

  • Using NGen on your assembly should eliminate the JIT cost. But it comes with the downside of having to deal with the GAC.

like image 181
CodesInChaos Avatar answered Oct 14 '22 09:10

CodesInChaos