Использование SSE в C# это возможно?

Я читал вопрос об оптимизации кода на C#, и одним из решений было использование C++ с SSE. Можно ли сделать SSE прямо из программы aC#?

9 ответов

Решение

Предстоящий релиз Mono 2.2 будет иметь поддержку SIMD. Мигель де Иказа писал о предстоящей функции здесь, а API здесь.

Хотя будет библиотека, которая будет поддерживать разработку во время выполнения Microsoft.NET Windows, она не будет иметь тех преимуществ в производительности, которые вы ищете, если вы не запустите код в среде выполнения Mono. Что может быть выполнимо в зависимости от ваших обстоятельств.

Обновление: выпущен Mono 2.2

Может ли C# явно сделать вызов SSE?

Нет. C# не может создать встроенный IL, гораздо меньше встроенной сборки x86/amd64.

CLR, а точнее JIT, будет использовать SSE, если он доступен, что устраняет необходимость его форсировать в большинстве случаев. Я говорю больше всего, потому что я не эксперт SSE, и я уверен, что есть случаи, когда это может быть полезным, и JIT не проводит оптимизацию.

SIMD для.NET будет доступен в ближайшее время. RyuJIT (JIT-компилятор следующего поколения для.NET), необходимый для этой функции ATM.

Вы должны использовать Microsoft.Numerics.Vectors.Vector<T> класс из пакета Microsoft.Bcl.Simd, чтобы воспользоваться этой функцией. Пример кода здесь.

Основываясь на этой публикации на форуме, компилятор MS JIT автоматически использует SSE, если SSE доступен на целевой машине.

Если у вас есть "кусок" работы, которую вы хотите выполнить, лучше всего написать ее на C++ с использованием встроенных функций MMX/SSE, а затем создать очень простой / управляемый clr класс C++, который обернет вашу функциональность и представит ее как.net класс. Тогда ваш код может просто использовать эту сборку, как если бы это был обычный класс.

Чтобы узнать больше об особенностях VC, вы можете взглянуть на эту маленькую ямочку, которую я написал много лет назад.

http://msdn.microsoft.com/en-us/library/0aws1s9k.aspx

О - я предполагаю, что вы действительно хотите использовать параллельные функции для ускорения чего-либо. Как уже отмечали другие - если вы просто хотите перемещать данные большими кусками и т.п., JIT уже знает, как использовать SSE для этих основ.

Филипп прав. У меня есть другой, более старый пост, показывающий похожий, но более подробный пример. Я фактически запустил этот код и сам изменил его, чтобы доказать себе, что он работает. Я обдумываю использование этой техники в проекте, над которым я работаю, и поэтому я ищу то, что может быть новым, поскольку оно немного старое. Как предполагает автор, вы можете написать любую функцию на C++, скомпилировать ее и скопировать байты в ваш C#.

http://blogs.msdn.com/b/devinj/archive/2005/07/12/438323.aspx

Я бы добавил, что класс CLI C++ от Joe также является хорошей идеей, однако я не думаю, что флаг компилятора sse и флаг / clr совместимы в одном проекте. Я только что проверил, что: нужно написать свой высокопроизводительный код в отдельном проекте, чтобы использовать флаг компилятора SSE (/arch:sse или /arch:sse2), поскольку / clr несовместим. Я думаю, что это лучший подход для выполнения чего-либо гораздо более сложного, чем простая арифметика с несколькими входами.

Недавно Microsoft выпустила бета-версию векторной библиотеки SIMD ( Microsoft.Bcl.Simd) для C#, которая требует установки RyuJIT CTP и работает только в Windows 8.

Вы также можете просто использовать собственную библиотеку SSE и вызывать ее из C#. Например, библиотека Yeppp, смотрите этот ответ Stackru.

Современный C# хорошо поддерживает инструкции SIMD/SSE и делает их довольно простыми в использовании. Не все инструкции пока поддерживаются.

Вот пример SSE .Sum() массива uint[]:

    using System.Numerics;

    private static ulong SumSseInner(this uint[] arrayToSum, int l, int r)
    {
        var sumVectorLower = new Vector<ulong>();
        var sumVectorUpper = new Vector<ulong>();
        var longLower      = new Vector<ulong>();
        var longUpper      = new Vector<ulong>();
        int sseIndexEnd = l + ((r - l + 1) / Vector<uint>.Count) * Vector<uint>.Count;
        int i;
        for (i = l; i < sseIndexEnd; i += Vector<int>.Count)
        {
            var inVector = new Vector<uint>(arrayToSum, i);
            Vector.Widen(inVector, out longLower, out longUpper);
            sumVectorLower += longLower;
            sumVectorUpper += longUpper;
        }
        ulong overallSum = 0;
        for (; i <= r; i++)
            overallSum += arrayToSum[i];
        sumVectorLower += sumVectorUpper;
        for (i = 0; i < Vector<long>.Count; i++)
            overallSum += sumVectorLower[i];
        return overallSum;
    }

Эта конкретная функция является частью бесплатного пакета nuget с открытым исходным кодом, HPCsharp, доступного на сайте nuget.org, который я поддерживаю.

Конечно, вы можете (более важный вопрос - почему бы вам? Просто оставьте это во время выполнения; это его работа).

C# позволяет сопоставить делегата с адресом памяти. Этот адрес памяти может содержать необработанные коды сборки. Вы можете прочитать больше на блоге Майкла Джанокаво.

Хотя я сам не пробовал, возможно, можно использовать Marshal.GetDelegateForFunctionPointer.

Другие вопросы по тегам