DEV Community

Cover image for SIMD Accelerated Numeric Types in C#: Complete Guide 2024
ByteHide
ByteHide

Posted on

SIMD Accelerated Numeric Types in C#: Complete Guide 2024

What Is SIMD and How Do We Implement It in .NET?

Let’s kick things off with what SIMD actually means. Picture this: instead of tackling tasks one-by-one like an assembly line, SIMD lets your machine juggle multiple pieces of data with a single instruction. This magical multitasking happens thanks to specialized hardware that splits data into batches, processing them simultaneously.

So, how do we harness this power in .NET? Say hello to the System.Numerics and System.Runtime.Intrinsics namespaces! These namespaces house a set of vector and matrix types designed to make SIMD processing a breeze. Not only does SIMD promise speed, but it also brings elegance and simplicity to parallel programming, making your code more readable and less complex. Talk about a win-win!

The Basics: Vectors and Matrices in .NET

Vectors and matrices may sound like something out of a math class, but they’re vital tools in SIMD processing. In programming terms:

  • Vectors are essentially arrays of numeric values.
  • Matrices are rectangular arrays composed of rows and columns of numeric values.

In .NET, we have a range of SIMD-accelerated vector and matrix types such as Vector2, Vector3, Vector4, Vector<T>, Matrix3x2, and Matrix4x4. These types allow you to store and manipulate numeric data efficiently, leveraging SIMD to perform operations concurrently.

Different SIMD Accelerated Numeric Types

From humble vectors to mighty matrices, let’s delve into the specific SIMD-accelerated types .NET offers.

Simple Vectors

Starting with the basics, we have Vector2, Vector3, and Vector4. These are our simple vectors, typically containing single-precision floating-point numbers.

using System.Numerics;

var vector2 = new Vector2(1f, 2f);
var vector3 = new Vector3(4f, 5f, 6f);
var vector4 = new Vector4(7f, 8f, 9f, 10f);
Enter fullscreen mode Exit fullscreen mode

With these simple types, you can perform operations like dot products and transformations. For instance, here’s how to find the dot product of two vectors:

public static float GetDotProductOfTwoVectors()
{
    var vector1 = new Vector3(1f, 2f, 3f);
    var vector2 = new Vector3(4f, 5f, 6f);
    return Vector3.Dot(vector1, vector2);
}
// Returns the result of the dot product of vector1 and vector2
Enter fullscreen mode Exit fullscreen mode

Advanced Vectors: Vector

For scenarios needing more flexibility, Vector<T> comes to the rescue. Unlike simple vectors, Vector<T> allows for dynamic sizes based on your CPU capabilities.

using System.Numerics;

var intVector = new Vector<int>(new Span<int>(new[] { 1, 2, 3, 4, 5, 6, 7, 8 }));
Enter fullscreen mode Exit fullscreen mode

Creating vectors with Vector<T> is flexible but can be tricky due to system-specific Vector<T>.Count values. Best practice involves loading vectors using array slices:

var span = new Span<int>(new[] { 1, 2, 3, 4, 5, 6, 7, 8 });
for (int i = 0; i < span.Length; i += Vector<int>.Count)
{
    var v = new Vector<int>(span.Slice(i, Vector<int>.Count));
    // Process vector 'v'
}
Enter fullscreen mode Exit fullscreen mode

Matrices

Finally, let’s talk about matrices—Matrix3x2 and Matrix4x4. These types are ideal for representing and manipulating data in a tabular form.

using System.Numerics;

var matrix1 = new Matrix3x2(1f, 2f, 5f, 6f, 9f, 10f);
var matrix2 = new Matrix4x4(1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f, 11f, 12f, 13f, 14f, 15f, 16f);
Enter fullscreen mode Exit fullscreen mode

With matrix types, you can perform operations like transposing and multiplying matrices:

var transposedMatrix = Matrix4x4.Transpose(matrix2);
var multipliedMatrix = Matrix4x4.Multiply(matrix2, transposedMatrix);
// Multiply and transpose matrices
Enter fullscreen mode Exit fullscreen mode

Benchmarking the Performance of SIMD Accelerated Numeric Types

Benchmarks! Or as I like to call it, the ultimate showdown. Let’s pit SIMD against non-SIMD implementations to see who’s faster.

SIMD Matrix Multiplication

Here’s how you can create and multiply two 4×4 matrices using SIMD:

public static Matrix4x4 CreateAndMultiplyTwoMatricesWithSIMD()
{
    var matrix = new Matrix4x4(1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f, 11f, 12f, 13f, 14f, 15f, 16f);
    return Matrix4x4.Multiply(matrix, matrix);
}
Enter fullscreen mode Exit fullscreen mode

Non-SIMD Matrix Multiplication

And here’s the non-SIMD alternative:

public static float[,] CreateAndMultiplyTwoMatricesWithoutSIMD()
{
    float[,] matrix = {
        { 1f, 2f, 3f, 4f },
        { 5f, 6f, 7f, 8f },
        { 9f, 10f, 11f, 12f },
        { 13f, 14f, 15f, 16f }
    };
    float[,] result = new float[4, 4];
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            result[i, j] = 0;
            for (int k = 0; k < 4; k++)
            {
                result[i, j] += matrix[i, k] * matrix[k, j];
            }
        }
    }
    return result;
}
Enter fullscreen mode Exit fullscreen mode

Enhance Your App Security with ByteHide

ByteHide offers an all-in-one cybersecurity platform specifically designed to protect your .NET and C# applications with minimal effort and without the need for advanced cybersecurity knowledge.

Why Choose ByteHide?

  • Comprehensive Protection: ByteHide provides robust security measures to protect your software and data from a wide range of cyber threats.
  • Ease of Use: No advanced cybersecurity expertise required. Our platform is designed for seamless integration and user-friendly operation.
  • Time-Saving: Implement top-tier security solutions quickly, so you can focus on what you do best—running your business.

Take the first step towards enhancing your App Security. Discover how ByteHide can help you protect your applications and ensure the resilience of your IT infrastructure.

Conclusion

In this article, you’ve taken a whirlwind tour of SIMD in .NET—what it is, why it’s awesome, and how to use SIMD-accelerated numeric types to boost your application’s performance. From vectors to matrices, we’ve highlighted the most crucial SIMD types and demonstrated their capabilities with code.

Remember, while SIMD can bring impressive performance gains, it’s not a silver bullet. Always benchmark your specific use cases to see if SIMD is the right fit. Go ahead, and take the plunge into the world of faster, more efficient C# programming. Your users (and your future self) will thank you!

Top comments (3)

Collapse
 
peter_truchly_4fce0874fd5 profile image
Peter Truchly

Very inspiring post!
I suppose it is a homework for the reader to do the actual benchmark. For anyone who is going to try this, I suggest to unroll all loops in non-SIMD version and rearrange writes of result to consecutive addresses.

Collapse
 
stevediaz profile image
stevediaz

Informative !

Collapse
 
jangelodev profile image
João Angelo

Hi ByteHide,
Top, very nice and helpful !
Thanks for sharing.