use std::time::Instant;
use win_auto_utils::script_engine::ScriptEngine;
fn create_engine() -> ScriptEngine {
ScriptEngine::with_builtin()
}
fn calculate_ips(count: u64, duration: std::time::Duration) -> f64 {
if duration.as_nanos() == 0 {
f64::INFINITY
} else {
count as f64 / duration.as_secs_f64()
}
}
fn generate_realistic_script() -> String {
r#"
// Configuration
mode keyboard send
mode mouse send
// Main automation loop
loop 5
// Navigate to target
move 100 200
click
sleep 100
// Keyboard shortcuts (simplified - just individual keys)
key A
key B
key C
sleep 50
// Move to next item
moverel 0 50
click
sleep 100
end
// Final cleanup
move 500 500
click
"#
.to_string()
}
fn generate_sub_scripts() -> Vec<String> {
vec![
r#"
move 100 200
click
sleep 100
"#
.to_string(),
r#"
key A
key B
key C
sleep 50
"#
.to_string(),
r#"
scrollup 3
sleep 100
"#
.to_string(),
r#"
move 300 400
click
sleep 150
key A
key B
key C
sleep 50
"#
.to_string(),
r#"
moverel 0 50
click
sleep 100
"#
.to_string(),
]
}
#[test]
fn test_realistic_100_line_script_performance() {
println!("\n=== Realistic 100-Line Script Performance ===\n");
let engine = create_engine();
let script_text = generate_realistic_script();
println!("Script length: {} characters", script_text.len());
println!("Estimated lines: ~{}", script_text.lines().count());
let compile_start = Instant::now();
let compiled = engine.compile(&script_text).unwrap();
let compile_time = compile_start.elapsed();
println!("\nCompilation:");
println!(" Time: {:?}", compile_time);
println!(" Instructions compiled: {}", compiled.instructions.len());
let exec1_start = Instant::now();
engine.execute(&compiled).unwrap();
let exec1_time = exec1_start.elapsed();
println!("\nFirst Execution:");
println!(" Time: {:?}", exec1_time);
println!(
" Instructions executed: {}",
compiled.instructions.len() * 5
);
let runs = 9;
let exec_cached_start = Instant::now();
for _ in 0..runs {
engine.execute(&compiled).unwrap();
}
let exec_cached_total = exec_cached_start.elapsed();
let exec_cached_avg = exec_cached_total / runs;
println!("\nCached Execution (avg of {} runs):", runs);
println!(" Time: {:?}", exec_cached_avg);
println!(
" Throughput: {:.0} IPS",
calculate_ips((compiled.instructions.len() * 5) as u64, exec_cached_avg)
);
println!("\n=== Performance Analysis ===");
let compilation_overhead_percent = if exec_cached_avg.as_nanos() > 0 {
(compile_time.as_nanos() as f64 / exec_cached_avg.as_nanos() as f64) * 100.0
} else {
0.0
};
println!(
"Compilation overhead: {:.1}% of execution time",
compilation_overhead_percent
);
println!(
"Memory footprint: ~{} KB (estimated)",
compiled.instructions.len()
* std::mem::size_of::<win_auto_utils::script_engine::instruction::InstructionData>()
/ 1024
);
if compilation_overhead_percent < 10.0 {
println!("\n✅ Compilation overhead is negligible (<10%)");
println!(" Recommendation: Compile once, execute multiple times");
} else if compilation_overhead_percent < 50.0 {
println!("\n⚠️ Compilation overhead is moderate (10-50%)");
println!(" Recommendation: Cache compiled scripts for repeated use");
} else {
println!("\n❌ Compilation overhead is significant (>50%)");
println!(" Recommendation: MUST cache compiled scripts");
}
println!("\n✅ Test completed\n");
}
#[test]
fn test_sub_script_pattern_performance() {
println!("\n=== Sub-Script Pattern Performance ===\n");
let engine = create_engine();
let sub_scripts = generate_sub_scripts();
println!("Number of sub-scripts: {}", sub_scripts.len());
println!(
"Average length: {} characters",
sub_scripts.iter().map(|s| s.len()).sum::<usize>() / sub_scripts.len()
);
println!("\nScenario 1: Compile Once, Execute Sequentially");
let compile_all_start = Instant::now();
let compiled_scripts: Vec<_> = sub_scripts
.iter()
.map(|s| engine.compile(s).unwrap())
.collect();
let compile_all_time = compile_all_start.elapsed();
println!(" Total compilation time: {:?}", compile_all_time);
println!(
" Average per script: {:?}",
compile_all_time / sub_scripts.len() as u32
);
let exec_seq_start = Instant::now();
for compiled in &compiled_scripts {
engine.execute(compiled).unwrap();
}
let exec_seq_time = exec_seq_start.elapsed();
println!(" Sequential execution time: {:?}", exec_seq_time);
println!("\nScenario 2: Compile + Execute On-Demand (No Caching)");
let total_start = Instant::now();
for script in &sub_scripts {
let compiled = engine.compile(script).unwrap();
engine.execute(&compiled).unwrap();
}
let total_time = total_start.elapsed();
println!(" Total time: {:?}", total_time);
println!("\n=== Performance Comparison ===");
let scenario1_total = compile_all_time + exec_seq_time;
let overhead = total_time.as_nanos() as f64 - scenario1_total.as_nanos() as f64;
let overhead_percent = if scenario1_total.as_nanos() > 0 {
(overhead / scenario1_total.as_nanos() as f64) * 100.0
} else {
0.0
};
println!("Scenario 1 (cached): {:?}", scenario1_total);
println!("Scenario 2 (on-demand): {:?}", total_time);
println!("Overhead of on-demand: {:.1}%", overhead_percent);
if overhead_percent > 20.0 {
println!("\n✅ Caching provides significant benefit!");
println!(" Recommendation: Pre-compile all sub-scripts at startup");
} else {
println!("\n⚠️ Caching benefit is minimal");
println!(" On-demand compilation may be acceptable for infrequent use");
}
println!("\n✅ Test completed\n");
}
#[test]
fn test_compilation_scaling_with_script_size() {
println!("\n=== Compilation Scaling with Script Size ===\n");
let engine = create_engine();
let test_cases = vec![
("Tiny (10 lines)", 10),
("Small (50 lines)", 50),
("Medium (100 lines)", 100),
("Large (200 lines)", 200),
("Very Large (500 lines)", 500),
];
println!(
"{:<25} {:<15} {:<15} {:<15}",
"Script Size", "Compile Time", "Instructions", "Time/Instr"
);
println!("{:-<70}", "");
for (name, line_count) in test_cases {
let mut script = String::new();
for _i in 0..line_count {
script.push_str(&format!("key A\n"));
}
let compile_start = Instant::now();
let compiled = engine.compile(&script).unwrap();
let compile_time = compile_start.elapsed();
let time_per_instr = if !compiled.instructions.is_empty() {
compile_time.as_nanos() as f64 / compiled.instructions.len() as f64
} else {
0.0
};
println!(
"{:<25} {:<15?} {:<15} {:<15.2} ns",
name,
compile_time,
compiled.instructions.len(),
time_per_instr
);
}
println!("\n✅ Scaling test completed\n");
}
#[test]
fn test_memory_footprint_analysis() {
println!("\n=== Memory Footprint Analysis ===\n");
let engine = create_engine();
let script_sizes = vec![10, 50, 100, 200, 500];
println!(
"{:<15} {:<20} {:<20} {:<15}",
"Lines", "Instructions", "Memory (KB)", "Per Instr (B)"
);
println!("{:-<70}", "");
for size in script_sizes {
let mut script = String::new();
for _ in 0..size {
script.push_str("key A\n");
}
let compiled = engine.compile(&script).unwrap();
let memory_bytes = compiled.instructions.len()
* std::mem::size_of::<win_auto_utils::script_engine::instruction::InstructionData>();
let memory_kb = memory_bytes as f64 / 1024.0;
let per_instr_bytes = if !compiled.instructions.is_empty() {
memory_bytes / compiled.instructions.len()
} else {
0
};
println!(
"{:<15} {:<20} {:<20.2} {:<15}",
size,
compiled.instructions.len(),
memory_kb,
per_instr_bytes
);
}
println!("\nNote: Memory footprint is linear with instruction count");
println!("For 100-line script: typically <10 KB");
println!("This is negligible for modern systems\n");
println!("\n✅ Memory analysis completed\n");
}
#[test]
fn test_execution_vs_compilation_ratio() {
println!("\n=== Execution vs Compilation Time Ratio ===\n");
let engine = create_engine();
let script_text = generate_realistic_script();
let compiled = engine.compile(&script_text).unwrap();
println!(
"Script: ~100 lines, {} instructions",
compiled.instructions.len()
);
let compile_start = Instant::now();
let _compiled = engine.compile(&script_text).unwrap();
let compile_time = compile_start.elapsed();
let exec_start = Instant::now();
engine.execute(&compiled).unwrap();
let exec_time = exec_start.elapsed();
let ratio = if exec_time.as_nanos() > 0 {
compile_time.as_nanos() as f64 / exec_time.as_nanos() as f64
} else {
f64::INFINITY
};
println!("\nResults:");
println!(" Compilation time: {:?}", compile_time);
println!(" Execution time: {:?}", exec_time);
println!(" Ratio (Compile/Exec): {:.2}x", ratio);
if ratio < 0.1 {
println!("\n✅ Compilation is <10% of execution time");
println!(" For single execution: compile+execute together is fine");
println!(" For repeated execution: definitely cache compilation");
} else if ratio < 1.0 {
println!("\n⚠️ Compilation is significant but less than execution");
println!(" Caching recommended for 2+ executions");
} else {
println!("\n❌ Compilation takes longer than execution!");
println!(" MUST cache compiled scripts");
}
println!("\n✅ Ratio analysis completed\n");
}