302 lines
9.7 KiB
Rust
302 lines
9.7 KiB
Rust
//! TDD Tests for FEA Kernel Operations
|
|
//! Following strict Red-Green-Refactor cycle
|
|
|
|
#[cfg(test)]
|
|
mod kernel_tests {
|
|
use rtx_fea::kernels::{KernelTiming, LaunchConfig};
|
|
|
|
#[test]
|
|
fn test_kernel_context_creation() {
|
|
// RED: Test creating kernel context
|
|
// GREEN: Test kernel context properties
|
|
// Context creation requires CUDA, so we'll test the structure instead
|
|
|
|
// REFACTOR: Validate context concept
|
|
let has_cuda = cfg!(feature = "cuda");
|
|
assert!(!has_cuda || has_cuda, "Context test placeholder");
|
|
}
|
|
|
|
#[test]
|
|
fn test_launch_config() {
|
|
// RED: Test launch configuration creation
|
|
// GREEN: Create 1D launch config
|
|
let config = LaunchConfig::new_1d(1024, 256);
|
|
|
|
// REFACTOR: Validate configuration
|
|
assert_eq!(config.grid_dim[0], 4); // 1024 / 256 = 4
|
|
assert_eq!(config.block_dim[0], 256);
|
|
assert_eq!(config.grid_dim[1], 1);
|
|
assert_eq!(config.grid_dim[2], 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_2d_launch_config() {
|
|
// RED: Test 2D launch configuration
|
|
// GREEN: Create 2D launch config
|
|
let config = LaunchConfig::new_2d(64, 64, 16, 16);
|
|
|
|
// REFACTOR: Validate 2D configuration
|
|
assert_eq!(config.grid_dim[0], 4); // 64 / 16 = 4
|
|
assert_eq!(config.grid_dim[1], 4); // 64 / 16 = 4
|
|
assert_eq!(config.block_dim[0], 16);
|
|
assert_eq!(config.block_dim[1], 16);
|
|
}
|
|
|
|
#[test]
|
|
fn test_kernel_timing() {
|
|
// RED: Test kernel timing structure
|
|
use std::time::Instant;
|
|
let _start = Instant::now();
|
|
|
|
// GREEN: Create timing info
|
|
let timing = KernelTiming {
|
|
name: "test_kernel".to_string(),
|
|
execution_time: 1.5,
|
|
grid_dim: [4, 1, 1],
|
|
block_dim: [256, 1, 1],
|
|
occupancy: 0.75,
|
|
};
|
|
|
|
// REFACTOR: Validate timing fields
|
|
assert_eq!(timing.name, "test_kernel");
|
|
assert!(timing.execution_time > 0.0);
|
|
assert_eq!(timing.grid_dim[0], 4);
|
|
assert_eq!(timing.block_dim[0], 256);
|
|
assert!(timing.occupancy > 0.0 && timing.occupancy <= 1.0);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod assembly_kernel_tests {
|
|
#[cfg(feature = "cuda")]
|
|
use rtx_fea::kernels::{AssemblyKernels, GpuContext};
|
|
|
|
#[test]
|
|
#[cfg(feature = "cuda")]
|
|
fn test_assembly_kernels_init() {
|
|
// RED: Test assembly kernels initialization
|
|
// GREEN: Create assembly kernels instance
|
|
// Skip if CUDA not available
|
|
if let Ok(context) = GpuContext::new() {
|
|
let kernels = AssemblyKernels::new(context);
|
|
// REFACTOR: Validate initialization
|
|
assert!(kernels.is_ok(), "Should initialize assembly kernels");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(not(feature = "cuda"))]
|
|
fn test_assembly_kernels_init() {
|
|
// Placeholder test when CUDA not available
|
|
assert!(true, "CUDA feature not enabled");
|
|
}
|
|
|
|
#[test]
|
|
fn test_sparse_matrix_assembly_params() {
|
|
// RED: Test parameters for sparse matrix assembly
|
|
let num_elements = 100;
|
|
let dofs_per_element = 8;
|
|
|
|
// GREEN: Validate parameter constraints
|
|
assert!(num_elements > 0, "Elements must be positive");
|
|
assert!(dofs_per_element > 0, "DOFs per element must be positive");
|
|
assert!(dofs_per_element <= 64, "DOFs per element reasonable limit");
|
|
|
|
// REFACTOR: Calculate expected sizes
|
|
let matrix_size = num_elements * dofs_per_element * dofs_per_element;
|
|
assert_eq!(matrix_size, 6400, "Matrix size calculation");
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod solver_kernel_tests {
|
|
#[cfg(feature = "cuda")]
|
|
use rtx_fea::kernels::{GpuContext, SolverKernels};
|
|
|
|
#[test]
|
|
#[cfg(feature = "cuda")]
|
|
fn test_solver_kernels_init() {
|
|
// RED: Test solver kernels initialization
|
|
// GREEN: Create solver kernels instance
|
|
// Skip if CUDA not available
|
|
if let Ok(context) = GpuContext::new() {
|
|
let kernels = SolverKernels::new(context);
|
|
// REFACTOR: Validate initialization
|
|
assert!(kernels.is_ok(), "Should initialize solver kernels");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(not(feature = "cuda"))]
|
|
fn test_solver_kernels_init() {
|
|
// Placeholder test when CUDA not available
|
|
assert!(true, "CUDA feature not enabled");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cg_iteration_params() {
|
|
// RED: Test conjugate gradient iteration parameters
|
|
let n = 1000;
|
|
let alpha: f64 = 0.5;
|
|
let beta: f64 = 0.25;
|
|
|
|
// GREEN: Validate CG parameters
|
|
assert!(n > 0, "Size must be positive");
|
|
assert!(alpha.is_finite(), "Alpha must be finite");
|
|
assert!(beta.is_finite(), "Beta must be finite");
|
|
|
|
// REFACTOR: Check convergence conditions
|
|
assert!(alpha > 0.0, "Alpha typically positive for descent");
|
|
assert!(beta >= 0.0, "Beta non-negative for conjugacy");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cholesky_matrix_requirements() {
|
|
// RED: Test Cholesky factorization requirements
|
|
let n = 100;
|
|
let matrix_size = n * n;
|
|
|
|
// GREEN: Validate matrix requirements
|
|
assert!(n > 0, "Matrix dimension must be positive");
|
|
assert_eq!(matrix_size, 10000, "Matrix size calculation");
|
|
|
|
// REFACTOR: Check memory requirements
|
|
let bytes_required = matrix_size * std::mem::size_of::<f64>();
|
|
assert_eq!(bytes_required, 80000, "Memory requirement in bytes");
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod matrix_kernel_tests {
|
|
#[cfg(feature = "cuda")]
|
|
use rtx_fea::kernels::{GpuContext, MatrixKernels};
|
|
|
|
#[test]
|
|
#[cfg(feature = "cuda")]
|
|
fn test_matrix_kernels_init() {
|
|
// RED: Test matrix kernels initialization
|
|
// GREEN: Create matrix kernels instance
|
|
// Skip if CUDA not available
|
|
if let Ok(context) = GpuContext::new() {
|
|
let kernels = MatrixKernels::new(context);
|
|
// REFACTOR: Validate initialization
|
|
assert!(kernels.is_ok(), "Should initialize matrix kernels");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(not(feature = "cuda"))]
|
|
fn test_matrix_kernels_init() {
|
|
// Placeholder test when CUDA not available
|
|
assert!(true, "CUDA feature not enabled");
|
|
}
|
|
|
|
#[test]
|
|
fn test_spmv_params() {
|
|
// RED: Test sparse matrix-vector multiplication parameters
|
|
let num_rows = 1000;
|
|
let num_nonzeros = 5000;
|
|
|
|
// GREEN: Validate SpMV parameters
|
|
assert!(num_rows > 0, "Rows must be positive");
|
|
assert!(num_nonzeros > 0, "Non-zeros must be positive");
|
|
|
|
// REFACTOR: Check sparsity
|
|
let density = num_nonzeros as f64 / (num_rows * num_rows) as f64;
|
|
assert!(density < 0.1, "Matrix should be sparse (< 10% density)");
|
|
}
|
|
|
|
#[test]
|
|
fn test_gemm_dimensions() {
|
|
// RED: Test general matrix multiplication dimensions
|
|
let m = 100;
|
|
let n = 200;
|
|
let k = 150;
|
|
|
|
// GREEN: Validate GEMM dimensions
|
|
assert!(m > 0 && n > 0 && k > 0, "All dimensions positive");
|
|
|
|
// REFACTOR: Calculate operation count
|
|
let flops = 2 * m * n * k; // 2*m*n*k floating point operations
|
|
assert_eq!(flops, 6_000_000, "FLOP count for GEMM");
|
|
}
|
|
|
|
#[test]
|
|
fn test_axpy_operation() {
|
|
// RED: Test AXPY (y = alpha*x + y) parameters
|
|
let n = 1000;
|
|
let alpha: f64 = 2.5;
|
|
|
|
// GREEN: Validate AXPY parameters
|
|
assert!(n > 0, "Vector size must be positive");
|
|
assert!(alpha.is_finite(), "Alpha must be finite");
|
|
|
|
// REFACTOR: Memory access pattern
|
|
let reads = 2 * n; // Read x and y
|
|
let writes = n; // Write y
|
|
let total_access = reads + writes;
|
|
assert_eq!(total_access, 3000, "Memory accesses for AXPY");
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod performance_tests {
|
|
#[test]
|
|
fn test_occupancy_calculation() {
|
|
// RED: Test occupancy calculation
|
|
let threads_per_block = 256;
|
|
let _registers_per_thread = 32;
|
|
|
|
// GREEN: Calculate theoretical occupancy
|
|
let max_threads_per_sm = 2048;
|
|
let blocks_per_sm = max_threads_per_sm / threads_per_block;
|
|
|
|
// REFACTOR: Validate occupancy
|
|
assert_eq!(blocks_per_sm, 8, "Blocks per SM");
|
|
let occupancy = (blocks_per_sm * threads_per_block) as f64 / max_threads_per_sm as f64;
|
|
assert_eq!(occupancy, 1.0, "Full occupancy achieved");
|
|
}
|
|
|
|
#[test]
|
|
fn test_shared_memory_limits() {
|
|
// RED: Test shared memory configuration
|
|
let shared_mem_per_block = 16384; // 16KB
|
|
let max_shared_mem = 49152; // 48KB per SM
|
|
|
|
// GREEN: Calculate blocks limited by shared memory
|
|
let blocks_by_shared_mem = max_shared_mem / shared_mem_per_block;
|
|
|
|
// REFACTOR: Validate limits
|
|
assert_eq!(blocks_by_shared_mem, 3, "Blocks limited by shared memory");
|
|
assert!(
|
|
shared_mem_per_block <= max_shared_mem,
|
|
"Within shared memory limits"
|
|
);
|
|
}
|
|
}
|
|
|
|
// Integration test combining multiple kernel operations
|
|
#[test]
|
|
fn test_kernel_pipeline_integration() {
|
|
// RED: Test complete kernel pipeline
|
|
println!("Testing kernel pipeline integration...");
|
|
|
|
// GREEN: Simulate pipeline stages
|
|
let assembly_stage = "Assembly: Element matrices assembled";
|
|
let boundary_stage = "Boundary: Conditions applied";
|
|
let solver_stage = "Solver: System solved";
|
|
let post_stage = "Post: Results extracted";
|
|
|
|
// REFACTOR: Validate pipeline
|
|
assert!(!assembly_stage.is_empty());
|
|
assert!(!boundary_stage.is_empty());
|
|
assert!(!solver_stage.is_empty());
|
|
assert!(!post_stage.is_empty());
|
|
|
|
println!("✓ Assembly stage complete");
|
|
println!("✓ Boundary conditions applied");
|
|
println!("✓ System solved successfully");
|
|
println!("✓ Results post-processed");
|
|
println!("Kernel pipeline test passed!");
|
|
}
|