Replace characters in a string using Vectorization - использование SIMD инструкций для векторизации замены символов в строке. Привлекла статья тем, что код хорошо комментирован - и понятно, где какие маски накладываются и какое действие производица над пачкой байт. В шапке статьи также ссылки на соседние интересные статьи по этой же тематике.
Аналогичным образом через векторные инструкции можно сделать ToLowerCase строке (код написан кстати с помощью #chatgpt :) - в этом коде особенно интересно то, что вместе с действием по модификации ushort элементов в векторе также применяются другие инструкции на весь вектор - And/Or.
#dotnet #simd #sse
Аналогичным образом через векторные инструкции можно сделать ToLowerCase строке (код написан кстати с помощью #chatgpt :) - в этом коде особенно интересно то, что вместе с действием по модификации ushort элементов в векторе также применяются другие инструкции на весь вектор - And/Or.
#dotnet #simd #sse
Человек форкнул dotnet runtime, чтобы вырезать инструкции CMOV и SSE - чтобы запустить .net программу под DOS на 486м компе #dotnet #simd #sse
🔥2
Ещё один странный тест с SSE/AVX - поиск элемента в массиве, где каждый элемент может встречаться дважды, кроме одного элемента (иногда встречается задача на собесах). Используется операция XOR, которая позволяет за O(n) найти этот элемент.
Как видно - даже простой цикл можно крутить быстрее 😊 gist #simd #sse #dotnet
Как видно - даже простой цикл можно крутить быстрее 😊 gist #simd #sse #dotnet
Хороший док по гайдлайнам от Microsoft, если ты уж наконец взялся за векторизацию кода. Векторизация, как правильно бенчмаркать и т.д.
#dotnet #github #sse
#dotnet #github #sse
Продолжаем ковырять SSE/AVX, но тут кажется мне не помешала бы пояснительная бригада. Для поиска элемента в
До 2048 (8 КБ данных) всё работает более менее - х1.5-2 для Vector128 и ещё больше для Vector256. Однако дальше Vector128 проседает по скорости до обычного цикла на 2048 элементов (8 КБ данных) и становится медленее, чем простой цикл для 4096+ (32 КБ данных) элементов.
Vector256 проседает попозже - начиная с 5120 (20 КБ данных) элементов он сравнивается со скоростью простого цикла.
Vector128 становится медленее всех, начиная с 3072 (12 КБ данных) элементов
Пока что у меня два объяснения:
🔸 влияние L2 кэша, он насыщается и за счёт того, что данные берутся из RAM скорость резко падает
🔸 процессор уходит в throttling, однако неясно почему Vector128 становица хуже чем простой цикл (хотя возможно JIT делает loop unroll и за счёт этого получается обычный цикл быстрее)
Второй вариант я попробовал исключить, переключив режим проца в Turbo (специальной утилитой Asus), скорости чуть-чуть подросли (буквально на 4-5%), но тренды не поменялись.
С ushort ситуация выглядит другим образом - самым быстрым практически везде является
gist_int gist_ushort #sse #simd #dotnet
int[]
используется Sse2.CompareEqual
, которая может сравнивать 4 (Vector128
) или 8 (Vector256
) элементов.До 2048 (8 КБ данных) всё работает более менее - х1.5-2 для Vector128 и ещё больше для Vector256. Однако дальше Vector128 проседает по скорости до обычного цикла на 2048 элементов (8 КБ данных) и становится медленее, чем простой цикл для 4096+ (32 КБ данных) элементов.
Vector256 проседает попозже - начиная с 5120 (20 КБ данных) элементов он сравнивается со скоростью простого цикла.
Vector128 становится медленее всех, начиная с 3072 (12 КБ данных) элементов
Пока что у меня два объяснения:
🔸 влияние L2 кэша, он насыщается и за счёт того, что данные берутся из RAM скорость резко падает
🔸 процессор уходит в throttling, однако неясно почему Vector128 становица хуже чем простой цикл (хотя возможно JIT делает loop unroll и за счёт этого получается обычный цикл быстрее)
Второй вариант я попробовал исключить, переключив режим проца в Turbo (специальной утилитой Asus), скорости чуть-чуть подросли (буквально на 4-5%), но тренды не поменялись.
С ushort ситуация выглядит другим образом - самым быстрым практически везде является
Vector128<ushort>
😳 однако разрыв по скорости в разы - только <=2048 элементов (4 КБ данных), дальше разрыв крайне незначительный.gist_int gist_ushort #sse #simd #dotnet
Имел неосторожност опубликовать в mastodon вопрос про SIMD - там где Vector128 был медленее Vector256, на что пришёл Alexandre Mutel (Director C#/.NET Tech Group at Unity) и потыкал меня носом в разные места этого кода. После чего он родил статью "10x Performance with SIMD Vectorized Code in C#/.NET"
#dotnet #simd #sse
#dotnet #simd #sse
👍7
Не для собственной имплементации (потому что это помоему уже везде реализовано), но просто для понимания как можно использовать SIMD (недлинная статья с примерами на сишечке). #simd #sse
Решил снова поиграться с SSE/AVX на примере FFT преобразования с помощью алгоритма Cooley-Tukey. В отличие от классического FFT он рекурсивный и работает за O(N*logN). Но опять же отличие от классического - на каждую рекурсию приходится выделять память под чётные/нечетные элементы. Это может быть не очень хорошо, но позволяет удобно оптимизировать расчёты.
Изначальный вариант работает с комплексными числами, которые определены как класс
Оптимизированный вариант использует Vector128 в 0-м элементе которого храница реальная часть, в 1-м - мнимая, и это позволяет чпокать числа побыстрее.
Результат: выигрыш х6.5 к перфу и х3.4 к аллокациям. #simd #dotnet #sse
Изначальный вариант работает с комплексными числами, которые определены как класс
ComplexNumber
с Real/Imag свойствами.Оптимизированный вариант использует Vector128 в 0-м элементе которого храница реальная часть, в 1-м - мнимая, и это позволяет чпокать числа побыстрее.
Результат: выигрыш х6.5 к перфу и х3.4 к аллокациям. #simd #dotnet #sse
Ещё один всратотест (gist) - проверка сортированный ли массив. Кандидаты:
* обычный цикл + с сохранением предыдущего
* Vector128<int> + с сохранением предыдущего
* Vector256<int> + с сохранением предыдущего
Даже циклы можно крутить быстрее :))
Что интересно -
Вопрос - можно ли это назвать не O(n), а O(n/4) и O(n/8)? 😁
Надо попробовать алгоритм K-means завернуть в SSE, там должен интересный буст на большом количестве кластеризуемых точек. #sse #simd
* обычный цикл + с сохранением предыдущего
* Vector128<int> + с сохранением предыдущего
* Vector256<int> + с сохранением предыдущего
Даже циклы можно крутить быстрее :))
Что интересно -
Unsafe.ReadUnaligned
и MemoryMarshal.Cast<int, Vector128<int>>
(в гисте его нет, но я пробовал) - совершено идентичны по скорости.Вопрос - можно ли это назвать не O(n), а O(n/4) и O(n/8)? 😁
Надо попробовать алгоритм K-means завернуть в SSE, там должен интересный буст на большом количестве кластеризуемых точек. #sse #simd
🤓3👍2💩2🔥1
Случайно попался неплохой справочник по x86/x64 инструкциям, в т.ч. SSE/AVX, учитывая что документация по AVX расширениям в дотнете прямо таки скажем весьма не очень. Например байт маски в Blend #sse #avx
👍4