use std::hint::black_box; use std::time::Instant; #[inline(never)] fn measure(operation: fn(&Input) -> Result, values: &Input, count: usize, score: fn(&Output) -> u64) -> (u128, u64) { let operation = black_box(operation); let start = Instant::now(); let mut checksum = 0u64; for _ in 0..count { if BORROW { // 保留 Result,通过借用观察输出,隔离取出所有权时的元数据搬运。 // 屏障只接收计分值;传入内部引用会使计时环重读 Result 标签并额外访存。 let value = operation(black_box(values)); checksum = checksum.wrapping_add(black_box(score(value.as_ref().unwrap()))); } else { let value = black_box(operation(black_box(values)).unwrap()); checksum = checksum.wrapping_add(score(&value)); } } (start.elapsed().as_nanos(), checksum) } fn compare(name: &str, values: &[Input], count: usize, generated: fn(&[Input]) -> Result, reference: fn(&[Input]) -> Result, score: fn(&Output) -> u64) { compare_named(name, values, count, generated, reference, score, "rust"); } fn compare_named(name: &str, values: &[Input], count: usize, generated: fn(&[Input]) -> Result, reference: fn(&[Input]) -> Result, score: fn(&Output) -> u64, reference_name: &str) { compare_output::(name, values, &[], count, generated, reference, score, reference_name); } fn compare_borrowed(name: &str, values: &[Input], count: usize, generated: fn(&[Input]) -> Result, reference: fn(&[Input]) -> Result, score: fn(&Output) -> u64) { compare_output::(&format!("{name}_borrowed"), values, &[], count, generated, reference, score, "rust"); } fn compare_bytes(name: &str, values: &dever_runtime::Bytes, count: usize, generated: fn(&dever_runtime::Bytes) -> Result, reference: fn(&dever_runtime::Bytes) -> Result, score: fn(&Output) -> u64) { compare_output::(name, values, &dever_runtime::Bytes::new(), count, generated, reference, score, "rust"); } fn compare_output(name: &str, values: &Input, empty: &Input, count: usize, generated: fn(&Input) -> Result, reference: fn(&Input) -> Result, score: fn(&Output) -> u64, reference_name: &str) { assert_eq!(generated(values).unwrap(), reference(values).unwrap()); assert_eq!(generated(empty).unwrap(), reference(empty).unwrap()); for operation in [generated, reference] { black_box(measure::(operation, values, 2000, score)); } for sample in 0..15 { // 每个标签各占首、中、末位五次,并交替正反顺序,避免固定前后关系。 let mut order = [("dever", generated), (reference_name, reference), ("control", generated)]; order.rotate_left(sample % 3); if sample / 3 % 2 == 1 { order.swap(0, 1); } let mut expected = None; for (implementation, operation) in order { let (elapsed, checksum) = measure::(operation, values, count, score); if let Some(expected) = expected { assert_eq!(checksum, expected); } expected = Some(checksum); println!("{name},{sample},{implementation},{elapsed},{checksum}"); } } }