When I’m describing what I do for a living to non-programmers I sometimes say that I solve puzzles. I solve fascinating puzzles that are different every day, and there’s no answer key, and very often nobody else knows the solution. Whether it’s figuring out why code is slow, or why it is crashing, or how to make code simpler and better, it’s all puzzles, and I love it.
This past weekend I worked on a puzzle which I thought was interesting, especially in the ways that it was different from ‘normal’ puzzles such as jigsaw or crossword puzzles.
Note: VS 2015 RTM has a bug in /DEBUG:FASTLINK which corrupts some debug information. It will be fixed in SP1.
Finding the puzzle
When most people solve puzzles it is because they are asked to on Facebook, or because they bought a book of puzzles, or they are in a math class pondering a train from Chicago…They are given a puzzle to do. In this case my first challenge was realizing that there was a puzzle to solve. I knew, from talking to the Visual Studio team at Microsoft and from reading their blog, that VC++ 2015 had a new /DEBUG:FASTLINK switch that could make PDB generation run faster. The puzzle was to enable this for Chromium in order to get faster builds. I decided that this was a worthwhile task that probably nobody else was working on. Challenge accepted!
Figuring out when you’ve won
Most puzzles have clearly defined winning conditions – fill in the Sudoku or finish the jigsaw puzzle. It’s pretty obvious when you’re done. However with FASTLINK this wasn’t as obvious. I could try timing the builds as I adjusted the build settings but build timings are notoriously fickle – affected by the disk cache, power settings, and more. However I knew that FASTLINK worked by not copying debug information from object files, so the PDB should be smaller when FASTLINK was working and that would be a much more stable metric than build time.
However, if you alternate between builds with and without FASTLINK you’ll find that the PDB size does not change. That’s because VC++ never shrinks PDBs, it just shifts data around inside the container, and increases its size when necessary. Therefore, whenever doing PDB size tests you always need to delete the PDB between runs. This is unrelated to incremental linking – it’s more related to PDB ages.
Figuring out the rules
The rules of most games are clearly stated, but in many programming puzzles they are not. In this case I adjusted the Chromium build settings to add FASTLINK, confirmed that it was being passed to the linker, and observed that the PDB size was unchanged.
I then tried a separate project – a ‘normal’ Visual Studio project (UIforETW, as it turns out) and verified that converting that to VC++ 2015 and setting FASTLINK worked as expected – the PDB got smaller.
Given one case that worked and another case that didn’t the next step is to understand what the difference is. I captured the .rsp file used by Chromium’s ninja build system and then called the linker directly. That let me modify the .rsp file in order to quickly iterate.
I tried rearranging command-line options and then I tried deleting command-line options. A bit of binary search and a bit of intuition led to the solution.
It turns out that FASTLINK is incompatible with /PROFILE. The /PROFILE switch is passed to the linker by default in Chromium builds which means that, by default, FASTLINK doesn’t work in Chromium. With that detail understood it was relatively easy to create a patch that, once it lands, will allow easy access to the VC++ 2015 FASTLINK feature.
We don’t need no stinkin’ documentation!
It would be nice if the /DEBUG:FASTLINK documentation mentioned this restriction, but at the time that I am writing this blog post there is no such documentation. There are a couple of blog posts that mention the FASTLINK feature, but the official VC++ documentation on VC++ 2015’s /DEBUG switch does not mention FASTLINK, and certainly doesn’t mention its restrictions. Such is the joy of working on the bleeding edge, being among the first to use a new feature.
To the victor, the spoils
My limited tests suggest that FASTLINK reduces elapsed link time by 33-55%, and reduces peak working set of the linker by 65-90%. PDB sizes are reduced by 65-72%. These are all worthwhile gains that will make switching Chromium to VC++ 2015 more worthwhile.
The PDB files created by FASTLINK are inherently machine local. That’s a reasonable tradeoff, but sometimes it is useful to be able to convert machine-local PDBs to portable PDBs. I’ve filed a bug requesting a tool to do this.
- FASTLINK apparently doesn’t work if you must debug in Mixed Mode
- FASTLINK has no effect on LTCG builds