-
Notifications
You must be signed in to change notification settings - Fork 745
Improve debugging experience #3464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
sharwell
commented
Jan 31, 2020
- Do not optimize test framework (stepping in debugger will have full information about parameters, locals, and breakpoints)
- Embed symbols in assemblies (eliminates the need to copy PDB files)
- Embed sources in assemblies (eliminates the need to download sources separately)
808e0a1
to
bb1abae
Compare
I'm concerned about this. Can you give us some idea of what performance we are giving up as well as some idea of how much time this would save you and how often this would happen? Stepping through release builds of libraries is a well-understood scenario. I'm not sure what makes NUnit a special case.
I'm a fan. Isn't .snupkg the current recommendation and also working out of the box these days for anyone with VS2019+, with a very simple fallback (add symbol download address) for folks on older VS?
I'm a fan. I do this absolutely everywhere I'm allowed. |
@sharwell because of our history, I trust you and this looks good, but I would appreciate it if you could provide a bit more explanation or point us to the documentation for the build properties you introduced. I like the change, but I'd like to read up a bit more on it if possible. |
Task("GitLink") | ||
.IsDependentOn("CreateImage") | ||
.Description("Source-indexes PDBs in the images directory to the current commit") | ||
.Does(() => | ||
{ | ||
var settings = new GitLink3Settings | ||
{ | ||
BaseDir = PROJECT_DIR | ||
}; | ||
GitLink3(GetFiles($"{CurrentImageDir}**/*.pdb"), settings); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 GitLink (and SourceLink) are used to help the debugger locate the original sources used for building an assembly, allowing for a seamless debugging experience. This pull request removes this functionality because the original sources are now embedded inside the DLL itself. It provides the best possible debugging experience (zero latency, zero configuration required) at the expense of a larger assembly (the DLL now contains the PDB and all the source files). Note that the embedded PDB uses the portable PDB format so even with the sources it's likely smaller than the "full" PDB format used in the past.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I did the numbers, the portable PDB+embedded source was 3.75× the size and Windows PDB+GitLink was 2.51× the size. I don't think size should be the determining factor though.
Embedded source requires VS 2017 Update 5+ for the debugger to locate the source. Do you know what version of VS is required to locate the source when the PDB is also embedded in the assembly?
I'm thinking that's far enough behind us now that it isn't a concern. Guessing that latest 2017 and 2019 both work.
<Optimize>false</Optimize> | ||
<DebugType>embedded</DebugType> | ||
<DebugSymbols>true</DebugSymbols> | ||
<EmbedAllSources>true</EmbedAllSources> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Two of these properties (Optimize=false and DebugSymbols=true) are the default settings you always see when building with
/p:Configuration=Debug
. - DebugType=portable is the default for .NET Standard and .NET Core (and perhaps all SDK projects). DebugType=embedded uses the same PDB format as portable, but instead of creating a standalone PDB it embeds the PDB itself inside the DLL.
- EmbedAllSources=true embeds all source files inside the PDB, which allows the debugger to locate source files without needing to look for them elsewhere. The source files end up embedded inside the DLL as a side effect of the PDB being embedded inside the DLL.
At this point, the debugging experience for end users will be very close to the experience NUnit developers have when debugging with a Debug build configuration. There are two differences:
- I doubt Edit and Continue will work.
- Release builds still do not define the
DEBUG
preprocessor symbol, so things likeDebug.Assert
will still not be included in the compiled code.
Since NUnit doesn't have heavy computation loops, I'm not expecting a significant observable change. The most likely observations will be increases in allocations associated with methods marked The best test case would likely be a project with a very large number of very small tests. |
I'm going to rebase this change to address the merge conflict. |
@sharwell I'm still curious what makes NUnit special, or is this coming from a blanket recommendation that all .NET libraries should consider switching to shipping debug builds? (And what is the source of the recommendation?) |
More the idea that unit testing frameworks are part of the developer's inner loop more than part of production code. The case where I found myself wishing for better debugging was trying to step through |
That helps, thanks! This type of change would thus not be applicable to the NUnit console, engine, or VSTest adapters then, I'm thinking? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with this but it is redoing the work you did @jnm2. Can you give it a second review?
https://github.com/nunit/nunit/blob/master/README.md#debugger-source-stepping also needs to be updated or deleted. |
@sharwell, @jnm2 After this change is seems that the debugger will always enter NUnit code when people are debugging their tests (no matter if "Enable Just My Code" is checked or not). It has reported in https://groups.google.com/g/nunit-discuss/c/f2yV4G_kdi8/m/ypWZfLSEDgAJ and I can also reproduce this. Do you know if it is possible to configure VS such that it does not enter NUnit code. |
I see, even with Just My Code turned off. I'm in favor of moving to the snupkg format then, since that uses the well-known nuget.org symbol server that has been built into VS for a while. |
@mikkelbu I would suggest filing an issue through Developer Community. I can't wrap my head around the idea that someone could have Just My Code enabled and not think it's a bug, so the response that makes the most sense to me is "obviously this behavior is correct, so I'm not sure what the question is 😕 ". But based on what I know of Just My Code, the behavior would be considered a bug in that scenario. |
@sharwell Just My Code is a lifesaver when you are working with libraries that handle exceptions or when you don't want extra waits every time you debug where VS loads symbols (even when using a whitelist). |
I've created the following issue in Developer Community - https://developercommunity2.visualstudio.com/t/The-debugger-enters-code-in-PackageRefer/1321266 |
From .NET Just My Code:
So one can argue that the .NET Debugger is correct by thinking NUnit* is user-code, as pdb is there and program optimizations are off. But I agree that this is counterintuitive and "Just my code" should be tightened to only consider "my" code. * Moq, etc. which also embeds the pdb have the same "issue". |
- Build portable PDBs - Create snupkg files for uploading symbols - Reinstate gitlink