Re: C# very optimisation
- From: "Willy Denoyette [MVP]" <willy.denoyette@xxxxxxxxxx>
- Date: Wed, 18 May 2005 20:55:15 +0200
"James Curran" <jamescurran@xxxxxxxx> wrote in message
news:eEEQId8WFHA.2288@xxxxxxxxxxxxxxxxxxxxxxx
> Everyone seems to be missing the important point about ++i vs i++
> optimization...
>
> Namely it comes in play mostly on user defined types with an overload
> operator ++.
>
> You're just not going to see the difference using an int.
>
> To understand this, imagine we have a class (MyClass), which has a
> member function (AddOne), and we want to implement op++ and ++op. (For
> the
> moment, I'm going to do this in C++)
>
> class MyClass
> {
> public:
> void AddOne() {.....}
>
> // The Pre-fix (++x) operator is rather straight forward.
> MyClass& operator++()
> {
> AddOne();
> return *this;
> }
>
> // the post-fix (x++) is a bit trickier
> MyClass operator++(int)
> {
> MyClass temp(*this);
> AddOne();
> return temp;
> }
> }
>
> Note that for the post fix, we've got to make two copies of MyClass
> (one
> in temp, and one for the return), which aren't needed in the pre-fix op++.
> Also, note that I could have written the post-fix as:
>
> MyClass operator++(int)
> {
> MyClass temp(*this);
> this->operator++(); // or ++(*this);
> return temp;
> }
>
> Now, let's write a similar class in C#:
>
> class MyClass
> {
> public void AddOne() {.....}
>
> public static MyClass operator++(MyClass a)
> {
> a.AddOne();
> return a;
> }
> }
>
> You'll note that this is the pre-fix operator++. So, where is the
> post-fix? The C# compiler creates it for you automatically. And is it
> written? Basically:
>
> public static MyClass operator++(MyClass a) // post-fix
> {
> MyClass b = a.Clone();
> ++a;
> return b;
> }
>
> So, like in the C++, the post-fix has to create a copy of the
> unaltered
> object, so that it can be returned.
>
> When an int is used, the operator method is inlined, so, when it's just
> "x++;" on a line by itself, the compile can see that the duped value isn't
> used, and it can remove the whole creation of it. When ++ is used on some
> other type object, the oper++ is done out-of-line, and so, the compiler
> cannot remove it.
>
> So, now, let's try your test again, but this using a class:
> using System;
> public class LikeAnInt
> {
> int n =0;
> public LikeAnInt(int i)
> {
> n = i;
> }
> public void AddOne()
> {
> ++n;
> }
> static public LikeAnInt operator++(LikeAnInt a)
> {
> a.AddOne();
> return a;
> }
> public int Val
> {
> get { return n; }
> }
> }
>
> public class MyClass
> {
> public static void Main()
> {
> DateTime d;
> TimeSpan t;
> int iMax = 1000000000;
> int j;
> // Test 1 : i++
> j = 0;
> d = DateTime.Now;
> for (LikeAnInt i = new LikeAnInt(0); i.Val < iMax; i++)
> j += i.Val;
> t = DateTime.Now - d;
> Console.WriteLine("i++ : {0}", t.TotalMilliseconds.ToString());
>
> // Test 2 : ++i
> j = 0;
> d = DateTime.Now;
> for (LikeAnInt i = new LikeAnInt(0); i.Val < iMax; ++i)
> j += i.Val;
> t = DateTime.Now - d;
> Console.WriteLine("++i : {0}", t.TotalMilliseconds.ToString());
> // Test 3 : i.AddOne()
> j = 0;
> d = DateTime.Now;
> for (LikeAnInt i = new LikeAnInt(0); i.Val < iMax; i.AddOne())
> j += i.Val;
> t = DateTime.Now - d;
> Console.WriteLine("i.AddOne : {0}", t.TotalMilliseconds.ToString());
> Console.Read();
> }
> }
>
> The Results:
> SnippetCompiler:
> i++ : 44206.6704
> ++i : 42848.6265
> Approx 3% faster
>
> VC#-Debug:
> i++ : 34887.6795
> ++i : 34731.5825
> Approx 0.3% faster
>
> VC#-Release:
> i++ : 1623.4088
> ++i : 1607.7991
> i.AddOne : 1607.7991
> Approx 0.9% faster
>
> A minmal difference, but it's beyond the "noise" level.
> --
> --
> Truth,
> James Curran
> [erstwhile VC++ MVP]
>
Please stop this nonsense about post/prefix increments.
Looak at the IL and more important look at the machine code generated by the
JIT.
Here is the what the JIT produced in optimized builds:
Post-increment loop
02c70086 b978519700 mov ecx,0x975178
02c7008b e8881f78fd call 003f2018
02c70090 895804 mov [eax+0x4],ebx
02c70093 8bf0 mov esi,eax
02c70095 eb0f jmp 02c700a6
02c70097 8b4604 mov eax,[esi+0x4]
02c7009a 8bd0 mov edx,eax
02c7009c c1fa1f sar edx,0x1f
02c7009f 03d8 add ebx,eax
02c700a1 13fa adc edi,edx
02c700a3 ff4604 inc dword ptr [esi+0x4]
02c700a6 817e0400ca9a3b cmp dword ptr [esi+0x4],0x3b9aca00
pre-increment loop
02c70086 b978519700 mov ecx,0x975178
02c7008b e8881f78fd call 003f2018
02c70090 895804 mov [eax+0x4],ebx
02c70093 8bf0 mov esi,eax
02c70095 eb0f jmp 02c700a6
02c70097 8b4604 mov eax,[esi+0x4]
02c7009a 8bd0 mov edx,eax
02c7009c c1fa1f sar edx,0x1f
02c7009f 03d8 add ebx,eax
02c700a1 13fa adc edi,edx
02c700a3 ff4604 inc dword ptr [esi+0x4]
02c700a6 817e0400ca9a3b cmp dword ptr [esi+0x4],0x3b9aca00
See the same routine gets executed for both loops.
Willy.
.
- References:
- C# very optimisation
- From: Ennixo
- Re: C# very optimisation
- From: Jon Skeet [C# MVP]
- Re: C# very optimisation
- From: Ennixo
- Re: C# very optimisation
- From: Lebesgue
- Re: C# very optimisation
- From: Ennixo
- Re: C# very optimisation
- From: Søren Reinke
- Re: C# very optimisation
- From: Helge Jensen
- Re: C# very optimisation
- From: Ennixo
- Re: C# very optimisation
- From: James Curran
- C# very optimisation
- Prev by Date: Re: Loading a char value from an SQL parameter - Crashing!
- Next by Date: Re: Why can't overloads take into account the return type.
- Previous by thread: Re: C# very optimisation
- Next by thread: Re: C# very optimisation
- Index(es):
Relevant Pages
|
Loading