Подтвердить что ты не робот

Как уменьшить дрожание для Java?

Чтобы решить эту проблему, я создал открытый Java Affinity library

Когда у меня есть несколько потоков, тесно взаимодействующих, это может уменьшить задержку и увеличить пропускную способность. Для однопоточных задач он все равно может немного уменьшить дрожание.


Эта программа рассматривает разницу во времени между вызовами System.nanoTime() и сообщает о них более 10x, 000 нс.

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, чтобы попытаться заблокировать одно ядро ​​ПОСЛЕ ЗАПУСКА процесса, но это не помогло, как я ожидал.

Я сконфигурировал поле для перемещения всех прерываний на cpus 0-3 и маску cpu для всего процесса с 0xFF до 0x0F. В top первые четыре процессора равны ~ 99% бездействия, а последние четыре процессора равны 100,0%.

Используя chrt -r 99 как root

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)

Похоже, что компиляция кода может вызвать задержку 3,62 мс каждый раз после 100 - 102 мс. По этой причине я игнорирую все в первую секунду как разминку.

4b9b3361

Ответ 1

Есть джиттер системы и джиттер JVM.

Для первого вы можете использовать параметр isolcpus во время загрузки, чтобы гарантировать, что на этих процессорах может работать только код вашего приложения

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

В идеале вы должны сделать jni-вызов (до вашего собственного jni-lib) до sched_setaffinity только для активного потока, чтобы у вас действительно ничего не было, кроме потока.

По моему опыту, джиттер системы сведен к минимуму с помощью isolcpus с прерываниями, обрабатываемыми только конкретными ядрами, отключением гиперпотока и отключением полностью использования управления питанием (это опции BIOS, когда они доступны для отключения всех c-state и p-state management) при запуске приложения на экранированных ядрах. Специфические для BIOS параметры, очевидно, специфичны для вашей материнской платы, поэтому вам нужно будет изучить это на основе вашей модели материнской платы.

Еще одна вещь на системном уровне - это локальная частота прерывания APIC (LOC, локальный прерыватель). Является ли это "рабочим столом с низкой задержкой" с использованием прерываний 1 кГц? в любом случае, вы можете ожидать, что дрожание будет группироваться вокруг интервала прерывания

2 Еще я ничего не знаю, но знаю, как источники дрожания; ядро tlb для прерывания и прерывания потока tlb в пользовательском пространстве. Некоторые ядра RT предлагают варианты управления ими, поэтому это может быть еще одна вещь для изучения. Вы также можете посмотреть этот сайт о создании приложений RT в ядре RT для получения дополнительных советов.