Cómo reducir jitter para Java?


Para resolver este problema he creado un código abierto Java Thread Affinity library

Cuando tengo un número de subprocesos que interactúan estrechamente puede reducir la latencia y aumentar el rendimiento. Para tareas de subprocesos individuales, todavía puede reducir un poco la fluctuación.


Este programa analiza la diferencia de tiempo entre llamadas a System.nanoTime() e informa de las que superan los 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);
    }
}

En mi máquina esto informa

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

He intentado chrt establecer prioridad en tiempo real y taskset para tratar de bloquear a un solo núcleo DESPUÉS DE INICIAR el proceso, pero estos no ayudaron como esperaba.

Configuré la caja para mover todas las interrupciones a las cpu 0-3 y la máscara de cpu para todos los procesos con 0xFF a 0x0F. En top las primeras cuatro cpu están ~99% inactivas y las últimas cuatro cpu están 100.0% inactivas.

Usando chrt -r 99 como raíz

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

Sin embargo, al usar taskset -c 7 solo (me he asegurado de que cpu7 esté libre)

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

Usando chrt - r 99 taskset -c 7

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

Parece que tratar de usar el conjunto de tareas después de que el proceso había comenzado no estaba funcionando para mí.

La cuestión más amplia es;

¿Cómo reducir el jitter para un proceso Java? Hay más consejos para reducir la fluctuación en Linux?

NOTA: No se produce GC durante la ejecución de este proceso (verificado con-verbosegc)

Parece que la compilación de código puede causar un retraso de 3.62 ms cada vez después de 100-102 ms. Por esta razón ignoro todo en el primer segundo como calentamiento.

Author: Jon, 2011-11-15

1 answers

Hay jitter del sistema y JVM jitter.

Para el primero, puede usar el parámetro isolcpus en el momento del arranque para asegurarse de que nada más que el código de su aplicación pueda ejecutarse en esas cpu

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

Lo ideal sería hacer una llamada jni (a su propia lib jni) hasta sched_setaffinity solo para el hilo activo para que realmente no tenga nada más que ese hilo corriendo allí.

En mi experiencia, el jitter del sistema se minimiza mediante el uso de isolcpu con interrupciones manejadas solo por núcleos específicos, hyper threading desactivado y absolutamente todo el uso de administración de energía eliminado (estas son opciones de bios cuando están disponibles para desactivar toda la administración de estado c y estado p) mientras ejecuta su aplicación en núcleos blindados. Las opciones específicas de la bios son obviamente específicas para su placa base, por lo que tendrá que mirar en base a su modelo de placa base.

Otra cosa que mirar en el nivel del sistema es el frecuencia de interrupción APIC local (LOC, contador de interrupción local). ¿Es este un "escritorio de baja latencia" que utiliza interrupciones de 1 kHz? de cualquier manera, puede esperar que el jitter se agrupe alrededor del intervalo de interrupción

2 más No sé prácticamente nada, pero soy consciente de que son fuentes de jitter; kernel tlb flush interrupts y userspace tlb flush interrupts. Algunos núcleos RT ofrecen opciones para controlarlos, por lo que esto podría ser otra cosa a tener en cuenta. También puede ver este sitio acerca de creación de aplicaciones RT en el núcleo RT para obtener más consejos.

 16
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-16 11:13:40