如何减少Java的抖动?

2022-09-01 21:18:19

为了解决这个问题,我创建了一个开源的Java线程关联库

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


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

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   

我试图设置实时优先级,并尝试在启动该过程后锁定到单个内核,但这些都没有像我预期的那样有所帮助。chrttaskset

我配置了该框以将所有中断移动到cpu 0-3,并将cpu掩码用于所有进程,0xFF 0x0F。在前四个 CPU 中,大约 99% 处于空闲状态,最后四个 CPU 处于 100.0% 空闲状态。top

用作根目录chrt -r 99

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

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

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 毫秒后出现 3.62 毫秒的延迟。出于这个原因,我忽略了第一秒作为热身的所有内容。


答案 1

有系统抖动和JVM抖动。

对于前者,您可以在引导时使用 isolcpus 参数,以确保除了应用程序代码之外,其他任何代码都可以在这些 cpu 上运行

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

理想情况下,你会做一个jni调用(对你自己的jni lib),只对活动线程,这样你实际上除了在那里运行的线程之外什么都没有。sched_setaffinity

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

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

2 另外,我几乎一无所知,但我知道这是紧张的来源;内核 tlb 刷新中断和用户空间 tlb 刷新中断。一些RT内核提供了控制这些的选项,所以这可能是另一件需要研究的事情。您还可以查看有关在RT内核上构建RT应用程序的网站以获取更多提示。


答案 2

推荐