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. C# Performance

C# Performance

Scheduled Pinned Locked Moved C#
performancequestioncsharpcss
14 Posts 10 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.
  • M MrEyes

    Out of sheer curiosity I have a quick question relating to C# performance. I have the two following methods:

    public static string VerboseProgrammingMethod()
    {
    System.Guid g = Guid.NewGuid();
    string s = g.ToString();
    string f = s.Substring(0,4);

    return f;
    }

    public static string OneLineProgrammingMethod()
    {
    return Guid.NewGuid().ToString().Substring(0, 4);
    }

    As you can see both of them will generate exactly the same output as they essentially perform the same functions. The question is is one of them quicker/less memory intensive than the other? I am under the impression that it doesnt make any difference whatsoever, but I would be grateful if somebody could confirm this

    L Offline
    L Offline
    leppie
    wrote on last edited by
    #5

    Like the others say, both are the same. #1 is must easier to debug though, and should allways be used (for clarity too). Make a habit of it. We are proffesionals, not script kiddie/wannabe hackers :) NOTE: That saying, I still take the 'short' route sometimes :-O xacc.ide-0.1.1.4 - now with LSharp integration and scripting :)

    M 1 Reply Last reply
    0
    • L leppie

      Like the others say, both are the same. #1 is must easier to debug though, and should allways be used (for clarity too). Make a habit of it. We are proffesionals, not script kiddie/wannabe hackers :) NOTE: That saying, I still take the 'short' route sometimes :-O xacc.ide-0.1.1.4 - now with LSharp integration and scripting :)

      M Offline
      M Offline
      MrEyes
      wrote on last edited by
      #6

      I totally agree with your professionals vs script kiddie comment, but on occasion it is sometimes necessary to make sacrifices for performance. As suggested by Jamie4C I created the following class library and ran it through ILDasm

      public class Class1
      {
      public static string VerboseProgrammingMethod()
      {
      System.Guid g = Guid.NewGuid();
      string s = g.ToString();
      string f = s.Substring(0,4);

      return f;
      }

      public static string OneLineProgrammingMethod()
      {
      return Guid.NewGuid().ToString().Substring(0, 4);
      }
      }
      }

      Now in theory the IL code for these two functions should be exactly the same, interestingly there are differences. I am no IL expert so this might be a red herring, but here is the IL code:

      .method public hidebysig static string VerboseProgrammingMethod() cil managed
      {
      // Code size 29 (0x1d)
      .maxstack 3
      .locals init ([0] valuetype [mscorlib]System.Guid g,
      [1] string s,
      [2] string f,
      [3] string CS$00000003$00000000)
      IL_0000: call valuetype [mscorlib]System.Guid [mscorlib]System.Guid::NewGuid()
      IL_0005: stloc.0
      IL_0006: ldloca.s g
      IL_0008: call instance string [mscorlib]System.Guid::ToString()
      IL_000d: stloc.1
      IL_000e: ldloc.1
      IL_000f: ldc.i4.0
      IL_0010: ldc.i4.4
      IL_0011: callvirt instance string [mscorlib]System.String::Substring(int32,
      int32)
      IL_0016: stloc.2
      IL_0017: ldloc.2
      IL_0018: stloc.3
      IL_0019: br.s IL_001b
      IL_001b: ldloc.3
      IL_001c: ret
      } // end of method Class1::VerboseProgrammingMethod

      .method public hidebysig static string OneLineProgrammingMethod() cil managed
      {
      // Code size 25 (0x19)
      .maxstack 3
      .locals init ([0] string CS$00000003$00000000,
      [1] valuetype [mscorlib]System.Guid CS$00000002$00000001)
      IL_0000: call valuetype [mscorlib]System.Guid [mscorlib]System.Guid::NewGuid()
      IL_0005: stloc.1
      IL_0006: ldloca.s CS$00000002$00000001
      IL_0008: call instance string [mscorlib]System.Guid::ToString()
      IL_000d: ldc.i4.0
      IL_000e: ldc.i4.4
      IL_000f: callvirt instance string [mscorlib]System.String::Substring(int32,
      int32)
      IL_0014: stloc.0
      IL_0015: br.s IL_0017
      IL_0017: ldloc.0
      IL_0018: ret
      } // end of method Class1::OneLineProgrammingMethod

      C 1 Reply Last reply
      0
      • M MrEyes

        I totally agree with your professionals vs script kiddie comment, but on occasion it is sometimes necessary to make sacrifices for performance. As suggested by Jamie4C I created the following class library and ran it through ILDasm

        public class Class1
        {
        public static string VerboseProgrammingMethod()
        {
        System.Guid g = Guid.NewGuid();
        string s = g.ToString();
        string f = s.Substring(0,4);

        return f;
        }

        public static string OneLineProgrammingMethod()
        {
        return Guid.NewGuid().ToString().Substring(0, 4);
        }
        }
        }

        Now in theory the IL code for these two functions should be exactly the same, interestingly there are differences. I am no IL expert so this might be a red herring, but here is the IL code:

        .method public hidebysig static string VerboseProgrammingMethod() cil managed
        {
        // Code size 29 (0x1d)
        .maxstack 3
        .locals init ([0] valuetype [mscorlib]System.Guid g,
        [1] string s,
        [2] string f,
        [3] string CS$00000003$00000000)
        IL_0000: call valuetype [mscorlib]System.Guid [mscorlib]System.Guid::NewGuid()
        IL_0005: stloc.0
        IL_0006: ldloca.s g
        IL_0008: call instance string [mscorlib]System.Guid::ToString()
        IL_000d: stloc.1
        IL_000e: ldloc.1
        IL_000f: ldc.i4.0
        IL_0010: ldc.i4.4
        IL_0011: callvirt instance string [mscorlib]System.String::Substring(int32,
        int32)
        IL_0016: stloc.2
        IL_0017: ldloc.2
        IL_0018: stloc.3
        IL_0019: br.s IL_001b
        IL_001b: ldloc.3
        IL_001c: ret
        } // end of method Class1::VerboseProgrammingMethod

        .method public hidebysig static string OneLineProgrammingMethod() cil managed
        {
        // Code size 25 (0x19)
        .maxstack 3
        .locals init ([0] string CS$00000003$00000000,
        [1] valuetype [mscorlib]System.Guid CS$00000002$00000001)
        IL_0000: call valuetype [mscorlib]System.Guid [mscorlib]System.Guid::NewGuid()
        IL_0005: stloc.1
        IL_0006: ldloca.s CS$00000002$00000001
        IL_0008: call instance string [mscorlib]System.Guid::ToString()
        IL_000d: ldc.i4.0
        IL_000e: ldc.i4.4
        IL_000f: callvirt instance string [mscorlib]System.String::Substring(int32,
        int32)
        IL_0014: stloc.0
        IL_0015: br.s IL_0017
        IL_0017: ldloc.0
        IL_0018: ret
        } // end of method Class1::OneLineProgrammingMethod

        C Offline
        C Offline
        Colin Angus Mackay
        wrote on last edited by
        #7

        Is this the debug or the release build? There shouldn't be any differences in the release build. The debug build will contain some differences which is why the first version of the code is easier to debug (the compiler doesn't perform so many optimisations in debug builds) ColinMackay.net "Man who stand on hill with mouth open will wait long time for roast duck to drop in." -- Confucius "If a man empties his purse into his head, no man can take it away from him, for an investment in knowledge pays the best interest." -- Joseph E. O'Donnell

        M 1 Reply Last reply
        0
        • C Colin Angus Mackay

          Is this the debug or the release build? There shouldn't be any differences in the release build. The debug build will contain some differences which is why the first version of the code is easier to debug (the compiler doesn't perform so many optimisations in debug builds) ColinMackay.net "Man who stand on hill with mouth open will wait long time for roast duck to drop in." -- Confucius "If a man empties his purse into his head, no man can take it away from him, for an investment in knowledge pays the best interest." -- Joseph E. O'Donnell

          M Offline
          M Offline
          MrEyes
          wrote on last edited by
          #8

          The above IL listings were from a debug build, but there are still differences in a release build:

          .method public hidebysig static string VerboseProgrammingMethod() cil managed
          {
          // Code size 25 (0x19)
          .maxstack 3
          .locals init (valuetype [mscorlib]System.Guid V_0,
          string V_1,
          string V_2)
          IL_0000: call valuetype [mscorlib]System.Guid [mscorlib]System.Guid::NewGuid()
          IL_0005: stloc.0
          IL_0006: ldloca.s V_0
          IL_0008: call instance string [mscorlib]System.Guid::ToString()
          IL_000d: stloc.1
          IL_000e: ldloc.1
          IL_000f: ldc.i4.0
          IL_0010: ldc.i4.4
          IL_0011: callvirt instance string [mscorlib]System.String::Substring(int32,
          int32)
          IL_0016: stloc.2
          IL_0017: ldloc.2
          IL_0018: ret
          } // end of method Class1::VerboseProgrammingMethod

          .method public hidebysig static string OneLineProgrammingMethod() cil managed
          {
          // Code size 21 (0x15)
          .maxstack 3
          .locals init (valuetype [mscorlib]System.Guid V_0)
          IL_0000: call valuetype [mscorlib]System.Guid [mscorlib]System.Guid::NewGuid()
          IL_0005: stloc.0
          IL_0006: ldloca.s V_0
          IL_0008: call instance string [mscorlib]System.Guid::ToString()
          IL_000d: ldc.i4.0
          IL_000e: ldc.i4.4
          IL_000f: callvirt instance string [mscorlib]System.String::Substring(int32,
          int32)
          IL_0014: ret
          } // end of method Class1::OneLineProgrammingMethod

          -- modified at 7:31 Monday 9th January, 2006

          M L 2 Replies Last reply
          0
          • M MrEyes

            The above IL listings were from a debug build, but there are still differences in a release build:

            .method public hidebysig static string VerboseProgrammingMethod() cil managed
            {
            // Code size 25 (0x19)
            .maxstack 3
            .locals init (valuetype [mscorlib]System.Guid V_0,
            string V_1,
            string V_2)
            IL_0000: call valuetype [mscorlib]System.Guid [mscorlib]System.Guid::NewGuid()
            IL_0005: stloc.0
            IL_0006: ldloca.s V_0
            IL_0008: call instance string [mscorlib]System.Guid::ToString()
            IL_000d: stloc.1
            IL_000e: ldloc.1
            IL_000f: ldc.i4.0
            IL_0010: ldc.i4.4
            IL_0011: callvirt instance string [mscorlib]System.String::Substring(int32,
            int32)
            IL_0016: stloc.2
            IL_0017: ldloc.2
            IL_0018: ret
            } // end of method Class1::VerboseProgrammingMethod

            .method public hidebysig static string OneLineProgrammingMethod() cil managed
            {
            // Code size 21 (0x15)
            .maxstack 3
            .locals init (valuetype [mscorlib]System.Guid V_0)
            IL_0000: call valuetype [mscorlib]System.Guid [mscorlib]System.Guid::NewGuid()
            IL_0005: stloc.0
            IL_0006: ldloca.s V_0
            IL_0008: call instance string [mscorlib]System.Guid::ToString()
            IL_000d: ldc.i4.0
            IL_000e: ldc.i4.4
            IL_000f: callvirt instance string [mscorlib]System.String::Substring(int32,
            int32)
            IL_0014: ret
            } // end of method Class1::OneLineProgrammingMethod

            -- modified at 7:31 Monday 9th January, 2006

            M Offline
            M Offline
            Mike Dimmick
            wrote on last edited by
            #9

            After a lot of pain I managed to get the Windows Debugger hooked up to a process containing these two methods (using the MethodImpl attribute to suppress inlining), and dump the JITted code. Here's the result: OneLineProgrammingMethod:

            sub esp,0x10
            xor eax,eax
            mov [esp],eax
            mov [esp+0x4],eax
            mov [esp+0x8],eax
            mov [esp+0xc],eax
            lea ecx,[esp]
            call mscorlib_79990000+0x35d28 (799c5d28)

            push 0x0
            lea ecx,[esp+0x4]
            mov edx,[01c415d0]
            call mscorlib_79990000+0x35de0 (799c5de0)
            push 0x4
            mov ecx,eax
            xor edx,edx
            cmp [ecx],ecx

            call mscorlib_79990000+0x6b20 (79996b20)
            add esp,0x10
            ret

            VerboseProgrammingMethod:

            sub esp,0x10
            xor eax,eax
            mov [esp],eax
            mov [esp+0x4],eax
            mov [esp+0x8],eax
            mov [esp+0xc],eax
            lea ecx,[esp]
            call dword ptr [mscorlib_79990000+0x234a08 (79bc4a08)]

            push 0x0
            lea ecx,[esp+0x4]
            mov edx,[01c415d0]
            call dword ptr [mscorlib_79990000+0x234a28 (79bc4a28)]
            push 0x4
            mov ecx,eax
            xor edx,edx
            cmp [ecx],ecx

            call mscorlib_79990000+0x6b20 (79996b20)
            add esp,0x10
            ret

            The only difference is that for some reason the JIT compiler has decided to call through a table for the verbose method - the functions called are exactly the same. I'm actually surprised - I was expecting the IL to be different since the C# compiler does very little optimisation but I wasn't expecting a difference in the JITted code. Nevertheless you should normally forget about micro-optimisations like this and concentrate on the areas that will have the biggest impact. Stability. What an interesting concept. -- Chris Maunder

            M 1 Reply Last reply
            0
            • M MrEyes

              The above IL listings were from a debug build, but there are still differences in a release build:

              .method public hidebysig static string VerboseProgrammingMethod() cil managed
              {
              // Code size 25 (0x19)
              .maxstack 3
              .locals init (valuetype [mscorlib]System.Guid V_0,
              string V_1,
              string V_2)
              IL_0000: call valuetype [mscorlib]System.Guid [mscorlib]System.Guid::NewGuid()
              IL_0005: stloc.0
              IL_0006: ldloca.s V_0
              IL_0008: call instance string [mscorlib]System.Guid::ToString()
              IL_000d: stloc.1
              IL_000e: ldloc.1
              IL_000f: ldc.i4.0
              IL_0010: ldc.i4.4
              IL_0011: callvirt instance string [mscorlib]System.String::Substring(int32,
              int32)
              IL_0016: stloc.2
              IL_0017: ldloc.2
              IL_0018: ret
              } // end of method Class1::VerboseProgrammingMethod

              .method public hidebysig static string OneLineProgrammingMethod() cil managed
              {
              // Code size 21 (0x15)
              .maxstack 3
              .locals init (valuetype [mscorlib]System.Guid V_0)
              IL_0000: call valuetype [mscorlib]System.Guid [mscorlib]System.Guid::NewGuid()
              IL_0005: stloc.0
              IL_0006: ldloca.s V_0
              IL_0008: call instance string [mscorlib]System.Guid::ToString()
              IL_000d: ldc.i4.0
              IL_000e: ldc.i4.4
              IL_000f: callvirt instance string [mscorlib]System.String::Substring(int32,
              int32)
              IL_0014: ret
              } // end of method Class1::OneLineProgrammingMethod

              -- modified at 7:31 Monday 9th January, 2006

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #10

              The latter seems to be faster, is this correct?

              D 1 Reply Last reply
              0
              • M Mike Dimmick

                After a lot of pain I managed to get the Windows Debugger hooked up to a process containing these two methods (using the MethodImpl attribute to suppress inlining), and dump the JITted code. Here's the result: OneLineProgrammingMethod:

                sub esp,0x10
                xor eax,eax
                mov [esp],eax
                mov [esp+0x4],eax
                mov [esp+0x8],eax
                mov [esp+0xc],eax
                lea ecx,[esp]
                call mscorlib_79990000+0x35d28 (799c5d28)

                push 0x0
                lea ecx,[esp+0x4]
                mov edx,[01c415d0]
                call mscorlib_79990000+0x35de0 (799c5de0)
                push 0x4
                mov ecx,eax
                xor edx,edx
                cmp [ecx],ecx

                call mscorlib_79990000+0x6b20 (79996b20)
                add esp,0x10
                ret

                VerboseProgrammingMethod:

                sub esp,0x10
                xor eax,eax
                mov [esp],eax
                mov [esp+0x4],eax
                mov [esp+0x8],eax
                mov [esp+0xc],eax
                lea ecx,[esp]
                call dword ptr [mscorlib_79990000+0x234a08 (79bc4a08)]

                push 0x0
                lea ecx,[esp+0x4]
                mov edx,[01c415d0]
                call dword ptr [mscorlib_79990000+0x234a28 (79bc4a28)]
                push 0x4
                mov ecx,eax
                xor edx,edx
                cmp [ecx],ecx

                call mscorlib_79990000+0x6b20 (79996b20)
                add esp,0x10
                ret

                The only difference is that for some reason the JIT compiler has decided to call through a table for the verbose method - the functions called are exactly the same. I'm actually surprised - I was expecting the IL to be different since the C# compiler does very little optimisation but I wasn't expecting a difference in the JITted code. Nevertheless you should normally forget about micro-optimisations like this and concentrate on the areas that will have the biggest impact. Stability. What an interesting concept. -- Chris Maunder

                M Offline
                M Offline
                MrEyes
                wrote on last edited by
                #11

                Mike Dimmick wrote:

                Nevertheless you should normally forget about micro-optimisations like this and concentrate on the areas that will have the biggest impact.

                In this example, I agree it is an "optimisation" that will save nano seconds if that. That being said, if the methods were dealing with much larger objects it could potentially be something worth considering.

                G 1 Reply Last reply
                0
                • K krieg38

                  The first methods creates two strings(s,f) and it should be more memory consuming.

                  G Offline
                  G Offline
                  Guffa
                  wrote on last edited by
                  #12

                  The two strings are created in both codes. The only difference is that the references to the strings are declared as variables in one code, while in the other code the compiler will create the references itself to handle the strings. --- b { font-weight: normal; }

                  1 Reply Last reply
                  0
                  • M MrEyes

                    Mike Dimmick wrote:

                    Nevertheless you should normally forget about micro-optimisations like this and concentrate on the areas that will have the biggest impact.

                    In this example, I agree it is an "optimisation" that will save nano seconds if that. That being said, if the methods were dealing with much larger objects it could potentially be something worth considering.

                    G Offline
                    G Offline
                    Guffa
                    wrote on last edited by
                    #13

                    As the only difference in coding is to keep references to the objects created, it doesn't matter how large the objects are. The size of a reference is always the same. When optimizing code it's very useful to know what the code really does, in order to find out what code is worth optimizing, and how. Example: int a = 42; string y = a + "," + a; That looks simple, but can be written much more efficient in this more lengthy way: int a = 42; string x = a.ToString(); string y = x + "," + x; The first code will be executed something like: int a = 42; string y = string.Concat(Number.FormatInt32((int)new Object(a), null, NumberFormatInfo.GetInstance(null)), (string)(object)",", Number.FormatInt32((int)new Object(a), null, NumberFormatInfo.GetInstance(null))); while the second code will be executed as: int a = 42; string x = Number.FormatInt32(a, null, NumberFormatInfo.GetInstance(null)); string y = string.Concat(x, ",", x); --- b { font-weight: normal; }

                    1 Reply Last reply
                    0
                    • L Lost User

                      The latter seems to be faster, is this correct?

                      D Offline
                      D Offline
                      Dave Kreskowiak
                      wrote on last edited by
                      #14

                      Probably a half second faster over the span of 1 million calls to it. But, of course, your milage may vary depending on your machine and how you drive it. RageInTheMachine9532 "...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome

                      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