【问题标题】:How to benchmark host multi-threaded CPU performance in Java?如何在 Java 中对主机多线程 CPU 性能进行基准测试?
【发布时间】:2019-04-10 14:56:29
【问题描述】:

我需要创建一个简单的 Java 应用程序,它只返回一个数字:估计的 CPU 性能。例如,当我在具有 4 个内核的机器上运行它时,我将获得大约两倍于使用 2 个内核运行的数字。这个应用程序应该使用 100% CPU 几秒钟来测量它。我真的不担心准确性。

我真的很惊讶我找不到任何已经这样做的 Java 库。当然也有其他语言的工具,但在我的环境中只有 Java 被认可。

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

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

【问题讨论】:

  • CPU 性能同时做什么?您实际尝试测量的内容可能很重要。执行此操作的正常方法是测量完成任务的总时间。
  • 如果您使用的是 linux,只需从 /proc/cpuinfo 读取 bogomips
  • @markspace 我不在乎。正如我所说,准确性对我来说根本不重要,只是粗略的数字。理想情况下,我正在寻找具有任何假设的现成解决方案。将有各种任务要执行,因为这些是 Jenkins 代理
  • @rkosegi 我不能为此使用/proc/cpuinfo,该基准测试必须按需运行(VM 性能可能会在不重启的情况下发生变化)
  • 那我就对手头的任务进行基准测试,并记录它的性能。如果该性能随时间发生变化,那么您可以调查该变化。这更好,因为它衡量的是您实际任务的时间,而不是一些任意的基准。

标签: java benchmarking


【解决方案1】:

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

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

例如,内存密集型应用程序在不同机器上的执行方式会有所不同,具体取决于 CPU 芯片的内存缓存大小和设计……以及内存速度。但如果应用程序是计算密集型的,那么性能将更多地取决于时钟频率和核心数量。

当核心数量很高和/或您有多个 CPU 芯片时,会出现 NUMA 单元和线程固定的影响等问题。

这些和类似的问题是试图独立于应用程序来衡量原始 CPU 性能的基准测试在很大程度上失宠的原因。 (MIPS 最初的意思是每秒百万(硬件)指令。现在它通常被称为每秒的神话指令……暗指将测量值作为真实应用程序性能的预测指标的虚假性)

【讨论】:

  • 完全同意。正如我强调的那样,我需要有一个非常粗略的数字。我不在乎细节。我只需要检测到由于某种原因,这个特定虚拟机的性能随着时间的推移而下降(例如,因为物理服务器被过度分配)。而且我只关心数量级的变化,例如这个虚拟机昨天可以在 1 分钟内计算出 100 万位 PI,但今天需要 10 分钟,所以肯定有问题。
  • 好吧……如果你正在寻找一个随机无意义的指标,在​​ N 个并行线程中计算 Pi 的前 D 位 N 次。并使用以下之一测量时钟时间或 CPU 时间:stackoverflow.com/a/7467299/139985
【解决方案2】:

这是最简单的一段代码,可以满足我的要求。它试图通过计算后续整数的平方根和来估计多个线程的 CPU 性能。可以调整变量iterations 以增加/减少基准的长度。在我的机器上使用默认值大约需要 7 秒。

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

class Benchmark {
    public static void main(String[] args) {
        final int iterations = 100_000_000;
        long start = System.currentTimeMillis();
        rangeClosed(1, 50).parallel()
                .forEach(i -> rangeClosed(1, iterations).mapToDouble(Math::sqrt).sum());
        System.out.println(System.currentTimeMillis() - start);
    }
}

【讨论】:

  • 很好地为您自己的问题提供了有用的答案,没有花言巧语
  • 所以您正在测量 FP sqrt 吞吐量。这很奇怪,而且与大多数 FP 工作负载的相关性并不高。例如你会看到 Haswell 与 Broadwell 和 Skylake 在相同的时钟速度下有非常大的加速(如 2 倍),而 mul/add/FMA 吞吐量没有改变。 BDW 引入了更高的基数除法/平方单位。 agner.org/optimize指令表;查看sqrtsd 吞吐量(8 到 14 对 4 到 8),假设它不使用 SIMD 进行矢量化。如果它确实矢量化,Skylake 将为 128 位和 256 位宽的矢量提供另一个很大的加速。
  • @PeterCordes 我不是用它来衡量哪个虚拟机更好或更快。我需要它只是为了进行健全性检查,以确保我的机器的性能与前一段时间大致相同,并且仍然从裸机获得相似数量的 CPU 周期。
  • 好的,是的,它应该每次在相同的硬件上以相同的方式运行。 (或者,如果 JVM 能够计算出如何自动矢量化,或者甚至优化掉一个你没有在任何地方分配的总和,那么速度会更快。)超线程可能不会帮助扩展线程数。运行这个的单个硬件线程(如果它几乎可以有效地进行 JIT)可能会使 sqrt 单元饱和。
  • @PeterCordes 你是对的,在这种情况下,看起来带有硬编码 Java 版本的 Docker 容器将是结果稳定性的解决方案
【解决方案3】:

Java Mcrobenchmark Harness (JMH) 是一个实现 Java 代码基准测试的工具包。

它衡量吞吐量或平均时间;你可以用它来估计 CPU 周期。

基本上,您需要使用@Benchmark 注释您要进行基准测试的方法。这个方法

他们的存储库中很少有JMH usage samples

总是recommended 让计算机在运行基准测试时独处,您应该关闭所有其他应用程序(如果可能)。如果您的计算机正在运行其他应用程序,这些应用程序可能会占用 CPU 时间并提供不正确(较低)的性能数据。

如果您想进一步了解 CPU 性能(周期、缓存使用情况、指令等),您可能需要使用 Linux perf

【讨论】:

  • 我不需要测量代码的性能。我正在寻找一个 Java 库(或想法如何编写这样的库),它将触发一些 CPU 繁重的任务,这些任务在可配置的时间内运行所有可用线程,因此我将得到大致说明当前 CPU 的数字此虚拟机的性能。
  • JMH 的 Blackhole 类具有 consumeCPU 方法,该方法只消耗 CPU 以避免 JIT 优化
  • 好的,但这仍然是单线程的。我正在寻找consumeAllCpus(long tokens) 方法,否则它是完美的。
【解决方案4】:

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));
        }

    }

}

【讨论】:

    猜你喜欢
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-28
    • 2010-10-05
    相关资源
    最近更新 更多