1- use super :: cli :: FailureReason ;
1+ use itertools :: Itertools ;
22use rayon:: prelude:: * ;
3- use std:: process:: Command ;
3+ use std:: { collections :: HashMap , process:: Command } ;
44
5+ pub const INTRINSIC_DELIMITER : & str = "############" ;
56fn runner_command ( runner : & str ) -> Command {
67 let mut it = runner. split_whitespace ( ) ;
78 let mut cmd = Command :: new ( it. next ( ) . unwrap ( ) ) ;
@@ -11,85 +12,106 @@ fn runner_command(runner: &str) -> Command {
1112}
1213
1314pub fn compare_outputs ( intrinsic_name_list : & Vec < String > , runner : & str , target : & str ) -> bool {
14- let intrinsics = intrinsic_name_list
15- . par_iter ( )
16- . filter_map ( |intrinsic_name| {
17- let c = runner_command ( runner)
15+ let ( c, rust) = rayon:: join (
16+ || {
17+ runner_command ( runner)
1818 . arg ( "./intrinsic-test-programs" )
19- . arg ( intrinsic_name)
2019 . current_dir ( "c_programs" )
21- . output ( ) ;
22-
23- let rust = runner_command ( runner)
20+ . output ( )
21+ } ,
22+ || {
23+ runner_command ( runner)
2424 . arg ( format ! ( "./target/{target}/release/intrinsic-test-programs" ) )
25- . arg ( intrinsic_name)
2625 . current_dir ( "rust_programs" )
27- . output ( ) ;
26+ . output ( )
27+ } ,
28+ ) ;
29+ let ( c, rust) = match ( c, rust) {
30+ ( Ok ( c) , Ok ( rust) ) => ( c, rust) ,
31+ failure => panic ! ( "Failed to run: {failure:#?}" ) ,
32+ } ;
2833
29- let ( c, rust) = match ( c, rust) {
30- ( Ok ( c) , Ok ( rust) ) => ( c, rust) ,
31- a => panic ! ( "{a:#?}" ) ,
32- } ;
34+ if !c. status . success ( ) {
35+ error ! (
36+ "Failed to run C program.\n stdout: {stdout}\n stderr: {stderr}" ,
37+ stdout = std:: str :: from_utf8( & c. stdout) . unwrap_or( "" ) ,
38+ stderr = std:: str :: from_utf8( & c. stderr) . unwrap_or( "" ) ,
39+ ) ;
40+ }
3341
34- if !c. status . success ( ) {
35- error ! (
36- "Failed to run C program for intrinsic `{intrinsic_name}`\n stdout: {stdout}\n stderr: {stderr}" ,
37- stdout = std:: str :: from_utf8( & c. stdout) . unwrap_or( "" ) ,
38- stderr = std:: str :: from_utf8( & c. stderr) . unwrap_or( "" ) ,
39- ) ;
40- return Some ( FailureReason :: RunC ( intrinsic_name. clone ( ) ) ) ;
41- }
42+ if !rust. status . success ( ) {
43+ error ! (
44+ "Failed to run Rust program.\n stdout: {stdout}\n stderr: {stderr}" ,
45+ stdout = std:: str :: from_utf8( & rust. stdout) . unwrap_or( "" ) ,
46+ stderr = std:: str :: from_utf8( & rust. stderr) . unwrap_or( "" ) ,
47+ ) ;
48+ }
4249
43- if !rust. status . success ( ) {
44- error ! (
45- "Failed to run Rust program for intrinsic `{intrinsic_name}`\n stdout: {stdout}\n stderr: {stderr}" ,
46- stdout = std:: str :: from_utf8( & rust. stdout) . unwrap_or( "" ) ,
47- stderr = std:: str :: from_utf8( & rust. stderr) . unwrap_or( "" ) ,
48- ) ;
49- return Some ( FailureReason :: RunRust ( intrinsic_name. clone ( ) ) ) ;
50- }
50+ info ! ( "Completed running C++ and Rust test binaries" ) ;
51+ let c = std:: str:: from_utf8 ( & c. stdout )
52+ . unwrap ( )
53+ . to_lowercase ( )
54+ . replace ( "-nan" , "nan" ) ;
55+ let rust = std:: str:: from_utf8 ( & rust. stdout )
56+ . unwrap ( )
57+ . to_lowercase ( )
58+ . replace ( "-nan" , "nan" ) ;
5159
52- info ! ( "Comparing intrinsic: {intrinsic_name}" ) ;
60+ let c_output_map = c
61+ . split ( INTRINSIC_DELIMITER )
62+ . filter_map ( |output| output. trim ( ) . split_once ( "\n " ) )
63+ . collect :: < HashMap < & str , & str > > ( ) ;
64+ let rust_output_map = rust
65+ . split ( INTRINSIC_DELIMITER )
66+ . filter_map ( |output| output. trim ( ) . split_once ( "\n " ) )
67+ . collect :: < HashMap < & str , & str > > ( ) ;
5368
54- let c = std:: str:: from_utf8 ( & c. stdout )
55- . unwrap ( )
56- . to_lowercase ( )
57- . replace ( "-nan" , "nan" ) ;
58- let rust = std:: str:: from_utf8 ( & rust. stdout )
59- . unwrap ( )
60- . to_lowercase ( )
61- . replace ( "-nan" , "nan" ) ;
69+ let intrinsics = c_output_map
70+ . keys ( )
71+ . chain ( rust_output_map. keys ( ) )
72+ . unique ( )
73+ . collect_vec ( ) ;
6274
63- if c == rust {
75+ info ! ( "Comparing outputs" ) ;
76+ let intrinsics_diff_count = intrinsics
77+ . par_iter ( )
78+ . filter_map ( |& & intrinsic| {
79+ let c_output = c_output_map. get ( intrinsic) . unwrap ( ) ;
80+ let rust_output = rust_output_map. get ( intrinsic) . unwrap ( ) ;
81+ if rust_output. eq ( c_output) {
6482 None
6583 } else {
66- Some ( FailureReason :: Difference ( intrinsic_name. clone ( ) , c, rust) )
84+ let diff = diff:: lines ( c_output, rust_output) ;
85+ let diffs = diff
86+ . into_iter ( )
87+ . filter_map ( |diff| match diff {
88+ diff:: Result :: Left ( _) | diff:: Result :: Right ( _) => Some ( diff) ,
89+ diff:: Result :: Both ( _, _) => None ,
90+ } )
91+ . collect_vec ( ) ;
92+ if diffs. len ( ) > 0 {
93+ Some ( ( intrinsic, diffs) )
94+ } else {
95+ None
96+ }
6797 }
6898 } )
69- . collect :: < Vec < _ > > ( ) ;
70-
71- intrinsics. iter ( ) . for_each ( |reason| match reason {
72- FailureReason :: Difference ( intrinsic, c, rust) => {
99+ . inspect ( |( intrinsic, diffs) | {
73100 println ! ( "Difference for intrinsic: {intrinsic}" ) ;
74- let diff = diff:: lines ( c, rust) ;
75- diff. iter ( ) . for_each ( |diff| match diff {
101+ diffs. into_iter ( ) . for_each ( |diff| match diff {
76102 diff:: Result :: Left ( c) => println ! ( "C: {c}" ) ,
77103 diff:: Result :: Right ( rust) => println ! ( "Rust: {rust}" ) ,
78- diff :: Result :: Both ( _ , _ ) => ( ) ,
104+ _ => ( ) ,
79105 } ) ;
80106 println ! ( "****************************************************************" ) ;
81- }
82- FailureReason :: RunC ( intrinsic) => {
83- println ! ( "Failed to run C program for intrinsic {intrinsic}" )
84- }
85- FailureReason :: RunRust ( intrinsic) => {
86- println ! ( "Failed to run rust program for intrinsic {intrinsic}" )
87- }
88- } ) ;
107+ } )
108+ . count ( ) ;
109+
89110 println ! (
90111 "{} differences found (tested {} intrinsics)" ,
91- intrinsics . len ( ) ,
112+ intrinsics_diff_count ,
92113 intrinsic_name_list. len( )
93114 ) ;
94- intrinsics. is_empty ( )
115+
116+ intrinsics_diff_count == 0
95117}
0 commit comments