Обманите JVM о количестве доступных ядер (на linux)

В какой-то мере необходимо сделать JVM думать, что он работает на машине с N ядрами на борту вместо реального количества ядер (например, 4 ядра вместо 16).

JVM работает под некоторой сборкой Linux, основанной на ядре Mandriva/Red Hat Linux.

Этот вопрос является пограничным, потому что я ожидаю различные решения этой проблемы. Это не чистый вопрос администрирования Linux, и он не является чистым вопросом программиста.

Итак... любые идеи?

Ответ 1

Следующая программа Java печатает количество процессоров, видимое виртуальной машиной Java:

public class AvailableProcessors {
    public static void main(String... args) {
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

Если я запускаю эту программу на своем домашнем компьютере, она печатает 4, что является фактическим количеством ядер (включая гиперпоточность). Теперь попробуем Java VM убедиться, что есть только два процессора:

$ echo '0-1' > /tmp/online
$ mount --bind /tmp/online /sys/devices/system/cpu/online

Если я снова запустил вышеуказанную программу, она печатает 2 вместо 4.

Этот трюк влияет на все процессы в вашей системе. Однако можно ограничить эффект только определенными процессами. Каждый процесс в Linux может иметь собственное пространство имен точек монтирования. См., Например, раздел Предпроцессные пространства имен на странице руководства mount (2). Вы можете, например, использовать lxc для запуска новых процессов со своим собственным пространством имен.

Ответ 2

Чтобы вернуть Runtime.getRuntime().availableProcessors() все, что вам нужно, вы можете переопределить функцию JVM_ActiveProcessorCount, используя трюк LD_PRELOAD. Вот крошечная программа для этого:

#include <stdlib.h>
#include <unistd.h>

int JVM_ActiveProcessorCount(void) {
    char* val = getenv("_NUM_CPUS");
    return val != NULL ? atoi(val) : sysconf(_SC_NPROCESSORS_ONLN);
}

Сначала создайте совместно используемую библиотеку:

gcc -O3 -fPIC -shared -Wl,-soname,libnumcpus.so -o libnumcpus.so numcpus.c

Затем запустите Java следующим образом:

$ LD_PRELOAD=/path/to/libnumcpus.so _NUM_CPUS=2 java AvailableProcessors