Speed up Visual Studio Builds

May 17, 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 loads 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’ve 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’ve 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’ve 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’re fit the profile of standard line-of-business application.


That’s it for now,
Arik Poznanski.


Add comment
facebook linkedin twitter email

Leave a Reply

9 comments

  1. elad katzMay 17, 2011 ב 08:14

    Great post Arik!

  2. David KempMay 17, 2011 ב 11:29

    Have you tried putting the obj directory on the ram drive?

  3. arikMay 17, 2011 ב 13:39

    David,
    I just assumed this happens automatically once I move the output folder,
    but didn’t really check.

    Do you know how this is done?

  4. Roni DoverMay 17, 2011 ב 18:28

    We faced the same issue here trying to work with very large solutions. The approach we found the most effective was to work with file references (a solution which posed many challenges of its own). We wrote about issues we faced and how we solved them in this post, which I hope might be useful for you as well: http://wordpress.qualisystems.net/?p=40

  5. William BartholomewMay 18, 2011 ב 00:59

    Hi Arik,

    The first hack shouldn’t be necessary in VS 2010. Go to Tools | Options | Projects and Solutions | Build and Run and change the maximum number of parallel project builds to the number of cores your machine has.

    Regards,
    William

  6. arikMay 18, 2011 ב 13:31

    Roni, interesting post.
    Nice to see another approach to this issue.

  7. arikMay 20, 2011 ב 14:11

    William, if I’m not mistaking, this affects only C++ projects.
    Do correct me if I’m wrong.

  8. Dave LudwigJune 1, 2011 ב 16:35

    The way you show msbuild being used looks rather easy, but when I started reading about msbuild it seems rather complicated to set up build scripts. Did you make build scripts, or is it as easy as you show?
    Thanks!

  9. arikJune 1, 2011 ב 16:44

    I didn’t make any script. I use it exactly as in this post.