Мой вопрос касается производительности Java по сравнению со скомпилированным кодом, например, C++/fortran/assembly в высокопроизводительных числовых приложениях. Я знаю, что это спорная тема, но я ищу конкретные ответы/примеры. Также сообщество вики. Я задавал подобные вопросы и раньше, но, думаю, я выразился в общих чертах и не получил ответов, которые искал.
Умножение матрицы на матрицу двойной точности, обычно известное как dgemm в библиотеке blas, позволяет достичь почти 100-процентной пиковой производительности ЦП (с точки зрения операций с плавающей запятой в секунду).
Есть несколько факторов, которые позволяют достичь этой производительности:
-
блокировка кеша для достижения максимальной локализации памяти
-
развертывание цикла для минимизации накладных расходов на управление
-
векторные инструкции, такие как SSE
-
предварительная загрузка из памяти
-
не гарантирует алиасинг памяти
Я видел множество тестов, использующих ассемблер, C++, Fortran, Atlas, поставщик BLAS (типичные случаи - матрица измерения 512 и выше). С другой стороны, я слышал, что основные байтовые скомпилированные языки/реализации, такие как Java, могут быть быстрыми или почти такими же быстрыми, как машинно-компилируемые языки. Однако я не видел определенных ориентиров, показывающих, что это так. Напротив, кажется (из моего собственного исследования) скомпилированные байты языки намного медленнее.
У вас есть хорошие тесты умножения матриц-матриц для Java/С#? может ли компилятор точно в срок (фактическая реализация, а не гипотетическая) создавать инструкции, которые удовлетворяют перечисленным пунктам?
Спасибо
Что касается производительности: каждый процессор имеет пиковую производительность, в зависимости от количества команд, которые процессор может выполнять в секунду. Например, современный процессор Intel с частотой 2 ГГц может достигать 8 миллиардов с двойной точностью добавления/умножения в секунду, что приводит к пиковой производительности 8 Гфлопс. Матрица-матричное умножение является одним из алгоритмов, который способен достичь почти полной производительности в отношении числа операций в секунду, основной причиной является более высокое соотношение вычислений к операциям с памятью (N^3/N^2)
. Числа меня интересуют, что-то порядка N > 500
.
Что касается реализации: детали более высокого уровня, такие как блокировка, выполняются на уровне исходного кода. Оптимизация нижнего уровня выполняется компилятором, возможно, с подсказками компилятора относительно выравнивания/псевдонима. Байт-скомпилированная реализация также может быть написана с использованием блочного подхода, поэтому в принципе детали исходного кода для достойной реализации будут очень похожи.