SIMD matrix
- Rust course
- Expert
- Lesson 44/46
- 7 min
Do parallel matrix multiplication with SIMD.
Final task: SIMD matrix
Write a 4×4 matrix-vector product in a SIMD-friendly form. The classic row-dot approach needs a horizontal reduction for every row. The column approach uses only vertical operations: the result vector is the sum of each column multiplied by the corresponding x component (y += column_j * x[j], "axpy"):
// y = A·x, A in column order: a[j] = column j
fn matvec(a: [[f32; 4]; 4], x: [f32; 4]) -> [f32; 4] {
let mut y = [0.0f32; 4];
for j in 0..4 {
for i in 0..4 { // a 4-lane vertical multiply-add
y[i] += a[j][i] * x[j];
}
}
y
}The inner loop maps directly onto a single 4-lane multiply-add instruction; no horizontal operation is needed.
Verification
An optimized kernel must always be compared with a simple reference implementation. A reference giving the same result with a row-ordered matrix:
fn matvec_ref(satirlar: [[f32; 4]; 4], x: [f32; 4]) -> [f32; 4] {
satirlar.map(|r| r.iter().zip(&x).map(|(a, b)| a * b).sum())
}
// converting to column order: the transpose
fn devrik(m: [[f32; 4]; 4]) -> [[f32; 4]; 4] {
std::array::from_fn(|j| std::array::from_fn(|i| m[i][j]))
}Practice Matrix-vector
Write the matvec, matvec_ref and devrik functions above. For the row-ordered [[1,2,0,0],[0,1,0,0],[0,0,2,0],[0,0,0,3]] and x = [1, 1, 1, 1], print the result of matvec(devrik(A), x) with {:?} and its equality with the reference, separated by a space.
Starter code
fn main() {
// buraya yaz
}Sample solution
fn matvec(a: [[f32; 4]; 4], x: [f32; 4]) -> [f32; 4] {
let mut y = [0.0f32; 4];
for j in 0..4 {
for i in 0..4 {
y[i] += a[j][i] * x[j];
}
}
y
}
fn matvec_ref(satirlar: [[f32; 4]; 4], x: [f32; 4]) -> [f32; 4] {
satirlar.map(|r| r.iter().zip(&x).map(|(a, b)| a * b).sum())
}
fn devrik(m: [[f32; 4]; 4]) -> [[f32; 4]; 4] {
std::array::from_fn(|j| std::array::from_fn(|i| m[i][j]))
}
fn main() {
let a = [
[1.0, 2.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 2.0, 0.0],
[0.0, 0.0, 0.0, 3.0],
];
let x = [1.0; 4];
let y = matvec(devrik(a), x);
println!("{:?} {}", y, y == matvec_ref(a, x));
}Expected output
[3.0, 1.0, 2.0, 3.0] true
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What is the advantage of column-order storage for this product?
- Less memory
- It's easier to write
- No advantage
- Each column is contiguous in memory; it fits into a vector with a single load Correct answer
Explanation: Choosing the data layout for the algorithm determines most of the SIMD performance.
2 Vertical multiply-add
for j in 0..4 {
for i in 0..4 {
y[i] += a[j][i] * x[____];
}
}
for j in 0..4 {
for i in 0..4 {
y[i] += a[j][i] * x[j];
}
}
Explanation: Every lane of column j is multiplied by the same x[j].
3 Approach and property
| Term | Meaning |
|---|---|
Row-dot |
Needs horizontal reduction |
Column axpy |
Only vertical |
Referans uygulama |
Verification |
Devrik |
Layout conversion |