views:

660

answers:

4

I'm writing a DSP application in C# (basically a multitrack editor). I've been profiling it for quite some time on different machines and I've noticed some 'curious' things.

On my home machine, the first run of the playback loop takes up about 50%-60% of the available time, (I assume it's due to the JIT doing its job), then for the subsequent loops it goes down to a steady 5% consumption. The problem is, if I run the application on a slower computer, the first run takes up more than the available time, causing the playback to get interrupted and messing the output audio, which is unacceptable. After that, it goes down to a 8%-10% consumption.

Even after the first run, the application keeps calling some time-consuming routines from time to time (every 2 seconds more or less), which causes the steady 5% consumption to experience very short peaks of 20%-25%. I've noticed that if I let the application run for a while these peaks will also go down to a 7%-10%. (I'm not sure if it's due to the JIT recompiling these portions of code).

So, I have a serious problem with the JIT. While the application will behave nicely even in very slow machines, these 'compiling storms' are going to be a big problem. I'm trying to figure out how to resolve this issue and I've come up with an idea, which is to mark all the 'sensible' routines with an attribute that will tell the application to 'squeeze' them beforehand during start-up, so they'll be fully optimized when they're really needed. But this is only an idea (and I don't like it too much either) and I wonder if there's a better solution to the whole problem.

I'd like to hear what you guys think.

(NGEN the application is not an option, I like and want all the JIT optimizations I can get.)

EDIT:

Memory consumption and garbage collection kicks are not an issue, I'm using object pools and the maximum peak of memory during playback is 304 Kb.

+4  A: 

The initial speed indeed sounds like Fusion+JIT, which would be helped by ILMerge (for Fusion) and NGEN (for JIT); you could always play a silent track through the system at startup so that this does all the hard work without the user noticing any distortion?

NGEN is a good option; is there a reason you can't use it?

The issues you mention after the initial load do not sound like they are related to JIT. Perhaps garbage collection.

Have you tried profiling? Both CPU and memory (collections)?

Marc Gravell
For me the the only reason not to use ngen would be that it requires administrative privileges during installation, thus not being applicable to per-user installations on corporate networks. Maybe that is the reason for the OP as well?
0xA3
Why not do NGEN as an option on install then? So if you have admin rights, do it. Otherwise warn the user and dont do it.
Nic Wise
+3  A: 

As Marc mentioned, the ongoing spikes do not sound like JIT issues. Other things to look for:

  • Garbage collection - are you allocating memory during your audio processing? If you're creating a lot of garbage, or even objects which survive a Gen 0 collection, this might cause noticible spikes. It sounds like you are doing some kind of pre-allocation, but watch out for hidden allocations in library code (even a foreach loop can allocate!)

  • Denormals. There is an issue with certain types of processors when dealing with very small floating point numbers which can cause CPU spikes. See http://www.musicdsp.org/files/denormal.pdf for details.

Edit:

Even if you don't want to use NGen, at least compare an NGen'd version so you can see what difference JITing makes

Jim Arnold
Interesting. I had no clue that denormals were such a monstrous speed bump.
Jeffrey Hantin
+4  A: 

You can trigger the JIT compiler to compile your entire set of assemblies during your application's initialization routine using the PrepareMethod .. method (without having to use NGen).

This solution is described in more detail here: Forcing JIT Compilation During Runtime.

Liran
+1  A: 

If you believe you are being impacted by JIT, then precompile your app with NGEN and run the tests again. There is no JIT overhead in code that has been compiled by NGEN. If you still see spikes in the NGEN'd app, then you know they are not caused by JIT.

dthorpe