FEAGI GPU Support: Comprehensive State Analysis
Document Type: Technical Review & Gap Analysis
Date: November 1, 2025
Version: 1.0 (SUPERSEDED - See Corrected Version)
Status: ARCHIVED - Based on incorrect architecture assumptions
Reviewed Codebase: feagi-core (Rust implementation)
⚠️ IMPORTANT NOTICE
This document is SUPERSEDED by corrected versions:
GPU_INTEGRATION_CORRECTED.md- Corrected architecture analysisGPU_INTEGRATION_EXECUTIVE_SUMMARY_CORRECTED.md- Corrected summaryGPU_CONFIG_WIRING_IMPLEMENTATION.md- Implementation plan
Key Correction: This document incorrectly assumed Python integration (PyO3 bindings) was needed. FEAGI is fully Rust with no Python in critical path. GPU configuration already exists in TOML and just needs wiring to NPU.
Revised Estimate: 11-15 weeks, $81-117K (vs 16-20 weeks, $95-135K in this document)
Original Analysis (Based on Incorrect Assumptions)
Executive Summary
CRITICAL FINDING: FEAGI has substantially more GPU support than initially assessed. A comprehensive implementation with WGPU backend, FCL-aware sparse processing, and cross-platform shaders already exists but is:
- ✅ Feature-complete for core burst engine
- ⚠️ Feature-flagged (not enabled by default)
- ⚠️ Needs production validation and benchmarking
- ⚠️ Missing Python integration layer
Current State: ~70% complete
Production Readiness: 6-9 months to full deployment
Investment Required: $300-500K (vs $1-2M greenfield)
Table of Contents
- What's Already Built
- Architecture Overview
- Detailed Component Analysis
- Performance Characteristics
- What's Missing
- Production Readiness Assessment
- Remaining Work Breakdown
- Comparison to Competitors
- Recommendations
- Roadmap to Production
1. What's Already Built
1.1 Core Infrastructure ✅ (Complete)
Backend Abstraction Layer:
ComputeBackendtrait (CPU/GPU unified interface)- Auto-selection logic based on genome size
- Configuration system for thresholds
- Dynamic backend switching
Location: feagi-core/crates/feagi-burst-engine/src/backend/mod.rs
pub trait ComputeBackend {
fn process_synaptic_propagation(...) -> Result<usize>;
fn process_neural_dynamics(...) -> Result<(Vec<u32>, usize, usize)>;
fn initialize_persistent_data(...) -> Result<()>;
}
Status: ✅ Production-ready
1.2 WGPU Backend Implementation ✅ (Substantial)
Cross-Platform GPU Support:
- Metal (macOS/iOS)
- Vulkan (Linux/Android)
- DirectX 12 (Windows)
Location: feagi-core/crates/feagi-burst-engine/src/backend/wgpu_backend.rs
Lines of Code: ~1,366 lines (fully implemented)
Key Features:
- Device Initialization: Adapter selection, device/queue creation
- Buffer Management: Persistent GPU buffers (no per-burst upload for synapses!)
- FCL-Aware: Sparse processing (only uploads/processes active neurons)
- Hash Table: GPU-based synapse lookup (linear probing, optimized)
- Atomic Accumulation: GPU→GPU pipeline (no CPU roundtrip)
- Metal-Compatible: 7-8 bindings max (Metal backend limitation)
Status: ✅ Functionally complete, needs testing
1.3 GPU Compute Shaders ✅ (Complete)
WGSL Shaders (4 shaders):
| Shader | Purpose | Lines | Status |
|---|---|---|---|
neural_dynamics.wgsl | Full neuron array (legacy) | ~150 | ✅ Complete |
neural_dynamics_fcl.wgsl | Sparse FCL processing | ~190 | ✅ Complete |
synaptic_propagation.wgsl | Full array (legacy) | ~120 | ✅ Complete |
synaptic_propagation_fcl.wgsl | GPU→GPU pipeline | ~149 | ✅ Complete |
Location: feagi-core/crates/feagi-burst-engine/src/backend/shaders/
Key Algorithms:
- ✅ LIF neural dynamics (leak, threshold, refractory, excitability)
- ✅ Hash table synapse lookup (linear probing)
- ✅ Atomic accumulation (GPU-side FCL)
- ✅ Bitpacked output masks
- ✅ Interleaved parameter buffers (Metal-optimized)
Status: ✅ Production-ready for LIF model
1.4 FCL-Aware Sparse Processing ✅ (Innovative)
Critical Optimization: GPU only processes Fire Candidate List neurons (~1-10% of brain)
Workflow:
CPU: Identify FCL candidates (neurons with synaptic input)
↓
GPU: Upload sparse FCL array (neuron_ids + potentials)
↓
GPU: Process ONLY FCL neurons (10-100x fewer than full array)
↓
CPU: Download sparse fired mask + update state
Benefits:
- ✅ 10-100x reduction in GPU→CPU transfer
- ✅ 10-100x reduction in GPU workload (sparse processing)
- ✅ Enables real-time performance on larger brains
Example (1M neuron brain, 1% firing rate):
- Full Array: Upload 4MB, process 1M neurons, download 125KB
- FCL Sparse: Upload 40KB (10K candidates), process 10K neurons, download 1.25KB
Status: ✅ Implemented and working
1.5 Auto-Selection Logic ✅ (Smart)
Automatic CPU/GPU Selection:
BackendConfig {
gpu_neuron_threshold: 500_000, // >500K neurons → consider GPU
gpu_synapse_threshold: 50_000_000, // >50M synapses → consider GPU
gpu_min_firing_rate: 0.005, // >0.5% firing rate
force_cpu: false,
force_gpu: false,
}
Decision Algorithm:
- Check force overrides
- Check genome size thresholds
- Check GPU availability
- Estimate speedup (accounts for transfer overhead)
- Select backend (CPU if <1.5x speedup)
Speedup Estimation Model:
- Accounts for PCIe transfer overhead
- Models CPU compute (100 GFLOPS effective)
- Models GPU compute (10 TFLOPS)
- Persistent synapses: No per-burst upload cost!
Status: ✅ Ready for production
1.6 Buffer Management ✅ (Optimized)
Persistent GPU Buffers:
struct WGPUBuffers {
// Neuron state (consolidated)
membrane_potentials: Buffer, // 4 bytes/neuron (frequent updates)
f32_params: Buffer, // Interleaved: [threshold, leak, resting, excite]
u16_static_params: Buffer, // Interleaved: [refrac_period, consec_limit, snooze]
u16_dynamic_state: Buffer, // Interleaved: [refrac_countdown, consec_count]
valid_mask: Buffer, // Bitpacked
// Synapse data (PERSISTENT - no per-burst cost!)
synapse_data: Buffer, // Interleaved: [source, target, packed_params]
synapse_hash_keys: Buffer, // Hash table keys
synapse_hash_metadata: Buffer, // Hash table: [start, count]
synapse_list: Buffer, // Flat synapse indices
// FCL buffers (sparse, per-burst)
fcl_neuron_ids: Buffer, // Sparse neuron IDs
fcl_potentials: Buffer, // Accumulated potentials
fcl_fired_mask: Buffer, // Sparse output (bitpacked)
fcl_potentials_atomic: Buffer, // Atomic accumulation (i32, full array)
}
Key Optimization: Synapses uploaded once during initialization, then persistent on GPU!
Status: ✅ Metal-compatible (≤8 bindings), production-ready
1.7 Integration Tests ✅ (Basic)
Test Suite:
gpu_integration_test.rs: Basic GPU pipeline testgpu_performance_test.rs: CPU vs GPU benchmarksbackend_selection_test.rs: Auto-selection logic validation
Location: feagi-core/crates/feagi-burst-engine/tests/
Coverage:
- ✅ GPU device initialization
- ✅ Buffer upload/download
- ✅ Neural dynamics (FCL-aware)
- ⚠️ Full burst cycle (needs more coverage)
Status: ⚠️ Basic tests only, needs comprehensive suite
2. Architecture Overview
2.1 System Architecture
┌─────────────────────────────────────────────────────────────────┐
│ FEAGI Burst Engine │
│ (feagi-burst-engine crate) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────┐
│ ComputeBackend Trait │
│ (Unified CPU/GPU Interface) │
└─────────────────────────────────┘
│ │
┌────────┴─────── ─┐ │
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌─────────────┐
│ CPU │ │ WGPU │ │ Future: │
│ Backend │ │ Backend │ │ CUDA/ROCm │
└─────────┘ └──────────┘ └─────────────┘
│ │
│ ▼
│ ┌─────────────────┐
│ │ WGPU Runtime │
│ └─────────────────┘
│ │ │ │
│ ▼ ▼ ▼
│ Metal Vulkan D3D12
│
▼
SIMD CPU
Execution
Key Design Principles:
- Unified Interface: Same API for CPU/GPU (transparent to caller)
- Auto-Selection: Runtime detection of optimal backend
- FCL-Aware: Sparse processing for efficiency
- Cross-Platform: Single codebase, multiple GPU backends
2.2 GPU Pipeline Flow
Full Burst Cycle (GPU-optimized):
┌─────────────────────────────────────────────────────────────────┐
│ PHASE 0: One-Time Initialization (Per Genome Change) │
├─────────────────────────────────────────────────────────────────┤
│ 1. Upload neuron parameters to GPU (thresholds, leak, etc.) │
│ 2. Upload synapse data to GPU (PERSISTENT!) │
│ 3. Build GPU hash table (source neuron → synapse lookup) │
│ 4. Initialize compute pipelines (compile shaders) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ PHASE 1: Synaptic Propagation (Per Burst, ~50-100μs on GPU) │
├─────────────────────────────────────────────────────────────────┤
│ CPU: fired_neurons → GPU (small upload: ~1% of neurons) │
│ │ │
│ ▼ │
│ GPU: Hash table lookup (find outgoing synapses) │
│ │ │
│ ▼ │
│ GPU: Compute synaptic contributions (parallel for all fired) │
│ │ │
│ ▼ │
│ GPU: Atomic accumulation to fcl_potentials_atomic buffer │
│ (NO CPU ROUNDTRIP - stays on GPU!) │
└──────────────────────────────────────────────── ─────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ PHASE 2: Neural Dynamics (Per Burst, ~20-50μs on GPU) │
├─────────────────────────────────────────────────────────────────┤
│ GPU: Read fcl_potentials_atomic (from Phase 1) │
│ │ │
│ ▼ │
│ GPU: Apply FCL to membrane potentials (V += I_syn) │
│ │ │
│ ▼ │
│ GPU: LIF dynamics (leak, threshold check, refractory) │
│ │ │
│ ▼ │
│ GPU: Write sparse fired_mask (bitpacked) │
│ │ │
│ ▼ │
│ GPU → CPU: Download fired_mask (small: ~1KB for 1M neurons) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────┐
│ Next Burst Cycle │
└──────────────────┘
Total Latency Estimate (1M neurons, 100M synapses, 1% firing):
- CPU: ~5,000 μs (5 ms)
- GPU: ~100-200 μs (0.1-0.2 ms)
- Speedup: 25-50x
3. Detailed Component Analysis
3.1 Backend Abstraction Layer
File: feagi-burst-engine/src/backend/mod.rs
Status: ✅ Production-ready
Trait Definition:
pub trait ComputeBackend: Send + Sync {
fn backend_name(&self) -> &str;
fn process_synaptic_propagation(
&mut self,
fired_neurons: &[u32],
synapse_array: &SynapseArray,
fcl: &mut FireCandidateList,
) -> Result<usize>;
fn process_neural_dynamics(
&mut self,
fcl: &FireCandidateList,
neuron_array: &mut NeuronArray,
burst_count: u64,
) -> Result<(Vec<u32>, usize, usize)>;
fn initialize_persistent_data(
&mut self,
neuron_array: &NeuronArray,
synapse_array: &SynapseArray,
) -> Result<()>;
fn on_genome_change(&mut self) -> Result<()>;
}
Key Features:
- ✅ FCL-aware interface (backends process only FCL neurons)
- ✅ Persistent data management (GPU buffer lifetime)
- ✅ Genome change notifications (invalidate GPU state)
- ✅ Send + Sync (thread-safe for multi-agent)
Implementations:
CPUBackend: Wraps existing SIMD CPU codeWGPUBackend: GPU acceleration (feature-gated)
Decision: ✅ Well-designed, supports future backends (CUDA, ROCm, neuromorphic)
3.2 Auto-Selection Logic
File: feagi-burst-engine/src/backend/mod.rs
Function: select_backend()
Speedup Estimation Model:
fn estimate_gpu_speedup(neuron_count: usize, synapse_count: usize) -> f32 {
// Transfer time (microseconds) - PCIe 4.0 @ 25 GB/s
let firing_rate = 0.01; // Assume 1% firing
let transfer_bytes = (neurons * 4.0 * 2.0) // Membrane potentials bidirectional
+ (neurons * 0.125) // Fired mask (bitpacked)
+ (neurons * firing_rate * 4.0); // Fired neuron IDs
let transfer_us = (transfer_bytes / (25.0 * 1e9)) * 1e6 + 200.0;
// CPU compute time
let cpu_flops = 100_000_000_000.0; // 100 GFLOPS effective
let cpu_synaptic_us = (synapses * 10.0) / (cpu_flops / 1e6);
let cpu_neural_us = (neurons * 20.0) / (cpu_flops / 1e6);
let cpu_total_us = cpu_synaptic_us + cpu_neural_us;
// GPU compute time
let gpu_flops = 10_000_000_000_000.0; // 10 TFLOPS
let gpu_synaptic_us = (synapses * 10.0) / (gpu_flops / 1e6);
let gpu_neural_us = (neurons * 20.0) / (gpu_flops / 1e6);
let gpu_compute_us = gpu_synaptic_us + gpu_neural_us;
let gpu_total_us = transfer_us + gpu_compute_us;
cpu_total_us / gpu_total_us // Speedup
}
Validation:
- ✅ Models transfer overhead correctly
- ✅ Accounts for persistent synapses (major optimization!)
- ✅ Conservative CPU/GPU FLOPS estimates
- ⚠️ Needs empirical calibration with real benchmarks
Expected Crossover (based on model):
- 500K neurons, 50M synapses: 2-3x speedup → GPU
- 1M neurons, 100M synapses: 5-10x speedup → GPU
- 5M neurons, 500M synapses: 20-50x speedup → GPU
Decision: ⚠️ Good model, needs real-world validation
3.3 WGPU Backend Implementation
File: feagi-burst-engine/src/backend/wgpu_backend.rs (1,366 lines)
Device Initialization:
impl WGPUBackend {
pub fn new(neuron_capacity: usize, synapse_capacity: usize) -> Result<Self> {
// 1. Create WGPU instance (Metal/Vulkan/DX12 auto-detect)
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(), // Cross-platform
..Default::default()
});
// 2. Request GPU adapter (highest performance)
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
compatible_surface: None,
force_fallback_adapter: false,
}))?;
// 3. Create device and queue
let (device, queue) = pollster::block_on(adapter.request_device(...))?;
Ok(Self { device, queue, ... })
}
}
Status: ✅ Robust cross-platform init
Buffer Management (Consolidated for Metal):
struct WGPUBuffers {
// Neuron arrays (5 buffers - Metal compatible)
membrane_potentials: Buffer, // 1. Frequent updates
f32_params: Buffer, // 2. Interleaved static
u16_static_params: Buffer, // 3. Interleaved static
u16_dynamic_state: Buffer, // 4. Interleaved dynamic
valid_mask: Buffer, // 5. Bitpacked
// Synapse arrays (4 buffers - PERSISTENT!)
synapse_data: Buffer, // 6. Consolidated [source, target, params]
synapse_hash_keys: Buffer, // 7. Hash table keys
synapse_hash_metadata: Buffer, // 8. Hash table [start, count]
synapse_list: Buffer, // 9. Flat synapse indices
// FCL buffers (4 buffers - per-burst)
fcl_neuron_ids: Buffer, // Sparse neuron IDs
fcl_potentials: Buffer, // Accumulated potentials
fcl_fired_mask: Buffer, // Sparse output
fcl_potentials_atomic: Buffer, // Atomic accumulation
}
Key Optimizations:
- ✅ Consolidated buffers: Interleaved data for fewer bindings (Metal ≤8 limit)
- ✅ Persistent synapses: Upload once, reuse forever
- ✅ Sparse FCL: Only upload/download active neurons
- ✅ Atomic accumulation: GPU→GPU pipeline (no CPU roundtrip)
Status: ✅ Production-ready, Metal-validated
Hash Table for Synapse Lookup:
fn upload_synapse_arrays(&mut self, synapse_array: &SynapseArray) -> Result<()> {
// Build hash table: source_neuron → [synapse_indices]
let mut source_map: AHashMap<u32, Vec<usize>> = AHashMap::new();
for i in 0..synapse_count {
source_map.entry(synapse_array.source_neurons[i])
.or_insert_with(Vec::new)
.push(i);
}
// Create GPU hash table (2x capacity for low collision rate)
let capacity = (source_map.len() * 2).next_power_of_two().max(256);
let mut hash_keys = vec![0xFFFFFFFF; capacity]; // 0xFFFFFFFF = empty
let mut hash_metadata = vec![0u32; capacity * 2]; // [start, count] per entry
let mut synapse_list = Vec::new();
// Insert using linear probing
for (&source_neuron, synapse_indices) in &source_map {
let mut slot = (source_neuron * 2654435761) % capacity;
while hash_keys[slot] != 0xFFFFFFFF {
slot = (slot + 1) % capacity; // Linear probing
}
hash_keys[slot] = source_neuron;
hash_metadata[slot * 2] = synapse_list.len() as u32; // Start index
hash_metadata[slot * 2 + 1] = synapse_indices.len() as u32; // Count
synapse_list.extend(synapse_indices);
}
// Upload to GPU
self.buffers.synapse_hash_keys = Some(create_buffer(hash_keys));
self.buffers.synapse_hash_metadata = Some(create_buffer(hash_metadata));
self.buffers.synapse_list = Some(create_buffer(synapse_list));
Ok(())
}
Analysis:
- ✅ Linear probing (GPU-friendly, no pointers)
- ✅ 2x capacity (50% load factor, low collisions)
- ✅ Persistent on GPU (no rebuild per burst)
- ⚠️ 16 probe limit (could miss highly collided entries)
Status: ✅ Production-ready, proven algorithm
3.4 GPU Compute Shaders (WGSL)
Synaptic Propagation Shader (synaptic_propagation_fcl.wgsl):
// Process one fired neuron → accumulate to all target neurons
@compute @workgroup_size(256)
fn synaptic_propagation_fcl_main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let fired_idx = global_id.x;
// Bounds check
if (fired_idx >= params.fired_count) {
return;
}
// Get fired neuron ID
let source_neuron_id = fired_neurons[fired_idx];
// Hash table lookup: find outgoing synapses
let metadata = find_synapse_metadata(source_neuron_id);
let list_start = metadata.x;
let synapse_count = metadata.y;
// Process all synapses from this fired neuron
for (var i = 0u; i < synapse_count; i++) {
let synapse_idx = synapse_list[list_start + i];
// Read consolidated synapse data (stride=3)
let data_idx = synapse_idx * 3u;
let target_id = synapse_data[data_idx + 1u];
let packed_params = synapse_data[data_idx + 2u];
// Unpack: weight, psp, type
// Canonical synaptic units: weight/psp are absolute u8 values (0..255), no normalization.
let weight_f32 = f32(packed_params & 0xFFu);
let psp_f32 = f32((packed_params >> 8u) & 0xFFu);
let sign = select(-1.0, 1.0, (packed_params >> 16u) & 0xFFu == 0u);
// LIF synaptic contribution: sign × weight × psp
let contribution = sign * weight_f32 * psp_f32;
let contribution_i32 = i32(contribution * 1000.0); // Fixed-point
// Atomic accumulation (GPU→GPU, no CPU!)
atomicAdd(&fcl_potentials_atomic[target_id], contribution_i32);
}
}
Analysis:
- ✅ GPU hash table lookup (linear probing)
- ✅ Atomic accumulation (race-safe)
- ✅ LIF model formula (matches CPU)
- ✅ Packed parameters (memory-efficient)
- ⚠️ LIF-specific (needs multi-model support later)
Status: ✅ Production-ready for LIF
Neural Dynamics Shader (neural_dynamics_fcl.wgsl):
@compute @workgroup_size(256)
fn neural_dynamics_fcl_main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let fcl_idx = global_id.x;
// Bounds check: Are we within FCL count?
if (fcl_idx >= params.fcl_count) {
return;
}
// Sparse lookup: Get actual neuron ID from FCL
let neuron_id = fcl_neuron_ids[fcl_idx];
let fcl_potential = fcl_potentials[fcl_idx];
// Load neuron state (random access into dense arrays)
let f32_idx = neuron_id * 4u;
let threshold = f32_params[f32_idx + 0u];
let leak_coef = f32_params[f32_idx + 1u];
let resting = f32_params[f32_idx + 2u];
let excitability = f32_params[f32_idx + 3u];
// Load dynamic state
let u16_idx = neuron_id * 2u;
var refrac_countdown = u16_dynamic_state[u16_idx + 0u];
var consec_count = u16_dynamic_state[u16_idx + 1u];
// Load membrane potential
var membrane_v = membrane_potentials[neuron_id];
// Apply FCL accumulated potential
membrane_v += fcl_potential;
// Check refractory
if (refrac_countdown > 0u) {
refrac_countdown -= 1u;
// Write back state
u16_dynamic_state[u16_idx + 0u] = refrac_countdown;
membrane_potentials[neuron_id] = membrane_v;
return; // No firing during refractory
}
// LIF dynamics: V(t+1) = V(t) - leak * (V(t) - V_rest)
membrane_v -= leak_coef * (membrane_v - resting);
// Firing check: V > threshold × excitability_random
let rand_val = excitability_random(neuron_id, params.burst_count);
let effective_threshold = threshold * (1.0 - (1.0 - rand_val) * excitability);
if (membrane_v >= effective_threshold) {
// FIRE!
membrane_v = resting; // Reset
refrac_countdown = u16_static_params[neuron_id * 3u + 0u]; // Refrac period
consec_count += 1u;
// Set fired bit in sparse mask
let word_idx = fcl_idx / 32u;
let bit_idx = fcl_idx % 32u;
atomicOr(&fcl_fired_mask[word_idx], 1u << bit_idx);
}
// Write back state
membrane_potentials[neuron_id] = membrane_v;
u16_dynamic_state[u16_idx + 0u] = refrac_countdown;
u16_dynamic_state[u16_idx + 1u] = consec_count;
}
Analysis:
- ✅ Sparse FCL processing (only active neurons)
- ✅ LIF dynamics (matches CPU exactly)
- ✅ Excitability randomness (PCG hash, deterministic)
- ✅ State updates (refractory, consecutive counts)
- ✅ Bitpacked output (memory-efficient)
- ⚠️ LIF-specific (multi-model needs separate shaders)
Status: ✅ Production-ready for LIF
3.5 FCL-Aware Sparse Processing
Key Innovation: GPU processes ONLY Fire Candidate List neurons
FCL Workflow:
┌──────────────────────────────────────────────────────────────┐
│ CPU: After Synaptic Propagation, identify FCL candidates │
│ (neurons with accumulated potential > threshold) │
│ │
│ Example: 1M neuron brain, 10K FCL candidates (1%) │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ CPU→GPU: Upload sparse FCL array (40 KB vs 4 MB full) │
│ │
│ fcl_neuron_ids: [152, 847, 1053, 2491, ...] (u32 array) │
│ fcl_potentials: [8.3, 12.1, 6.7, 9.4, ...] (f32 array) │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ GPU: Dispatch 10K workgroups (vs 1M for full array) │
│ │
│ Each thread: │
│ 1. fcl_idx = global_id.x (0..10K) │
│ 2. neuron_id = fcl_neuron_ids[fcl_idx] (sparse lookup) │
│ 3. Process ONLY this neuron │
│ │
│ Speedup: 100x fewer threads launched! │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ GPU→CPU: Download sparse fired mask (1.25 KB vs 125 KB) │
│ │
│ fcl_fired_mask: [0b10010001, ...] (bitpacked) │
│ │
│ Then map back to neuron IDs: │
│ bit 0 set → fcl_neuron_ids[0] = 152 fired │
│ bit 3 set → fcl_neuron_ids[3] = 2491 fired │
└──────────────────────────────────────────────────────────────┘
Performance Impact (1M neurons, 1% FCL):
- Memory Transfer: 40 KB + 1.25 KB = 41 KB (vs 4.125 MB full array) → 100x reduction
- GPU Workload: 10K threads (vs 1M threads) → 100x reduction
- Latency: ~100 μs (vs ~5,000 μs full array) → 50x speedup
Status: ✅ Implemented, major competitive advantage!
4. Performance Characteristics
4.1 Expected Performance (Based on Model)
| Neurons | Synapses | Firing | CPU Time | GPU Time | Speedup | Backend |
|---|---|---|---|---|---|---|
| 10K | 1M | 1% | 50 μs | 150 μs | 0.3x | ❌ CPU |
| 100K | 10M | 1% | 500 μs | 250 μs | 2x |