Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Performance?  (Read 11829 times)

0 Members and 1 Guest are viewing this topic.

Xeon06

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Performance?
« on: January 23, 2010, 06:23:46 pm »
Hey all,

I've been messing around with SFML 2.0 and I found a few things. First of all, this basic app takes 25% of my CPU usage and about 23 MBs of memory. Is this normal?

Code: [Select]

using System;
using SFML.Window;
using SFML.Graphics;

namespace SFML1
{
class Game
{
static void Main()
{
RenderWindow app = new RenderWindow(new VideoMode(500, 500, 32), "SFML1");
app.Closed += new EventHandler(OnClosed);

while (app.IsOpened())
{
app.DispatchEvents();
app.Clear();


app.Display();
}
}

static void OnClosed(object sender, EventArgs e)
{
((Window)sender).Close();

if (System.Diagnostics.Debugger.IsAttached) //Hotfix for app crashing in Debug mode when using a String2D
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
}
}


Adding a call System.Threading.Thread.Sleep(1) puts the CPU usage at 0% instead of 25. Shouldn't SFML already implement a mechanism like that already? I'm sure there's a good reason it doesn't, if you guys could enlighten me.

Also, instantiating a Text object every frame ends up locking up the application after ~10 seconds or so on my machine:
Code: [Select]

using System;
using SFML.Window;
using SFML.Graphics;

namespace SFML1
{
class Game
{
static void Main()
{
RenderWindow app = new RenderWindow(new VideoMode(500, 500, 32), "SFML1");
app.Closed += new EventHandler(OnClosed);

float time = 0;

while (app.IsOpened())
{
app.DispatchEvents();
app.Clear();

time += app.GetFrameTime();
app.Draw(new Text(time.ToString()));

app.Display();
}
}

static void OnClosed(object sender, EventArgs e)
{
((Window)sender).Close();

if (System.Diagnostics.Debugger.IsAttached) //Hotfix for app crashing in Debug mode when using a String2D
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
}
}


Monitoring the Task Manager's memory usage and System.GC.GetTotalMemory I can observe that memory usage gradually increases until the hang up, where it shoots back down. Of course, instantiating the Text object only once and then changing its DisplayedString property does not make it hang, but does that mean we always have to declare our Text objects before the loop?

Thanks, and sorry for all these topics and questions I'm making as of lately.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Performance?
« Reply #1 on: January 23, 2010, 06:33:29 pm »
Quote
First of all, this basic app takes 25% of my CPU usage and about 23 MBs of memory. Is this normal?

Yes for the CPU (you program is basically an endless loop with no pause), for the memory I'm not sure, I'm not familiar with .Net applications.

Quote
Adding a call System.Threading.Thread.Sleep(1) puts the CPU usage at 0% instead of 25. Shouldn't SFML already implement a mechanism like that already? I'm sure there's a good reason it doesn't, if you guys could enlighten me.

You can either use Window.SetFramerateLimit or Window.UseVerticalSync.

Quote
Monitoring the Task Manager's memory usage and System.GC.GetTotalMemory I can observe that memory usage gradually increases until the hang up, where it shoots back down. Of course, instantiating the Text object only once and then changing its DisplayedString property does not make it hang, but does that mean we always have to declare our Text objects before the loop?

No, this looks like a bug to me. I'll see that, thanks for your feedback :)
Laurent Gomila - SFML developer

Xeon06

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Performance?
« Reply #2 on: January 24, 2010, 02:13:30 am »
Thanks!

Xeon06

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Performance?
« Reply #3 on: February 05, 2010, 10:29:23 pm »
Ok I have investigated a bit more and here are my findings.

The leak only happens when you create new instances of the Text object containing the same string. Here, running these  each frame produce the leak:

Code: [Select]

new Text();

Code: [Select]

new Text("test");


I modified the source code a bit, adding trace code to the Destroy method of the Text class, and I notice that the destruction only kicks in after the application has taken up a lot of memory, and this is usually followed by the program hanging up or throwing an AccessViolationException somewhere in Text.cs (usually in the Destroy method).

These examples works fine:
Code: [Select]

new Text(new Random().Next().ToString());

Since the text changes every frame, Destroy is called a lot more and the memory stays at a stable low.

While looking through the source code, I noticed that most things implementing Drawable (Text, Shape) are exclusively bindings to the C dlls. With that in mind, I tried the following code:

Code: [Select]

new Shape();


and sure enough, memory leak there too. I'm guessing this is due to some bad memory handling in the transfer between C and C#. I know you are very busy doing other things and the Dotnet binding is probably one of your last priorities, but I am really looking forward to using it properly for a project so if you have any idea or pointers in how to fix this, I'll look into this and try to get a solution.[/code]

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Performance?
« Reply #4 on: February 05, 2010, 10:53:05 pm »
Thanks for the time you spent investingating this issue.

Unfortunately I have no idea, and it's even worse because I can't reproduce the problem on my machine. So I'm afraid I won't be able to help much :(
Laurent Gomila - SFML developer

Xeon06

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Performance?
« Reply #5 on: February 05, 2010, 11:17:17 pm »
Weird. Well if it can help, I just sent the following files to a friend and he says he can see it happening, both the memory hogging and the crash.
http://dl.dropbox.com/u/3310651/MemLeak2.rar

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Performance?
« Reply #6 on: February 06, 2010, 12:08:45 am »
Ok thanks, I'll try it :)
Laurent Gomila - SFML developer

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Performance?
« Reply #7 on: February 06, 2010, 07:13:29 pm »
Sorry, but I have no problem with these examples. They work perfectly on my computer.
Laurent Gomila - SFML developer

Xeon06

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Performance?
« Reply #8 on: February 06, 2010, 11:01:44 pm »
Wow, then I am totally flabbergasted. Have you let them run more than 1 minute and have you tried checking the memory using the task manager? I did some profiling using ANTS and after 16 seconds of running the exact application I provided you, there are over 28K Text instances.

http://dl.dropbox.com/u/3310651/sfml_memleak.png

Xeon06

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Performance?
« Reply #9 on: February 11, 2010, 09:18:43 pm »
Ok so I made some tests, asked around on a few forums (FP, SO) and I ruled out OS as the cause of the problem. Someone on FP mentionned that using Sleep ceased the problem, so it might be a timing related issue, maybe the GC doesn't have enough time to clean things up?

Either way, I think I know what the real problem is; the use of unmanaged objects. If you make a loop in the frame of say a thousand iterations and create a new shape a thousand times a frame, it will consume enormous memory and fill up your RAM in no time because you are referencing unmanaged objects. However, I reproduced the Shape class in managed C# and did the same experiment, it all goes fine with next to no overhead.

What I'm basically saying is that the best way to do this, in my opinion, would be to have functions that directly draw things (Text, Shapes, maybe even Sprites?) and writing the classes in managed C#. Only one DllImport, the draw call (which would be huge, but still) would be needed.

I really really love this project, the simplicity of it, and I love .Net, so I dream of combining the two. However, right now, it isn't really possible to use SFML in the ".NET mentality", that is we have to be careful not to leak memory and whatnot.

I would be willing to help out with this, I tried checking it out but I barely know C and C++ and I couldn't really understand what was going on (.Net is a binding to C which in turn uses C++?) but I would be more than glad to write the managed classes for you if you ever decided on such a path. I understand that the .Net binding must be your last priority but I think it could turn out great.

If you want, email me and we can talk about this (I speak french if that can help).[/url]

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Performance?
« Reply #10 on: February 11, 2010, 09:33:46 pm »
Well, the binding works flawlessly for me and apparently most of the other users, I'm definitely not going to rewrite the graphics module from scratch to solve this "issue".

At least I'd like to understand what's really happening before taking such a decision. I don't see why the use of P/Invoke would change how objects are collected, all these calls are properly wrapped into managed .Net classes. I can't see any reason for the GC to process them differently.

If there's something wrong somewhere (there might be, I'm not a .Net expert), I'd prefer understanding and solving it properly rather than designing a new API ;)

At the moment you can try a workaround like manually invoking the GC at every iteration.
Laurent Gomila - SFML developer

Xeon06

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Performance?
« Reply #11 on: February 11, 2010, 10:42:01 pm »
I understand  :(

Xeon06

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Performance?
« Reply #12 on: February 12, 2010, 03:55:48 am »
I just spent a few hours in IRC with guys trying to figure this out, we went back to stack traces up to the native C++ DLLs, even dissassembly and whatnot. I think I know what's happening. Finalizers in C# are run in a separate thread, and according to the guys in ##csharp, the native csfml DLLs aren't thread safe, so we either get an AccessViolationException or it loops up in the accessor part, something like that. The reason why not everyone can reproduce the problem is that different systems have different timing schedules for GC, that also explains why using Sleep helps up to a point. I remember reading on the site somewhere something about not calling sfml functions from different threads as it wasn't thread safe. Will this ever change? I won't bother you (or myself in some respect) with this anymore after this answer, I will simply go back to XNA with a broken heart :P.

For reference if someone is interested, here is the IRC log:
http://dl.dropbox.com/u/3310651/memleak_irc.txt

And the spreadsheet with my test candidates:
http://spreadsheets.google.com/ccc?key=0AhcHeJlLGEVUdG1TTi1mTkFxeFlHYVRISXhjbFBDUmc&hl=en

The links to the other people who helped me I posted previously.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Performance?
« Reply #13 on: February 12, 2010, 09:12:15 am »
I read the whole IRC log, thanks for it.

I know that SFML is not 100% thread-safe, but I do my best to provide thread-safety where it is necessary. I never thought about the destructor of the Text class, but after having a look at your call stack I found a possible issue.

Text instances have a pointer to the Font they use, and this pointer is wrapped into a special "smart" pointer class that I wrote. This smart pointer is notified whenever the font is destroyed, which involves maintaining a list of these pointers in the Font instance. What happens in your app, I think, is that both insertion and removal happen at the same time in the font's list, from two different threads. And this is probably not thread-safe.

I made a quick fix, can you update your working copy and test again? I updated the CSFML binaries in dotnet/extlibs so that you can test without recompiling everything :)

PS: I'm not an expert in .Net, but this binding is not a "quick and dirty" implementation that I wrote to answer the demand. I am really involved in its evolution, and I read a lot about how GC and memory works in .Net ; I am aware of the GC collecting objects in a separate thread and made my best so that it can work properly (it previously caused other problems, because objects may be collected even after the main thread has ended).
I just wanted to make things clear for those people who have a bad opinion of SFML.Net ;)
Laurent Gomila - SFML developer

Xeon06

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Performance?
« Reply #14 on: February 12, 2010, 09:28:51 pm »
You sir, are awesome. It works. Just to be sure, I started it this morning before going to college at 0650, and now at 1505 it was still running with no problem.

Whew, this was a long journey, but in the end, worth it IMO. I cannot thank you enough to have born with me through this and for this fix. You save me from having to use XNA :D.

Now, seeing as this is programming, I expect it to stop working within a week and I try not to get my expectations up, but for all intent and purposes, it seems to work flawlessly. If something starts messing up, I'll be sure to inform you. In the meantime, merci beaucoup.