1+ use std:: time:: Instant ;
2+
3+ #[ derive( Clone , Copy ) ]
4+ struct DataPoint {
5+ value : f64 ,
6+ timestamp : u64 ,
7+ category : u32 ,
8+ }
9+
10+ struct CachePredictionDemo {
11+ sequential_data : Vec < DataPoint > ,
12+ random_data : Vec < DataPoint > ,
13+ size : usize ,
14+ }
15+
16+ impl CachePredictionDemo {
17+ fn new ( size : usize ) -> Self {
18+ let mut sequential_data: Vec < DataPoint > = ( 0 ..size)
19+ . map ( |i| DataPoint {
20+ value : i as f64 ,
21+ timestamp : i as u64 ,
22+ category : i as u32 % 10 ,
23+ } )
24+ . collect ( ) ;
25+
26+ // Create random access pattern
27+ let mut random_data = sequential_data. clone ( ) ;
28+ use std:: collections:: hash_map:: DefaultHasher ;
29+ use std:: hash:: { Hash , Hasher } ;
30+
31+ // Simple shuffle using hash-based swapping
32+ for i in 0 ..size {
33+ let mut hasher = DefaultHasher :: new ( ) ;
34+ i. hash ( & mut hasher) ;
35+ let j = ( hasher. finish ( ) as usize ) % size;
36+ random_data. swap ( i, j) ;
37+ }
38+
39+ Self {
40+ sequential_data,
41+ random_data,
42+ size,
43+ }
44+ }
45+
46+ // Cache-friendly: Sequential access pattern
47+ fn process_sequential ( & self ) -> ( f64 , std:: time:: Duration ) {
48+ let start = Instant :: now ( ) ;
49+ let mut sum = 0.0 ;
50+
51+ // Sequential access - cache prefetcher can predict next addresses
52+ for data_point in & self . sequential_data {
53+ sum += data_point. value ;
54+ // Simulate some computation
55+ if data_point. category % 2 == 0 {
56+ sum += data_point. timestamp as f64 * 0.1 ;
57+ }
58+ }
59+
60+ let duration = start. elapsed ( ) ;
61+ ( sum, duration)
62+ }
63+
64+ // Cache-unfriendly: Random access pattern
65+ fn process_random ( & self ) -> ( f64 , std:: time:: Duration ) {
66+ let start = Instant :: now ( ) ;
67+ let mut sum = 0.0 ;
68+
69+ // Random access - cache prefetcher cannot predict
70+ for data_point in & self . random_data {
71+ sum += data_point. value ;
72+ // Same computation as sequential version
73+ if data_point. category % 2 == 0 {
74+ sum += data_point. timestamp as f64 * 0.1 ;
75+ }
76+ }
77+
78+ let duration = start. elapsed ( ) ;
79+ ( sum, duration)
80+ }
81+
82+ // Matrix multiplication showing cache blocking optimization
83+ fn matrix_multiply_naive ( a : & [ Vec < f64 > ] , b : & [ Vec < f64 > ] ) -> Vec < Vec < f64 > > {
84+ let n = a. len ( ) ;
85+ let mut c = vec ! [ vec![ 0.0 ; n] ; n] ;
86+
87+ // Poor cache locality: accessing B column-wise
88+ for i in 0 ..n {
89+ for j in 0 ..n {
90+ for k in 0 ..n {
91+ c[ i] [ j] += a[ i] [ k] * b[ k] [ j] ; // b[k][j] = bad cache access
92+ }
93+ }
94+ }
95+ c
96+ }
97+
98+ fn matrix_multiply_cache_friendly ( a : & [ Vec < f64 > ] , b : & [ Vec < f64 > ] ) -> Vec < Vec < f64 > > {
99+ let n = a. len ( ) ;
100+ let mut c = vec ! [ vec![ 0.0 ; n] ; n] ;
101+
102+ // Better cache locality: reorder loops to access memory sequentially
103+ for i in 0 ..n {
104+ for k in 0 ..n {
105+ for j in 0 ..n {
106+ c[ i] [ j] += a[ i] [ k] * b[ k] [ j] ; // Better: a[i][k] stays in register
107+ }
108+ }
109+ }
110+ c
111+ }
112+
113+ fn benchmark_matrix_operations ( & self , size : usize ) {
114+ let matrix_a: Vec < Vec < f64 > > = ( 0 ..size)
115+ . map ( |i| ( 0 ..size) . map ( |j| ( i + j) as f64 ) . collect ( ) )
116+ . collect ( ) ;
117+
118+ let matrix_b: Vec < Vec < f64 > > = ( 0 ..size)
119+ . map ( |i| ( 0 ..size) . map ( |j| ( i * 2 + j) as f64 ) . collect ( ) )
120+ . collect ( ) ;
121+
122+ println ! ( "🔄 Matrix Multiplication Benchmark ({}x{}):" , size, size) ;
123+
124+ let start = Instant :: now ( ) ;
125+ let _ = Self :: matrix_multiply_naive ( & matrix_a, & matrix_b) ;
126+ let naive_time = start. elapsed ( ) ;
127+
128+ let start = Instant :: now ( ) ;
129+ let _ = Self :: matrix_multiply_cache_friendly ( & matrix_a, & matrix_b) ;
130+ let optimized_time = start. elapsed ( ) ;
131+
132+ println ! ( " Naive approach: {:?}" , naive_time) ;
133+ println ! ( " Cache-optimized: {:?}" , optimized_time) ;
134+ println ! ( " Speedup: {:.2}x" ,
135+ naive_time. as_nanos( ) as f64 / optimized_time. as_nanos( ) as f64 ) ;
136+ }
137+
138+ fn run_benchmarks ( & self ) {
139+ println ! ( "🧪 Cache Prediction Performance Analysis" ) ;
140+ println ! ( "Dataset size: {} elements ({:.2} MB)" ,
141+ self . size,
142+ ( self . size * std:: mem:: size_of:: <DataPoint >( ) ) as f64 / 1024.0 / 1024.0 ) ;
143+
144+ println ! ( "\n 📊 Memory Access Pattern Comparison:" ) ;
145+
146+ let ( seq_result, seq_time) = self . process_sequential ( ) ;
147+ let ( rand_result, rand_time) = self . process_random ( ) ;
148+
149+ println ! ( "🔄 Sequential Access (Cache-Friendly):" ) ;
150+ println ! ( " Result: {:.2}" , seq_result) ;
151+ println ! ( " Time: {:?}" , seq_time) ;
152+
153+ println ! ( "🎲 Random Access (Cache-Unfriendly):" ) ;
154+ println ! ( " Result: {:.2}" , rand_result) ;
155+ println ! ( " Time: {:?}" , rand_time) ;
156+
157+ let slowdown = rand_time. as_nanos ( ) as f64 / seq_time. as_nanos ( ) as f64 ;
158+ println ! ( "📈 Performance Impact:" ) ;
159+ println ! ( " Random access is {:.2}x slower" , slowdown) ;
160+ println ! ( " Cache prediction saves {:.1}% execution time" ,
161+ ( 1.0 - 1.0 /slowdown) * 100.0 ) ;
162+
163+ // Matrix multiplication demo
164+ println ! ( "\n " ) ;
165+ self . benchmark_matrix_operations ( 256 ) ;
166+
167+ println ! ( "\n 🎯 Key Insights:" ) ;
168+ println ! ( "• Hardware prefetchers predict sequential patterns automatically" ) ;
169+ println ! ( "• Random access patterns defeat cache prediction mechanisms" ) ;
170+ println ! ( "• Algorithm design should consider memory access patterns" ) ;
171+ println ! ( "• Cache-friendly code can be orders of magnitude faster" ) ;
172+ }
173+ }
174+
175+ fn main ( ) {
176+ // Test with different sizes to see cache effects
177+ let demo = CachePredictionDemo :: new ( 1_000_000 ) ; // ~24MB dataset
178+ demo. run_benchmarks ( ) ;
179+
180+ println ! ( "\n 💡 Cache Prediction Mechanisms Explained:" ) ;
181+ println ! ( "1. **Stride Prefetching**: Detects sequential access patterns" ) ;
182+ println ! ( "2. **Stream Prefetching**: Identifies multiple memory streams" ) ;
183+ println ! ( "3. **Temporal Prediction**: Recently accessed → likely to access again" ) ;
184+ println ! ( "4. **Spatial Prediction**: Nearby addresses → likely to access soon" ) ;
185+ }
0 commit comments