SIMD (Single Instruction, Multiple Data)

Computation Graphs & ML Infrastructure advanced Building with AI 11 min read

Overview

SIMD (Single Instruction, Multiple Data) is a class of parallel computing architecture where a single CPU instruction operates on multiple data elements simultaneously. Instead of processing one number at a time in a loop, SIMD packs multiple values into wide registers (128-bit, 256-bit, or 512-bit) and applies the same operation to all of them in a single clock cycle. This is the hardware foundation that makes CPU-based AI inference practical.

Neural networks are fundamentally linear algebra engines — they perform millions of multiply-accumulate operations across weight matrices and activation vectors. Without SIMD, a CPU would need to execute each multiplication and addition individually, making inference prohibitively slow. With SIMD, a single instruction can multiply 16 floating-point numbers at once (using 512-bit AVX-512 registers), reducing the instruction count by 16x and dramatically cutting loop overhead.

For AI engineers, understanding SIMD matters because it determines the performance characteristics of CPU inference, affects quantization strategy choices, and explains why certain data layouts and batch sizes perform better than others. When you’re running models on edge devices, laptops, or servers without GPUs, SIMD is the primary hardware accelerator you’re relying on.

How It Works

Scalar vs. SIMD Processing

In traditional scalar processing, the CPU fetches one instruction and applies it to one data element per cycle. To add four pairs of numbers, you need four separate add instructions. With SIMD, the same four pairs are loaded into a single wide register, and one vector add instruction processes all four simultaneously.

SIMD Parallelism

SIMD operates on data-level parallelism — multiple independent data elements processed by the same operation. This is distinct from thread-level parallelism (multiple cores) or instruction-level parallelism (pipelining). SIMD works within a single core, using wider registers to process more data per instruction.

// Scalar: 4 separate additions
float a[4] = {1.0, 2.0, 3.0, 4.0};
float b[4] = {5.0, 6.0, 7.0, 8.0};
float c[4];
for (int i = 0; i < 4; i++) {
    c[i] = a[i] + b[i];  // 4 instructions
}

// SIMD (SSE): 1 vector addition
__m128 va = _mm_load_ps(a);    // Load 4 floats into 128-bit register
__m128 vb = _mm_load_ps(b);    // Load 4 floats into 128-bit register
__m128 vc = _mm_add_ps(va, vb); // Add all 4 pairs in 1 instruction
_mm_store_ps(c, vc);            // Store results

SIMD Instruction Set Evolution

SIMD has evolved through progressively wider registers and more capable instruction sets:

SIMD for Matrix Multiplication

Matrix multiplication is the dominant operation in neural network inference. A single transformer layer performs multiple large matrix multiplications: query/key/value projections, attention score computation, and feed-forward network passes. SIMD accelerates these by processing multiple elements of each dot product simultaneously.

// Matrix multiply inner loop with AVX2 (8-wide float32)
// Computes C[i][j] += A[i][k] * B[k][j] for 8 values of j at once
for (int i = 0; i < M; i++) {
    for (int j = 0; j < N; j += 8) {          // Step by 8 (AVX2 width)
        __m256 sum = _mm256_setzero_ps();       // 8 accumulators
        for (int k = 0; k < K; k++) {
            __m256 a = _mm256_broadcast_ss(&A[i*K + k]); // Broadcast A[i][k]
            __m256 b = _mm256_load_ps(&B[k*N + j]);      // Load B[k][j..j+7]
            sum = _mm256_fmadd_ps(a, b, sum);             // FMA: sum += a * b
        }
        _mm256_store_ps(&C[i*N + j], sum);     // Store 8 results
    }
}
Fused Multiply-Accumulate (FMA)

The FMA instruction computes a × b + c in a single operation — exactly what neural network dot products need. Without FMA, this requires separate multiply and add instructions. FMA doubles throughput for multiply-accumulate-heavy workloads like matrix multiplication and convolution.

Memory Alignment and Data Layout

SIMD performance depends critically on memory alignment. When data is aligned to register boundaries (16-byte for SSE, 32-byte for AVX, 64-byte for AVX-512), the CPU can load it in a single cycle. Misaligned access may require two loads and a shift, halving throughput. This is why inference frameworks carefully control tensor memory layout, padding dimensions to multiples of the SIMD width.

AVX-512 Power Considerations

AVX-512 delivers the highest throughput but has a significant tradeoff: it is extremely power-hungry. When AVX-512 instructions execute on multiple cores simultaneously, the CPU may reduce its clock frequency (known as “frequency throttling”) to stay within its thermal envelope. Benchmarks show AVX-512 matrix operations running 1.8x faster than AVX2 on a single core, but multicore scaling can be limited by thermal throttling. Production inference servers must account for this in capacity planning.

Practical Applications

CPU Inference Frameworks

Major inference engines use SIMD extensively under the hood:

Quantization and SIMD Synergy

SIMD and quantization are complementary optimizations. When model weights are quantized from float32 to int8 or int4, SIMD registers can pack even more elements: a 256-bit register holds 8x float32 but 32x int8. This is why quantized models see disproportionately large speedups on CPUs — they benefit from both reduced memory bandwidth and higher SIMD throughput. Modern frameworks like llama.cpp use specialized SIMD kernels for common quantization formats (Q4_0, Q4_K_M, Q8_0).

Choosing the Right Instruction Set

When deploying inference on CPUs, consider the target hardware:

Key Takeaways

Further Reading