如何减少Java的抖动?

如何减少Java的抖动?,java,linux,real-time,Java,Linux,Real Time,为了解决这个问题,我创建了一个开源软件 当我有多个线程紧密交互时,它可以减少延迟并提高吞吐量。对于单线程任务,它仍然可以大大减少抖动 这个程序查看调用System.nanoTime()之间的时间差,并报告超过10x,000 ns的调用 public class TimeJumpingMain { static final long IGNORE_TIME = 1000 * 1000 * 1000; // the first second to allow warmup. sta

为了解决这个问题,我创建了一个开源软件

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


这个程序查看调用
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);
    }
}
我已尝试
chrt
设置实时优先级,并尝试在启动进程后锁定到单个核心,但这些都没有如我所预期的那样有效

我将该框配置为将所有中断移到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-c7
时(我已经确保cpu7是免费的)

使用
chrt-r99任务集-c7

Time jumped 7 / 1 / 0 times by at least 10 / 100 / 1,000 us in 120.0 seconds  
似乎在进程启动后尝试使用taskset对我不起作用

更广泛的问题是

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

注意:在该进程的运行过程中不会发生GC(使用-verbosegc进行检查)


似乎在100-102毫秒之后,代码编译每次都会导致3.62毫秒的延迟。因此,我在预热的第一秒钟忽略了所有内容。

存在系统抖动和JVM抖动

对于前者,您可以在引导时使用isolcpus参数,以确保只有应用程序代码才能在这些cpu上运行

理想情况下,您只需要为活动线程执行一个jni调用(对您自己的jni库)到
sched_setaffinity
,这样您就可以在那里运行线程了

根据我的经验,在屏蔽内核上运行应用程序时,通过使用ISOLCPU(中断仅由特定内核处理)、关闭超线程以及完全取消所有电源管理(当这些选项可用于关闭所有c-state和p-state管理时,这些是bios选项),系统抖动被最小化。bios特定的选项显然是特定于您的主板的,因此您需要根据您的主板型号进行研究

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


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

尽量不要在热循环中打印,只需将结果添加到arraylist中以减少系统调用。您是否也检查了编译器的启动?似乎在进程启动后尝试使用taskset对我不起作用。我从来没有设法使它工作(之后),所以如果我需要CPU亲和力,我依靠预选它。LOC是100赫兹。我会非常感兴趣,如果有一种方法来关闭这些,但他们似乎不会造成太多的开销。你试过CentOS吗?(你是这里的马特吗?)有没有关于在centos上使用ISOLCPU的建议?@PeterLawrey(和马特),除了“操作系统”强加的尖峰之外,java和RT是一个困难的问题,因为编译器和GC都需要以更高的优先级运行,但Linux通常不提供这一点。虽然IBM在运行微秒GC周期方面做出了一些努力,但预热所有代码路径以使编译器不会(去)优化任何内容可能会很困难。matt的不同之处。我没有在centos上尝试过这一点,假设您有一个SMP内核,并且您确保在引导时将ISOLCPU设置为内核参数,那么它应该可以正常工作。当然!100Hz时的LOC开销应该很小,但很可能每10毫秒就会出现一次抖动。因此,您无法将其关闭(afaik)。我有一个脚本,用于设置所有进程并设置中断的smp_亲和力。在没有重新启动的情况下,它似乎为我提供了与ISOLCPU相同的功能。一旦我对它感到满意,这个选项听起来是在重启时设置它的最佳方式。
Time jumped 24 / 1 / 0 times by at least 10 / 100 / 1,000 us in 120.0 seconds 
Time jumped 7 / 1 / 0 times by at least 10 / 100 / 1,000 us in 120.0 seconds