9

Can I run a program that heavily uses exceptions in the debugger and not catch the exceptions in the debugger?

Specifically I'm trying to use the TSQL ScriptDOM parser, and I understand that it's use of ANTLR is slow in debug mode.

It is not that strange if you look at the debug output, you will find that this is caused by the Microsoft® SQL Server® 2012 Transact-SQL ScriptDom parser, since this is based on the ANTLR framework, it unrolls AST productions using exceptions, this is what it makes it slow when running inside the debugger.

I completely understand that .net exceptions are slow when thrown

How can I avoid the slowness when running with the standard DEBUG configuration, with the debugger attached?

  • I've disabled intellitrace.
  • I've undefined the DEBUG constant.
  • I've turned off exception messages in the Tools > Options > Debugging > Output Window.

What else can I try?

  • a CLR setting I can change via the app.config?
  • an option to change in Visual Studio?

This is the specific code I am using for parsing.

TSqlParser parser = new TSql110Parser(false);
IList<ParseError> errors;
TSqlFragment fragment = parser.Parse(new StringReader(sqltext), out errors);

When run using CTRL+F5 it finishes quickly, and using F5 (debugger attached), I give up waiting.

Community
  • 1
  • 1
JJS
  • 6,431
  • 1
  • 54
  • 70
  • Can you try putting a breakpoint, detaching the debugger, then doing a [`Debugger.Launch()`](https://msdn.microsoft.com/en-us/library/system.diagnostics.debugger(v=vs.110).aspx) after the parse has completed. If it works I will post it as an answer. – Scott Chamberlain Oct 28 '15 at 15:55
  • @ScottChamberlain this is a workaround to get past the code that throws the exceptions. You should move the question to an answer as it's a valid solution, but does not answer if the debugger has a setting that can be changed or not. In this case, I'm disabling the debugger to bypass the issue. – JJS Oct 28 '15 at 17:00

4 Answers4

7

One possible workaround you can do (I ran in to a similar issue where a image processing library would throw a OutOfMemoryException if used while the debugger was attached on a particularly large dataset) is put a breakpoint before calling in to the 3rd party library code and detaching the debugger, after the breakpoint re-attach the debugger with a Debugger.Launch().

#if DEBUG
bool debuggerAttached = Debugger.IsAttached;
if(debuggerAttached)
{
    Debugger.Break(); //Detach the debugger to make the next section faster.
}
#endif

TSqlParser parser = new TSql110Parser(false);
IList<ParseError> errors;
TSqlFragment fragment = parser.Parse(new StringReader(sqltext), out errors);

#if DEBUG
if(debuggerAttached && !Debugger.IsAttached)
{
    Debugger.Launch();
}
#endif
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • @ScottChamerlain - great code example that demonstrates the workaround. Great use of pre-compiler symbols too! Thanks for contributing. – JJS Nov 02 '15 at 17:38
  • This does not seem to work. Debugger.Break() will not detach the debugger, it will trigger a breakpoint which is not the goal here (https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.debugger.break?view=netcore-2.2). – Kristof Verbiest Feb 12 '19 at 14:56
  • 1
    @KristofVerbiest The detach is a manual operation done via the Visual Studio UI. There is no way to detach via code easily. – Scott Chamberlain Feb 13 '19 at 04:54
4

You can't stop the exceptions and first chance exceptions are slow under the debugger as the process is paused, operation is transferred over to the debugger to say whether it wants to know about it or not and then the client is restarted again (until the next one). That is how the Win32 Debug Api works I am afraid.

I do quite a lot of debugging of ScriptDom and the best I have come up with is parsing small scripts that are well formed and valid.

I try to limit the script to just the part that has an issue.

ed

JJS
  • 6,431
  • 1
  • 54
  • 70
Ed Elliott
  • 6,666
  • 17
  • 32
  • can you give a citation for your answer from the vendor? http://blogs.msdn.com/b/visualstudioalm/archive/2015/03/03/make-debugging-faster-with-visual-studio.aspx - in the heading of Large number of exceptions was exactly what I was looking for. – JJS Nov 02 '15 at 17:37
  • just to clarify, do you mean a citation for why first chance exceptions are slow or why there are lots of first chance exceptions? – Ed Elliott Nov 02 '15 at 21:54
  • specifically the behavior how a process is paused, reported in the debugger and then resumed. I don't have a method of profiling this, but I assume this is what causes the slow-down. My link in the previous comment specifies that this is one of the reasons for the slowdown. – JJS Nov 02 '15 at 21:56
  • 2
    Also, worth noting that they made this scenario better in VS2015 using DebuggerNonUserCode - http://blogs.msdn.com/b/visualstudioalm/archive/2015/02/23/performance-improvement-when-debugging-net-code-with-visual-studio-2015.aspx – JJS Nov 02 '15 at 21:59
  • Well when a first chance exception happens in the client an EXCEPTION_DEBUG_INFO is fired with dwFirstChance set to 0 (https://msdn.microsoft.com/en-us/library/windows/desktop/ms679326(v=vs.85).aspx) - If you have a debugger attached this is fired whether you say debug your user code or not - the child process is frozen until you call ContinueDebugEvent (https://msdn.microsoft.com/en-us/library/windows/desktop/ms679285(v=vs.85).aspx) to see how debuggers work compile and run: https://msdn.microsoft.com/en-us/library/windows/desktop/ms681675(v=vs.85).aspx – Ed Elliott Nov 02 '15 at 22:12
  • one more link, an old article I wrote on .net exceptions and why they are so expensive: https://www.simple-talk.com/dotnet/.net-framework/a-look-at-exceptions-in-.net-applications/ It isn't from microsoft but is still true today with the exception types you are seeing. – Ed Elliott Nov 02 '15 at 22:21
  • thank you for the answer Ed. Article looks great too. – JJS Nov 02 '15 at 23:22
  • no probs, honestly the best way to debug the scriptdom is just to use small scripts wherever possible - it is quicker to build a small test case than wait over and over again :) – Ed Elliott Nov 02 '15 at 23:25
  • I agree. Debugging small is a workaround. I wanted to know what caused the slow behavior, and whether it could be disabled. Your link contains additional detail about 'how' exceptions work, how they're implemented in windows, and how VS handles them. I was sick of the 'workaround' answers. – JJS Nov 02 '15 at 23:27
3

If you have some code which throws a lot of exceptions, it can perform very slowly if the debugger is attached.

To improve the speed of such a method, you can add the DebuggerNonUserCode attribute to the top. For example:

[DebuggerNonUserCode]
public static bool IsArchive(string filename)
{
    bool result = false;
    try
    {
        //this calls an external library, which throws an exception if the file is not an archive
        result = ExternalLibrary.IsArchive(filename);
    }
    catch
    {

    }
    return result;
}
Fidel
  • 7,027
  • 11
  • 57
  • 81
  • How does this address the original question? The Assembly I was using was clearly already NonUserCode, distributed by Microsoft. – JJS May 20 '19 at 18:40
  • Hi JJS, I had a very similar situation to you. The call to IsArchive([stream]) is to an external library. I call it many (millions) of times and have to deal with exceptions. I found that adding the attribute meant that the program duration dropped from 49 minutes down to 7 minutes.So I was answering your query "How can I avoid the slowness when running with the standard DEBUG configuration, with the debugger attached?" – Fidel May 20 '19 at 23:18
  • If I understand, you're saying IsArchive(string) is your usercode, and you were wrapping the external code IsArchive(FileStream). Enhance your answer explaining which part is the external code, maybe with a comment in the code block... – JJS May 21 '19 at 16:00
  • Thanks JJS, that's a fair comment. I've updated the answer – Fidel May 21 '19 at 23:05
2

It is not actually .NET exceptions that are slow, although they are not exactly a speed demon. You can throw a fat ten thousand of them before you lose a second of your life. It is in fact your debugger that's slow. It dutifully reports the exception in your Output window, that's quite expensive.

Very easy to fix, right-click the window while you are debugging and untick "Exception Messages". You can make that setting permanent with Tools > Options > Debugging > Output Window.

If you still have to wait too long then be sure to debug your code with small datasets so you just don't have to wait forever. The odds that code only fails on 100,000 but not on 100 data items are drastically low. It is very important that you test your app to handle large amounts of data to verify that it can scale well. But you only ever do that with the Release build without the debugger attached.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I've already tried turning off output messages for exceptions. I have updated the question to reflect this. – JJS Oct 28 '15 at 16:54
  • you raise a valid point. Only debug with bad data. This is a workaround and does not answer my original question of how to make the debugger not slow down in the face of exceptions. – JJS Oct 28 '15 at 16:59
  • ?hmya? I realize I may be asking for a pony. If so, I'd like definitive documentation that it's actually a unicorn, and can't be had. – JJS Oct 28 '15 at 17:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/93708/discussion-between-jjs-and-hans-passant). – JJS Oct 29 '15 at 15:41