强制.NET JIT编译器在应用程序启动期间生成最优化的代码

我正在用C#编写一个DSP应用程序(基本上是一个多轨编辑器)。 我在不同的机器上进行了很长一段时间的分析,我注意到了一些“好奇”的东西。

在我的家用机器上,回放循环的第一次运行占用了可用时间的大约50%-60%,(我认为这是由于JIT正在完成其工作),然后对于后续循环,它会下降到稳定的5 % 消费。 问题是,如果我在较慢的计算机上运行应用程序,第一次运行占用的时间超过可用时间,导致播放中断并弄乱输出音频,这是不可接受的。 之后,它降至8%-10%的消费量。

即使在第一次运行之后,应用程序仍然不时地调用一些耗时的例程(每2秒或多或少),这导致稳定的5%消耗经历非常短的20%-25%的峰值。 我注意到如果我让应用程序运行一段时间,这些峰值也会下降到7%-10%。 (我不确定这是否是由于JIT重新编译这些代码部分)。

所以,我对JIT有一个严重的问题。 虽然应用程序即使在非常慢的机器中也能很好地运行,但这些“编译风暴”将成为一个大问题。 我试图弄清楚如何解决这个问题,我想出了一个想法,即用一个属性标记所有’明智的’例程,告诉应用程序在启动时预先“挤压”它们因此,当他们真正需要时,他们将完全优化。 但这只是一个想法(我也不太喜欢),我想知道是否有更好的解决方案来解决整个问题。

我想听听你们的想法。

(NGEN应用程序不是一个选项,我喜欢并希望我能获得所有JIT优化。)

编辑:

内存消耗和垃圾收集没有问题,我正在使用对象池,播放期间的最大内存峰值为304 Kb。

您可以使用PrepareMethod …方法触发JIT编译器在应用程序初始化例程期间编译整个程序集集(无需使用NGen )。

此处更详细地描述了此解决方案: 在运行时强制JIT编译 。

初始速度确实听起来像Fusion + JIT,ILMerge(适用于Fusion)和NGEN(适用于JIT)可以提供帮助; 您可以在启动时始终通过系统播放静音轨道,以便在没有用户注意到任何失真的情况下完成所有艰苦工作?

NGEN是一个不错的选择; 有没有理由你不能使用它?

初始加载提到的问题听起来并不像是与JIT有关。 也许垃圾收集。

你尝试过剖析吗? CPU和内存(集合)?

正如Marc所说,持续的峰值听起来不像JIT问题。 其他要寻找的东西:

  • 垃圾收集 – 你在音频处理过程中分配内存吗? 如果您正在创建大量垃圾,甚至是在Gen 0集合中存活的对象,这可能会导致明显的峰值。 听起来你正在进行某种预分配,但要注意库代码中的隐藏分配(即使是foreach循环也可以分配!)

  • 非正规数。 在处理可能导致CPU峰值的非常小的浮点数时,某些类型的处理器存在问题。 有关详细信息,请参见http://www.musicdsp.org/files/denormal.pdf 。

编辑:

即使您不想使用NGen,至少要比较一个NGen版本,这样您就可以看出JITing的不同之处

如果您认为自己受到JIT的影响,那么请使用NGEN预编译您的应用并再次运行测试。 NGEN编译的代码中没有JIT开销。 如果您仍然在NGEN的应用程序中看到尖峰,那么您知道它们不是由JIT引起的。