C/С++ по сравнению с Java/С# в высокопроизводительных приложениях

Мой вопрос касается производительности 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.

Что касается реализации: детали более высокого уровня, такие как блокировка, выполняются на уровне исходного кода. Оптимизация нижнего уровня выполняется компилятором, возможно, с подсказками компилятора относительно выравнивания/псевдонима. Байт-скомпилированная реализация также может быть написана с использованием блочного подхода, поэтому в принципе детали исходного кода для достойной реализации будут очень похожи.

Ответы

Ответ 1

Сравнение VC++/.NET 3.5/Mono 2.2 в сценарии умножения чистой матрицы:

Источник

Mono с Mono.Simd имеет большое значение для сокращения разрыва в производительности с оптимизированной вручную C++, но версия C++ по-прежнему явно самая быстрая. Но Mono сейчас на уровне 2.6 и может быть ближе, и я ожидаю, что если .NET когда-нибудь получит что-то вроде Mono.Simd, он может быть очень конкурентоспособным, так как здесь нет большой разницы между .NET и последовательным C++.

Ответ 2

Все факторы, которые вы указываете, возможно, выполняются с помощью ручной оптимизации памяти/кода для вашей конкретной задачи. Но JIT-компилятор не располагает достаточной информацией о вашем домене, чтобы сделать код оптимальным, поскольку вы делаете его вручную, и можете применять только общие правила оптимизации. В результате он будет медленнее, чем код манипуляции с матрицей C/С++ (но может использовать 100% CPU, если вы этого хотите:)

Ответ 4

Java не может конкурировать с C в умножении матриц, одной из причин является то, что при каждом доступе к массиву проверяется, превышены ли границы массива. Дальнейшая математика Java медленная, она не использует процессор sin(), cos().

Ответ 5

в чисто математическом сценарии (вычисление 25 типов или трехмерных координат алгебраических поверхностей) c++ превосходит Java в соотношении 2,5