C# very optimisation

  • Thread starter Thread starter Ennixo
  • Start date Start date
James said:
No, actually there was. Remember that the original C compiler was
written for a very small machine -- one which measured memory in KB, not MB
(and probably measure it with only 2 digits or fewer)

Can you point to a C-compiler, even a *really* old one, that does not
optimize "x = x + 1" to some available ASM instruction (if one exists on
that architecture) that increments x?
Nothing about it the language is superflious. If the syntax was
different, the code produced would be different. The best way to see this
is to consider what you can't do with a particular syntax:
Since the compiler was very stupid with no optimizations, ANY statement
written in that form would be translated the same way.

I have never seen any compiler do that. Do you have an example?

[...more examples cutted...]

I have implemented compilers, i know how code generation works. If a
compiler have *any* optimizations at all I would hazard a guess that "x
= x + c" is optimized.
 
Ennixo said:
so try this sample code (paste in Main method) and you will think that
++i is really faster than other ways to increment by 1. (note: run in
RELEASE mode)

No I won't, because I can run ildasm and see that the generated code
for both loops is the same.
 
Ennixo said:
i read it in a source code from csharpfr.com and i saw it in some
sources of codeproject.com

Unfortunately that's the kind of myth which often spreads :(

It's always worth looking a bit deeper than an initial benchmark - try
moving the code around and see what happens, try looking at the
generated IL etc.
 
James Curran said:
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.
--


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.
 
Since the dawn of time, C programmers use i++ only when pre-incremented
value of i is needed. Otherwise they use ++i. This has been my experience
for the past 20 years working in C and C++. There is no point in saving the
pre-incremented value if you don't need it.

In the past the pre-increment and post-increment versions did have a
significant difference in performance even in C, if you want to go back to
the dawn of time. This is well known among older C developers. But they are
semantically different as well, so you may as well use the correct operator
in the correct spot, and lessen confusion.

The pre-increment and post-increment versions were invented for good
reasons.

- Frank
 
The pre-increment and post-increment versions were invented for good
reasons.

Umm... because the PDP-11 happened to have those two modes? :)
 
Frank Hileman said:
Since the dawn of time, C programmers use i++ only when pre-incremented
value of i is needed. Otherwise they use ++i. This has been my experience
for the past 20 years working in C and C++. There is no point in saving the
pre-incremented value if you don't need it.

Whereas in for loops, I've almost always seen it as i++, just because
it shows you what you're dealing with before what you're going to do
with it, even though you don't care about the pre-incremented value.

I've also almost always seen it as i++ on lines on its own - ++i is
very rare in the code I've seen...
In the past the pre-increment and post-increment versions did have a
significant difference in performance even in C, if you want to go back to
the dawn of time. This is well known among older C developers. But they are
semantically different as well, so you may as well use the correct operator
in the correct spot, and lessen confusion.

I very rarely use either in the case where it makes any difference - it
takes longer reading the code that way than separating the lines,
usually.
 
++i or i++ can go in any expression, not just a for loop, and they mean
something completely different. So there is a good reason for having both
versions. At the end of the for clause, either one works, but it looks
strange to use i++ when you don't need it. It does not help a novice
understand the operator either.

- Frank
 
Frank Hileman said:
++i or i++ can go in any expression, not just a for loop, and they mean
something completely different. So there is a good reason for having both
versions. At the end of the for clause, either one works, but it looks
strange to use i++ when you don't need it. It does not help a novice
understand the operator either.

As I said, i++ may look strange to you, but ++i looks strange to me. I
just find i++ more immediately readable.
 
Bruce said:

post increment is certainly are very handy when using pointers as iterators.

I have very rarely had to use pre-increment, mostly those places are
better written with the increment as a statement.

Funnily, IEnumerator is quite close to being used as "i++" when you do:

foreach ( object o in enumerable )

My favorite example of that is:

void CopyTo(Array a, int index) {
foreach ( object o in this )
a.SetValue(o, index++);
}

..... which is almost....

void memcpy(const void *src, void* dst, int length) {
for( const void* o = src; o < src+lengh; ++src )
*(dst++) = o;
}
 
Jon Skeet said:
As I said, i++ may look strange to you, but ++i looks strange to me. I
just find i++ more immediately readable.

I agree, I've very rarely seen ++i used in a for loop (or at all for that
matter). Most of the time people just use i++...
 
++i or i++ can go in any expression, not just a for loop, and they mean
something completely different. So there is a good reason for having both
versions. At the end of the for clause, either one works, but it looks
strange to use i++ when you don't need it. It does not help a novice
understand the operator either.


I have to agree with Jon Skeet here - I have only very rarely seen ++i
used - it's almost always i++. I find ++i much "stranger" than i++.
I've been programming in C since 1974.

And I agree with Jon that when it could be used in some complicated
statement where it actually makes a difference whether it's pre or
post incremented, that I almost always separate it out into a usage of
the variable i and then on another line, I increment the variable.
There is much less confusion about what it means that way, and it
really doesn't cost anything of any significance in terms of
efficiency.

C programmers frequently have a tendency to write inscrutable lines of
code, pleasing themselves with the amount of functionality that they
can pack into that one line of code. Like:

x += ar(**i++);

(the old joke about C programmers is that they claim that they can
write a whole operating system in one line of code)

But the result is an unreadable and error-prone program. As an actual
working programmer for 30 years, I have found that it is far more
important in the real world to write code that can be maintained by
the next programmer that it is to be clever and shave 4 machine cycles
off the pocessing.

My mantra: "always write your programs as if the next programmer to
maintain that code will be a 350-lb homicidal psychopath with a
chainsaw and your home address."
 
goody8 said:
I have to agree with Jon Skeet here - I have only very rarely seen ++i
used - it's almost always i++. I find ++i much "stranger" than i++.
I've been programming in C since 1974.

And I agree with Jon that when it could be used in some complicated
statement where it actually makes a difference whether it's pre or
post incremented, that I almost always separate it out into a usage of
the variable i and then on another line, I increment the variable.
There is much less confusion about what it means that way, and it
really doesn't cost anything of any significance in terms of
efficiency.

C programmers frequently have a tendency to write inscrutable lines of
code, pleasing themselves with the amount of functionality that they
can pack into that one line of code. Like:

x += ar(**i++);

(the old joke about C programmers is that they claim that they can
write a whole operating system in one line of code)

But the result is an unreadable and error-prone program. As an actual
working programmer for 30 years, I have found that it is far more
important in the real world to write code that can be maintained by
the next programmer that it is to be clever and shave 4 machine cycles
off the pocessing.

My mantra: "always write your programs as if the next programmer to
maintain that code will be a 350-lb homicidal psychopath with a
chainsaw and your home address."

Well, there is a big difference between 1974 C and today's C++.
While it was common sense to use i++ in C, in C++ it's preferable to use ++i
when you don't need the original value, the reason for this is that it is
slightly more efficient to use the pre-increment operator in C++ like James
Curran explained a few messages ago.

Willy.
 
Well, there is a big difference between 1974 C and today's C++.

Is there really? My, my! And here I am still using my PDP11 C
compiler these days.... Wow... I guess you really CAN learn
something new on usenet.

BTW - I have been programming professionally in C++ since 1990, in
Borland, MS and Mac. I've taught classes in C++. These days I'm
mostly using C#.

While it was common sense to use i++ in C, in C++ it's preferable to use ++i
when you don't need the original value, the reason for this is that it is
slightly more efficient to use the pre-increment operator in C++ like James
Curran explained a few messages ago.

Nonsense. There is no real difference between C and C++ with regard
to the auto-incrementing. And either will work just fine, it's merely
a matter of personal preference. Even if I were to believe that there
is a difference between them (and I don't - see Helge Jensen's
comparisons in this thread of the machine language produce for each of
the cases, and others' benchmarks). But that's all compiler-dependent
anyway - some might very well be "slightly more efficient". But
unless you're doing it 10 million times in a tight loop, it's not
going to make any difference at all in your program.

And anyway, as I said, in my 30 years of professional programming, I
really don't recall anyone using pre-increment when post-increment
would also work. It just seems more natural to me to write i++ than
++i.


But, as a friend once remarked, "If it doesn't matter, it doesn't
matter." And my corollary to that Law of Nature is, "if it takes and
oscilloscope to tell the difference, it doesn't matter."
 
When you implement the operator yourself, the difference is obvious. See
Stroustroup, The C++ Programming Language, section 19.3, for an example of
implementing a postfix increment operator on a user-defined type.

Checked_iter operator++(int) // postfix ++
{
Checked_iter tmp = *this;
++*this; // checked by prefix ++
return tmp;
}

A copy of the original must be made, the increment performed, and the copy
returned. Depending on the meaning of "copy" (how big your user defined type
is, how copy is implemented, etc), and whether the temporary is later
needed, the temporary may be optimized away by your C++ compiler.

In C# the operator is implemented the same way. You do not get to
distinguish between the prefix and postfix operators when implementing your
own user-defined type. You can only implement the prefix version. The
postfix version is implemented by the compiler, and the copy is made for you
automatically. Currently the CLR does not optimize away temporaries produced
in structure operator overloads. C# does seem to perform the optimization
for primitives when the operator is used in a statement. It can never be
optimized away in an expression, as that would change the meaning.

In the same book, there is some discussion about why people hate or love the
operators, and the concise code produced using them (section 6.2.5).

New developers should be aware of the difference between the prefix and
postfix operators, even if others have ignored the difference for years.
Once you are aware of the difference, the postfix version seems the odd one.
 
goody8 said:
Is there really? My, my! And here I am still using my PDP11 C
compiler these days.... Wow... I guess you really CAN learn
something new on usenet.

BTW - I have been programming professionally in C++ since 1990, in
Borland, MS and Mac. I've taught classes in C++. These days I'm
mostly using C#.

Impressive but so what?, I'm a professional programmer since 1969 (yes I'm
that old) in BCPL later in B followed by C in 1974 and since 1990 in C++
(with a few years of Assembly in between), I've built system level
components for (and at) DEC's PDP11, Ultrix, VAX VMS, Alpha Open VMS and
OSF later True UNIX 64 and Windows NT on Alpha, I wrote some of the HAL code
and drivers for NT Alpha was a developer on the Clusters for NT on alpha
(taken over by MSFT to build Windows Cluster Server) was member of the
porting group since the early beginning of NT (1990/1) [written for a large
part using C++, was completely rewritten in C ; you want to know why? - on
MIPS later on ALPHA system], until the port of Windows2000 for alpha (whe
even had a 64 bit version of W2K for Alpha never released you probably know
why). Still mostly using C/C++ as system language but also using C# for
general purpose.
What does this prove, guess nothing...
Nonsense. There is no real difference between C and C++ with regard
to the auto-incrementing.

*** Sure there is it's small but there is.

And either will work just fine, it's merely
a matter of personal preference. Even if I were to believe that there
is a difference between them (and I don't - see Helge Jensen's
comparisons in this thread of the machine language produce for each of
the cases, and others' benchmarks). But that's all compiler-dependent
anyway - some might very well be "slightly more efficient". But
unless you're doing it 10 million times in a tight loop, it's not
going to make any difference at all in your program.

*** Note: The machine language was produced by me, and is the result of
JITed C# code NOT C++, want to see what the C++ compiler generates? You
would be suprised.

And anyway, as I said, in my 30 years of professional programming, I
really don't recall anyone using pre-increment when post-increment
would also work. It just seems more natural to me to write i++ than
++i.

*** So does it to me, but as a said the new 'C++ design guides" do prefer
the pre-increment form ....



You don't have to believe me, look what experts have to say about this:

1. Herb Sutter.
Exceptional C++.
C++ In-Depth Series. Addison Wesley, 2000.
and
C++ Coding Standards

Page 50 Item 28. Prefer calling prefix forms.



2. Meyers' Effective C++ and More Effective C++

3. http://givemefish.com/C++FAQ.pdf
1.4 What is the difference between++var and var++?

4.

http://www.artlogic.com/careers/styleguide.html

snip from :Large-scale Statements:

Note that we prefer to use the pre-increment ++i as a general habit. It is
guaranteed in all languages that use this construct to work identically to
the more commonly seen post-increment i++ that dates back to the earliest
days of the C language. In C++, however, maintaining this habit prevents
possible inefficiencies when looping over an object that exposes an
iteratable interface. Consider the likely cost difference between:
typedef std::vector MyVector;
MyVector vec;
// assume the vector gets filled here....
for (MyVector::const_iterator i = vec.begin(); i != vec.end(); i++)
{
// clever and important code here...
}
and:

for (MyVector::const_iterator i = vec.begin(); i != vec.end(); ++i)
{
// even more clever and important code here...
}
5.

http://www.robthebloke.org/cppdir/StandardTemplateLibrary.htm



6.

http://www.accu.org/bookreviews/public/reviews/d/d002169.htm

<snip

Unncessary use of post-increment:
It is now well known that for iteration pre-increment usually provides
better performance than post-increment. Still, the book uses post-increment
throughout all the examples, thereby creating and destroying an unnecessary
temporary. A good compiler may be able to optimise away that temporary,
still it is not good nor common practice. In fact, in other places avoiding
temporaries is explicitly a concern (Section 7.4.1, for example).

/snip>

And there's probably a lot more..

Willy.
 
goody8 said:
Is there really? My, my! And here I am still using my PDP11 C
compiler these days.... Wow... I guess you really CAN learn
something new on usenet.

BTW - I have been programming professionally in C++ since 1990, in
Borland, MS and Mac. I've taught classes in C++. These days I'm
mostly using C#.

Impressive but so what?, I'm a professional programmer since 1969 (yes I'm
that old) in BCPL later in B followed by C in 1974 and since 1990 in C++
(with a few years of Assembly in between), I've built system level
components for (and at) DEC's PDP11, Ultrix, VAX VMS, Alpha Open VMS and
OSF later True UNIX 64 and Windows NT on Alpha, I wrote some of the HAL code
and drivers for NT Alpha was a developer on the Clusters for NT on alpha
(taken over by MSFT to build Windows Cluster Server) was member of the
porting group since the early beginning of NT (1990/1) [written for a large
part using C++, was completely rewritten in C ; you want to know why? - on
MIPS later on ALPHA system], until the port of Windows2000 for alpha (whe
even had a 64 bit version of W2K for Alpha never released you probably know
why). Still mostly using C/C++ as system language but also using C# for
general purpose.
What does this prove, guess nothing...


Yes, of course. I was merely responding to the snide remark about
"Well, there is a big difference between 1974 C and today's C++", as
if I was still using a 1974 C compiler. And also, that remark was
meaningless because there is no difference between the auto-increment
in C and C++ (at least not for integers, which is what we were talking
about - for complex objects and overridden operators, sure there's new
stuff with C++).

*** Sure there is it's small but there is.

Like what? (seriously - I'm not trying to be argumentative on that
point - I'd really like to know what the small difference is).
 
Back
Top