Some simple coding techniques to push C# as fast as possible (1 Viewer)

A

Anonymous

Guest
Hello All, I'm new to this forum, but a C# engineer. Love the MP product, and was excited to see you guys really blazed ahead and used C# for the implementation. I read some postings about improving performance, and just wanted to shoot you some things.

My company is EXTREMELY concerned with performance. Every possible IL instruction that can be reduced, every nanosecond gained, is a win in their opinion. With that said, I did a series of benchmarking tests on various common uses of C#, and some other general suggestions to possibly improve performance with Beta2. So, here are some obvious things to change/fix if you so desire to improve performance: (Note: I benchmarked all these situations with the NT high performance monitor calls through C#)

1) Stay away from foreach loops, the performance is horrible. Especially when walking through System.Collection classes. The absolute fastest way to walk anything is with a for loop, but not just any for loop. You must take the end loop check out of the for statement. So, for instance:

for (int i=0; i < myArray.Count; i++) // Slower way

int nSize = myArray.Count;
for (int i=0; i < nSize; i++) // Faster way

Although there is an MSDN article stating that the release optimizer takes benefit in using the myArray.Count in the 'for' to remove the boundry check in the 'for' block code, it's still slower. Maybe .NET 2.0 will fix this. Of course, doing a calcuation in the for is even worse, like this:

for (int i=0; i < nSize/2; i++)

This division is evaluated every time, which is of course bad. So, point #1, remove all foreach statements and take the loop checks out of the for statement.

2) Next, an obvious one which you may already do. Implement a dispose pattern for all your objects, and dispose them just like you would in C++. The GC lets you get lazy, but at the expense of it taking cycles from you during the GC cleanup. Treat your new'd classes like C++, you never know when the GC will decide it needs to execute.

3) If/else statements are far faster than switch statements, even at 10 conditions, even with pumping the last 'if' check millions of times. You can at least order the if statements based on which ones you think will be checked more than others. C# organizes a case statement to optimal searching, so it rearranges things on you potentially. switch looks nice, but it's slower.

4) If you do a 'new' on a class, don't bother checking for NULL, since 'new' throws an exception. You'll never get control in your code after a 'new' and have the reference be NULL. It's just wasted 'if' checks.

5) Try to prevent object creation as rule of thumb. Don't 'new' objects in the declaration or constructor if they can be done later. They may never be needed, so their declaration could potentially be skipped.

6) Prefer 'as' object casting to the C style casting. It's simply faster.

7) Methods are inlined if they are under 32 bytes of IL, so keep those properties small if possible. You can roughly do about 3 lines of code in the property and keep it under 32 bytes of IL.

8 ) Remove numberic type conversions if possible, they are very expensive.

9) Learn about C# boxing, and how it's a performance killer. Granted, Boxing is the real killer, unboxing is far less expensive. Try to prevent any boxing in performance critical areas.

Ok, that's it for now. Hopefully this information is of some use. Keep up the great work you guys.
 
A

Anonymous

Guest
Hey Chris,

i just started to look into C# (just because of MP :roll: ) and i really appreciate your posting.

for (int i=0; i < nSize/2; i++)

This division is evaluated every time...
Are you sure about that ? That would be a bad compiler design ... Actually a compiler evaluates the Division one time and tries to loop it backwards to 0. Otherwise forward using an additional Register. I can't really believe that the division is evluated every loop.
 
A

Anonymous

Guest
Well, you could change nSize inside the for loop, so I'm not sure how the compiler would get out of evaluating it every time, or at least checking that nSize hasn't changed. Now, the compiler may be smart enough to see that nSize isn't being changed inside the loop and store that calculation. On that matter I couldn't answer. Regardless of it all, to maximize performance you should take that calculation out of the 'for' line. (assuming you don't change nSize in the loop of course!)
 

waeberd

Portal Pro
August 16, 2004
314
1
Fribourg (CH)
A

Anonymous

Guest
I'm an experienced C# Software Developer (read not engineer) and I have another view of "performance tuning" I'd like to share.

DO NOT OPTIMIZE CODE UNLESS IT’S REQUIRED!!!

I've see way too much code that’s been "optimized" for maximum performance that’s become so unreadable and maintainable its nearly impossible to fix minor bug never mind add new features! Developers can spend countless hours coding "better for loops" and learn the details of C# garbage collection and still write horribly bad performing code. Your tips, although very useful in specific situations, if applied to every line of code in MP or any other application will lead to increased dev times and even project failure. Think about your point 2 (treat new classes like C++), If I had to dispose every object I created why the HELL would I use C#!?!?! I might as well use C++.

Now back to my main point. The best way to increase performance is to target problem areas and try to find better ways of implementing specific problem functions/algorithms. The hard part is finding these problem areas. Code reviews by more experienced developers are a good way to do this, but sometimes that’s not even enough. Luckily there are a whole group of tools dedicated to helping you do this. They are called Code and Memory Profilers... learn them and love them. I've personally used DevPartner with great success. (they have a free version here)
http://tinyurl.com/2oct4
They help you find places where you are using the most clock cycles and memory. In most cases the profiler can point you directly at specific lines of code in your algorithms and framework calls. A few examples I've run into are:
1) Expensive searches (ie a simple linear search instead of a binary search)
2) Unnecessary memory allocation (ie creating new object in for loops)
3) Using .NET Framework reflection (ie using object.GetType() everywhere)
4) Framework bugs (I found a memory leak in the .NET XML module to do with a specific version of an overloaded method! Which M$ fixed in a new release of the Framework  )
These are more subtle problems that can creep up in even the most “optimized” code base. In my opinion its better to make your code readable and maintainable so that when these issues come up you are able to find the problem areas and take care of them.

Sorry if I came off a little harsh, but I’m sick and tired of junior devs (and some “sr” ones too !) running around “optimizing” their code for no reason at all and then me having to jump in and fix a major issue because they screwed it up so bad that they can’t even read their own code! </rant>
 
A

Anonymous

Guest
Avoid premature optimization, design for performance instead

Well said, Shawn.
For a slightly less heated take on the topic, I recommend two wiki topics at c2.com:
http://c2.com/cgi/wiki?PrematureOptimization
http://c2.com/cgi/wiki?DesignForPerformance

As my first year computer science professor said, detailed optimizations are often "penny wise and pound foolish". There's no point in focusing on looping syntax to gain 5 ms in performance, if you fail to consider your network communication strategy and waste 2 s in extra round trips.

yours,
Don Kirkby
 

waeberd

Portal Pro
August 16, 2004
314
1
Fribourg (CH)
Yeah Shawn, you're very right!
The "make it stable" / "use profilers" / "optimize where it's really needed" approach happens to be the most efficient IMHO!

It's very easy to optimize parts that don't slow down the application AT ALL... and code-optimizing is a never-ending process...

If you can detect real bottlenecks at first sight.... congratulations!
But I am often *very* surprised where the time really flies away when reading profiler results, so I simply gave up guessing where bottlenecks could be... use profilers!!

Keep hackin' :)

Daniel

btw: At the job, I use AQTime http://www.automatedqa.com/products/aqnet.asp (for Delphi, but there's a .NET version). Not very cheap but simply awesome once you get used to it!!
 
A

Anonymous

Guest
I wasn't suggesting optimizing the entire code based on my suggestions. C# is fast enough, the GC is fast enough, for 90+% of normal coding operations. But there may be something critical which needs optimizing. I'm a huge fan of writing the most readable code possible, it's the only way in the long haul to support a stable code base.

Regarding the dispose pattern, I didn't make this up, you can find that on numerious MSDN sites with regard to writing high performance C# code. And for good reason. If you're doing something which is pushing the CPU hard and your thread gets bumped out for the GC, that may be a situation which isn't acceptable from a performance standpoint. Maybe it causes a hiccup when recording video, who knows. Those bugs are hard to find and diagnose for sure.
 

Frodo

Retired Team Member
  • Premium Supporter
  • April 22, 2004
    1,518
    121
    52
    The Netherlands
    Home Country
    Netherlands Netherlands
    if you profile MP (with nprof or ants) you'll see that
    90% of all cpu power used goes in guifont.cs
    in the method drawtext
    In my opinion its better to optimize this then to
    randomly optimize some code which may take up 0.00001 % cpu

    frodo
     

    Users who are viewing this thread

    Top Bottom