scirs2_neural/wasm/
mod.rs

1//! WebAssembly target support for neural networks
2//!
3//! This module provides comprehensive WebAssembly compilation and deployment support including:
4//! - WASM module generation with optimized neural network execution
5//! - JavaScript/TypeScript bindings for web integration
6//! - WebGL/WebGPU acceleration support
7//! - Memory management and streaming for large models
8//! - Web Workers integration for background inference
9//! - Progressive loading and caching strategies
10//!
11//! # Module Organization
12//!
13//! - [`bindings`] - JavaScript and TypeScript binding generation
14//! - [`memory`] - Memory management and configuration
15//! - [`exports`] - WASM compilation and export configuration
16
17pub mod bindings;
18pub mod exports;
19pub mod memory;
20
21// Re-export main types and functions for backward compatibility
22
23// From bindings module
24pub use bindings::{
25    BindingGenerator, BundleFormat, BundlingConfig, ModuleSystem, WebBindingConfig,
26    WebBindingLanguage,
27};
28
29// From memory module
30pub use memory::{
31    CacheStorage, CacheStrategy, CachingConfig, LoadingStrategy, MemoryAlignment, MemoryBreakdown,
32    MemoryGrowthStrategy, MemoryManager, MemoryRequirements, ParallelConfig, PreloadingConfig,
33    ProgressiveLoadingConfig, VersioningStrategy, WasmMemoryConfig, WasmMemoryExport,
34    WasmMemoryImport,
35};
36
37// From exports module
38pub use exports::{
39    BundleInfo, InlineLevel, MessagingStrategy, PerformanceHint, ProfilingConfig, ProfilingFormat,
40    TextureFormat, WasmCompilationConfig, WasmCompilationResult, WasmCompiler, WasmDebugConfig,
41    WasmExports, WasmFeatures, WasmFunctionExport, WasmFunctionImport, WasmGlobalExport,
42    WasmGlobalImport, WasmImports, WasmOptimization, WasmSignature, WasmTableExport,
43    WasmTableImport, WasmType, WasmVersion, WebAccelerationConfig, WebGLConfig, WebGPUConfig,
44    WebIntegrationConfig, WorkerConfig, WorkerPoolConfig, WorkerType,
45};
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50    use crate::layers::Dense;
51    use crate::models::sequential::Sequential;
52    use crate::serving::PackageMetadata;
53    use rand::SeedableRng;
54    use std::collections::HashMap;
55    use tempfile::TempDir;
56
57    #[test]
58    fn test_wasm_module_integration() {
59        // Test that all modules work together
60        let temp_dir = TempDir::new().unwrap();
61        let mut rng = rand::rngs::SmallRng::seed_from_u64(42);
62
63        // Create a simple model
64        let mut model: Sequential<f32> = Sequential::new();
65        let dense = Dense::new(10, 1, Some("relu"), &mut rng).unwrap();
66        model.add_layer(dense);
67
68        // Create configurations
69        let wasm_config = WasmCompilationConfig::default();
70        let web_config = WebIntegrationConfig::default();
71        let metadata = PackageMetadata {
72            name: "test-model".to_string(),
73            version: "1.0.0".to_string(),
74            description: "Test WebAssembly model".to_string(),
75            author: "SciRS2".to_string(),
76            license: "MIT".to_string(),
77            platforms: vec!["wasm".to_string()],
78            dependencies: HashMap::new(),
79            input_specs: Vec::new(),
80            output_specs: Vec::new(),
81            runtime_requirements: crate::serving::RuntimeRequirements {
82                min_memory_mb: 256,
83                cpu_requirements: crate::serving::CpuRequirements {
84                    min_cores: 1,
85                    instruction_sets: Vec::new(),
86                    min_frequency_mhz: None,
87                },
88                gpu_requirements: None,
89                system_dependencies: Vec::new(),
90            },
91            timestamp: chrono::Utc::now().to_rfc3339(),
92            checksum: "test".to_string(),
93        };
94
95        // Create compiler
96        let compiler = WasmCompiler::new(
97            model,
98            wasm_config,
99            web_config,
100            metadata,
101            temp_dir.path().to_path_buf(),
102        );
103
104        // Test compilation process
105        let result = compiler.compile();
106        assert!(result.is_ok());
107
108        let compilation_result = result.unwrap();
109        assert!(compilation_result.wasm_module.exists());
110        assert!(!compilation_result.bindings.is_empty());
111        assert!(compilation_result.bundle_info.total_size > 0);
112    }
113
114    #[test]
115    fn test_memory_manager_integration() {
116        // Test memory manager with different configurations
117        let performance_manager = MemoryManager::performance_optimized();
118        let constrained_manager = MemoryManager::resource_constrained();
119
120        let model_size = 10 * 1024 * 1024; // 10MB model
121
122        let perf_requirements = performance_manager.calculate_memory_requirements(model_size);
123        let constrained_requirements =
124            constrained_manager.calculate_memory_requirements(model_size);
125
126        // Performance config should use more memory
127        assert!(perf_requirements.total > constrained_requirements.total);
128
129        // Both should handle the model size
130        assert!(performance_manager.is_suitable_for_model(model_size));
131        assert!(constrained_manager.is_suitable_for_model(model_size));
132    }
133
134    #[test]
135    fn test_binding_generator_integration() {
136        let temp_dir = TempDir::new().unwrap();
137
138        // Test different binding configurations
139        let js_config = WebBindingConfig {
140            target_language: WebBindingLanguage::JavaScript,
141            module_system: ModuleSystem::ESModules,
142            type_definitions: false,
143            documentation: false,
144            bundling: BundlingConfig {
145                enable: false,
146                format: BundleFormat::Single,
147                minify: false,
148                tree_shaking: false,
149                code_splitting: false,
150            },
151        };
152
153        let ts_config = WebBindingConfig {
154            target_language: WebBindingLanguage::TypeScript,
155            module_system: ModuleSystem::ESModules,
156            type_definitions: true,
157            documentation: true,
158            bundling: BundlingConfig {
159                enable: true,
160                format: BundleFormat::Single,
161                minify: true,
162                tree_shaking: true,
163                code_splitting: false,
164            },
165        };
166
167        let both_config = WebBindingConfig {
168            target_language: WebBindingLanguage::Both,
169            module_system: ModuleSystem::ESModules,
170            type_definitions: true,
171            documentation: true,
172            bundling: BundlingConfig {
173                enable: true,
174                format: BundleFormat::Chunked,
175                minify: true,
176                tree_shaking: true,
177                code_splitting: true,
178            },
179        };
180
181        // Test JavaScript generation
182        let js_generator = BindingGenerator::new(temp_dir.path().to_path_buf(), js_config);
183        let js_bindings = js_generator.generate_bindings().unwrap();
184        assert_eq!(js_bindings.len(), 1);
185        assert!(js_bindings[0].to_string_lossy().ends_with(".js"));
186
187        // Test TypeScript generation
188        let ts_generator = BindingGenerator::new(temp_dir.path().to_path_buf(), ts_config);
189        let ts_bindings = ts_generator.generate_bindings().unwrap();
190        assert_eq!(ts_bindings.len(), 1);
191        assert!(ts_bindings[0].to_string_lossy().ends_with(".ts"));
192
193        // Test both generation
194        let both_generator = BindingGenerator::new(temp_dir.path().to_path_buf(), both_config);
195        let both_bindings = both_generator.generate_bindings().unwrap();
196        assert_eq!(both_bindings.len(), 2);
197    }
198
199    #[test]
200    fn test_configuration_defaults() {
201        // Test all default configurations are valid
202        let wasm_config = WasmCompilationConfig::default();
203        assert_eq!(wasm_config.target_version, WasmVersion::SIMD);
204        assert!(wasm_config.features.simd);
205        assert!(wasm_config.features.bulk_memory);
206        assert!(wasm_config.optimization_level.lto);
207
208        let web_config = WebIntegrationConfig::default();
209        assert_eq!(
210            web_config.bindings.target_language,
211            WebBindingLanguage::Both
212        );
213        assert!(web_config.caching.enable);
214        assert!(web_config.progressive_loading.enable);
215        assert!(web_config.workers.enable);
216
217        let memory_config = WasmMemoryConfig::default();
218        assert_eq!(memory_config.initial_pages, 256);
219        assert_eq!(memory_config.maximum_pages, Some(1024));
220        assert_eq!(
221            memory_config.growth_strategy,
222            MemoryGrowthStrategy::OnDemand
223        );
224    }
225
226    #[test]
227    fn test_wasm_features_validation() {
228        // Test WASM feature combinations
229        let mvp_features = WasmFeatures {
230            simd: false,
231            threads: false,
232            bulk_memory: false,
233            reference_types: false,
234            exception_handling: false,
235            tail_calls: false,
236            multi_value: false,
237            wasi: false,
238        };
239
240        let modern_features = WasmFeatures {
241            simd: true,
242            threads: true,
243            bulk_memory: true,
244            reference_types: true,
245            exception_handling: false,
246            tail_calls: false,
247            multi_value: true,
248            wasi: false,
249        };
250
251        // Test version compatibility
252        let mvp_config = WasmCompilationConfig {
253            target_version: WasmVersion::MVP,
254            features: mvp_features,
255            ..Default::default()
256        };
257
258        let simd_threads_config = WasmCompilationConfig {
259            target_version: WasmVersion::SIMDThreads,
260            features: modern_features,
261            ..Default::default()
262        };
263
264        // Verify configurations make sense
265        assert_eq!(mvp_config.target_version, WasmVersion::MVP);
266        assert!(!mvp_config.features.simd);
267
268        assert_eq!(simd_threads_config.target_version, WasmVersion::SIMDThreads);
269        assert!(simd_threads_config.features.simd);
270        assert!(simd_threads_config.features.threads);
271    }
272
273    #[test]
274    fn test_memory_requirements_calculation() {
275        let manager = MemoryManager::performance_optimized();
276
277        // Test different model sizes
278        let small_model = 1024 * 1024; // 1MB
279        let medium_model = 10 * 1024 * 1024; // 10MB
280        let large_model = 100 * 1024 * 1024; // 100MB
281
282        let small_req = manager.calculate_memory_requirements(small_model);
283        let medium_req = manager.calculate_memory_requirements(medium_model);
284        let large_req = manager.calculate_memory_requirements(large_model);
285
286        // Larger models should require more memory
287        assert!(small_req.total < medium_req.total);
288        assert!(medium_req.total < large_req.total);
289
290        // All should include model memory
291        assert_eq!(small_req.model_memory, small_model);
292        assert_eq!(medium_req.model_memory, medium_model);
293        assert_eq!(large_req.model_memory, large_model);
294
295        // Check breakdown percentages sum to 100%
296        let breakdown = medium_req.breakdown_percentages();
297        let total_percent = breakdown.base_percent
298            + breakdown.model_percent
299            + breakdown.cache_percent
300            + breakdown.preload_percent
301            + breakdown.worker_percent;
302        assert!((total_percent - 100.0).abs() < 0.1);
303    }
304
305    #[test]
306    fn test_chunk_size_recommendations() {
307        let manager = MemoryManager::performance_optimized();
308
309        let small_model = 512 * 1024; // 512KB
310        let medium_model = 10 * 1024 * 1024; // 10MB
311        let large_model = 200 * 1024 * 1024; // 200MB
312
313        let small_chunk = manager.recommended_chunk_size(small_model);
314        let medium_chunk = manager.recommended_chunk_size(medium_model);
315        let large_chunk = manager.recommended_chunk_size(large_model);
316
317        // Verify chunk size adaptation
318        assert!(small_chunk < medium_chunk);
319        assert!(medium_chunk <= large_chunk);
320
321        // Base chunk size should be used for medium models
322        assert_eq!(medium_chunk, manager.progressive_config().chunk_size);
323    }
324}