Click here to Skip to main content
Click here to Skip to main content

Speed up Visual Studio Builds

By , 17 May 2011
 

Recently I got involved in a big project where we had a single solution with approximately 100 projects.

Why 100 Projects in a Solution?

The reason for a 100 projects solution is that like in many modular systems these days, we have the following three tiers:

  1. A few core / common projects every project will use.
  2. A large amount of modules, independent of each other. This tier directly depends on tier 1.
  3. A few end-projects which load the different modules. This tier indirectly depends on tier 2.

image

So, yes, we could create several solutions with each tier compiling only when needed and using DLL reference instead of project references, but the amount of changes in all the tiers was still large enough and I’ve already seen this kind of build process fail miserably. So this was no go.

Build time took 15 minutes for the whole solution. Since we enforced a gated check-in policy in the company, this was really a pain point for the developers.

Note that the developers’ computers were strong enough, with 8GB ram, Intel Core i7 CPU and SSD disks.

So I started investigating what can be done to improve the situation.

Step 1: Build Projects in Parallel

Although the PC has 8 logical cores, the build system in Visual Studio 2010, when using C#, still uses only a single core! (Note: This is not the case in C++ build system.)

So after browsing the web, I found how you can manually trigger msbuild yourself as a Visual Studio external tool to compile your solution in parallel.

image

More details on how to set this up can be found in the following post by Scott Hanselman: http://www.hanselman.com/blog/HackParallelMSBuildsFromWithinTheVisualStudioIDE.aspx

After setting this up, I got an approximate build time of 10.2 minutes. Not bad for a few minutes of work! Also, got the following beautiful image out of my CPUs, where you can really see them at work:

image

Step 2: Beware of Copy Local = True

In our 100-projects solution, lots of projects reference each other, obviously. In addition to these references, we also reference several 3rd party components, practically from each module.

All the above caused that whenever we would compile the solution, over 4.5 GB of files were written. The majority (95%) of the writes were DLLs which were copied to the output folder of each project.

To check out how many writes are done in your compilation, check out this post.

Anyway, 4.5 GB takes a long time to write, even on an SSD drive.

So the next step was to eliminate those writes. To do this, we changed almost all of the “Copy local” settings in all the referenced DLLs from the default True to False. This will prevent the referenced DLLs to be copied to the output folder of each project.

image

Note: Some file names were blacked to protect the client’s properties.

In addition, we also changed the output folder of all the projects to a single folder, so all generated DLLs are copied to the one and only place where we actually run them. Doing so dropped the writes while compiling to under 200 MB, a huge time saver. Specifically, build time dropped to 7.5 minutes!

Step 3: Use RAM Disk

A RAM disk is a logical disk which resides entirely on the RAM.
It is extremely fast (faster than any SSD), but it is erased on every power-down, so only use it for temporary files.

Of course, you should have enough RAM to spare for this disk (the memory is pre-allocated for the disk use only), but on an 8GB PC, it’s usually not an issue.

There are several programs you can use to set up a RAM disk. I used DataRam RamDisk which supplies a free version with the ability to create a RAM disk up to 4 GB (1 or 2 GB should be sufficient for any build).

Configuration of the RAM disk is very easy:

image

After you download, install and format your new RAM disk, you can move your single output folder to it. If you want to keep your output folder in the same build drive, you can simply create a symbolic link between the current output folder and a folder on the RAM disk. This way makes the using of the RAM disk optional, only for users with sufficient memory.

To create a symbolic link between your build folder and your new RAM disk folder, use the following line:

mklink /D C:\Dev\MyCurrnetBuildFolder\Source\bin R:\bin

where R: is your RAM disk folder.

Note: You should change the path according to your build folder and your RAM drive settings.

Result: Adding the RAM disk reduced compilation time to less than 5 minutes! This is a 66% reduction of the original time!

Summary

In this post, we’ve seen how you can decrease build time. Of course, I can’t make any guarantees. Every project has its own characteristics and problems, but the steps provided can probably reduce the build time if you fit the profile of standard line-of-business applications.

That’s it for now,
Arik Poznanski.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

Arik Poznanski
Software Developer (Senior) Sela Technology Center
Israel Israel
Arik Poznanski is a Senior Consultant and Instructor at Sela Technology Center. He completed two B.Sc. degrees in Mathematics & Computer Science, summa cum laude, from the Technion in Israel.
 
Arik has extensive knowledge and experience in many Microsoft technologies, including .NET with C#, WPF, Silverlight, WinForms, Interop, COM/ATL programming, C++ Win32 programming and reverse engineering (assembly, IL).
Follow on   Twitter

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionMulti-core, Visual Studio 2012memberPopeDarren17-Apr-13 12:55 
The machine I most recently received has multiple cores. It also has windows 7 on it so, naturally, I installed VS 2012.
 
My question is simple enough: do all the pointers found within this article still apply to VS 2012? It seems to be building in parallel already when I watch the task manager's performance monitor.
 
I have copy local = false on most of the dlls.
 
Should I still use RAM disk?
 
Thanks in advance!
GeneralMy vote of 5memberShlomiO27-Jan-13 22:59 
Nice one - thanks!
Questionmsbuild and file locksmemberJesseChisholm25-Jun-12 10:54 
Just so you know, there are times with msbuild will lock a file in one core, and try to update it in another core.
 
It is rare, but when this happens, the only known resolution is to reboot your system.
Frown | :(
 
For this reason, our developers (of our large solution that sometimes does this) use devenv; even though msbuild is faster - rebooting is way slower. Smile | :)
 
-Jesse
GeneralMy vote of 5memberzenwalker198520-Jun-12 18:30 
My vote 5, today i found out that my 56 project solution would take half time with msbuild. Thanks to you and Scott.
QuestionThanks !memberAmir Hosein Nasr2-Oct-11 10:47 
I cant say any more ! Big Grin | :-D Poke tongue | ;-P
GeneralStrategy for single output folder and RAM diskmemberKevin Finke16-Jun-11 11:53 
Our solution has 60 projects. We have a few tiers, including 3 WCF services, a web site for hosting the XAPs, and a Silverlight Prism app with several modules.
 
I've been experimenting with ways to increase the performance of the build for everyone, as there are about 20 of us working on the project, and everyone's complaining over the build time.
 
I've followed most of the advice in this article, but I'm a little confused with a good strategy for where to output to, as well as which assemblies to stop copying locally. I've run through each project in the server tier so far, and my strategy was that if this project was not a "hosting" project (the wcf projects, the web project, a test project, etc) then it didn't need any assemblies copied local. Most things seem to work, I have one wcf project that complains over not loading an assembly, i'm assuming I just got too agressive.
 
As for the output folder, though, what are we trying to achieve? It seems that wcf services still want everything in the \bin folder of the project, which is on the c: drive. Do I set all projects that run in the same tier to the same output folder?
 
Your suggestions would be appreciated.
GeneralRe: Strategy for single output folder and RAM diskmvpArik Poznanski16-Jun-11 12:01 
Well, the point in removing the local copies was to save time in compiling, since these DLLs are not needed in most output folders of the modules.
However, these DLLs are required in the host application folder, so you can either leave the local copies of this project, which I think is what you have done.
Or, simply change the output folder of the modules DLLs to the host build folder.
Arik Poznanski

GeneralRe: Strategy for single output folder and RAM diskmemberKevin Finke16-Jun-11 12:02 
Can you change the output folder of a web app / wcf service? For your scenario, what builds to the ram drive?
GeneralYou can configure all temporary files to use the ramdrive as well.membercac_23-May-11 2:05 
You can configure all temporary files to use the ramdrive as well.
Ex: .NET temporaries, IE temporaries, etc…
 
Instead of altering each project's web.config, you should alter the machine's web.config:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\web.config
 
to include these parameters:
<compilation batch="false" tempDirectory="R:\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files">
 
That is, switch from drive c: to drive r:.
This way, all projects that are built on that machine will send the .net temporaries to the ramdrive.
 
(Now, don't send this web.config to production environment!!!)
GeneralMy vote of 5memberRhuros17-May-11 21:05 
nice tips, worth implementing...

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130617.1 | Last Updated 17 May 2011
Article Copyright 2011 by Arik Poznanski
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid