第二次运行托管应用程序显示的性能与第一次不同

时间:2009-01-23 06:08:23

标签: performance api benchmarking performancecounter

我有一个基准测试应用程序来测试我编写的一些API的性能。在这个基准测试应用程序中,我基本上使用QueryPerformanceCounter并通过在频率调用API之前和之后除去QPC值的差异来获得时序。但基准测试结果似乎有所不同如果我从不同的驱动器运行应用程序(在同一组Dll上运行相同的可执行文件)。此外,在特定驱动器上,第一次运行应用程序,关闭应用程序并再次重新运行它会产生不同的基准测试结果。谁能解释这种行为?我在这里错过了什么吗?

一些更有用的信息:

行为是这样的:运行应用程序,关闭它并再次重新运行,基准测试结果似乎在第二次运行时得到改善,之后保持不变。在从C盘运行的情况下,此行为更加突出。 我还想提一下,我的基准测试应用程序可以选择重新运行/重新测试特定的API,而无需关闭应用程序。我确实理解有涉及的jitting,但我不明白的是,在第一次运行app时,当你多次重新运行API而不关闭应用程序时,性能在几次运行后稳定,然后当你关闭并重新运行时同样的测试,性能似乎有所改善。

另外,如何从不同的驱动器运行时考虑性能变化?

[信息更新]

我做了 ngen ,现在来自同一位置的不同游戏之间的性能差异消失了。即如果我打开基准测试应用程序,运行一次,关闭它并从同一位置重新运行它,它会显示相同的值。

但我现在遇到了另一个问题。当我从D驱动器启动应用程序并运行它几次(在同一个基准测试版本中的几次API迭代),然后从第3次迭代开始,所有API的性能似乎下降了大约20% 。然后,如果您关闭并重新启动应用程序并运行它,前2次迭代,它会给出正确的值(与从C获得的值相同),然后性能再次超出该值。从C驱动器运行时看不到此行为。从C盘开始,无论你跑多少次,它都非常一致。

我正在使用大型双数组来测试我的API性能。我担心GC会在测试之间启动,所以我打电话给GC.Collect()& GC.WaitForPendingFinalizers()明确地在每次测试之前和之后。所以我不认为它与GC有任何关系。

我尝试使用AQ时间来了解从第3次迭代开始发生的事情,但有趣的是,当我使用AQ时间分析它运行应用程序时,性能根本不会下降。

性能计数器并不表示任何有趣的IO活动。

由于  NIRANJAN

4 个答案:

答案 0 :(得分:4)

运行应用程序会将其可执行文件和其他文件从硬盘驱动器带入操作系统的磁盘缓存(在RAM中)。如果之后很快再次运行,许多这些文件可能仍然在缓存中。 RAM比磁盘快得多。

当然,一个磁盘可能比另一个磁盘快。

答案 1 :(得分:3)

是。它被称为Just-In-Time compiling。基本上,您的应用程序部署为MSIL(Microsoft中间语言),并且第一次运行时,它将转换为本机代码。

您可以随时运行NGen(请参阅上面的文章),或者在性能测试脚本中预热一段时间,在实际对性能进行基准测试之前,它会在场景中运行几次。

答案 2 :(得分:1)

我认为这里有一系列效果:

首先,多次在测试工具中运行相同的功能,每次使用相同的数据,可能会有所改善,因为:

  • JIT编译将优化最常运行的代码以提高性能(Cory Foy为mentioned already
  • 程序代码将位于磁盘缓存中(Crashwork为mentioned already
  • 如果程序代码足够小并且执行得足够频繁,那么某些程序代码将位于CPU缓存中

如果测试工具中每次运行该功能的数据不同,这可以解释为什么再次关闭和运行测试工具可以改善结果:数据现在在磁盘缓存中,这不是第一次。

最后,是的,即使两个“驱动器”位于同一物理磁盘上,它们也会有不同的性能:数据可以从磁盘盘片的外部读取得比内部更快。如果它们是不同的物理磁盘,那么性能差异似乎很可能。此外,一个磁盘可能比另一个磁盘碎片更多,导致更长的搜索时间和更慢的数据传输速率。

答案 3 :(得分:1)

此外,其他因素可能会发挥作用。机器上的文件系统缓存,最近使用的数据缓冲等

除非你专门测量冷启动时间,否则最好运行多次测试(或几百次!)并在整个设备中取平均值。