【问题标题】:How to reduce jitter for Java?如何减少 Java 的抖动?
【发布时间】:2011-12-29 17:41:24
【问题描述】:

为了解决这个问题,我创建了一个开源Java Thread Affinity library

当我有多个线程密切交互时,它可以减少延迟并提高吞吐量。对于单线程任务,它仍然可以减少相当多的抖动。


此程序查看调用 System.nanoTime() 之间的时间差异并报告超过 10x,000 ns 的时间差异。

public class TimeJumpingMain {
    static final long IGNORE_TIME = 1000 * 1000 * 1000; // the first second to allow warmup.
    static final int minJump = 10; // smallest jump of 10 us.
    static final int midJump = 100; // mid size jump of 100 us.
    static final int bigJump = 1000; // big jump of 1 ms.

    public static void main(String... args) {
        int[] intervalTimings = new int[1000];
        int[] jumpTimings = new int[1000];

        long start = System.nanoTime();
        long prev = start;
        long prevJump = start;
        int jumpCount = 0;
        int midJumpCount = 0;
        int bigJumpCount = 0;

        while (true) {
            long now = System.nanoTime();
            long jump = (now - prev) / 1000;
            if (jump > minJump && now - start > IGNORE_TIME) {
                long interval = (now - prevJump) / 1000;
                if (jumpCount < intervalTimings.length) {
                    intervalTimings[jumpCount] = (int) interval;
                    jumpTimings[jumpCount] = (int) jump;
                }
                if (jump >= midJump)
                    midJumpCount++;
                if (jump >= bigJump)
                    bigJumpCount++;
                prevJump = now;
                jumpCount++;
            }
            prev = now;
            if (now - start > 120L * 1000 * 1000 * 1000 + IGNORE_TIME)
                break;
        }
        System.out.println("interval us\tdelay us");
        for (int i = 0; i < jumpCount && i < intervalTimings.length; i++) {
            System.out.println(intervalTimings[i] + "\t" + jumpTimings[i]);
        }
        System.out.printf("Time jumped %,d / %,d / %,d times by at least %,d / %,d / %,d us in %.1f seconds %n",
                jumpCount, midJumpCount, bigJumpCount, minJump, midJump, bigJump, (System.nanoTime() - start - IGNORE_TIME) / 1e9);
    }
}

在我的机器上报告

Time jumped 2,905 / 131 / 20 times by at least 10 / 100 / 1,000 us in 120.0 seconds   

我尝试chrt 设置实时优先级,taskset 尝试在启动进程后锁定到单个核心,但这些都没有像我预期的那样有帮助。

我将框配置为将所有中断移动到 cpu 0-3,并将所有进程的 cpu 掩码从 0xFF 移动到 0x0F。在top 中,前四个 cpu 大约 99% 空闲,最后四个 cpu 空闲 100.0%。

使用chrt -r 99 作为根

Time jumped 673 / 378 / 44 times by at least 10 / 100 / 1,000 us in 120.0 seconds 

但是,当单独使用taskset -c 7 时(我已经确定 cpu7 是免费的)

Time jumped 24 / 1 / 0 times by at least 10 / 100 / 1,000 us in 120.0 seconds 

使用chrt - r 99 taskset -c 7

Time jumped 7 / 1 / 0 times by at least 10 / 100 / 1,000 us in 120.0 seconds  

似乎在进程开始后尝试使用任务集对我不起作用。

更广泛的问题是;

如何减少 Java 进程的抖动?还有其他减少 Linux 抖动的技巧吗?

注意:此进程运行期间不会发生 GC(使用 -verbosegc 检查)

似乎代码编译在 100 - 102 ms 之后每次可能会导致 3.62 ms 的延迟。出于这个原因,我忽略了第一秒的所有内容作为热身。

【问题讨论】:

  • 尽量不要在热循环中打印,只需将结果添加到arraylist中以减少系统调用。你也检查了编译器的启动吗?
  • 似乎在进程开始后尝试使用任务集对我不起作用。我从来没有设法让它工作(之后),所以如果我需要 CPU我依赖于预先选择它。

标签: java linux real-time


【解决方案1】:

有系统抖动和 JVM 抖动。

对于前者,您可以在启动时使用 isolcpus 参数来确保只有您的应用程序代码可以在这些 cpus 上运行

http://www.novell.com/support/viewContent.do?externalId=7009596&sliceId=1

理想情况下,您应该只为活动线程执行一个 jni 调用(对您自己的 jni 库)到 sched_setaffinity,这样您就真的只有在那里运行的那个线程。

根据我的经验,系统抖动可以通过使用 isolcpus 最小化,中断仅由特定内核处理,关闭超线程,并且绝对移除所有使用的电源管理(这些是 bios 选项,当它们可用于关闭所有c-state 和 p-state 管理),同时在屏蔽核心上运行您的应用程序。 BIOS 特定选项显然特定于您的主板,因此您需要根据您的主板型号进行调查。

另一个看系统级的是本地 APIC 中断(LOC,本地中断计数器)频率。这是使用 1kHz 中断的“低延迟桌面”吗?无论哪种方式,您都可以预期抖动会在中断间隔周围聚集

还有 2 个我几乎一无所知,但我知道这是抖动的来源;内核 tlb 刷新中断和用户空间 tlb 刷新中断。一些 RT 内核提供了控制这些选项的选项,因此这可能是另一回事。您还可以查看this site关于在 RT 内核上构建 RT 应用程序的更多提示。

【讨论】:

  • LOC 为 100 Hz。如果有办法关闭这些,我会非常感兴趣,但是它们似乎不会造成太多开销。你在 CentOS 上试过吗? editthis.info/wiki/User:Ascensus (你是这里的 matt 吗?)对于在 centos 中使用 isolcpus 有什么建议吗?
  • @PeterLawrey(和马特),除了“操作系统”强加的尖峰之外,java 和 RT 是一个困难的问题,因为编译器和 GC 都需要以更高的优先级运行,但这通常不可用对于 Linux。尽管 IBM 努力运行微秒级 GC 周期,但预热所有代码路径以使编译器不会(反)优化任何内容可能会很困难。
  • 不同的亚光。我没有在 centos 上尝试过这个,假设你有一个 SMP 内核并且你确保 isolcpus 在启动时被设置为内核参数,那么它应该可以工作。当然是YMMV! 100Hz 的 LOC 开销应该很小,但您可能每 10ms 就会出现一次抖动,因此您无法将其关闭(afaik)
  • 我有脚本,它设置所有进程并设置中断的 smp_affinity。 IT 似乎给了我与 isolcpus 相同的功能,无需重新启动。一旦我对它感到满意,这个选项听起来是能够在重新启动时设置它的最佳方式。
猜你喜欢
  • 2020-04-21
  • 1970-01-01
  • 1970-01-01
  • 2015-06-13
  • 1970-01-01
  • 1970-01-01
  • 2010-11-21
  • 2020-05-04
  • 1970-01-01
相关资源
最近更新 更多