如何用Java基准测试主机多线程CPU性能?

时间:2019-04-10 14:56:30

标签: java benchmarking

我需要创建一个仅返回一个数字的简单Java应用程序:估计的CPU性能。例如,当我在4核的机器上运行它时,我得到的数字大约是2核的机器的两倍。此应用应使用100%CPU持续几秒钟以进行测量。我真的不担心准确性。

我真的很惊讶,因为我找不到任何已经做到这一点的Java库。当然,还有其他语言的工具,但是在我的环境中,只有Java被批准。

我目前的想法是在代码中使用SciMark 2.0中的类并从多个线程运行它,但是此工具看起来很混乱(例如,类名以小写字母开头),我需要编写自定义代码才能运行这些线程并结合结果。

我能更好地解决这个问题吗?

4 个答案:

答案 0 :(得分:1)

如果我对您的理解正确,那么您的目标是衡量系统性能而不是应用程序性能。

这是问题所在。系统性能不能降低到一个有意义的数字。实际上,系统性能甚至CPU性能都是多维的。

例如,一个占用大量内存的应用程序将在不同的机器上执行不同的操作,具体取决于CPU芯片的内存高速缓存大小和设计...以及内存速度。但是,如果应用程序是计算密集型的,那么性能将更多地取决于时钟速率和内核数。

然后,当核心数量很高和/或您有多个CPU芯片时,就会出现诸如NUMA单元和线程固定之类的问题。

这些和类似的问题是为什么试图测量独立于应用程序的原始CPU性能的基准测试在很大程度上已不受欢迎。 (MIPS原本是指每秒百万条(硬件)指令。现在通常被称为每秒神话指令……暗示该措施的虚伪性可预测实际应用程序性能)

答案 1 :(得分:0)

Java Mcrobenchmark Harness (JMH)是用于实现Java代码基准的工具包。

它测量吞吐量或平均时间;您可以使用它来估算CPU周期。

基本上,您需要使用@Benchmark进行基准测试。

存储库中JMH usage samples很少。

在运行基准测试时,总是recommended让计算机单独运行,并且您应关闭所有其他应用程序(如果可能)。如果您的计算机运行的是其他应用程序,则这些应用程序可能会花费CPU时间,并且会给出错误的(较低的)性能数字。

如果您想进一步挖掘CPU性能(周期,缓存使用情况,说明等),则可能需要使用Linux perf

答案 2 :(得分:0)

这是执行我想要的最简单的代码。它尝试通过计算后续整数的平方根之和来估计多个线程的CPU性能。可以调整变量print(a) : tensor([[-1.7739, 0.8073, 0.0472, -0.4084], [ 0.6378, 0.6575, -1.2970, -0.0625], [ 1.7970, -1.3463, 0.9011, -0.8704], [ 1.5639, 0.7123, 0.0385, 1.8410]]) print(torch.argmax(a, dim=1)) tensor([1, 1, 0, 3]) 以增加/减少基准长度。在我的计算机上,使用默认值大约需要7秒钟。

iterations

答案 3 :(得分:0)

Michal,感谢您的回答,我借用并添加了一些线程来帮助我诊断客户端的AIX计算机上的虚拟CPU性能问题。

import static java.util.stream.IntStream.rangeClosed;

public class Main {

    public static void main(String[] args) {
        if (args.length < 2) {
            System.out.println("Usage: benchmark [million iterations] [maxThreads]");
            return;
        }

        final int MILLION = 1_000_000;
        final int iterations = Integer.parseInt(args[0]);
        final int maxThreads = Integer.parseInt(args[1]);

        for (int threads = 1; threads < maxThreads; threads++) {
            long start = System.currentTimeMillis();
            int count = iterations * MILLION / threads;
            rangeClosed(1, threads).parallel()
                .forEach(i -> rangeClosed(1, count).mapToDouble(Math::sqrt).sum());

            System.out.println(String.format("Benchmark of %d M iterations on %d thread(s): %d ms", iterations, threads, System.currentTimeMillis() - start));
        }

    }

}