Українська
Підсумки
Висновки
SIMD – паралелізм усередині ядра: одна інструкція обробляє 4, 8 або 16 чисел у регістрах XMM, YMM чи ZMM. JIT .NET не векторизує цикли автоматично, тому векторизацію записують явно: переносним Vector<T> змінної ширини, векторами фіксованої ширини Vector128/256/512 з перевіркою IsHardwareAccelerated або платформними інтринсиками з перевіркою IsSupported і запасним шляхом. Порівняння повертають маски, які замінюють умовні переходи (ConditionalSelect) або перетворюються на бітові маски (ExtractMostSignificantBits). Векторний цикл завжди доповнюють обробкою хвоста, а небезпечні методи завантаження використовують лише з перевіреними межами. Для типових операцій над масивами найкращий вибір – TensorPrimitives. Поєднання SIMD і потоків ефективне, коли обчислення переважає переміщення даних; інакше межею стає пропускна здатність пам’яті. Множення матриць показує всі рівні оптимізації: порядок циклів ikj, блочне множення для кешу, SIMD у внутрішньому циклі та потоки за рядками плиток дали прискорення в 105 разів. Метод Гаусса розпаралелюють у межах кроку виключення, метод Якобі – повністю, а Гаусса–Зейделя – червоно-чорним впорядкуванням. Векторизований код перевіряють дизасемблером і порівнюють з еталоном з допуском.
Питання для самоперевірки
- Що таке SIMD? Чим векторизація відрізняється від багатопотоковості?
- Які векторні регістри мають процесори x86-64? Скільки чисел
floatіdoubleу кожному? - Які набори інструкцій SIMD ви знаєте? Що таке AVX10 і навіщо він потрібен?
- Чому JIT .NET і компілятори C++ без спеціальних ключів не векторизують суму
float? - Від чого залежить
Vector<T>.Count? Як змінити ширинуVector<T>? - Чим
Vector256<T>відрізняється відVector<T>? Навіщо перевірятиIsHardwareAccelerated? - Що повертає векторне порівняння? Як працюють
ConditionalSelectіExtractMostSignificantBits? - Що таке апаратні інтринсики? Як забезпечити роботу коду на процесорі без потрібного набору?
- Як перевірити всі шляхи векторизованого коду на одному ПК?
- Що таке хвіст масиву? Як його обробляють для суми та для пошуку?
- Навіщо потрібні
MemoryMarshal.GetReference,LoadUnsafeіMemoryMarshal.Cast? Які в них ризики? - Що таке вирівнювання пам’яті й коли використовують
NativeMemory.AlignedAlloc? - Які операції надає
TensorPrimitivesі коли його варто обрати? - Чому потоки не прискорюють суму великого масиву понад межу пропускної здатності пам’яті?
- Опишіть рівні BLAS. Чому порядок циклів ikj швидший за ijk?
- Як працює блочне множення матриць і як вибрати розмір плитки? Що таке GFLOPS?
- Які частини методу Гаусса можна розпаралелити?
- Чому метод Якобі легко розпаралелюється, а Гаусса–Зейделя – ні? Що таке червоно-чорне впорядкування?
Корисні посилання
- SIMD та апаратні інтринсики в .NET: https://learn.microsoft.com/dotnet/standard/simd
- Тип
Vector<T>: https://learn.microsoft.com/dotnet/api/system.numerics.vector-1 - Простір імен
System.Runtime.Intrinsics: https://learn.microsoft.com/dotnet/api/system.runtime.intrinsics - Інтринсики x86: https://learn.microsoft.com/dotnet/api/system.runtime.intrinsics.x86
- Інтринсики Arm
AdvSimd: https://learn.microsoft.com/dotnet/api/system.runtime.intrinsics.arm.advsimd TensorPrimitives: https://learn.microsoft.com/dotnet/api/system.numerics.tensors.tensorprimitivesNativeMemory.AlignedAlloc: https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.nativememory.alignedalloc- Дизасемблер BenchmarkDotNet: https://benchmarkdotnet.org/articles/features/disassembler.html
- Intel Intrinsics Guide: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html
- BLAS: https://www.netlib.org/blas/