Re: C# very optimisation




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



.



Relevant Pages

  • Re: C# very optimisation
    ... You're just not going to see the difference using an int. ... class MyClass ... note that I could have written the post-fix as: ... Approx 0.3% faster ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Fridays the thirteenth. (And a little puzzle.)
    ... -- compiler) is the usual method ... int febdays ... -- We're going to go round a loop dealing with each year in turn. ... -- other languages call) ...
    (uk.people.silversurfers)
  • Re: C code is not generating required results.
    ... int main ... the array by the size of an element. ... prevent the user of your program from entering more characters than ... want to loop. ...
    (comp.lang.c)
  • Re: long double versions of functions in gcc under Cygwin
    ... rather than the nearest enclosing one) and a decent exception ... them it doesn't seem like goto usage would be affected ... int typfun() ... Why use a for loop when it is just a while loop in disguise? ...
    (comp.lang.c)
  • Re: enum type int or unsigned int?
    ... that have type int and may appear wherever such are permitted. ... values of all the members of the enumeration. ... "enum" types are declared via the following syntax: ... so the loop will continue to run. ...
    (comp.lang.c)

Loading