Я читал вопрос о оптимизации кода С#, и одним из решений было использование С++ с SSE. Можно ли выполнить SSE непосредственно из программы С#?
Использование SSE в С# возможно?
Ответ 1
Предстоящая Mono версия 2.2 будет иметь поддержку SIMD. Miguel de Icaza рассказал о предстоящей функции здесь, а API здесь.
Хотя будет библиотека, которая будет поддерживать разработку в среде исполнения Microsoft.NET Windows, она не будет иметь преимуществ производительности, которые вы ищете, если вы не запустите код в режиме исполнения Mono. Что может быть выполнимо в зависимости от ваших обстоятельств.
Обновление: Mono 2.2 выпущено
Ответ 2
Может ли С# явно вызвать вызов SSE?
Нет. С# не может создать встроенный IL гораздо меньше встроенной сборки x86/amd64.
CLR и, более конкретно, JIT, будут использовать SSE, если это будет доступно, устраняя необходимость принудительного его использования в большинстве случаев. Я говорю больше всего, потому что я не эксперт SSE, и я уверен, что есть случаи, когда это может быть полезно, и JIT не делает оптимизацию.
Ответ 3
SIMD для .NET будет доступен в ближайшем будущем. RyuJIT (компилятор JIT следующего поколения для .NET), необходимый для этой функции ATM.
Вы можете использовать класс Microsoft.Numerics.Vectors.Vector<T>
из пакет Microsoft.Bcl.Simd, чтобы воспользоваться этой возможностью. Пример кода здесь.
Ответ 4
Основываясь на этот форум, компилятор MS JIT автоматически использует SSE, если SSE доступно на целевой машине.
Ответ 5
Если у вас есть "кусок" работы, которую вы хотите сделать, лучше всего написать ее на С++ с использованием встроенных MMX/SSE-функций, а затем создать очень простой/управляемый CLM-класс, который обертывает вашу функциональность и предоставляет ее как класс .net. Тогда ваш код может просто использовать эту сборку, как если бы это был обычный класс.
Для получения дополнительной информации о VC intrinsics вы можете посмотреть на эту маленькую мелодию, которую я написал много лет назад.
http://msdn.microsoft.com/en-us/library/0aws1s9k.aspx
О, я предполагаю, что вы на самом деле хотите использовать параллельные функции, чтобы что-то ускорить. Как указывали другие, если вы просто хотите переместить данные в более крупные куски и т.п., JIT уже знает, как использовать SSE для этих основ.
Ответ 6
Филипп прав. У меня есть еще одна, более старая статья с похожим, но более подробным примером. Я действительно запускаю этот код и сам модифицировал его, чтобы доказать, что он работает. Я рассматриваю использование этой техники в проекте, в котором я работаю, и поэтому я ищу, чтобы увидеть, что может быть новым, так как это немного устарело. Как предполагает автор, вы можете написать любую функцию, которую вы хотите на С++, скомпилировать ее, а затем скопировать байты в ваш С#.
http://blogs.msdn.com/b/devinj/archive/2005/07/12/438323.aspx
Я бы добавил, что класс Joe CLI С++ тоже хорошая идея, однако я не думаю, что флаг sse-компилятора и флаг /clr совместимы в одном проекте. Я просто подтвердил, что: нужно написать свой высокопроизводительный код в отдельном проекте, чтобы использовать флаг компилятора SSE (/arch: sse или /arch: sse2), поскольку /clr несовместим. Чтобы сделать что-либо гораздо более сложное, чем простая арифметика на нескольких входах, я считаю, что это лучший подход.
Ответ 7
Недавно Microsoft выпустила бета-библиотеку SIMD (Microsoft.Bcl.Simd) для С#, которая требует установки RyuJIT CTP и работает только с Windows 8.
Вы также можете использовать собственную SSE-библиотеку и вызывать ее из С#. Например, библиотека Yeppp, см. fooobar.com/questions/157316/....
Ответ 8
Наконец, возможно. Здесь сообщение http://blogs.msdn.com/b/dotnet/archive/2014/04/07/the-jit-finally-proposed-jit-and-simd-are-getting-married.aspx
Ответ 9
Современный С# хорошо поддерживает инструкции 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, который я поддерживаю.
Ответ 10
Конечно, вы можете (более важный вопрос - почему бы вам просто оставить его во время выполнения, что его работа).
С# позволяет сопоставить делегат с адресом памяти. Этот адрес памяти может содержать необработанные коды сборки. Вы можете больше узнать о блог Майкла Джагнаково.
Хотя я и не пробовал себя, возможно использовать Marshal.GetDelegateForFunctionPointer.