C# very optimisation

  • Thread starter Thread starter Ennixo
  • Start date Start date
E

Ennixo

hi,

do you know where i can find some ebooks or websites talking about C#
optimisation ?

for exemple, i just learned that ++i is faster than i++. i would like to
know more about the things that can make code faster than fast.

thank you.
 
Ennixo said:
do you know where i can find some ebooks or websites talking about C#
optimisation ?

for exemple, i just learned that ++i is faster than i++.

In C#? I don't think so. It *can* be faster in *some* languages, but
it's rarely going to make a significant difference.
i would like to
know more about the things that can make code faster than fast.

Proper design and profiling when necessary, basically. Micro-
optimisations rarely make a significant difference to overall
performance - even if tweaking your code makes one section of code five
times faster, unless a significant amount of time is spent in that part
of the code, it's not going to make much difference. Obviously it
depends on the app, but in many apps these days the most significant
performance bottlenecks come from things like network/database access,
bad choice of threading, etc.

Furthermore, micro-optimisations tend to come at the expense of the
code being as readable as it can be, which IMO should be the primary
goal.

If your app isn't performing well enough, get a profiler and find out
exactly where the bottleneck is. At that point, and only at that point,
should you be really worried about micro-optimisations.
 
Jon Skeet [C# MVP] a écrit :
Furthermore, micro-optimisations tend to come at the expense of the
code being as readable as it can be, which IMO should be the primary
goal.

generaly yes, but this is for image processing, so i need to optimize as
much as i can, even if the code becomes 10x bigger and unreadable
 
When talking about image processing, a VERY big performance bonus can be
gained when using unmanaged (unsafe) code and pointers. I remember an
article saying unmanaged image processing can be up to 28 times faster than
managed.
Here it is
http://tinyurl.com/3sux8


Ennixo said:
Jon Skeet [C# MVP] a écrit :
Furthermore, micro-optimisations tend to come at the expense of the
code being as readable as it can be, which IMO should be the primary
goal.

generaly yes, but this is for image processing, so i need to optimize as
much as i can, even if the code becomes 10x bigger and unreadable
 
Lebesgue a écrit :
When talking about image processing, a VERY big performance bonus can be
gained when using unmanaged (unsafe) code and pointers. I remember an
article saying unmanaged image processing can be up to 28 times faster than
managed.
Here it is
http://tinyurl.com/3sux8

Thank you, i already use unsafe for my processing of course but i would
like to know more about little optimisations now (juste like "++i"
instead of "i++")

but i will read MSDN's unsafe image processing page because i never saw
it before =)
 
Thank you, i already use unsafe for my processing of course but i would
like to know more about little optimisations now (juste like "++i" instead
of "i++")

++i and i++ is not the same if used within things like calling methods and
stuff like that.

Is the one considered faster than the other ?
 
for exemple, i just learned that ++i is faster than i++. i would like to
know more about the things that can make code faster than fast.

Where did you read that? There shouldn't be any difference from the
generated code performance.

However, in C# there are similar rules for performance like it is in C++.
The basics in C# are avoiding boxing and use StringBuilder instead of
strings but that shouldn't be useful for image processing anyway.
 
cody a écrit :
Where did you read that? There shouldn't be any difference from the
generated code performance.

i read it in a source code from csharpfr.com and i saw it in some
sources of codeproject.com
 
Try a profiler, and optimize the places when processing time is actually
used. That way your optimizations may actually matter instead of just
waste your time and make the code unreadable.
++i and i++ is not the same if used within things like calling methods and
stuff like that.

more precicely, ++i and i++ are not the same when used as an expression.
Is the one considered faster than the other ?

When defining your own "operator++" the x++ variant needs to copy the
old object, ++x does not.

I can't imagine that there is *any* difference whatsoever for the
performance using ++i or i++ (esp. on integral types), and will continue
to think that untill I see a test-program proving otherwise.
 
Ennixo said:
cody a écrit :

i read it in a source code from csharpfr.com and i saw it in some sources
of codeproject.com

I don't think it matter at all.i++ og ++i just add's 1 to the variable.

But if you have some documentation about it i would love to see it.
 
Helge Jensen a écrit :
I can't imagine that there is *any* difference whatsoever for the
performance using ++i or i++ (esp. on integral types), and will continue
to think that untill I see a test-program proving otherwise.

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)

DateTime d;
TimeSpan t;
int iMax = 1000000000;
int j;

// Test 1 : i++
j = 0;
d = DateTime.Now;
for (int i = 0; i < iMax; i++)
j += i;
t = DateTime.Now - d;
Console.WriteLine("i++ : {0}", t.TotalMilliseconds.ToString());


// Test 2 : ++i
j = 0;
d = DateTime.Now;
for (int i = 0; i < iMax; ++i)
j += i;
t = DateTime.Now - d;
Console.WriteLine("++i : {0}", t.TotalMilliseconds.ToString());

// Test 3 : i += 1
j = 0;
d = DateTime.Now;
for (int i = 0; i < iMax; i += 1)
j += i;
t = DateTime.Now - d;
Console.WriteLine("i += 1 : {0}", t.TotalMilliseconds.ToString());


// Test 4 : i = i + 1
j = 0;
d = DateTime.Now;
for (int i = 0; i < iMax; i = i + 1)
j += i;
t = DateTime.Now - d;
Console.WriteLine("i = i + 1 : {0}", t.TotalMilliseconds.ToString());


Console.Read();
 
Ennixo said:
Helge Jensen a écrit :


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)

Sorry to say but no difference worth mentioning, sometimes the one is faster
sometimes the other.

Run #1
i++ : 5167,4304
++i : 5107,344
i += 1 : 5047,2576
i = i + 1 : 5087,3152


Run #2
i++ : 5037,2432
++i : 5117,3584
i += 1 : 5067,2864
i = i + 1 : 5067,2864


Run #5
i++ : 5047,2576
++i : 5117,3584
i += 1 : 5037,2432
i = i + 1 : 5127,3728


Run #4
i++ : 5127,3728
++i : 5107,344
i += 1 : 5027,2288
i = i + 1 : 5077,3008
 
It is not just an optimization to use ++i instead of i++, although that is
established. It is for readability. Using i++ means you need the value of i
before it has been incremented. Using ++i simply means: increment. So by
using i++ where you don't need it, you are making code less readable. It is
good practice to use ++ correctly.

Regards,
Frank Hileman

check out VG.net: http://www.vgdotnet.com
Animated vector graphics system
Integrated Visual Studio .NET graphics editor
 
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 will not. try rearranging the order of the executed statements.
Lots of things are going on behind your back in the .NET runtime.

To resolve this matter once and for all, here is an example test function:


class Test
{
public static void test(uint iterations)
{
int j = 0;
for ( uint i = 0; i < iterations; ++i )
j += j;
for ( uint i = 0; i <iterations; i++ )
j += j;
}
}

If i translate this in release-mode and apply ildasm to disassemble i
get the code below (my comments). The code is *exactly* the same for the
++i and i++ loops.

..method public hidebysig static void test(unsigned int32 iterations)
cil managed
{
// Code size 35 (0x23)
.maxstack 2
.locals init ([0] int32 j,
[1] unsigned int32 i,
[2] unsigned int32 V_2)
// here comes loop with ++i
IL_0000: ldc.i4.0 // ->0
IL_0001: stloc.0 // j = (0)
IL_0002: ldc.i4.0 // ->0
IL_0003: stloc.1 // i1 = (0)
IL_0004: br.s IL_000e //
IL_0006: ldloc.0 // ->j
IL_0007: ldloc.0 // ->j
IL_0008: add // ->(j+j)
IL_0009: stloc.0 // j = (j+j)
IL_000a: ldloc.1 // ->i1
IL_000b: ldc.i4.1 // ->1
IL_000c: add // ->(i1+1)
IL_000d: stloc.1 // i1 = (i1+1)
IL_000e: ldloc.1 // ->i1
IL_000f: ldarg.0 // ->iterations
IL_0010: blt.un.s IL_0006 // if (i1 != iterations) goto IL_0006
// here comes loop with i++
IL_0012: ldc.i4.0 // -> 0
IL_0013: stloc.2 // i2 = (0)
IL_0014: br.s IL_001e // goto IL_001E
IL_0016: ldloc.0 // -> j
IL_0017: ldloc.0 // -> j
IL_0018: add // ->(j+j)
IL_0019: stloc.0 // j = (j+j)
IL_001a: ldloc.2 // -> i2
IL_001b: ldc.i4.1 // -> 1
IL_001c: add // ->(i2+1)
IL_001d: stloc.2 // i2=(i2+1)
IL_001e: ldloc.2 // -> i2
IL_001f: ldarg.0 // -> iterations
IL_0020: blt.un.s IL_0016 // if (i2 != iterations) goto IL0016
IL_0022: ret // return
} // end of method Test::test
 
Frank said:
It is not just an optimization to use ++i instead of i++, although that is

It is not an "optimization" in .NET, or on any integral type of any
C/C++-compiler I know of.
established. It is for readability. Using i++ means you need the value of i
before it has been incremented. Using ++i simply means: increment. So by

No, "++i" and "i++" are *both* expressions. "i = i + 1" and "i += 1",
are statements. Using "++i" as a statement is equivalent to "i = i + 1",
or "i += 1".

Remember that the syntax of "for" is

'for' '(' STMT ';' EXPR ';' STMT ')' BLOCK_OR_STMT

not:

'for' '(' STMT ';' EXPR ';' EXPR ')' BLOCK_OR_STMT

So we should really be writing:

for ( int i = 0; i < limit; i += 1 )

otherwise you are discard the value of an expression.

but since the dawn of time C-programmers have preferred the (1 character
shorter) "i++" to "i+=1". There have *never* *ever* been *any*
performance-reason for this.

I C++ you have overloadable operator++, and this means that you *can*
construct classes where the left++ is cheaper than the right++,
therefore you see C++ programmers do:

for ( IT it = begin; it != end; ++it )

which *may* yield better performance in *rare* cases (the optimizer
solves most simple cases).
using i++ where you don't need it, you are making code less readable. It is
good practice to use ++ correctly.

Which is not really much except in indexing in loops:

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

that i prefer to:

public void CopyTo(Array a, int index)
{
foreach ( object o in this )
{
a.SetValue(o, index);
index += 1;
}
}
 
very strange, i always have these results (with very little variation)
i++ : 4600
++i : 3900
i += 1 : 4600
i = i + 1 : 4600

Søren Reinke a écrit :
 
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]

Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
 
James Curran wrote:

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;
}

No, From the help-files:

The run-time processing of a postfix increment or decrement operation of
the form x++ or x-- consists of the following steps:

If x is classified as a variable:
x is evaluated to produce the variable.
The value of x is saved.
The selected operator is invoked with the saved value of x as its argument.
The value returned by the operator is stored in the location given by
the evaluation of x.
The saved value of x becomes the result of the operation.


Which means that the post-operator++ will only work "as expected" if x
is a struct. Try the example program below.
So, like in the C++, the post-fix has to create a copy of the unaltered
object, so that it can be returned.

If the type is a struct, otherwise a *wrong* (or unhelpfull, at least)
post-operator++ is generated. for C# a struct-return is always a
bit-by-bit copy, so no copy-constructor can be run here, the old struct
is simply copied bit-by bit and has the operator++ applied to it.
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.

Have you disassembled the code to verify that the optimizer does this?
(on structs... of course it won't on classes).

===> test program <===
using System;
class C
{
int i;
public static C operator++(C c) { c.i += 1; return c; }
public override string ToString() { return i.ToString(); }
}
struct S
{
int i;
public static S operator++(S s) { s.i += 1; return s; }
public override string ToString() { return i.ToString (); }
}
class Test
{
public static void print(string prefix, C c)
{ Console.WriteLine("{0}: {1}, id={2}", prefix, c, c.GetHashCode()); }
public static void print(string prefix, S s)
{ Console.WriteLine("{0}: {1}, id={2}", prefix, s, s.GetHashCode()); }

public static void Main()
{
S s = new S();
print("s", s);
print("++s", ++s);
print("s", s);
print("s++", s++);
print("s", s);

C c = new C();
print("c", c);
print("++c", ++c);
print("c", c);
print("c++", c++);
print("c", c);
}
}
===> output <===
s: 0, id=0
++s: 1, id=1
s: 1, id=1
s++: 1, id=1
s: 2, id=2
c: 0, id=1
++c: 1, id=1
c: 1, id=1
c++: 2, id=1
c: 2, id=1
 
but since the dawn of time C-programmers have preferred the (1 character
shorter) "i++" to "i+=1". There have *never* *ever* been *any*
performance-reason for this.

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)

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:

The most basic form is
A = B + C;
This would translate into assembler to basically:

ld temp, B ; load B into temp
add temp, C ; add C to temp;
ld A, temp ; Load temp into A

Since the compiler was very stupid with no optimizations, ANY statement
written in that form would be translated the same way.

But, sometimes, you wanted to write:
A = A + C;
This could be translated the same way, but there's a faster way:
add A, C; ; add C to A
But a different translation required a different syntax, hence:
A +=C;

But, sometimes, you wanted to to write:
A = A + 1;
This could be translated the same way, but there's a faster way:
inc A ; increment A
But a different translation required a different syntax, hence:
A++;
--
Truth,
James Curran
[erstwhile VC++ MVP]

Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
 
Helge is dead on the money.

Ennixo, if you want faster _and_ more readable code, use i += 1 rather
than preincrement. It says exactly what you want to do, and it's a
statement, not an expression, so there is no confusion about creating
copies of anything. The more you tell the compiler about your precise
intentions, the better code it will generate.

In all of this, though, I wonder why you're even bothering with a
managed language. I would think that you would be much better off doing
the heavy lifting in unmanaged C++...?
 
Back
Top