// ๐Ÿ”ฌ ์‹ค์ œ ํ•˜๋“œ์›จ์–ด AI ๋ฐ ํ…์„œ ์—ฐ์‚ฐ ์‹ค์ธก ๋ฒค์น˜๋งˆํฌ ์Šค์œ„ํŠธ (src/bin/run_ai_benchmarks.rs) use std::time::Instant; use rayon::prelude::*; use rand::Rng; fn main() { println!("============================================================"); println!(" ๐Ÿงช [์‹ค์ œ ๋กœ์ปฌ ํ•˜๋“œ์›จ์–ด] AI ๋ฐ ๋ณต์žก๊ณ„ ์„ฑ๋Šฅ ์‹ค์ธก ๋ฒค์น˜๋งˆํฌ"); println!("============================================================\n"); // ------------------------------------------------------------- // 1. ํ–‰๋ ฌ ๊ณฑ์…ˆ (Dense MatMul / GFLOPS ์ธก์ •) // ------------------------------------------------------------- println!("โ–ถ [ํ…Œ์ŠคํŠธ 1] ํ‘œ์ค€ ์‹ ๊ฒฝ๋ง ํ•ต์‹ฌ ์—ฐ์‚ฐ: 1024x1024 FP32 Dense MatMul"); let n = 1024; let mut rng = rand::thread_rng(); let a: Vec = (0..n * n).map(|_| rng.gen_range(-1.0..1.0)).collect(); let b: Vec = (0..n * n).map(|_| rng.gen_range(-1.0..1.0)).collect(); let mut c = vec![0.0f32; n * n]; // ์›Œ๋ฐ์—… for i in 0..10 { c[i] = a[i] * b[i]; } let start = Instant::now(); // ๋ณ‘๋ ฌ ํƒ€์ผ๋ง ํ–‰๋ ฌ ๊ณฑ์…ˆ c.par_chunks_mut(n).enumerate().for_each(|(i, row)| { for k in 0..n { let a_val = a[i * n + k]; for j in 0..n { row[j] += a_val * b[k * n + j]; } } }); let matmul_time = start.elapsed().as_secs_f64(); let total_flops = 2.0 * (n as f64) * (n as f64) * (n as f64); let gflops = (total_flops / matmul_time) / 1e9; println!(" โ””โ”€ ์†Œ์š” ์‹œ๊ฐ„: {:.4} ์ดˆ | ์‹ค์ธก ์—ฐ์‚ฐ๋ ฅ: {:.2} GFLOPS\n", matmul_time, gflops); // ------------------------------------------------------------- // 2. ์–ดํ…์…˜(Attention) ์—ฐ์‚ฐ ์‹œํ€€์Šค ๊ธธ์ด๋ณ„ ๋ ˆ์ดํ„ด์‹œ ์ธก์ • // ------------------------------------------------------------- println!("โ–ถ [ํ…Œ์ŠคํŠธ 2] ํŠธ๋žœ์Šคํฌ๋จธ Self-Attention O(N^2) ์‹œํ€€์Šค๋ณ„ ์ง€์—ฐ์‹œ๊ฐ„"); let d_head = 64; for &seq_len in &[512, 1024, 2048] { let q: Vec = (0..seq_len * d_head).map(|_| rng.gen_range(-1.0..1.0)).collect(); let k: Vec = (0..seq_len * d_head).map(|_| rng.gen_range(-1.0..1.0)).collect(); let start_att = Instant::now(); // Attention Score: Q * K^T (seq_len x seq_len) let _scores: Vec = (0..seq_len).into_par_iter().flat_map(|i| { let mut row = vec![0.0f32; seq_len]; let q_vec = &q[i * d_head..(i + 1) * d_head]; for j in 0..seq_len { let k_vec = &k[j * d_head..(j + 1) * d_head]; let mut dot = 0.0f32; for d in 0..d_head { dot += q_vec[d] * k_vec[d]; } row[j] = dot; } row }).collect(); let att_dur = start_att.elapsed().as_secs_f64() * 1000.0; println!(" โ””โ”€ ์‹œํ€€์Šค ๊ธธ์ด {:4} ํ† ํฐ: ๋ ˆ์ดํ„ด์‹œ {:.2} ms", seq_len, att_dur); } println!(); // ------------------------------------------------------------- // 3. BioPhys 8-State ๋ณต์žก๊ณ„ ์—”์ง„ 100๋งŒ ๋…ธ๋“œ ์Šค์ผ€์ผ๋ง ์ธก์ • // ------------------------------------------------------------- println!("โ–ถ [ํ…Œ์ŠคํŠธ 3] BioPhys 8-State ๋ณต์žก๊ณ„ ์—”์ง„ ์ฒ˜๋ฆฌ๋Ÿ‰ (์Šค์ผ€์ผ๋ณ„ ์‹ค์ธก)"); for &grid_size in &[256, 512, 1024] { let total_nodes = grid_size * grid_size; let bedrock: Vec = vec![0.1f32; total_nodes]; let mut topsoil: Vec = vec![0.5f32; total_nodes]; let start_engine = Instant::now(); for _ in 0..5 { let s = grid_size as i32; let next: Vec = (0..grid_size).into_par_iter().flat_map(|y| { let mut row = Vec::with_capacity(grid_size); for x in 0..grid_size { let idx = y * grid_size + x; let u = ((y as i32 - 1 + s) % s * s + x as i32) as usize; let d = ((y as i32 + 1) % s * s + x as i32) as usize; let l = (y as i32 * s + (x as i32 - 1 + s) % s) as usize; let r = (y as i32 * s + (x as i32 + 1) % s) as usize; let neighbor_e = (topsoil[u] + topsoil[d] + topsoil[l] + topsoil[r]) * 0.25; row.push(neighbor_e + bedrock[idx]); } row }).collect(); topsoil = next; } let dur = start_engine.elapsed().as_secs_f64(); let updates = (total_nodes as f64 * 5.0) / dur; println!(" โ””โ”€ ๊ฒฉ์ž {:4}x{:4} ({:7} ๋…ธ๋“œ): ์ฒ˜๋ฆฌ๋Ÿ‰ {:.2} MCell/sec", grid_size, grid_size, total_nodes, updates / 1e6); } println!("\n============================================================"); println!(" โœ… ์‹ค์ œ ๋กœ์ปฌ ํ•˜๋“œ์›จ์–ด ๋ฒค์น˜๋งˆํฌ ์ „ ํ•ญ๋ชฉ ์ธก์ • ์™„๋ฃŒ"); println!("============================================================"); }