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.
  • 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