Slowdowns / 'Anti-Hotspot'

Started by
7 comments, last by frob 11 years, 6 months ago
Hi,

I'm working on my Quad-Tree for a while now, to generate the landcape. I optimized it pretty nicely so its able to produce new quads in 1 - 2ms.
The problem is that C# slows down when there wasn't create a new quad for a while (while means starting from 500ms).
Here an example:

Node gen; total 106ms noise 69 vert 11 rest
Node gen; total 2ms noise 1 vert 0 rest 1
Node gen; total 2ms noise 0 vert 0 rest 1
Node gen; total 2ms noise 0 vert 0 rest 1
Node gen; total 3ms noise 0 vert 0 rest 2
Node gen; total 4ms noise 2 vert 0 rest 1
Node gen; total 7ms noise 1 vert 0 rest 6
Node gen; total 4ms noise 2 vert 0 rest 2
Node gen; total 37ms noise 1 vert 0 rest 35
Node gen; total 3ms noise 1 vert 0 rest 1
Node gen; total 19ms noise 17 vert 0 rest 1
Node gen; total 18ms noise 17 vert 0 rest 1
Node gen; total 19ms noise 17 vert 0 rest 1
Node gen; total 19ms noise 17 vert 0 rest 1
Node gen; total 2ms noise 1 vert 0 rest 1
Node gen; total 2ms noise 1 vert 0 rest 1
Node gen; total 22ms noise 16 vert 0 rest 4
Node gen; total 2ms noise 1 vert 0 rest 1
Node gen; total 18ms noise 17 vert 0 rest 1
Node gen; total 19ms noise 17 vert 0 rest 1
Node gen; total 19ms noise 17 vert 0 rest 1
Node gen; total 18ms noise 15 vert 0 rest 2
Node gen; total 19ms noise 17 vert 0 rest 1
Node gen; total 18ms noise 17 vert 0 rest 1
Node gen; total 2ms noise 1 vert 0 rest 1
Node gen; total 18ms noise 16 vert 0 rest 1
Node gen; total 2ms noise 1 vert 0 rest 1
Node gen; total 19ms noise 17 vert 0 rest 1
Node gen; total 2ms noise 0 vert 0 rest 1
Node gen; total 2ms noise 1 vert 0 rest 1


As you can see the time for the generation CAN be very fast, but it slows down for no reason :(
The difficulty of the data to create dosen't change at all.

I know that C# / .NET optimizes parts of code that are 'in heavy use'like the hotspot technology in JVM.
Is there any way to enable it manually? How do you handle it?
Advertisement

As you can see the time for the generation CAN be very fast, but it slows down for no reason


There's always a reason. For C#, that reason is usually the garbage collector.
What you need to diagnose the issues is a profiler.

There's always a reason. For C#, that reason is usually the garbage collector.


Can I avoid this problem by creating nodes in a new thread?


What you need to diagnose the issues is a profiler.


Mh... I don't think this is what I need. It's not that I don't understand which parts of code lines are slow, I don't know why the are getting slow by random.

[quote name='Telastyn' timestamp='1348606320' post='4983732']
There's always a reason. For C#, that reason is usually the garbage collector.


Can I avoid this problem by creating nodes in a new thread?


What you need to diagnose the issues is a profiler.


Mh... I don't think this is what I need. It's not that I don't understand which parts of code lines are slow, I don't know why the are getting slow by random.
[/quote]

This is not random. There is a reason for it, probably a lack of memory.

The profiler will tell you if you have enough memory or not.

Can I avoid this problem by creating nodes in a new thread?


No.

Another idea is that the resolution of your timer isn't fine enough to measure the true duration of your work. The large difference depends then on if you happen to catch the timer on the outward or inward swing
Quadtrees tend to be very computationally expensive, and even worse - tend to do lots of heap allocations in loops. I couldn't tell you without looking at your code, but it may be possible that the problem is the garbage collector. If you wanted to stay using c#, you may be able call the GC class and have it clean up after every node is created.

It's unusual that the garbage collector would block you that badly unless you were doing LOTS of heap allocations that keep the variables alive for periods of time where the garbage collector can't figure out if it should treat the variables as a short-lifespan object or a long-lifespan object.

I suggest you read this article and become more acquainted with the GC. http://msdn.microsoft.com/en-us/library/ms973837.aspx
I you're using generics (i.e. List<Node>) or any other kind of List inside your QuadTree and adding one node at a time, it is very well worth creating your list with a initial size like this;

List<Node> nodes = new List<Node>(32) rather than use the default of "1". As the list extends .net will double the memory allocation for it each time it reaches the end of its preallocated buffer limit - which takes time. If you initialize it to a reasonable guesstimate of the likely size, .net will allocate the memory once-only during class initialization without the need to allocation incrementally with the attendant memory fragmentation. Of course, you dont want to guess too big, because the memory is actually allocated.

I wouldn't recommend touching the GC at all - it does the job its supposed to do. Many people recommend GC.Collect "to make .net faster" but its often an error; the real problem is in the excessive allocation and reallocation of objects and the fragementation that leads from it. For instance; always consider using a for(int) loop rather than a foreach() within quadtree parsing - foreach() creates and destroys and enumerator object - expensive in the kind of nested looping common in quadtrees, whereas the old fashioned for(int) doesn't.

As recommended by the other posters - you reallly, really need to use a profiler. VS.net has one built in, otherwise Ants is a very good one.

I wouldn't recommend touching the GC at all - it does the job its supposed to do. Many people recommend GC.Collect "to make .net faster" but its often an error; the real problem is in the excessive allocation and reallocation of objects and the fragementation that leads from it. For instance; always consider using a for(int) loop rather than a foreach() within quadtree parsing - foreach() creates and destroys and enumerator object - expensive in the kind of nested looping common in quadtrees, whereas the old fashioned for(int) doesn't.

As recommended by the other posters - you reallly, really need to use a profiler. VS.net has one built in, otherwise Ants is a very good one.


This is especially true in games.

Here in our studio we use C# for multiple titles. We never need to force garbage collection to run.

Almost certainly you are creating unnecessary objects and either leaving them in use or casually throwing them away. That is an area that C++ at least forces you to deal with so you realize when you are doing it, C# makes it very easy to create many unnecessary objects consuming your memory in horrible ways.

When performance suddenly slows, we can usually track it down to a programmer spewing out temporary objects or using weak references. A few moments on the profiler will find the source of these allocations rather quickly.

This topic is closed to new replies.

Advertisement