mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-19 01:48:47 +00:00
feat(demos): Add GPU-only demonstration (simplified single-GPU test)
New 203-line GPU-only demonstration (simplified without MPI complexity): Setup and validation (lines 1-52): - Checks for CUDA availability, exits if not found - Reports GPU model and memory - Sets up problem: 10000 nodes, 1000 elements - Type-stable data: nodes (Float64), connectivity (Int), E, ν GPU kernel (lines 54-120): - assemble_element_kernel! for CUDA - Type-stable: Float64, Int32, CuDeviceMatrix/Vector - No allocations in kernel - Computes simplified assembly: K_local = E * (1-ν²) Execution (lines 122-170): - Transfers data to GPU (nodes, connectivity) - Reports bytes transferred - Launches kernel with thread blocks - Transfers results back from GPU Verification (lines 172-203): - Compares computed vs expected values - Reports success/failure - Key achievements summary: * Type-stable kernel compiled * Fast GPU memory transfer (typed arrays) * Zero allocations in kernel - Why it matters: Dict-based storage CANNOT compile for GPU - Conclusion: type stability required for modern HPC Purpose: Simpler test than full MPI version, focuses on GPU capability Run: julia demos/gpu_only_demo.jl (requires CUDA GPU)
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env julia
|
||||
#
|
||||
# GPU-Only Demonstration (No MPI Required)
|
||||
#
|
||||
# Demonstrates that type-stable field data can execute on real CUDA GPU.
|
||||
# Simpler than full GPU+MPI demo - just shows GPU capability.
|
||||
#
|
||||
|
||||
using LinearAlgebra
|
||||
|
||||
println("="^70)
|
||||
println("GPU Type-Stable Kernel Demonstration")
|
||||
println("="^70)
|
||||
println()
|
||||
|
||||
# Try to load CUDA
|
||||
CUDA_AVAILABLE = false
|
||||
try
|
||||
@eval using CUDA
|
||||
if CUDA.functional()
|
||||
global CUDA_AVAILABLE = true
|
||||
println("✅ CUDA GPU detected: $(CUDA.name(CUDA.device()))")
|
||||
println(" Memory: $(CUDA.totalmem(CUDA.device()) ÷ 10^9) GB")
|
||||
println()
|
||||
else
|
||||
println("❌ CUDA.jl loaded but no functional GPU detected")
|
||||
exit(1)
|
||||
end
|
||||
catch e
|
||||
println("❌ CUDA.jl not available: $e")
|
||||
println(" Install with: using Pkg; Pkg.add(\"CUDA\")")
|
||||
exit(1)
|
||||
end
|
||||
|
||||
println("="^70)
|
||||
println("Demonstration: Type-Stable Assembly Kernel")
|
||||
println("="^70)
|
||||
println()
|
||||
|
||||
# Problem setup
|
||||
n_nodes = 10000
|
||||
n_elements = 1000
|
||||
|
||||
println("Setup:")
|
||||
println(" Nodes: $n_nodes")
|
||||
println(" Elements: $n_elements")
|
||||
println()
|
||||
|
||||
# Type-stable data structures
|
||||
nodes = rand(Float64, 3, n_nodes)
|
||||
connectivity = rand(1:n_nodes, 8, n_elements)
|
||||
E = 210e3 # Young's modulus
|
||||
ν = 0.3 # Poisson's ratio
|
||||
|
||||
println("Data types (type-stable):")
|
||||
println(" nodes: $(typeof(nodes))")
|
||||
println(" connectivity: $(typeof(connectivity))")
|
||||
println(" E: $(typeof(E))")
|
||||
println(" ν: $(typeof(ν))")
|
||||
println()
|
||||
|
||||
# Define GPU kernel
|
||||
function assemble_element_kernel!(
|
||||
K_elements::CuDeviceMatrix{Float64},
|
||||
nodes::CuDeviceMatrix{Float64},
|
||||
connectivity::CuDeviceMatrix{Int32},
|
||||
E::Float64,
|
||||
ν::Float64,
|
||||
n_elements::Int32
|
||||
)
|
||||
# GPU thread indexing
|
||||
idx = (blockIdx().x - 1) * blockDim().x + threadIdx().x
|
||||
|
||||
if idx <= n_elements
|
||||
# Type-stable access to element data
|
||||
# In real FEM: would integrate over Gauss points
|
||||
# Here: simplified computation to demonstrate GPU execution
|
||||
|
||||
# Mock stiffness calculation
|
||||
K_local = E * (1 - ν^2)
|
||||
|
||||
# Store result
|
||||
K_elements[idx, 1] = K_local
|
||||
end
|
||||
|
||||
return nothing
|
||||
end
|
||||
|
||||
println("="^70)
|
||||
println("Step 1: Transfer Data to GPU")
|
||||
println("="^70)
|
||||
println()
|
||||
|
||||
# Calculate sizes
|
||||
nodes_bytes = sizeof(nodes)
|
||||
conn_bytes = sizeof(connectivity)
|
||||
total_bytes = nodes_bytes + conn_bytes
|
||||
|
||||
println("Transferring to GPU:")
|
||||
println(" nodes: $(nodes_bytes ÷ 1024) KB")
|
||||
println(" connectivity: $(conn_bytes ÷ 1024) KB")
|
||||
println(" Total: $(total_bytes ÷ 1024) KB")
|
||||
println()
|
||||
|
||||
# Transfer to GPU
|
||||
d_nodes = CuArray(nodes)
|
||||
d_connectivity = CuArray(Int32.(connectivity))
|
||||
d_K_elements = CUDA.zeros(Float64, n_elements, 64)
|
||||
|
||||
println("✅ Data on GPU")
|
||||
println()
|
||||
|
||||
println("="^70)
|
||||
println("Step 2: Launch GPU Kernel")
|
||||
println("="^70)
|
||||
println()
|
||||
|
||||
# Kernel launch configuration
|
||||
threads_per_block = 256
|
||||
blocks = cld(n_elements, threads_per_block)
|
||||
|
||||
println("Kernel configuration:")
|
||||
println(" Threads per block: $threads_per_block")
|
||||
println(" Blocks: $blocks")
|
||||
println(" Total threads: $(blocks * threads_per_block)")
|
||||
println()
|
||||
|
||||
println("Launching kernel...")
|
||||
@cuda threads = threads_per_block blocks = blocks assemble_element_kernel!(
|
||||
d_K_elements, d_nodes, d_connectivity, E, ν, Int32(n_elements)
|
||||
)
|
||||
|
||||
# Wait for completion
|
||||
CUDA.synchronize()
|
||||
|
||||
println("✅ Kernel executed successfully")
|
||||
println()
|
||||
|
||||
println("="^70)
|
||||
println("Step 3: Transfer Results from GPU")
|
||||
println("="^70)
|
||||
println()
|
||||
|
||||
K_elements = Array(d_K_elements)
|
||||
result_bytes = sizeof(K_elements)
|
||||
|
||||
println("Transferred from GPU:")
|
||||
println(" Results: $(result_bytes ÷ 1024) KB")
|
||||
println()
|
||||
|
||||
println("="^70)
|
||||
println("Step 4: Verify Results")
|
||||
println("="^70)
|
||||
println()
|
||||
|
||||
expected_value = E * (1 - ν^2)
|
||||
actual_values = K_elements[:, 1]
|
||||
all_match = all(abs.(actual_values .- expected_value) .< 1e-10)
|
||||
|
||||
println("Verification:")
|
||||
println(" Expected value: $expected_value")
|
||||
println(" First result: $(actual_values[1])")
|
||||
println(" All elements match: $(all_match ? "✅" : "❌")")
|
||||
println()
|
||||
|
||||
if all_match
|
||||
println("="^70)
|
||||
println("✅ SUCCESS: Type-Stable GPU Kernel Executed Correctly")
|
||||
println("="^70)
|
||||
println()
|
||||
println("Key Achievements:")
|
||||
println()
|
||||
println("1. Type-stable kernel compiled for GPU")
|
||||
println(" - All parameters have concrete types (Float64, Int32)")
|
||||
println(" - No Dict{String,Any} or runtime dispatch")
|
||||
println(" - Compiler generated optimized GPU machine code")
|
||||
println()
|
||||
println("2. Fast GPU memory transfer")
|
||||
println(" - Typed arrays transferred as contiguous buffers")
|
||||
println(" - No serialization overhead")
|
||||
println(" - Same pattern works for MPI communication")
|
||||
println()
|
||||
println("3. Zero allocations in kernel")
|
||||
println(" - All arrays pre-allocated")
|
||||
println(" - In-place operations only")
|
||||
println(" - Required for GPU execution")
|
||||
println()
|
||||
println("Why This Matters:")
|
||||
println()
|
||||
println("• Dict{String,Any} field storage CANNOT compile for GPU")
|
||||
println(" - Compiler error: cannot determine types")
|
||||
println(" - Would prevent any GPU acceleration")
|
||||
println()
|
||||
println("• Type-stable storage (Matrix{Float64}) works everywhere:")
|
||||
println(" - CPU: 9-92× faster (measured)")
|
||||
println(" - GPU: Enables execution (demonstrated)")
|
||||
println(" - MPI: Fast transfers (same pattern)")
|
||||
println()
|
||||
println("Conclusion: Type stability is not optional for modern HPC")
|
||||
println("="^70)
|
||||
else
|
||||
println("❌ FAILED: Results don't match expected values")
|
||||
end
|
||||
Reference in New Issue
Block a user