CS61C: Great Ideas in Computer Architecture (aka Machine Structures)
Lecture 21: SIMD, Thread-level Parallelism
Instructor: Justin Yokota
CS 61C
Summer 2026
CS 61C
Summer 2026
CS 61C
Summer 2026
CS 61C
Summer 2026
Agenda
5
CS 61C
Summer 2026
Why Parallelism?
6
CS 61C
Summer 2026
7
CS 61C
Summer 2026
8
CS 61C
Summer 2026
9
CS 61C
Summer 2026
Higher Clock Speed?
10
CS 61C
Summer 2026
Faster Memory Accesses/More Transistors?
11
CS 61C
Summer 2026
More complicated operations?
12
CS 61C
Summer 2026
More computers?
13
CS 61C
Summer 2026
Why Parallelism?
14
Time | = | Instructions | Cycles | Time |
Program | Program | Instruction | Cycle |
CS 61C
Summer 2026
Toy Example: Vector Sum
15
0b0000 0001 = 1 | 0b0000 0010 = 2 | 0b0000 0011 = 3 | 0b0000 0100 = 4 |
0b0000 0101 = 5 | 0b0000 0110 = 6 | 0b0000 0111 = 7 | 0b0000 1000 = 8 |
| | | |
0b0000 0110 = 6 | 0b0000 1000 = 8 | 0b0000 1010 = 10 | 0b0000 1100 = 12 |
CS 61C
Summer 2026
Toy Example: Vector Sum: Naive
lb t0 0(a0) lb t0 1(a0) lb t0 2(a0) lb t0 3(a0)�lb t1 0(a1) lb t1 1(a1) lb t1 2(a1) lb t1 3(a1)�add t0 t0 t1 add t0 t0 t1 add t0 t0 t1 add t0 t0 t1�sb t0 0(a2) sb t0 1(a2) sb t0 2(a2) sb t0 3(a2)
16
0b0000 0001 = 1 | 0b0000 0010 = 2 | 0b0000 0011 = 3 | 0b0000 0100 = 4 |
0b0000 0101 = 5 | 0b0000 0110 = 6 | 0b0000 0111 = 7 | 0b0000 1000 = 8 |
| | | |
0b0000 0110 = 6 | 0b0000 1000 = 8 | 0b0000 1010 = 10 | 0b0000 1100 = 12 |
CS 61C
Summer 2026
Toy Example: Vector Sum: Single Add
lw t0 0(a0)�lw t1 0(a1)�add t0 t0 t1�sw t0 0(a2)
17
0b0000 0001 | 0000 0010 | 0000 0011 | 0000 0100 = 16909060 |
0b0000 0101 | 0000 0110 | 0000 0111 | 0000 1000 = 84281096 |
| | | |
0b0000 0110 | 0000 1000 | 0000 1010 | 0000 1100 = 101190156 |
CS 61C
Summer 2026
Toy Example: Vector Sum: Single Add Problem
lw t0 0(a0)�lw t1 0(a1)�add t0 t0 t1�sw t0 0(a2)
18
0b0000 0001 | 1000 0010 | 0000 0011 | 0000 0100 = 25297668 |
0b0000 0101 | 1000 0110 | 0000 0111 | 0000 1000 = 92669704 |
| | | |
0b0000 0111 | 0000 1000 | 0000 1010 | 0000 1100 = 117967372 |
CS 61C
Summer 2026
Toy Example: Vector Sum: Vectorized Add
lw t0 0(a0)�lw t1 0(a1)�vec_add t0 t0 t1�sw t0 0(a2)
19
0b0000 0001 = 1 | 0b0000 0010 = 2 | 0b0000 0011 = 3 | 0b0000 0100 = 4 |
0b0000 0101 = 5 | 0b0000 0110 = 6 | 0b0000 0111 = 7 | 0b0000 1000 = 8 |
| | | |
0b0000 0110 = 6 | 0b0000 1000 = 8 | 0b0000 1010 =10 | 0b0000 1100 = 12 |
CS 61C
Summer 2026
SIMD Instructions
20
CS 61C
Summer 2026
SIMD Instructions
21
CS 61C
Summer 2026
Intel Intrinsics
22
CS 61C
Summer 2026
Intel Intrinsics: Types
23
CS 61C
Summer 2026
Intel Intrinsics: Instructions
24
CS 61C
Summer 2026
Vector Sum (128-bit registers, 32-bit integers
__mm128i avec = _mm_load_si128(a);�__mm128i bvec = _mm_load_si128(b);�__mm128i sum = _mm_add_epi32(avec, bvec);�_mm_store_si128(c, sum);
25
0x0000 0001 | 0x0000 0002 | 0x0000 0003 | 0x0000 0004 |
0x0000 0005 | 0x0000 0006 | 0x0000 0007 | 0x0000 0008 |
| | | |
0x0000 0006 | 0x0000 0008 | 0x0000 000A | 0x0000 000C |
CS 61C
Summer 2026
Common mistakes when working with SIMD instructions
26
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
27
| | | | | 17 | 18 | 19 | 20 |
| | | | | 21 | 22 | 23 | 24 |
| | | | | 25 | 26 | 27 | 28 |
| | | | | 29 | 30 | 31 | 32 |
| | | | | | | | |
1 | 2 | 3 | 4 | | | | | |
5 | 6 | 7 | 8 | | | | | |
9 | 10 | 11 | 12 | | | | | |
13 | 14 | 15 | 16 | | | | | |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
28
| | | | | 17 | 21 | 25 | 29 |
| | | | | 18 | 22 | 26 | 30 |
| | | | | 19 | 23 | 27 | 31 |
| | | | | 20 | 24 | 28 | 32 |
| | | | | | | | |
1 | 2 | 3 | 4 | | | | | |
5 | 6 | 7 | 8 | | | | | |
9 | 10 | 11 | 12 | | | | | |
13 | 14 | 15 | 16 | | | | | |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
__m128 v3 = _mm128_set1_ps(0);
29
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
| | | | | | | | | | | | | | | | | | |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
__m128 v1 = _mm128_load_ps(&arr);�__m128 v2 = _mm128_load_ps(&arrtwo);
30
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
| | | | | | | | | | 0 | 0 | 0 | 0 | | | | | |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
v3 = _mm256_fmadd_ps(v1, v2, v3);
31
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
1 | 2 | 3 | 4 | | 1 | 1 | 1 | 1 | | 0 | 0 | 0 | 0 | | | | | |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
int i;�for(i = 0; i < arrlen/4*4;i+=4) {� __m128 v1 = _mm128_load_ps(arr+i);� __m128 v2 = _mm128_load_ps(arrtwo+i);� v3 = _mm256_fmadd_ps(v1, v2, v3); }
32
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
1 | 2 | 3 | 4 | | 1 | 1 | 1 | 1 | | 1 | 2 | 3 | 4 | | | | | |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
int i;�for(i = 0; i < arrlen/4*4;i+=4) {� __m128 v1 = _mm128_load_ps(arr+i);� __m128 v2 = _mm128_load_ps(arrtwo+i);� v3 = _mm256_fmadd_ps(v1, v2, v3); }
33
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
5 | 6 | 7 | 8 | | 1 | 1 | 1 | 1 | | 6 | 8 | 10 | 12 | | | | | |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
int i;�for(i = 0; i < arrlen/4*4;i+=4) {� __m128 v1 = _mm128_load_ps(arr+i);� __m128 v2 = _mm128_load_ps(arrtwo+i);� v3 = _mm256_fmadd_ps(v1, v2, v3); }
34
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
9 | 10 | 11 | 12 | | 1 | 1 | 1 | 1 | | 15 | 18 | 21 | 24 | | | | | |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
//Force alignment�float mem[4] __attribute__ ((aligned (32)));�_mm128_store(mem, v3);
35
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
13 | 14 | 15 | 16 | | 1 | 1 | 1 | 1 | | 28 | 32 | 36 | 40 | | | | | |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
for(;i<arrlen;i++) {� mem[0]+=arr[i]*arrtwo[i];�}
36
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
13 | 14 | 15 | 16 | | 1 | 1 | 1 | 1 | | 28 | 32 | 36 | 40 | | 28 | 32 | 36 | 40 |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
for(;i<arrlen;i++) {� mem[0]+=arr[i]*arrtwo[i];�}
37
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
13 | 14 | 15 | 16 | | 1 | 1 | 1 | 1 | | 28 | 32 | 36 | 40 | | 45 | 32 | 36 | 40 |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
for(;i<arrlen;i++) {� mem[0]+=arr[i]*arrtwo[i];�}
38
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
13 | 14 | 15 | 16 | | 1 | 1 | 1 | 1 | | 28 | 32 | 36 | 40 | | 63 | 32 | 36 | 40 |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
return mem[0]+mem[1]+mem[2]+mem[3];
39
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
v1 | | v2 | | v3 | | mem | ||||||||||||
13 | 14 | 15 | 16 | | 1 | 1 | 1 | 1 | | 28 | 32 | 36 | 40 | | 82 | 32 | 36 | 40 |
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
__m128 v3 = _mm128_set1_ps(0);�int i;�for(i = 0; i < arrlen/4*4;i+=4) {� __m128 v1 = _mm128_load_ps(arr+i);� __m128 v2 = _mm128_load_ps(arrtwo+i);� v3 = _mm256_fmadd_ps(v1, v2, v3); �}�float mem[4] __attribute__ ((aligned (32)));�_mm128_store(mem, v3);�for(;i<arrlen;i++) {� mem[0]+=arr[i]*arrtwo[i];�}�return mem[0]+mem[1]+mem[2]+mem[3];
40
CS 61C
Summer 2026
Applying DLP to Matrix Multiply
41
| | | | | 17 | 21 | 25 | 29 |
| | | | | 18 | 22 | 26 | 30 |
| | | | | 19 | 23 | 27 | 31 |
| | | | | 20 | 24 | 28 | 32 |
| | | | | | | | |
1 | 2 | 3 | 4 | | | | | |
5 | 6 | 7 | 8 | | | | | |
9 | 10 | 11 | 12 | | | | | |
13 | 14 | 15 | 16 | | | | | |
CS 61C
Summer 2026
42
CS 61C
Summer 2026
43
CS 61C
Summer 2026
44
CS 61C
Summer 2026
Conclusion
45
CS 61C
Summer 2026
Agenda
46
CS 61C
Summer 2026
Terminology
47
CS 61C
Summer 2026
Terminology
48
CS 61C
Summer 2026
Why Parallelism?
49
Time | = | Instructions | Cycles | Time |
Program | Program | Instruction | Cycle |
CS 61C
Summer 2026
Parallel Computing
50
CS 61C
Summer 2026
Multithreading vs Multiprocess Code
51
CS 61C
Summer 2026
Multithreading Framework Overview
52
CS 61C
Summer 2026
Multithreading: Fork-Join Model
53
CS 61C
Summer 2026
Multithreading: Fork-Join Model in Human Terms
54
CS 61C
Summer 2026
Multithreading: Scaling Efficiency
55
CS 61C
Summer 2026
OpenMP
56
CS 61C
Summer 2026
#pragma omp parallel
#pragma omp parallel�{� //parallel code�}
57
CS 61C
Summer 2026
Parallel Hello World
#include <stdio.h>�#include <omp.h>�int main () {� int x = 0; //Shared variable� #pragma omp parallel� {� int tid = omp_get_thread_num(); //Private variable� x++;� printf("Hello World from thread %d, x = %d\n", tid, x);� if(tid==0) {� printf("Number of threads = %d\n", omp_get_num_threads());� }� }� printf("Done with parallel segment\n");�}
58
CS 61C
Summer 2026
Shared vs Private variables
#pragma omp parallel private(var) shared(var2)
59
CS 61C
Summer 2026
For loops
60
CS 61C
Summer 2026
For loops
61
CS 61C
Summer 2026
For loops
62
CS 61C
Summer 2026