How nakulbhat/golicuda works
Purpose and Execution Model
golicuda is a native CUDA/C++ Conway’s Game of Life simulator. It runs either as an interactive GPU-rendered application or as a headless benchmark/simulation process. The executable entry point is src/main.cu, with shared application declarations in include/main.h.
Startup, CLI, and Configuration
Startup parses runtime choices for grid dimensions, generation limits, initialization, kernel mode, rendering, and synchronization. Command-line handling is isolated in src/args.cu / include/args.h; help output is in src/help.cu / include/help.h. These settings determine the simulation representation and dispatch path before GPU resources are initialized.
Simulation State and Initialization
The central state layer owns grid dimensions, active generation buffers, run/pause state, viewport data, and likely mode-specific resources. It is defined by src/state.cu and include/state.h. Initialization can populate the grid with GPU-generated random cells, explicit CLI cell coordinates, or an RLE pattern. Standard RLE parsing/loading is handled by src/rle.cu and include/rle.h, with glider.rle as a repository pattern input.
CUDA Compute Backend
src/cuda_functions.cu / include/cuda_functions.h contain the GPU-side simulation operations and kernel-dispatch boundary. Runtime selection supports element, row, column, shared-memory tiled, bitpacked, and atomic-bitpacked algorithms. All implement toroidal neighbor lookup and advance the board through ping-pong buffers: one device grid is read for a generation while the alternate grid receives its successor state, then buffer ownership swaps.
Representation Boundary
Byte-per-cell and 32-cells-per-word bitpacked modes are materially different data layouts. The state and CUDA layers must consistently select matching allocation, initialization, step kernel, and rendering logic. Bitpacked mode reduces device memory traffic; atomic bitpacked uses per-cell bit writes with CUDA atomics, making synchronization behavior part of the compute contract.
Rendering and Interactivity
The graphical path is implemented in src/render.cu / include/render.h. It integrates CUDA with an OpenGL pixel buffer object (PBO), allowing CUDA to write display pixels into GPU-shared graphics memory rather than copying through host memory. GLFW/GLEW and OpenGL 3.3 provide windowing, input, and presentation. The render loop processes pause, pan, zoom, reset, and VSync controls, then coordinates simulation stepping and frame presentation. Headless mode bypasses this graphics path.
Runtime and Build Dependencies
The project requires NVIDIA CUDA (sm_50+; Makefile defaults to sm_86), CUDA curand for random initialization, OpenGL 3.3+, GLFW3, and GLEW. Makefile is the primary native build entry point. Nix development/build metadata is also present in flake.nix and flake.lock.
Outputs and Measurement
Verbose interactive execution exposes FPS for kernel/render profiling; disabling VSync permits uncapped throughput measurements. Headless finite-generation runs provide a compute-focused execution path. Existing result artifacts, results/gens_power.csv and results/res_scaling.csv, indicate generation/power and resolution-scaling experiment outputs.
Main entry points: main.cu Application entry · state.cu Simulation state · cuda_functions.cu CUDA dispatch · args.cu CLI parser
Components 15
Build
- Native build · Builds the CUDA/C++ executable with the target GPU architecture.
Makefile - Nix environment
flake.nix
Startup & State
- Application entry · Selects interactive or headless execution.
src/main.cu - CLI parser · Parses dimensions, generation limits, initialization, kernel, rendering, and synchronization choices.
src/args.cu - CLI help
src/help.cu - Simulation state · Owns grid buffers, dimensions, run state, and viewport data.
src/state.cu - RLE loader
src/rle.cu
CUDA Simulation
- CUDA dispatch · Selects and launches matching layout-specific simulation operations.
src/cuda_functions.cu - Life kernels · Toroidal element, row, column, tiled, bitpacked, and atomic-bitpacked generation steps.
- Device ping-pong grids · Alternating source and destination generation buffers.
Interactive Rendering
- Render loop · Handles input, stepping, and presentation for interactive mode.
src/render.cu - CUDA/OpenGL PBO · CUDA writes display pixels directly into GPU-shared OpenGL memory.
- GLFW/GLEW/OpenGL · Provides windowing, input, and OpenGL 3.3 presentation.
Inputs & Results
- Glider pattern
glider.rle - Benchmark results · Generation/power and resolution-scaling measurements.
results/gens_power.csv
Connections 17
- Native build → Application entry: builds
- Nix environment → Native build: development environment
- Application entry → CLI parser: parses options
- CLI parser → CLI help: requests help
- CLI parser → Simulation state: configures
- Application entry → Simulation state: initializes
- Glider pattern → RLE loader: loads
- RLE loader → Simulation state: populates grid
- Simulation state → CUDA dispatch: selects representation and step mode
- CUDA dispatch → Life kernels: dispatches
- Life kernels → Device ping-pong grids: reads and writes generations
- CUDA dispatch → Simulation state: swaps active buffers
- Application entry → Render loop: interactive mode
- Render loop → CUDA dispatch: coordinates simulation steps
- Render loop → CUDA/OpenGL PBO: maps for CUDA pixels
- CUDA/OpenGL PBO → GLFW/GLEW/OpenGL: presents
- Application entry → Benchmark results: headless benchmark output