java - 什么是微基准测试?

标签 java performance benchmarking jit microbenchmark

我听说过这个词,但我不完全确定它是什么意思,所以:

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

最佳答案

这正是它在锡 jar 上所说的 - 它正在测量“小”事物的性能,例如对操作系统内核的系统调用。

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

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil" -- 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 个应用程序,并在您启动计算机时将应用程序代码预加载到内存中!

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

因此,在很多情况下,微基准测试并不是一个有用的指标。它绝对不会用定义明确的测试用例(分析)代替整个程序的基准测试。首先编写可读代码,然后配置文件以查看需要做什么(如果有)。

我想强调的是,微基准测试本身本身并不邪恶,但人们必须小心使用它们(对于与计算机相关的许多其他事情都是如此)

关于java - 什么是微基准测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2842695/

相关文章:

python-2.7 - pytest-timeit或pytest-benchmark在精度s上哪个更好?

java - 如何在Tomcat V6.0.45中运行Spring 3.2项目

c - 性能 AVX-512 与 MIC 上的自动矢量化(英特尔至强融核协处理器)

mysql - 以不同方式对三列进行索引

python - 为什么 Python 中的局部变量访问比类成员访问更快?

java - 基准 C++ 与 Java,不切实际的结果

java - Android ComputableFuture 无法与 Firestore 配合使用

java - 执行Linux命令的方法失败

java - Java 源文件是否可以在编译时运行任意代码?

linux - QPainter::drawText 在 Linux 上的糟糕表现