什么是微基准测试?


69

我听说过使用过这个术语,但是我不确定它的含义,因此:

  • 它是什么意思,不是什么意思?
  • 什么是IS和IS N'T微基准测试的一些示例?
  • 微基准测试有哪些危险,如何避免?
    • (或者这是好事吗?)

5
现在是我睡觉的时间,所以这里只是一个愚蠢的评论,它包含一个链接,可让您开始阅读材料:java.sun.com/docs/hotspot/HotSpotFAQ.html(请检查TOC底部的“基准测试”一章)。
BalusC 2010年

9
仅比基准测试有用的百万分之一:-)
Stephen C

Answers:


83

它的意思恰恰是它在锡罐上所说的-它正在衡量“小”东西的性能,例如对操作系统内核的系统调用。

危险在于人们可能会使用从微基准测试中获得的任何结果来指示优化。众所周知:

我们应该忘掉效率低下的问题,比如说大约有97%的时间:过早的优化是万恶之源” –唐纳德·努斯(Donald Knuth)

可能有许多因素会扭曲微基准测试的结果。编译器优化就是其中之一。如果要测量的操作花费的时间很少,以至于您用来测量的时间要比实际操作本身花费的时间更长,那么您的微基准测试也会出现偏差。

例如,有人可能会对for循环的开销进行微基准测试:

void TestForLoop()
{
    time start = GetTime();

    for(int i = 0; i < 1000000000; ++i)
    {
    }

    time elapsed = GetTime() - start;
    time elapsedPerIteration = elapsed / 1000000000;
    printf("Time elapsed for each iteration: %d\n", elapsedPerIteration);
}

显然,编译器可以看到该循环绝对不执行任何操作,并且根本不会为该循环生成任何代码。因此,价值elapsedelapsedPerIteration是几乎无用。

即使循环执行了一些操作:

void TestForLoop()
{
    int sum = 0;
    time start = GetTime();

    for(int i = 0; i < 1000000000; ++i)
    {
        ++sum;
    }

    time elapsed = GetTime() - start;
    time elapsedPerIteration = elapsed / 1000000000;
    printf("Time elapsed for each iteration: %d\n", elapsedPerIteration);
}

编译器可能会看到该变量sum将不会用于任何东西,并且对其进行了优化,并且也优化了for循环。可是等等!如果我们这样做:

void TestForLoop()
{
    int sum = 0;
    time start = GetTime();

    for(int i = 0; i < 1000000000; ++i)
    {
        ++sum;
    }

    time elapsed = GetTime() - start;
    time elapsedPerIteration = elapsed / 1000000000;
    printf("Time elapsed for each iteration: %d\n", elapsedPerIteration);
    printf("Sum: %d\n", sum); // Added
}

编译器可能很聪明,可以意识到它sum始终是一个常数,并且还可以对其进行优化。如今,许多人会对编译器的优化功能感到惊讶。

但是,编译器无法优化的事情呢?

void TestFileOpenPerformance()
{
    FILE* file = NULL;
    time start = GetTime();

    for(int i = 0; i < 1000000000; ++i)
    {
        file = fopen("testfile.dat");
        fclose(file);
    }

    time elapsed = GetTime() - start;
    time elapsedPerIteration = elapsed / 1000000000;
    printf("Time elapsed for each file open: %d\n", elapsedPerIteration);
}

即使这不是有用的测试!操作系统可能会看到文件被打开得非常频繁,因此它可能会将其预加载到内存中以提高性能。几乎所有操作系统都可以这样做。当您打开应用程序时,也会发生同样的事情-操作系统可能会找出打开最多的前5个应用程序,并在启动计算机时将应用程序代码预加载到内存中!

实际上,有无数变量在起作用:引用的局部性(例如数组与链表),缓存和内存带宽的影响,编译器内联,编译器实现,编译器切换,处理器核心数量,处理器级别的优化,操作系统调度程序,操作系统后台进程等。

因此,在许多情况下,微基准测试并不是完全有用的指标。它绝对不能用定义良好的测试用例(分析)代替整个程序的基准测试。首先编写可读代码,然后进行概要分析以查看需要完成的操作(如果有)。

我想强调一点,微基准本身并不是邪恶的,但人们必须谨慎使用它们(对于与计算机相关的许多其他事情,这是正确的)


8
很好的评论,尽管Knuth表示过早考虑优化不应影响DESIGN(而不是“指示性优化”)。将设计迎合早期基准测试的结果通常会导致设计不灵活。 en.wikipedia.org/wiki/Program_optimization
Eric J.

1
是的,但是我可能会补充说,有人如何优化程序会影响其设计。我想了解的一点是,微基准测试很少能为您提供有用的信息。
硅片2010年

这些程序是否应该真正打印“开销”,那么打印的内容不是开销而是每次迭代的整个时间?
Thomas Padron-McCarthy

我将其更改为Time elapsed for <whatever>,我想这是我们正在测量的更准确的术语。但是使用微基准测试,您所测量的可能与实际代码本身无关!
2010年

1
实际上,Knuth指的是在很少真正了解软件执行的情况下完成的性能优化。
威廉·劳斯

8

没有微基准测试的定义,但是当我使用微基准测试时,它的意思是一个小的人造基准测试,旨在测试某些特定硬件1或语言功能的性能。相反,更好的基准是设计用于执行实际任务的真实程序。(在这两种情况之间划清界限是毫无意义的,IMO,我不会尝试。)

微观基准测试的危险在于,编写基准测试很容易得出完全误导的结果。Java微基准测试中的一些常见陷阱是:

  • 编写编译器可以推断出的代码是没有用的工作,因此会完全优化,
  • 没有考虑到Java内存管理的“笨拙”性质,并且
  • 不考虑JVM启动的影响;例如,加载和JIT编译类所花费的时间,以及(相反)一旦方法被JIT编译后,执行速度就会加快。

但是,即使您已经解决了上述问题,仍然存在无法解决基准测试的系统性问题。基准测试的代码和行为通常与您真正关心的内容无关。即您的应用程序将如何执行。您有太多“隐藏变量”,无法从基准测试推广到典型程序,更不用说您的程序了。

由于这些原因,我们定期建议人们不要浪费时间使用微基准测试。相反,最好编写简单自然的代码,并使用分析器来识别需要手动优化的区域。有趣的是,通常会发现,实际应用中最重要的性能问题是由于数据结构和算法(包括网络,数据库和与线程相关的瓶颈)的不良设计所致,而不是典型的微基准所试图解决的问题。测试。

@BalusC在热点常见问题解答页面上提供了指向该主题资料的出色链接。这是Brian Goetz的IBM白皮书的链接。


1-专家甚至不会尝试使用Java进行硬件基准测试。字节码和硬件之间发生太多“复杂的事情”,无法从原始结果中得出关于硬件的有效/有用的结论。您最好使用更接近硬件的语言。例如C甚至汇编代码。


第一段:微基准化不是“更糟”或“更好”。对于不同的事物它只是有用的。如果您想了解特定型号CPU的L1D缓存负载使用延迟,请使用微基准测试,而不是尝试从Crysis,SPECint2006和任何其他非微基准测试的帧率中收集该信息。如果您要调整在一个较小的数据集中进行很多指针跟踪的其他函数,则可以使用该数字来进行有根据的猜测,以了解L1D加载使用延迟是否是主要瓶颈,或者是否有其他事情可以而是进行调整。
彼得·科德斯

但是,使用优化的编译器对高级语言中的单个“语言结构”进行微基准测试通常完全是虚假的。如果您查看asm,则编译器使用for()vs.do{}while()if()vs. x ? y : z(以及哪个更好)构建循环的差异通常特定于周围的代码,而不是语言构造。
彼得·科德斯

(我想几年前发表评论时,我没有注意到这个问题被标记为Java。是的,同意您不能使用Java来学习硬件,而只是学习JVM在硬件上的运行方式。较大功能的一小部分可能导致其进行不同的优化,尤其是使用运行时可用的性能分析信息...因此,是的,100%同意,Java微基准测试可能不是一个好计划,即使使用JMH之类的东西可行。)
彼得·科德斯

4
  • 它是什么意思,不是什么意思?

我要说的是,微基准测试只是意味着测量一些微小的东西。Tiny可能与上下文有关,但通常在单个系统调用或类似级别上。基准测试是指以上所有内容。

  • 什么是IS和IS N'T微基准测试的一些示例?

这篇(归档的)文章列出了测量getpid()系统调用的时间以及使用memcpy()作为微基准测试的示例来测量复制内存的时间的方法

对算法实现等的任何衡量均不算作微基准测试。特别是结果报告列出了减少执行时间的任务,因此很少将其作为微基准测试。

  • 微基准测试有哪些危险,如何避免?

明显的危险是它会诱使开发人员优化程序的错误部分。另一个危险是,精确地测量小物体非常困难。避免这种情况的最简单方法可能只是了解程序中花费最多时间的位置。

人们通常会说“不做微基准测试”,但他们可能的意思是“不要基于微基准测试做出优化决策”。

  • (或者这是好事吗?)

它本身并不像这里的其他人那么坏,而且很多网页似乎都在暗示。它有地方。我从事程序重写和运行时方面编织等工作。我们通常会发布所添加指令的微基准,而不是为了指导任何优化,而是确保我们的额外代码几乎不会影响重写程序的执行。

但是,这是一门艺术,特别是在具有JIT,预热时间等的VM的上下文中。此处(归档)描述了一种针对Java的详细描述的方法。


回复:热身等:看惯用的绩效评估方式吗?对于在现代CPU和OS上无法做到这一点的一些陷阱。
彼得·科德斯

2

“ Java Performance:The Definitive Guide”(Java性能:权威指南)一书中包含以下有关微基准的定义和示例:

  1. 微基准

    微基准测试是一种旨在测量非常小的单元性能的测试:调用同步方法与非同步方法所需的时间;创建线程与使用线程池的开销;执行一种算术算法与另一种实现的时间;等等。

    微基准测试似乎是一个好主意,但很难正确编写。考虑以下代码,这是尝试编写一个微基准测试,该微基准测试测试了计算第50个斐波那契数的方法的不同实现的性能:

public void doTest(){
double l;
long then = System.currentTimeMillis();

for(int i = 0; i < nLoops; i++){
 l = fibImpl1(50);
}

long now = system.currentTimeMillis();
System.out.println("Elapsed time: " + (now - then))

}

...

private double fibImpl1(int n){
if(n < 0) throw new IllegalArgumentException("Must be > 0");
if(n == 0) return 0d;
if(n == 1) return 1d;
double d = fibImpl1(n - 2) + fibImpl(n - 1);
if(Double.isInfinited(d)) throw new ArithmeticException("Overflow");
return d;
}

微基准测试必须使用其结果。

此代码的最大问题是它实际上从未更改任何程序状态。由于从未使用过Fibonacci计算的结果,因此编译器可以自由地放弃该计算,因此智能编译器(包括当前的Java 7和8编译器)将最终执行以下代码:

long then = System.currentTimeMillis();
long now = System.currentTimeMillis();
System.out.println("Elapsed time: " + (now - then));

结果,无论斐波那契方法的实现方式是什么,或者应该执行循环的次数,经过的时间都只有几毫秒。

有一个解决该特定问题的方法:确保读取或不写入每个结果。实际上,将l的定义从局部变量更改为实例变量(使用volatile关键字声明)将允许测量方法的性能。


您几乎总是需要查看优化编译器的汇编语言输出,以确保您的微基准测试确实可以测量您的预期。进行一些您不想要的优化是很容易的。我绝对同意他们很难正确书写。如此多的性能问题都会得到诸如“为什么不自己测量它?”这样的注释,就好像某人测量他们甚至不完全理解的东西一样容易。
彼得·科德斯


-1

微基准测试是基准测试,我认为这不值得。有效基准测试是基准测试,我认为值得。

一般而言,微基准测试(如计算机模拟所言)试图衡量某些非常细粒度的任务的性能,这很难做得好,而且在实际性能令人头痛的情况下通常毫无意义。


因此,您的定义是微基准测试根本没有用,对吗?那是我的印象,但是我只是不想排除任何东西,在某些我需要关心的情况下,它实际上可能是“有用的”。
多基因润滑剂

1
微基准测试已放入性能工程师工具集中。不幸的是,大多数工程师不是性能工程师,这意味着您将得到有缺陷的测试和结果。一个良好的微观基准可以揭示各种操作的单位成本,当完整的基准不能代表您的应用程序软件和系统执行模型时,可以更好地为分析服务。
威廉·劳斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.