Для решения этой проблемы я создал открытый исходный код Java Thread 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
, чтобы попытаться подключиться к одному ядру после запуска процесса, но это не помогло, как я ожидал.
Я настроил коробку для перемещения всех прерываний на процессор 0-3 и маску процессора для всего процесса с 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 мс. По этой причине я игнорирую все в первую секунду как разогрев.