Elias Abuamer
ID: 2220206976
Fares Etweabi
ID: 2200208829
Modern processors can execute instructions much faster than data can be retrieved from main memory. To reduce this gap, computer systems use a hierarchy of caches (L1 and L2) that store frequently accessed data closer to the CPU.
However, when the required data is not available in the cache, a cache miss occurs and the processor must access the slower DDR3 main memory. This significantly increases memory access latency and reduces overall system performance.
CPU Model
X86TimingSimpleCPU
L1 I-Cache
16 KB
L1 D-Cache
64 KB
L2 Cache
256 KB
Main Memory
DDR3
The objective of this project is to reduce memory access latency and improve performance by introducing a hardware prefetching mechanism into the cache hierarchy and comparing its performance with the original baseline system.
The default Hello World program provided by gem5 is too small to generate meaningful memory activity. Therefore, a custom C program called array_sum.c was developed and compiled.
This program creates a large array and sequentially accesses all elements while computing their sum. Because the memory accesses follow a predictable pattern, the workload is suitable for evaluating cache behavior and prefetching techniques.
To improve cache performance, a Stride Prefetcher was attached to the L2 cache.
The prefetcher monitors memory access patterns and attempts to predict future memory requests. When a sequential pattern is detected, it fetches future cache blocks before the CPU explicitly requests them.
Config 1
Degree = 2
Config 2
Degree = 4
Config 3
Degree = 8
We wrote a custom C program array_sum.c that allocates a 10-million element integer array, initialises each element, then sums them all. The sequential memory-access pattern makes it ideal for exercising the cache and evaluating prefetching.
#include <stdio.h>
#define N 10000000
int A[N];
int main() {
long long sum = 0;
for (int i = 0; i < N; i++) A[i] = i;
for (int i = 0; i < N; i++) sum += A[i];
printf("Sum = %lld\n", sum);
return 0;
}
We simulated the benchmark on the two-level cache system without any prefetcher to establish a performance baseline. The following command was used:
build/X86/gem5.opt \ configs/learning_gem5/part1/two_level.py \ ./array_sum
The key metrics were then extracted from m5out/stats.txt:
grep "simTicks" m5out/stats.txt grep "simInsts" m5out/stats.txt grep -i "overallMissRate" m5out/stats.txt
Result: 237.71 B ticks with an L2 miss rate of 99.98% — confirming severe cache pressure.
We edited configs/learning_gem5/part1/caches.py to attach a StridePrefetcher to the L2 cache. Two changes were required:
import m5
from m5.objects import Cache, StridePrefetcher
class L2Cache(Cache):
size = "256KiB"
assoc = 8
tag_latency = 20
data_latency = 20
...
prefetcher = StridePrefetcher(degree=4)
Re-run the same gem5 command and collect simTicks, simInsts, and overallMissRate from stats.txt to compare against baseline.
To find the optimal configuration, the degree parameter was changed and the experiment was repeated. Degree controls how many future cache lines the prefetcher fetches ahead on each stride detection.
Degree 2
degree=2
Conservative
Degree 4 ★
degree=4
Optimal
Degree 8
degree=8
Aggressive
# degree 2 prefetcher = StridePrefetcher(degree=2) # degree 8 prefetcher = StridePrefetcher(degree=8)
After each change, re-run the simulation and record the stats. Results from all three degrees are compared in the Experimental Results slide.
| Configuration | simTicks (B) | L2 Miss Rate | Accuracy | Coverage |
|---|---|---|---|---|
| No Prefetch | 237.71 | 99.98% | — | — |
| Degree 2 | 143.56 | 5.00% | 48.7% | 98.2% |
| Degree 4 | 142.25 | 1.79% | 25.6% | 98.3% |
| Degree 8 | 142.74 | 1.73% | 13.2% | 98.3% |
| Degree | Prefetches Issued | Useful Prefetches |
|---|---|---|
| 2 | 2.44 M | 1.19 M |
| 4 | 4.81 M | 1.23 M |
| 8 | 9.30 M | 1.23 M |
Although Degree 8 generated nearly twice as many prefetch requests as Degree 4, the number of useful prefetches remained almost unchanged. As a result, memory traffic increased while the performance improvement became negligible.
This demonstrates that increasing prefetch aggressiveness beyond a certain point can reduce efficiency rather than improve it.
This project successfully demonstrated the effectiveness of hardware prefetching in reducing memory access latency.
By developing a custom memory-intensive workload and integrating a Stride Prefetcher into the L2 cache, execution time was reduced from 237.7B ticks to approximately 142.3B ticks.
Among all tested configurations, Degree 4 provided the best balance between performance improvement and prefetch efficiency, making it the optimal configuration for this workload.