@@ -27,14 +27,37 @@ pub mod git {
2727 }
2828
2929 pub fn extract_commit_hash ( file : & str ) -> String {
30- // input: "target/$commit_id/test_name.raw"
30+ // input: "target/regression_artifacts/ $commit_id/test_name.raw"
3131 // output: "$commit_id"
32- file. split ( "target/" )
32+ file. split ( "target/regression_artifacts/ " )
3333 . nth ( 1 )
3434 . and_then ( |s| s. split ( '/' ) . next ( ) )
3535 . map ( |s| s. to_string ( ) )
3636 . unwrap_or_default ( ) // This will return an empty string if the Option is None
3737 }
38+
39+ pub fn is_mainline ( commit_hash : & str ) -> bool {
40+ // Execute the git command to check which branches contain the given commit.
41+ let output = Command :: new ( "git" )
42+ . args ( [ "branch" , "--contains" , commit_hash] )
43+ . output ( )
44+ . expect ( "Failed to execute git branch" ) ;
45+
46+ // If the command fails, it indicates that the commit is either detached
47+ // or does not exist in any branches. Meaning, it is not part of mainline.
48+ if !output. status . success ( ) {
49+ return false ;
50+ }
51+
52+ // Convert the command output to a string and check each line.
53+ let branches = String :: from_utf8_lossy ( & output. stdout ) ;
54+ branches. lines ( ) . any ( |branch| {
55+ // Trim the branch name to remove any leading or trailing whitespace.
56+ // The branch name could be prefixed with '*', indicating the current branch.
57+ // We check for both "main" and "* main" to account for this possibility.
58+ branch. trim ( ) == "main" || branch. trim ( ) == "* main"
59+ } )
60+ }
3861}
3962
4063#[ cfg( test) ]
@@ -117,7 +140,7 @@ mod tests {
117140 impl RawProfile {
118141 fn new ( test_name : & str ) -> Self {
119142 let commit_hash = git:: get_current_commit_hash ( ) ;
120- create_dir_all ( format ! ( "target/{commit_hash}" ) ) . unwrap ( ) ;
143+ create_dir_all ( format ! ( "target/regression_artifacts/ {commit_hash}" ) ) . unwrap ( ) ;
121144
122145 let raw_profile = Self {
123146 test_name : test_name. to_owned ( ) ,
@@ -143,7 +166,10 @@ mod tests {
143166 }
144167
145168 fn path ( & self ) -> String {
146- format ! ( "target/{}/{}.raw" , self . commit_hash, self . test_name)
169+ format ! (
170+ "target/regression_artifacts/{}/{}.raw" ,
171+ self . commit_hash, self . test_name
172+ )
147173 }
148174
149175 // Returns the annotated profile associated with a raw profile
@@ -154,8 +180,9 @@ mod tests {
154180 /// Return the raw profiles for `test_name` in "git" order. `tuple.0` is older than `tuple.1`
155181 ///
156182 /// This method will panic if there are not two profiles.
183+ /// This method will also panic if both commits are on different logs (not mainline).
157184 fn query ( test_name : & str ) -> ( RawProfile , RawProfile ) {
158- let pattern = format ! ( "target/**/*{}.raw" , test_name) ;
185+ let pattern = format ! ( "target/regression_artifacts/ **/*{}.raw" , test_name) ;
159186 let raw_files: Vec < String > = glob:: glob ( & pattern)
160187 . expect ( "Failed to read glob pattern" )
161188 . filter_map ( Result :: ok)
@@ -167,18 +194,28 @@ mod tests {
167194 test_name : test_name. to_string ( ) ,
168195 commit_hash : git:: extract_commit_hash ( & raw_files[ 0 ] ) ,
169196 } ;
170-
171197 let profile2 = RawProfile {
172198 test_name : test_name. to_string ( ) ,
173199 commit_hash : git:: extract_commit_hash ( & raw_files[ 1 ] ) ,
174200 } ;
175201
176- if git:: is_older_commit ( & profile1. commit_hash , & profile2. commit_hash ) {
177- ( profile1, profile2)
178- } else if git:: is_older_commit ( & profile2. commit_hash , & profile1. commit_hash ) {
179- ( profile2, profile1)
202+ // xor returns true if exactly one commit is mainline
203+ if git:: is_mainline ( & profile1. commit_hash ) ^ git:: is_mainline ( & profile2. commit_hash ) {
204+ // Return the mainline as first commit
205+ if git:: is_mainline ( & profile1. commit_hash ) {
206+ ( profile1, profile2)
207+ } else {
208+ ( profile2, profile1)
209+ }
180210 } else {
181- panic ! ( "The commits are not in the same log" ) ;
211+ // Neither or both profiles are on the mainline, so return the older one first
212+ if git:: is_older_commit ( & profile1. commit_hash , & profile2. commit_hash ) {
213+ ( profile1, profile2)
214+ } else if git:: is_older_commit ( & profile2. commit_hash , & profile1. commit_hash ) {
215+ ( profile2, profile1)
216+ } else {
217+ panic ! ( "The commits are not in the same log, are identical, or there are not two commits available" ) ;
218+ }
182219 }
183220 }
184221 }
@@ -211,7 +248,10 @@ mod tests {
211248 }
212249
213250 fn path ( & self ) -> String {
214- format ! ( "target/{}/{}.annotated" , self . commit_hash, self . test_name)
251+ format ! (
252+ "target/regression_artifacts/{}/{}.annotated" ,
253+ self . commit_hash, self . test_name
254+ )
215255 }
216256
217257 fn instruction_count ( & self ) -> i64 {
@@ -240,7 +280,7 @@ mod tests {
240280 assert_command_success ( diff_output. clone ( ) ) ;
241281
242282 // write the diff to disk
243- create_dir_all ( format ! ( "target/diff" ) ) . unwrap ( ) ;
283+ create_dir_all ( "target/regression_artifacts/ diff" ) . unwrap ( ) ;
244284 let diff_content = String :: from_utf8 ( diff_output. stdout )
245285 . expect ( "Invalid UTF-8 in cg_annotate --diff output" ) ;
246286 write ( diff_profile. path ( ) , diff_content) . expect ( "Failed to write to file" ) ;
@@ -249,7 +289,7 @@ mod tests {
249289 }
250290
251291 fn path ( & self ) -> String {
252- format ! ( "target/diff/{}.diff" , self . test_name)
292+ format ! ( "target/regression_artifacts/ diff/{}.diff" , self . test_name)
253293 }
254294
255295 fn assert_performance ( & self , max_diff : f64 ) {
0 commit comments