NDepend

Improve your .NET code quality with NDepend

Improve Visual Studio Build Performance

Improve Visual Studio Build Performance

Time is your most precious asset and slow build is high in the list of developer’s productivity killers. With slow build the penalty is twofold:

  • not only the time taken to build is lost,
  • but often – during long enough build – your focus gets stolen by other tasks like mail check, coffee, social network… And when a programmer gets distracted, it takes a “good while” until she/he start editing code again.

Thus struggling for shorter build time is essential. This post discusses various tooling and strategies to Improve Visual Studio Build Performance:

Visualize and Measure Build Performance

Prior to improving one must first measure and understand. The Visual Studio extension Visual Studio Build Timer displays a live chart about your build in Visual Studio. This extension seems not well know and it doesn’t work yet with Visual Studio 2022. Nevertheless it can be an eye opener.

Our main solution for NDepend consists of 37 projects, including test projects. Compiling them all takes 43 seconds on my beefy laptop (64GB RAM, Xeon 6 Cores, 2x 1TB SSD). Btw, developing with a powerful machine is essential. Each saving done on hardware will likely costs a hundred more in terms of developer time and focus wasted.

Here is a GIF of our build on VS 2019 accelerated. Let’s hope this extension will be ported to Visual Studio 2022.

VS Built Time Extension

Visual Studio Solution Filters

More than 40 seconds build is a killer. As most of other development shops, we usually work with only a few projects loaded at a time. Thus it became a habit to unload manually unnecessary projects to achieve faster compilation. But the process of unloading projects set can be improved significantly by defining some solution filter files (.slnf extension). To create a solution filter just unload some projects, right click the solution item in the Solution Explorer panel, and click the menu Save as Solution Filter.

Save As Visual Studio Solution Filter

Visual Studio considers solution filter files (.slnf) as solution files (.sln) in the Start Window and also in MRU (Most Recently Used) menus. Also like a solution file, a filter file is a textual file that can be easily edited.

Solution Filters Visual Studio Start Window

Loading a solution filter file just loads target projects and totally ignore others projects: they are not even shown as unloaded. The filter name is reminded in the top solution item to help.

Visual Studio Solution Filtered Loaded

It is up to you to define your solution filters. Some filters can be defined upfront: for example when some large projects are stable enough and not churned often. Some other filters are best defined at development time and can be ephemeral. For example when you realize that a particular refactoring task only impacts a few application and tests projects.

Keep in mind that unloading project comes with a downside: if the public API of a low-level project gets refactored with VS or R# refactoring tools, changes won’t be reflected in unloaded consumer projects.

Incremental Build

Within the Visual studio context, MSBuild checks if a project output is up-to-date or not, to determine if it needs to be compiled. This feature is named Incremental Build and is essential to significantly reduces the number of projects compiled and thus, to achieve most of the time way faster build.

Common causes for a project for not being up-to-date are:

  • One of the file used as project input (source file, resource file…) has a newer timestamp than the timestamp of a project output file (.dll, .pdb, .xml documentation…).
  • The project depends on at least one project that is not up-to-date.

Incremental build checks cannot be perfect, especially when some non-trivial features are used. For example if one of the project file has the property Copy to Output Directory set to Copy Always, the project will never be considered as up-to-date. Such cause is not obvious and an investigation must be conducted to find the glitch. To investigate, in the Visual Studio > Options > Projects and Solutions > SDK-Style Projects, set the Up to Date Checks value from None to Minimal.

Visual Studio Up to Date Checks Log

Now in the Output window we can see this log:

Such log is a good hint of the cause of what forces the project to be recompiled every time. To solve this just set Copy to Output Directory to Copy if Newer.

Copy if Newer

The procedure to know if your solution has a problem with incremental build is easy: first use the command Build > Rebuild Solution then use the command Build > Build Solution. If some projects are recompiled the second time, then investigate.

Btw in the screenshot above the extension VSColorOutput64 is used to have color in the Visual Studio 2022 output panel. The same extension for Visual Studio 2019 is named VSColorOutput.

Other Considerations to Improve Build Performance

First, this might sound obvious but things like Anti-Virus or running under a VM can significantly slow down all development tasks, especially builds.

Make sure you use parallel builds and also have “Only Build Startup and Dependencies on Run” in the Visual Studio option dialog: Project and Solutions > Build and Run:

Visual Studio Options for Faster Build

Another point: By default Visual Studio compiles each project in its own .\bin\Debug directory and copy there all assemblies referenced by the project. I remember doing so was a real build performance killer with older Visual Studio versions like VS 2013 and earlier. Hopefully this has been fixed. Nevertheless if a project P is referenced by N other projects, there exists N+1 versions of the P assembly. Not only this waste of resource is not satisfying but it might be well that the N+1 versions of P get out-of-sync, for example because some projects are unloaded in the Visual Studio Solution Explorer. This can lead to some unexpected behaviors at run time, like getting a MissingMethodException. This is why we make sure that all projects of a solution (except test projects) share the same output directory ..\bin\Debug. This way each assembly exists in a single version and we don’t waste resources.

Visual Studio Project Output Path

Hot-Reload to skip Build

With the new .NET hot-reload feature (formerly known as Edit and Continue), the cycle [ code – build – launch – reach state to test – test it ] gets shortened since the steps [ build – launch – reach state to test ] can be skipped in many edit situations (but not all kind of edits are supported as explained here).

With hot reload, somehow source code changes get tracked, compiled and injected into the process to patch executed binaries. Interestingly enough injecting changes with hot reload is significantly faster than rebuilding the concerned Visual Studio project. It means that with Hot Reload the unit of build is finer-grained than the project/assembly level.

Most of the time the source code modifications between two builds represent a tiny fraction of the rebuilt code. We can imagine that in the future the build pipeline could benefit from this technology to improve the performance of incremental build by injecting code modifications in the binary instead of rebuilding the entire binary. This is purely speculative but here is a hint about the feasibility: In Visual Studio 2022  hot reload can be enabled to speed up test execution by skipping expensive builds for supported kind of edits. Notice this feature is still experimental and only works for .NET 6.

Visual Studio 2022 Hot Reload In Test

Conclusion

Do yourself and your team a favor by shortening build time for most builds. Invest in powerful hardware, use the right tools and conduct regularly investigations to determine what can be improved.

 

My dad being an early programmer in the 70's, I have been fortunate to switch from playing with Lego, to program my own micro-games, when I was still a kid. Since then I never stop programming.

I graduated in Mathematics and Software engineering. After a decade of C++ programming and consultancy, I got interested in the brand new .NET platform in 2002. I had the chance to write the best-seller book (in French) on .NET and C#, published by O'Reilly and also did manage some academic and professional courses on the platform and C#.

Over my consulting years I built an expertise about the architecture, the evolution and the maintenance challenges of large & complex real-world applications. It seemed like the spaghetti & entangled monolithic legacy concerned every sufficiently large team. As a consequence, I got interested in static code analysis and started the project NDepend.

Today, with more than 12.000 client companies, including many of the Fortune 500 ones, NDepend offers deeper insight and full control on their application to a wide range of professional users around the world.

I live with my wife and our twin kids Léna and Paul in the beautiful island of Mauritius in the Indian Ocean.