Menggunakan jenis numerik yang dipercepat-SIMD
SIMD (Instruksi tunggal, data jamak) menyediakan dukungan perangkat keras untuk melakukan operasi pada beberapa bagian data, secara paralel, menggunakan satu instruksi. Di .NET, ada sekumpulan jenis yang dipercepat SIMD di bawah namespace layanan System.Numerics. Operasi SIMD dapat diparalelkan pada tingkat perangkat keras. Itu meningkatkan throughput komputasi vektorisasi, yang umum dalam aplikasi matematika, ilmiah, dan grafis.
Jenis yang dipercepat-SIMD .NET
Jenis yang dipercepat-SIMD .NET mencakup jenis berikut:
Jenis Vector2, Vector3, dan Vector4, yang mewakili vektor dengan nilai Single 2, 3, dan 4.
Dua jenis matriks, Matrix3x2, yang mewakili matriks 3x2, dan Matrix4x4, yang mewakili matriks 4x4 dari nilai Single.
Jenis Plane, yang mewakili bidang dalam ruang tiga-dimensi menggunakan nilai Single.
JenisQuaternion, yang mewakili vektor yang digunakan untuk mengodekan rotasi fisik tiga dimensi menggunakan nilai Single.
Jenis, Vector<T> yang mewakili vektor dari jenis numerik tertentu dan menyediakan serangkaian operator yang luas yang mendapat manfaat dari dukungan SIMD. Jumlah instans Vector<T> diperbaiki untuk masa pakai aplikasi, tetapi nilainya Vector<T>.Count tergantung pada CPU komputer yang menjalankan kode.
Catatan
Jenis Vector<T> tidak disertakan dalam .NET Framework. Anda harus menginstal paket NuGet System.Numerics.Vectors untuk mendapatkan akses ke jenis ini.
Jenis yang dipercepat-SIMD diimplementasikan dengan cara demikian sehingga dapat digunakan dengan perangkat keras yang tidak dipercepat-SIMD atau kompiler JIT. Untuk memanfaatkan instruksi SIMD, aplikasi 64-bit Anda harus dijalankan oleh runtime yang menggunakan kompiler RyuJIT. Kompiler RyuJIT disertakan dalam .NET Core dan di .NET Framework 4.6 dan yang lebih baru. Dukungan SIMD hanya disediakan saat menargetkan prosesor 64-bit.
Bagaimana cara menggunakan SIMD?
Sebelum menjalankan algoritma SIMD kustom, dimungkinkan untuk memeriksa apakah komputer host mendukung SIMD dengan menggunakan Vector.IsHardwareAccelerated, yang mengembalikan Boolean. Ini tidak menjamin bahwa akselerasi-SIMD diaktifkan untuk jenis tertentu, tetapi merupakan indikator bahwa didukung oleh beberapa jenis.
Vektor Sederhana
Jenis yang dipercepat-SIMD yang paling primitif di .NET adalah jens Vector2, Vector3, dan Vector4, yang mewakili vektor dengan nilai Single 2, 3, dan 4 . Contoh di bawah ini menggunakan Vector2 untuk menambahkan dua vektor.
var v1 = new Vector2(0.1f, 0.2f);
var v2 = new Vector2(1.1f, 2.2f);
var vResult = v1 + v2;
Dimungkinkan juga untuk menggunakan vektor .NET untuk menghitung properti matematika vektor lainnya seperti Dot product
, Transform
, Clamp
, dan sebagainya.
var v1 = new Vector2(0.1f, 0.2f);
var v2 = new Vector2(1.1f, 2.2f);
var vResult1 = Vector2.Dot(v1, v2);
var vResult2 = Vector2.Distance(v1, v2);
var vResult3 = Vector2.Clamp(v1, Vector2.Zero, Vector2.One);
Matrix
Matrix3x2, yang mewakili matriks 3x2, dan Matrix4x4, yang mewakili matriks 4x4. Dapat digunakan untuk perhitungan terkait-matriks. Contoh di bawah ini menunjukkan perkalian matriks ke matriks transpose korespondennya menggunakan SIMD.
var m1 = new Matrix4x4(
1.1f, 1.2f, 1.3f, 1.4f,
2.1f, 2.2f, 3.3f, 4.4f,
3.1f, 3.2f, 3.3f, 3.4f,
4.1f, 4.2f, 4.3f, 4.4f);
var m2 = Matrix4x4.Transpose(m1);
var mResult = Matrix4x4.Multiply(m1, m2);
Vektor<T>
Vector<T> memberikan kemampuan untuk menggunakan vektor yang lebih lama. Jumlah instans Vector<T> diperbaiki, tetapi nilainya Vector<T>.Count tergantung pada CPU komputer, di mana kode dijalankan.
Contoh berikut menunjukkan cara menghitung jumlah element-wise dari dua larik menggunakan Vector<T>.
double[] Sum(double[] left, double[] right)
{
if (left is null)
{
throw new ArgumentNullException(nameof(left));
}
if (right is null)
{
throw new ArgumentNullException(nameof(right));
}
if (left.Length != right.Length)
{
throw new ArgumentException($"{nameof(left)} and {nameof(right)} are not the same length");
}
int length = left.Length;
double[] result = new double[length];
// Get the number of elements that can't be processed in the vector
// NOTE: Vector<T>.Count is a JIT time constant and will get optimized accordingly
int remaining = length % Vector<double>.Count;
for (int i = 0; i < length - remaining; i += Vector<double>.Count)
{
var v1 = new Vector<double>(left, i);
var v2 = new Vector<double>(right, i);
(v1 + v2).CopyTo(result, i);
}
for (int i = length - remaining; i < length; i++)
{
result[i] = left[i] + right[i];
}
return result;
}
Keterangan
SIMD lebih memungkinkan untuk menghapus satu hambatan dan mengekspos throughput memori berikutnya, misalnya. Secara umum manfaat performa penggunaan SIMD bervariasi tergantung pada skenario tertentu, dan dalam beberapa kasus bahkan dapat berkinerja lebih buruk daripada kode setara non-SIMD yang lebih sederhana.