Optimising Visual Studio Build Times

by Naeem Khedarun 16. July 2011 00:58

 

At my current workplace we have 203 projects in a single tanged web of a solution. This unfortunately means the majority of projects need to be built for any of the services or sites to function, thus breaking down the solution is not a viable solution at the moment. So I took a look at reducing those build times, and here are my results:

Rebuilding your solution

Running a rebuild in visual studio 2008 takes…

7:42 minutes

*Sigh* Let’s try the same thing in the Visual Studio 2008 Command prompt:

Msbuild.exe mysolution.sln /t:rebuild

2:39 minutes

*Wow* Let’s add some tweaks, first up is the multicore build tweak.

Msbuild.exe mysolution.sln /t:rebuild /m

1:25 minutes

*Pretty cool* There’s a strange bug in the normal command line which slows down execution of running programs. So let’s use a filelogger instead of a console logger.

Msbuild.exe mysolution.sln /t:rebuild /m /noconsolelogger /fl

Try it out and see if you get a decent benefits!

Building your solution

Running a normal build inside Visual Studio takes:

3:10 minutes

And using the command line:

Msbuild.exe mysolution.sln /t:build

27 Seconds

Now with the multicore tweak:

Msbuild.exe mysolution.sln /t:build /m

12 Seconds

So all in all not a bad way to manage a solution with 203 projects in it!

Happy deving…

Categories: msbuild | VS2008

Using PowerShell to automate setting CopyLocal to false

by Naeem Khedarun 22. June 2011 12:31

 

It’s been stressed that CopyLocal is slow and evil, so I wanted to see what the impact was on our codebase.

First we need to load the project file and pull out the references sections.

[xml]$s = get-content $projectFile

$references = $s.Project.ItemGroup | Where-Object { $_.Reference -ne $null }
$projectReferences = $s.Project.ItemGroup | Where-Object { $_.ProjectReference -ne $null }

Next we can iterate through the child nodes, and if they are missing the Private tag, add it in.

foreach($reference in $references.ChildNodes)
{ 
    if($reference.Private -eq $null)
    {
        [System.Xml.XmlElement]$copyLocal = $s.CreateElement("Private", "http://schemas.microsoft.com/developer/msbuild/2003")
        $copyLocal.InnerText = "False"
        [Void]$reference.AppendChild($copyLocal) 
    }
}

We can do a similar thing with the project references if your solution builds into a single folder.

foreach($reference in $projectReferences.ChildNodes)
{ 
    if($reference.Private -eq $null)
    {
        [System.Xml.XmlElement]$copyLocal = $s.CreateElement("Private", "http://schemas.microsoft.com/developer/msbuild/2003")
        $copyLocal.InnerText = "False"
        [Void]$reference.AppendChild($copyLocal) 
    }
}

Then all we need to do is save the file and we are done!

$s.save($projectFile)

If you want to apply this too all the project files in a directory, recursively then you could do:

Get-ChildItem $directory -include *.csproj,*.vbproj -Recurse | foreach ($_) { 
    Set-CopyLocalFalse $_.fullname $true
}

You can find the source for this in the SlightlyPosher distribution, or look at the source for the file.

Preliminary tests on our build time dropped from 6:30 minutes to 3:48 minutes thanks to this!

XmlLists with Psake / Powershell

by Naeem Khedarun 7. November 2010 00:07

On a POSH roll here, this time I needed to list out the Include attributes for references in an msbuild file. Let’s take a look at the POSH script equivalent of XmlList:

function xmlList([string]$file, [string]$xpath, [hashtable]$namespaces) { 
    [xml] $fileXml = Get-Content $file 
    $xmlNameTable = new-object System.Xml.NameTable
    $xmlNameSpace = new-object System.Xml.XmlNamespaceManager($xmlNameTable)

    foreach($key in $namespaces.keys)
    {
        $xmlNameSpace.AddNamespace($key, $namespaces.$key);
    }
    $nodes = @()
    $node = $fileXml.SelectNodes($xpath, $xmlNameSpace) 
    $node | ForEach-Object { $nodes += @($_.Value)}
    
    return $nodes
}

Now to use this we can do this:

$namespaces = @{ "xsi" = "http://schemas.microsoft.com/developer/msbuild/2003"}
$xpath = "//xsi:Reference/xsi:HintPath/../@Include"

$nodes = xmlList "$examplesdest_dir\NBehave.Examples.csproj" $xpath $namespaces

And it gives us a list of the references in the msbuild file.

image

Categories: Powershell | Psake | msbuild