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 Offline
    M Offline
    MrEyes
    wrote on last edited by
    #1

    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

    J K L 3 Replies Last reply
    0
    • 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

      J Offline
      J Offline
      J4amieC
      wrote on last edited by
      #2

      run an app called ildasm from the VSNet command prompt and open your assembly with both methods in. You should see that the generated IL is exactly the same.

      1 Reply Last reply
      0
      • 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

        K Offline
        K Offline
        krieg38
        wrote on last edited by
        #3

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

        M G 2 Replies Last reply
        0
        • K krieg38

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

          M Offline
          M Offline
          mav northwind
          wrote on last edited by
          #4

          I'm afraid that's not true, since the resulting IL is identical. Regards, mav

          1 Reply Last reply
          0
          • 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