1#![allow(dead_code)] #![allow(unused_variables)] use thiserror::Error;
33use torsh_core::{DType, DeviceType, TorshError};
34
35pub mod abstract_interpretation;
36pub mod adaptive_compilation;
37pub mod advisor;
38pub mod analysis;
39pub mod benchmarking;
40pub mod codegen;
41pub mod const_eval;
42pub mod cranelift_backend;
43pub mod custom_ops;
44pub mod debug_symbols;
45pub mod debugger;
46pub mod differentiable_compilation;
47pub mod error_diagnostics;
48pub mod fusion;
49pub mod generics;
50pub mod graph;
51pub mod hardware_tuning;
52pub mod ir;
53pub mod llvm_backend;
54pub mod lowering;
55pub mod metaprogramming;
56pub mod mlir_backend;
57pub mod neural_compilation;
58pub mod optimization_advisor;
59pub mod optimizer;
60pub mod partial_evaluation;
61pub mod pgo;
62pub mod plugin_system;
63pub mod polyhedral_optimization;
64pub mod probabilistic_compilation;
65pub mod profiler;
66pub mod program_synthesis;
67pub mod runtime;
68pub mod script;
69pub mod specialization;
70pub mod speculative_optimization;
71pub mod symbolic_execution;
72pub mod trace_viz;
73pub mod tracing;
74pub mod type_inference;
75
76#[cfg(test)]
77pub mod compilation_test;
78
79pub use abstract_interpretation::{
81 AbstractAnalysisResult, AbstractDomain, AbstractInterpretationConfig, AbstractInterpreter,
82 AbstractValue, ConstantDomain, IntervalDomain, SignDomain,
83};
84pub use adaptive_compilation::{
85 AdaptiveCompiler, AdaptiveConfig, CompilationStrategy, PerformanceMetrics,
86};
87pub use codegen::CodeGenerator;
88pub use const_eval::{ConstEvalConfig, ConstantEvaluator, ConstantValue, EvaluationResult};
89pub use custom_ops::{get_custom_op, list_custom_ops, register_custom_op, CustomOpBuilder};
90pub use debug_symbols::{DebugSymbolConfig, DebugSymbolManager, SourceLocation, SymbolTable};
91pub use debugger::{
92 BreakpointLocation, DebugCommand, DebugSession, DebugState, DebugValue, DebuggerConfig,
93 ExecutionLocation, InspectionTarget, JitDebugger,
94};
95pub use differentiable_compilation::{
96 CompilationParams, CompilationTrainer, DiffCompilationResult, DifferentiableCompiler,
97 GumbelSoftmax, PerformanceMetrics as DiffPerformanceMetrics, SoftDecision,
98};
99pub use error_diagnostics::{
100 DiagnosticError, ErrorCategory, ErrorDiagnosticsManager, ErrorSeverity,
101};
102pub use fusion::{FusionStrategy, KernelFusion};
103pub use generics::{
104 create_type_param, shape_constraint, trait_constraint, GenericFunctionManager,
105 GenericFunctionTemplate, ParameterKind, TypeConstraint, TypeParameter,
106};
107pub use graph::{ComputationGraph, Edge, Node, NodeId};
108pub use hardware_tuning::{
109 Architecture, HardwareInfo, HardwareTuner, HardwareTuningConfig, TuningRecommendation,
110};
111pub use llvm_backend::{LlvmBackend, LlvmOptimizer};
112pub use metaprogramming::{
113 CodeTemplate, DynamicCodeGenerator, GeneratedCode, GraphReflection, MacroDefinition,
114 MetaprogrammingEngine, RuntimeReflector, TemplateParameters,
115};
116pub use mlir_backend::{MlirBackend, MlirOptimizer, MlirPass};
117pub use neural_compilation::{
118 CompilationStrategy as NeuralCompilationStrategy, GraphFeatures, NeuralCompiler,
119 NeuralCompilerConfig, OptimizationDecision,
120};
121pub use optimizer::GraphOptimizer;
122pub use partial_evaluation::{
123 ConstantFolder, EvaluationStatistics, FunctionSpecializer, OptimizedGraph, OptimizedIrModule,
124 PartialEvalConfig, PartialEvaluator,
125};
126pub use pgo::{
127 OptimizationRecommendation as PgoRecommendation, OptimizationType as PgoOptimizationType,
128 PgoConfig, ProfileGuidedOptimizer,
129};
130pub use plugin_system::{
131 load_all_plugins, load_plugin, Plugin, PluginCapability, PluginManager, PluginMetadata,
132 PluginRegistry,
133};
134pub use polyhedral_optimization::{
135 AffineExpr, AffineSchedule, LoopNest, PolyhedralConfig, PolyhedralOptimizer, Polyhedron,
136 TransformationMatrix, TransformationType,
137};
138pub use probabilistic_compilation::{
139 BetaDistribution, MonteCarloResult, NormalDistribution, ProbabilisticCompilationResult,
140 ProbabilisticCompiler, ProbabilisticConfig, ProbabilisticPerformance, UncertainDecision,
141};
142pub use profiler::{PerformanceEvent, ProfilerConfig, ProfilerManager, ProfilingSession};
143pub use program_synthesis::{
144 ExampleBuilder, ProgramSynthesizer, SynthesisExample, SynthesisResult, SynthesisStrategy,
145 SynthesisTemplate, SynthesisValue,
146};
147pub use runtime::JitRuntime;
148pub use script::{export_torchscript, import_torchscript, ScriptCompiler};
149pub use specialization::{
150 create_specialized_type, SpecializationConfig, SpecializedType, TypeSpecializer,
151};
152pub use speculative_optimization::{
153 DeoptimizationEvent, SpeculationResult, SpeculativeConfig, SpeculativeOptimizer,
154};
155pub use symbolic_execution::{
156 Constraint, ConstraintSet, ExecutionState, SymbolicExecutionConfig, SymbolicExecutionEngine,
157 SymbolicExecutionResult, SymbolicGraph, SymbolicValue,
158};
159pub use trace_viz::{
160 TraceEvent, TraceVisualizationManager, VisualizationConfig, VisualizationSession,
161};
162
163pub use optimization_advisor::{
165 analyze_computation_graph, analyze_with_benchmarks, analyze_with_profiling, create_advisor,
166 create_advisor_with_config, create_fast_config, create_production_config,
167 create_thorough_config, quick_analyze, AdvisorConfig, AnalysisInput, CostBenefitAnalysis,
168 OptimizationAdvisor, OptimizationRecommendation, OptimizationReport, OptimizationType,
169 PatternAnalysis, PerformanceAnalysis, SystemConstraints, TargetPlatform, UserPreferences,
170};
171
172pub type IrFunction = ir::IrModule; pub type IrInstruction = ir::Instruction; #[derive(Error, Debug)]
178pub enum JitError {
179 #[error("Graph construction failed: {0}")]
180 GraphError(String),
181
182 #[error("Fusion error: {0}")]
183 FusionError(String),
184
185 #[error("Code generation failed: {0}")]
186 CodeGenError(String),
187
188 #[error("Optimization error: {0}")]
189 OptimizationError(String),
190
191 #[error("Runtime error: {0}")]
192 RuntimeError(String),
193
194 #[error("Unsupported operation: {0}")]
195 UnsupportedOp(String),
196
197 #[error("Compilation error: {0}")]
198 CompilationError(String),
199
200 #[error("Analysis error: {0}")]
201 AnalysisError(String),
202
203 #[error("Abstract interpretation error: {0}")]
204 AbstractInterpretationError(String),
205
206 #[error("Backend error: {0}")]
207 BackendError(#[from] TorshError),
208
209 #[error("Not implemented: {0}")]
213 NotImplemented(String),
214}
215
216impl From<String> for JitError {
217 fn from(msg: String) -> Self {
218 JitError::RuntimeError(msg)
219 }
220}
221
222pub type JitResult<T> = Result<T, JitError>;
223
224#[derive(Debug, Clone)]
226pub struct JitConfig {
227 pub fusion_strategy: FusionStrategy,
229
230 pub enable_optimizations: bool,
232
233 pub max_fusion_size: usize,
235
236 pub enable_profiling: bool,
238
239 pub target_device: DeviceType,
241
242 pub enable_caching: bool,
244
245 pub enable_specialization: bool,
247
248 pub specialization_config: SpecializationConfig,
250}
251
252impl Default for JitConfig {
253 fn default() -> Self {
254 Self {
255 fusion_strategy: FusionStrategy::Default,
256 enable_optimizations: true,
257 max_fusion_size: 8,
258 enable_profiling: false,
259 target_device: DeviceType::Cpu,
260 enable_caching: true,
261 enable_specialization: true,
262 specialization_config: SpecializationConfig::default(),
263 }
264 }
265}
266
267pub struct JitCompiler {
269 config: JitConfig,
270 runtime: JitRuntime,
271 specializer: TypeSpecializer,
272 generics: GenericFunctionManager,
273 debug_symbols: DebugSymbolManager,
274 profiler: ProfilerManager,
275 trace_viz: TraceVisualizationManager,
276 error_diagnostics: ErrorDiagnosticsManager,
277}
278
279impl JitCompiler {
280 pub fn new(config: JitConfig) -> Self {
282 Self {
283 runtime: JitRuntime::new(config.clone()),
284 specializer: TypeSpecializer::new(config.specialization_config.clone()),
285 generics: GenericFunctionManager::with_defaults(),
286 debug_symbols: DebugSymbolManager::with_defaults(),
287 profiler: ProfilerManager::with_defaults(),
288 trace_viz: TraceVisualizationManager::with_defaults(),
289 error_diagnostics: ErrorDiagnosticsManager::with_defaults(),
290 config,
291 }
292 }
293
294 pub fn compile(&mut self, graph: ComputationGraph) -> JitResult<CompiledModule> {
296 graph
298 .validate()
299 .map_err(|e| JitError::GraphError(format!("{:?}", e)))?;
300
301 let inferred_graph = self.apply_type_shape_inference(graph)?;
303
304 let optimized_graph = if self.config.enable_optimizations {
306 let optimizer = GraphOptimizer::new();
307 optimizer.optimize(inferred_graph)?
308 } else {
309 inferred_graph
310 };
311
312 let fusion = KernelFusion::new(self.config.fusion_strategy.clone());
314 let fused_graph = fusion.apply(optimized_graph)?;
315
316 let ir_module = crate::lowering::lower_graph_to_ir(&fused_graph, "jit_module".to_string())?;
318
319 let optimized_ir = self.apply_ir_optimizations(ir_module)?;
321
322 let compiled_kernels = self.generate_code(&optimized_ir)?;
324
325 Ok(CompiledModule {
327 graph: fused_graph,
328 kernels: compiled_kernels,
329 runtime: self.runtime.clone(),
330 })
331 }
332
333 fn apply_type_shape_inference(
335 &self,
336 mut graph: ComputationGraph,
337 ) -> JitResult<ComputationGraph> {
338 use crate::type_inference::{ShapeInference, TypeInference};
339
340 let mut type_inf = TypeInference::new();
342 type_inf.infer_types(&graph)?;
343
344 let mut shape_inf = ShapeInference::new();
346 shape_inf.infer_shapes(&graph)?;
347
348 let node_ids: Vec<_> = graph.nodes().map(|(id, _)| id).collect();
350 for node_id in node_ids {
351 if let Some(inferred_type) = type_inf.get_type(node_id) {
352 if let Some(node_mut) = graph.node_mut(node_id) {
353 node_mut.dtype = inferred_type;
354 }
355 }
356 if let Some(inferred_shape) = shape_inf.get_shape(node_id) {
357 if let Some(node_mut) = graph.node_mut(node_id) {
358 node_mut.output_shape = inferred_shape.clone();
359 }
360 }
361 }
362
363 Ok(graph)
364 }
365
366 fn apply_ir_optimizations(
368 &self,
369 mut ir_module: crate::ir::IrModule,
370 ) -> JitResult<crate::ir::IrModule> {
371 use crate::lowering::{IrConstantFolding, IrDeadCodeElimination, IrPass};
372
373 let dce = IrDeadCodeElimination;
375 dce.run(&mut ir_module)?;
376
377 let cf = IrConstantFolding;
379 cf.run(&mut ir_module)?;
380
381 ir_module.validate().map_err(JitError::GraphError)?;
383
384 Ok(ir_module)
385 }
386
387 fn generate_code(&self, ir_module: &crate::ir::IrModule) -> JitResult<Vec<CompiledKernel>> {
389 match self.config.target_device {
390 DeviceType::Cpu => {
391 #[cfg(feature = "cranelift-backend")]
392 {
393 let mut codegen = crate::cranelift_backend::CraneliftCodeGen::new()?;
394 codegen.generate(ir_module)
395 }
396 #[cfg(not(feature = "cranelift-backend"))]
397 {
398 let codegen = CodeGenerator::new(self.config.target_device.clone());
400 codegen.generate_interpreter(ir_module)
401 }
402 }
403 _ => {
404 let codegen = CodeGenerator::new(self.config.target_device);
406 codegen.generate_from_ir(ir_module)
407 }
408 }
409 }
410}
411
412pub struct CompiledModule {
414 graph: ComputationGraph,
415 kernels: Vec<CompiledKernel>,
416 runtime: JitRuntime,
417}
418
419impl CompiledModule {
420 pub fn execute(&self, inputs: &[TensorRef]) -> JitResult<Vec<TensorRef>> {
422 self.runtime.execute(&self.graph, &self.kernels, inputs)
423 }
424
425 pub fn stats(&self) -> ExecutionStats {
427 self.runtime.stats()
428 }
429}
430
431pub struct CompiledKernel {
433 pub id: String,
435
436 pub source_nodes: Vec<NodeId>,
438
439 pub code: Vec<u8>,
441
442 pub metadata: KernelMetadata,
444}
445
446#[derive(Debug, Clone)]
448pub struct KernelMetadata {
449 pub inputs: Vec<TensorDesc>,
451
452 pub outputs: Vec<TensorDesc>,
454
455 pub shared_memory: usize,
457
458 pub block_size: (usize, usize, usize),
460
461 pub grid_size: (usize, usize, usize),
463}
464
465#[derive(Debug, Clone)]
467pub struct TensorDesc {
468 pub dtype: DType,
469 pub shape: Vec<usize>,
470 pub strides: Vec<usize>,
471 pub offset: usize,
472}
473
474#[derive(Debug, Clone, Default)]
476pub struct ExecutionStats {
477 pub total_time_us: u64,
479
480 pub kernel_launches: usize,
482
483 pub memory_transferred: usize,
485
486 pub cache_hit_rate: f32,
488}
489
490#[derive(Clone, Debug)]
492pub struct TensorRef {
493 pub data: Vec<f32>,
495}
496
497pub fn trace<F>(_func: F, _example_inputs: &[TensorRef]) -> JitResult<CompiledModule>
533where
534 F: Fn(&[TensorRef]) -> Vec<TensorRef>,
535{
536 Err(JitError::NotImplemented(
537 "JIT tracing is not implemented: capturing a graph requires tensor \
538 operation interception, which is not wired up yet. Refusing to return an \
539 empty module that would masquerade as a compiled one — use \
540 torsh_jit::script() with a ScriptableModule instead."
541 .to_string(),
542 ))
543}
544
545pub fn script<M>(module: M) -> JitResult<CompiledModule>
547where
548 M: ScriptableModule,
549{
550 script::script(module)
551}
552
553pub trait ScriptableModule {
555 fn to_graph(&self) -> JitResult<ComputationGraph>;
557}
558
559pub mod utils {
561 use super::{graph, ComputationGraph, DType, FusionStrategy, JitConfig};
562
563 #[must_use]
571 pub fn estimate_compilation_time(graph: &ComputationGraph) -> u64 {
572 let node_count = graph.nodes().count();
573 let edge_count = graph.edges().count();
574
575 let base_overhead = 10; let node_time = (node_count as f64 * 0.5) as u64;
578 let edge_time = (edge_count as f64 * 0.1) as u64;
579
580 base_overhead + node_time + edge_time
581 }
582
583 #[must_use]
590 pub fn estimate_memory_usage(graph: &ComputationGraph) -> usize {
591 let mut total_bytes = 0;
592
593 for (_, node) in graph.nodes() {
594 let elements: usize = node.output_shape.dims().iter().product();
595 let dtype_size = match node.dtype {
596 DType::F32 | DType::I32 | DType::U32 | DType::QInt32 => 4,
597 DType::F64 | DType::I64 | DType::U64 | DType::C64 => 8,
598 DType::F16 | DType::BF16 | DType::I16 => 2,
599 DType::I8 | DType::U8 | DType::Bool | DType::QInt8 | DType::QUInt8 => 1,
600 DType::C128 => 16,
601 };
602
603 total_bytes += elements * dtype_size;
604 }
605
606 let overhead = graph.nodes().count() * 256; total_bytes + overhead
609 }
610
611 #[must_use]
618 pub fn should_jit_compile(graph: &ComputationGraph) -> bool {
619 let node_count = graph.nodes().count();
620
621 if node_count < 5 {
623 return false;
624 }
625
626 let fusion_opportunities = count_fusion_opportunities(graph);
628 if fusion_opportunities > 3 {
629 return true; }
631
632 node_count >= 10
635 }
636
637 fn count_fusion_opportunities(graph: &ComputationGraph) -> usize {
639 let mut opportunities = 0;
640
641 for (node_id, node) in graph.nodes() {
642 let predecessors = graph.predecessors(node_id).count();
644
645 if predecessors > 0 && is_fusible_op(&node.op) {
646 opportunities += 1;
647 }
648 }
649
650 opportunities
651 }
652
653 fn is_fusible_op(op: &graph::Operation) -> bool {
655 matches!(
656 op,
657 graph::Operation::Add
658 | graph::Operation::Sub
659 | graph::Operation::Mul
660 | graph::Operation::Div
661 | graph::Operation::Relu
662 | graph::Operation::Sigmoid
663 | graph::Operation::Tanh
664 | graph::Operation::Gelu
665 | graph::Operation::Exp
666 | graph::Operation::Log
667 | graph::Operation::Sqrt
668 | graph::Operation::Neg
669 | graph::Operation::Abs
670 )
671 }
672
673 #[must_use]
677 pub fn recommend_config(graph: &ComputationGraph) -> JitConfig {
678 let node_count = graph.nodes().count();
679 let fusion_ops = count_fusion_opportunities(graph);
680
681 let mut config = JitConfig::default();
682
683 if fusion_ops > 10 {
685 config.fusion_strategy = FusionStrategy::Aggressive;
686 config.max_fusion_size = 16;
687 } else if fusion_ops > 5 {
688 config.fusion_strategy = FusionStrategy::Default;
689 config.max_fusion_size = 8;
690 } else {
691 config.fusion_strategy = FusionStrategy::Conservative;
692 config.max_fusion_size = 4;
693 }
694
695 config.enable_optimizations = node_count >= 10;
697
698 config.enable_profiling = node_count >= 50;
700
701 config
702 }
703
704 #[must_use]
711 pub fn estimate_flops(graph: &ComputationGraph) -> u64 {
712 let mut total_flops = 0u64;
713
714 for (_, node) in graph.nodes() {
715 let elements: u64 = node.output_shape.dims().iter().product::<usize>() as u64;
716
717 let op_flops = match &node.op {
718 graph::Operation::MatMul => {
719 let dim = (elements as f64).sqrt() as u64;
722 2 * dim * dim * dim
723 }
724 graph::Operation::Conv2d { .. } => {
725 elements * 9 }
728 graph::Operation::Add
729 | graph::Operation::Sub
730 | graph::Operation::Mul
731 | graph::Operation::Div => elements,
732 graph::Operation::Relu | graph::Operation::Abs | graph::Operation::Neg => {
733 elements / 2 }
735 graph::Operation::Exp
736 | graph::Operation::Log
737 | graph::Operation::Sqrt
738 | graph::Operation::Sin
739 | graph::Operation::Cos => {
740 elements * 10 }
742 graph::Operation::Sigmoid | graph::Operation::Tanh | graph::Operation::Gelu => {
743 elements * 5 }
745 _ => elements, };
747
748 total_flops += op_flops;
749 }
750
751 total_flops
752 }
753
754 #[must_use]
762 pub fn estimate_arithmetic_intensity(graph: &ComputationGraph) -> f64 {
763 let flops = estimate_flops(graph) as f64;
764 let bytes = estimate_memory_usage(graph) as f64;
765
766 if bytes > 0.0 {
767 flops / bytes
768 } else {
769 0.0
770 }
771 }
772}
773
774#[cfg(test)]
775mod tests {
776 use super::*;
777 use crate::graph::{Node, Operation};
778
779 #[test]
780 fn test_jit_config_default() {
781 let config = JitConfig::default();
782 assert!(config.enable_optimizations);
783 assert_eq!(config.max_fusion_size, 8);
784 assert!(!config.enable_profiling);
785 }
786
787 #[test]
788 fn test_jit_compiler_creation() {
789 let config = JitConfig::default();
790 let _compiler = JitCompiler::new(config);
791 assert!(true);
793 }
794
795 #[test]
796 fn test_utils_estimate_compilation_time() {
797 let mut graph = ComputationGraph::new();
798
799 let time = utils::estimate_compilation_time(&graph);
801 assert!(time >= 10); for i in 0..10 {
805 let node = Node::new(Operation::Add, format!("node_{}", i))
806 .with_output_shapes(vec![Some(crate::graph::shape_from_slice(&[100]))])
807 .with_dtypes(vec![DType::F32])
808 .with_device(DeviceType::Cpu);
809 graph.add_node(node);
810 }
811
812 let time_with_nodes = utils::estimate_compilation_time(&graph);
813 assert!(time_with_nodes > time); }
815
816 #[test]
817 fn test_utils_estimate_memory_usage() {
818 let mut graph = ComputationGraph::new();
819
820 let node = Node::new(Operation::Add, "test".to_string())
822 .with_output_shapes(vec![Some(crate::graph::shape_from_slice(&[100, 100]))])
823 .with_dtypes(vec![DType::F32])
824 .with_device(DeviceType::Cpu);
825 graph.add_node(node);
826
827 let memory = utils::estimate_memory_usage(&graph);
828
829 let expected_min = 100 * 100 * 4;
831 assert!(memory >= expected_min);
832 }
833
834 #[test]
835 fn test_utils_should_jit_compile() {
836 let mut graph = ComputationGraph::new();
837
838 for i in 0..3 {
840 let node = Node::new(Operation::Add, format!("node_{}", i))
841 .with_output_shapes(vec![Some(crate::graph::shape_from_slice(&[10]))])
842 .with_dtypes(vec![DType::F32])
843 .with_device(DeviceType::Cpu);
844 graph.add_node(node);
845 }
846
847 assert!(!utils::should_jit_compile(&graph));
848
849 for i in 3..15 {
851 let node = Node::new(Operation::Add, format!("node_{}", i))
852 .with_output_shapes(vec![Some(crate::graph::shape_from_slice(&[10]))])
853 .with_dtypes(vec![DType::F32])
854 .with_device(DeviceType::Cpu);
855 graph.add_node(node);
856 }
857
858 assert!(utils::should_jit_compile(&graph));
859 }
860
861 #[test]
862 fn test_utils_recommend_config() {
863 let mut graph = ComputationGraph::new();
864
865 let mut prev_nodes = Vec::new();
867
868 for i in 0..15 {
869 let op = if i % 3 == 0 {
870 Operation::Add
871 } else if i % 3 == 1 {
872 Operation::Mul
873 } else {
874 Operation::Relu
875 };
876
877 let node = Node::new(op, format!("node_{}", i))
878 .with_output_shapes(vec![Some(crate::graph::shape_from_slice(&[100]))])
879 .with_dtypes(vec![DType::F32])
880 .with_device(DeviceType::Cpu);
881 let node_id = graph.add_node(node);
882
883 if let Some(&prev) = prev_nodes.last() {
885 graph.add_edge(
886 prev,
887 node_id,
888 crate::graph::Edge {
889 src_output: 0,
890 dst_input: 0,
891 },
892 );
893 }
894
895 prev_nodes.push(node_id);
896 }
897
898 let config = utils::recommend_config(&graph);
899
900 assert!(config.enable_optimizations);
902 assert!(config.max_fusion_size >= 4);
904 }
905
906 #[test]
907 fn test_utils_estimate_flops() {
908 let mut graph = ComputationGraph::new();
909
910 let node = Node::new(Operation::MatMul, "matmul".to_string())
912 .with_output_shapes(vec![Some(crate::graph::shape_from_slice(&[64, 64]))])
913 .with_dtypes(vec![DType::F32])
914 .with_device(DeviceType::Cpu);
915 graph.add_node(node);
916
917 let flops = utils::estimate_flops(&graph);
918
919 assert!(flops > 100_000);
921 }
922
923 #[test]
924 fn test_utils_estimate_arithmetic_intensity() {
925 let mut graph = ComputationGraph::new();
926
927 let node = Node::new(Operation::Add, "add".to_string())
929 .with_output_shapes(vec![Some(crate::graph::shape_from_slice(&[1000]))])
930 .with_dtypes(vec![DType::F32])
931 .with_device(DeviceType::Cpu);
932 graph.add_node(node);
933
934 let intensity = utils::estimate_arithmetic_intensity(&graph);
935
936 assert!(intensity > 0.0);
938 assert!(intensity.is_finite());
939 }
940
941 #[test]
942 fn test_trace_refuses_instead_of_returning_empty_module() {
943 let result = trace(|_inputs| vec![], &[]);
946 assert!(matches!(result, Err(JitError::NotImplemented(_))));
947 }
948
949 #[test]
950 fn test_jit_error_display() {
951 let error = JitError::GraphError("test error".to_string());
952 let display = format!("{}", error);
953 assert!(display.contains("test error"));
954 }
955
956 #[test]
957 fn test_jit_config_builder_pattern() {
958 let config = JitConfig {
959 fusion_strategy: FusionStrategy::Aggressive,
960 enable_optimizations: true,
961 max_fusion_size: 16,
962 enable_profiling: true,
963 target_device: DeviceType::Cpu,
964 enable_caching: true,
965 enable_specialization: false,
966 specialization_config: SpecializationConfig::default(),
967 };
968
969 assert_eq!(config.fusion_strategy, FusionStrategy::Aggressive);
970 assert!(config.enable_optimizations);
971 assert_eq!(config.max_fusion_size, 16);
972 assert!(config.enable_caching);
973 }
974}
975
976pub const VERSION: &str = env!("CARGO_PKG_VERSION");
978pub const VERSION_MAJOR: u32 = 0;
979pub const VERSION_MINOR: u32 = 1;
980pub const VERSION_PATCH: u32 = 0;
981
982#[allow(ambiguous_glob_reexports)]
984pub mod prelude {
985 pub use crate::{
986 abstract_interpretation::*, adaptive_compilation::*, codegen::*, const_eval::*,
987 custom_ops::*, debug_symbols::*, debugger::*, differentiable_compilation::*,
988 error_diagnostics::*, fusion::*, graph::*, optimizer::*, runtime::*, script::*, tracing::*,
989 };
990}