Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Performance penalty of Debug.Assert in .NET

Performance penalty of Debug.Assert in .NET

Scheduled Pinned Locked Moved C#
csharpquestionc++visual-studiodebugging
11 Posts 5 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    Rob Philpott
    wrote on last edited by
    #1

    I'm writing some low level C# which is doing bit level operations (shifting/logic) which needs to be very high performance (real time application). Usually, I'd just do some checks and throw an exception if things aren't right, but I can't afford the overhead of that here. Back in the day, in C++ I'd just use assertions for my checks which would cease to exist completely in the release build. In C#, we have Debug.Assert but its use seems greyer to me, because debug vs. release in .NET is greyer. Macros disappear depending on switches, but it seems the only way a Debug.Assert can disappear is if its hardedcoded in the JIT that way. So my question I guess is does the Debug.Assert make it into the MSIL regardless of debug/release, and then does the JIT just remove it for release and remove it completely? What happens with something like this in a release build, does the counter increment?

    Debug.Assert(++counter != 100);

    Regards, Rob Philpott.

    OriginalGriffO J 3 Replies Last reply
    0
    • R Rob Philpott

      I'm writing some low level C# which is doing bit level operations (shifting/logic) which needs to be very high performance (real time application). Usually, I'd just do some checks and throw an exception if things aren't right, but I can't afford the overhead of that here. Back in the day, in C++ I'd just use assertions for my checks which would cease to exist completely in the release build. In C#, we have Debug.Assert but its use seems greyer to me, because debug vs. release in .NET is greyer. Macros disappear depending on switches, but it seems the only way a Debug.Assert can disappear is if its hardedcoded in the JIT that way. So my question I guess is does the Debug.Assert make it into the MSIL regardless of debug/release, and then does the JIT just remove it for release and remove it completely? What happens with something like this in a release build, does the counter increment?

      Debug.Assert(++counter != 100);

      Regards, Rob Philpott.

      OriginalGriffO Offline
      OriginalGriffO Offline
      OriginalGriff
      wrote on last edited by
      #2

      See here: Assertions in Managed Code - Visual Studio | Microsoft Docs[^]

      Quote:

      In Visual Basic and Visual C#, you can use the Assert method from either Debug or Trace, which are in the System.Diagnostics namespace. Debug class methods are not included in a Release version of your program, so they do not increase the size or reduce the speed of your release code.

      I'd be tempted to check with ILSpy, but I believe all the assertion code including the condition check are discarded in Release builds.

      "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony AntiTwitter: @DalekDave is now a follower!

      "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
      "Common sense is so rare these days, it should be classified as a super power" - Random T-shirt

      1 Reply Last reply
      0
      • R Rob Philpott

        I'm writing some low level C# which is doing bit level operations (shifting/logic) which needs to be very high performance (real time application). Usually, I'd just do some checks and throw an exception if things aren't right, but I can't afford the overhead of that here. Back in the day, in C++ I'd just use assertions for my checks which would cease to exist completely in the release build. In C#, we have Debug.Assert but its use seems greyer to me, because debug vs. release in .NET is greyer. Macros disappear depending on switches, but it seems the only way a Debug.Assert can disappear is if its hardedcoded in the JIT that way. So my question I guess is does the Debug.Assert make it into the MSIL regardless of debug/release, and then does the JIT just remove it for release and remove it completely? What happens with something like this in a release build, does the counter increment?

        Debug.Assert(++counter != 100);

        Regards, Rob Philpott.

        OriginalGriffO Offline
        OriginalGriffO Offline
        OriginalGriff
        wrote on last edited by
        #3

        I just checked, and Debug.Assert is completely removed from Release code: Code:

            private void FrmMain\_Shown(object sender, EventArgs e)
                {
                ...
                string\[\] dataWithCounts = dataFromTextBox.GroupBy(d => d).Select(g =>$"{g.Key}({g.Count()})").ToArray();
                Debug.Assert(dataWithCounts.Count() != 3);
                }
        

        Debug:

        IL_008c: call class [mscorlib]System.Collections.Generic.IEnumerable`1 [System.Core]System.Linq.Enumerable::Select, string>(class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Func`2)
        IL_0091: call !!0[] [System.Core]System.Linq.Enumerable::ToArray(class [mscorlib]System.Collections.Generic.IEnumerable`1)
        IL_0096: stloc.1
        IL_0097: ldloc.1
        IL_0098: call int32 [System.Core]System.Linq.Enumerable::Count(class [mscorlib]System.Collections.Generic.IEnumerable`1)
        IL_009d: ldc.i4.3
        IL_009e: ceq
        IL_00a0: ldc.i4.0
        IL_00a1: ceq
        IL_00a3: call void [System]System.Diagnostics.Debug::Assert(bool)
        IL_00a8: nop
        IL_00a9: ret
        } // end of method FrmMain::FrmMain_Shown

        Release:

        IL\_0089: call class \[mscorlib\]System.Collections.Generic.IEnumerable\`1 \[System.Core\]System.Linq.Enumerable::Select, string>(class \[mscorlib\]System.Collections.Generic.IEnumerable\`1, class \[mscorlib\]System.Func\`2)
        IL\_008e: call !!0\[\] \[System.Core\]System.Linq.Enumerable::ToArray(class \[mscorlib\]System.Collections.Generic.IEnumerable\`1)
        IL\_0093: pop
        IL\_0094: ret
        

        "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony AntiTwitter: @DalekDave is now a follower!

        "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
        "Common sense is so rare these days, it should be classified as a super power" - Random T-shirt

        R 2 Replies Last reply
        0
        • OriginalGriffO OriginalGriff

          I just checked, and Debug.Assert is completely removed from Release code: Code:

              private void FrmMain\_Shown(object sender, EventArgs e)
                  {
                  ...
                  string\[\] dataWithCounts = dataFromTextBox.GroupBy(d => d).Select(g =>$"{g.Key}({g.Count()})").ToArray();
                  Debug.Assert(dataWithCounts.Count() != 3);
                  }
          

          Debug:

          IL_008c: call class [mscorlib]System.Collections.Generic.IEnumerable`1 [System.Core]System.Linq.Enumerable::Select, string>(class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Func`2)
          IL_0091: call !!0[] [System.Core]System.Linq.Enumerable::ToArray(class [mscorlib]System.Collections.Generic.IEnumerable`1)
          IL_0096: stloc.1
          IL_0097: ldloc.1
          IL_0098: call int32 [System.Core]System.Linq.Enumerable::Count(class [mscorlib]System.Collections.Generic.IEnumerable`1)
          IL_009d: ldc.i4.3
          IL_009e: ceq
          IL_00a0: ldc.i4.0
          IL_00a1: ceq
          IL_00a3: call void [System]System.Diagnostics.Debug::Assert(bool)
          IL_00a8: nop
          IL_00a9: ret
          } // end of method FrmMain::FrmMain_Shown

          Release:

          IL\_0089: call class \[mscorlib\]System.Collections.Generic.IEnumerable\`1 \[System.Core\]System.Linq.Enumerable::Select, string>(class \[mscorlib\]System.Collections.Generic.IEnumerable\`1, class \[mscorlib\]System.Func\`2)
          IL\_008e: call !!0\[\] \[System.Core\]System.Linq.Enumerable::ToArray(class \[mscorlib\]System.Collections.Generic.IEnumerable\`1)
          IL\_0093: pop
          IL\_0094: ret
          

          "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony AntiTwitter: @DalekDave is now a follower!

          R Offline
          R Offline
          Rob Philpott
          wrote on last edited by
          #4

          That's interesting. I just tried a similar thing with dotPeek, and the assertion is still visible in the release code, though your explanation above seems more plausible. Thanks for the link also - it backs up what you have above. I'm wondering if there is some other optimization switch in play here which explains why I can still see it...

          Regards, Rob Philpott.

          Richard DeemingR 1 Reply Last reply
          0
          • OriginalGriffO OriginalGriff

            I just checked, and Debug.Assert is completely removed from Release code: Code:

                private void FrmMain\_Shown(object sender, EventArgs e)
                    {
                    ...
                    string\[\] dataWithCounts = dataFromTextBox.GroupBy(d => d).Select(g =>$"{g.Key}({g.Count()})").ToArray();
                    Debug.Assert(dataWithCounts.Count() != 3);
                    }
            

            Debug:

            IL_008c: call class [mscorlib]System.Collections.Generic.IEnumerable`1 [System.Core]System.Linq.Enumerable::Select, string>(class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Func`2)
            IL_0091: call !!0[] [System.Core]System.Linq.Enumerable::ToArray(class [mscorlib]System.Collections.Generic.IEnumerable`1)
            IL_0096: stloc.1
            IL_0097: ldloc.1
            IL_0098: call int32 [System.Core]System.Linq.Enumerable::Count(class [mscorlib]System.Collections.Generic.IEnumerable`1)
            IL_009d: ldc.i4.3
            IL_009e: ceq
            IL_00a0: ldc.i4.0
            IL_00a1: ceq
            IL_00a3: call void [System]System.Diagnostics.Debug::Assert(bool)
            IL_00a8: nop
            IL_00a9: ret
            } // end of method FrmMain::FrmMain_Shown

            Release:

            IL\_0089: call class \[mscorlib\]System.Collections.Generic.IEnumerable\`1 \[System.Core\]System.Linq.Enumerable::Select, string>(class \[mscorlib\]System.Collections.Generic.IEnumerable\`1, class \[mscorlib\]System.Func\`2)
            IL\_008e: call !!0\[\] \[System.Core\]System.Linq.Enumerable::ToArray(class \[mscorlib\]System.Collections.Generic.IEnumerable\`1)
            IL\_0093: pop
            IL\_0094: ret
            

            "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony AntiTwitter: @DalekDave is now a follower!

            R Offline
            R Offline
            Rob Philpott
            wrote on last edited by
            #5

            Ok explained. dotPeek will use the actual source when its available rather than disassemble. Indeed the assertion never makes into MSIL. I'm learning all sorts of new things today. :)

            Regards, Rob Philpott.

            OriginalGriffO 1 Reply Last reply
            0
            • R Rob Philpott

              That's interesting. I just tried a similar thing with dotPeek, and the assertion is still visible in the release code, though your explanation above seems more plausible. Thanks for the link also - it backs up what you have above. I'm wondering if there is some other optimization switch in play here which explains why I can still see it...

              Regards, Rob Philpott.

              Richard DeemingR Offline
              Richard DeemingR Offline
              Richard Deeming
              wrote on last edited by
              #6

              Does your release build still have the DEBUG conditional compilation symbol defined? Reference Source[^] ConditionalAttribute Class (System.Diagnostics) | Microsoft Docs[^]


              "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

              "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

              R 1 Reply Last reply
              0
              • Richard DeemingR Richard Deeming

                Does your release build still have the DEBUG conditional compilation symbol defined? Reference Source[^] ConditionalAttribute Class (System.Diagnostics) | Microsoft Docs[^]


                "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                R Offline
                R Offline
                Rob Philpott
                wrote on last edited by
                #7

                Nope, good thought though. TRACE is defined. Explanation is below, dotPeek uses the actual source rather than reconstituted when available, so it was showing even for the release build.

                Regards, Rob Philpott.

                1 Reply Last reply
                0
                • R Rob Philpott

                  Ok explained. dotPeek will use the actual source when its available rather than disassemble. Indeed the assertion never makes into MSIL. I'm learning all sorts of new things today. :)

                  Regards, Rob Philpott.

                  OriginalGriffO Offline
                  OriginalGriffO Offline
                  OriginalGriff
                  wrote on last edited by
                  #8

                  Yeah, I like dotPeek, but that "use the source" bit has thrown me a couple of times. ILSpy is a bit more basic, but sometimes that's exactly what you want.

                  "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony AntiTwitter: @DalekDave is now a follower!

                  "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
                  "Common sense is so rare these days, it should be classified as a super power" - Random T-shirt

                  L 1 Reply Last reply
                  0
                  • OriginalGriffO OriginalGriff

                    Yeah, I like dotPeek, but that "use the source" bit has thrown me a couple of times. ILSpy is a bit more basic, but sometimes that's exactly what you want.

                    "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony AntiTwitter: @DalekDave is now a follower!

                    L Offline
                    L Offline
                    Luc Pattyn
                    wrote on last edited by
                    #9

                    Quote:

                    a bit more basic, but sometimes that's exactly what you want.

                    We have a special forum for that :doh:

                    Luc Pattyn [My Articles] Nil Volentibus Arduum

                    OriginalGriffO 1 Reply Last reply
                    0
                    • L Luc Pattyn

                      Quote:

                      a bit more basic, but sometimes that's exactly what you want.

                      We have a special forum for that :doh:

                      Luc Pattyn [My Articles] Nil Volentibus Arduum

                      OriginalGriffO Offline
                      OriginalGriffO Offline
                      OriginalGriff
                      wrote on last edited by
                      #10

                      :laugh: Nobody really wants VB!

                      "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony AntiTwitter: @DalekDave is now a follower!

                      "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
                      "Common sense is so rare these days, it should be classified as a super power" - Random T-shirt

                      1 Reply Last reply
                      0
                      • R Rob Philpott

                        I'm writing some low level C# which is doing bit level operations (shifting/logic) which needs to be very high performance (real time application). Usually, I'd just do some checks and throw an exception if things aren't right, but I can't afford the overhead of that here. Back in the day, in C++ I'd just use assertions for my checks which would cease to exist completely in the release build. In C#, we have Debug.Assert but its use seems greyer to me, because debug vs. release in .NET is greyer. Macros disappear depending on switches, but it seems the only way a Debug.Assert can disappear is if its hardedcoded in the JIT that way. So my question I guess is does the Debug.Assert make it into the MSIL regardless of debug/release, and then does the JIT just remove it for release and remove it completely? What happens with something like this in a release build, does the counter increment?

                        Debug.Assert(++counter != 100);

                        Regards, Rob Philpott.

                        J Offline
                        J Offline
                        jsc42
                        wrote on last edited by
                        #11

                        An Assert should never modify data

                        1 Reply Last reply
                        0
                        Reply
                        • Reply as topic
                        Log in to reply
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes


                        • Login

                        • Don't have an account? Register

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • World
                        • Users
                        • Groups