@@ -18,6 +18,7 @@ use std::process::Command;
18
18
19
19
use object:: read:: archive:: ArchiveFile ;
20
20
use object:: BinaryFormat ;
21
+ use sha2:: Digest ;
21
22
22
23
use crate :: bolt:: { instrument_with_bolt, optimize_with_bolt} ;
23
24
use crate :: builder:: { Builder , Kind , RunConfig , ShouldRun , Step } ;
@@ -1915,9 +1916,9 @@ fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
1915
1916
// We perform the instrumentation/optimization here, on the fly, just before they are being
1916
1917
// packaged into some destination directory.
1917
1918
let postprocessed = if builder. config . llvm_bolt_profile_generate {
1918
- instrument_with_bolt ( source)
1919
+ builder . ensure ( BoltInstrument :: new ( source. to_path_buf ( ) ) )
1919
1920
} else if let Some ( path) = & builder. config . llvm_bolt_profile_use {
1920
- optimize_with_bolt ( source , & Path :: new ( & path) )
1921
+ builder . ensure ( BoltOptimize :: new ( source . to_path_buf ( ) , path. into ( ) ) )
1921
1922
} else {
1922
1923
source. to_path_buf ( )
1923
1924
} ;
@@ -2007,6 +2008,121 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection
2007
2008
}
2008
2009
}
2009
2010
2011
+ /// Creates an output path to a BOLT-manipulated artifact for the given `file`.
2012
+ /// The hash of the file is used to make sure that we don't mix BOLT artifacts amongst different
2013
+ /// files with the same name.
2014
+ ///
2015
+ /// We need to keep the file-name the same though, to make sure that copying the manipulated file
2016
+ /// to a directory will not change the final file path.
2017
+ fn create_bolt_output_path ( builder : & Builder < ' _ > , file : & Path , hash : & str ) -> PathBuf {
2018
+ let directory = builder. out . join ( "bolt" ) . join ( hash) ;
2019
+ t ! ( fs:: create_dir_all( & directory) ) ;
2020
+ directory. join ( file. file_name ( ) . unwrap ( ) )
2021
+ }
2022
+
2023
+ /// Instrument the provided file with BOLT.
2024
+ /// Returns a path to the instrumented artifact.
2025
+ #[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
2026
+ pub struct BoltInstrument {
2027
+ file : PathBuf ,
2028
+ hash : String ,
2029
+ }
2030
+
2031
+ impl BoltInstrument {
2032
+ fn new ( file : PathBuf ) -> Self {
2033
+ let mut hasher = sha2:: Sha256 :: new ( ) ;
2034
+ hasher. update ( t ! ( fs:: read( & file) ) ) ;
2035
+ let hash = hex:: encode ( hasher. finalize ( ) . as_slice ( ) ) ;
2036
+
2037
+ Self { file, hash }
2038
+ }
2039
+ }
2040
+
2041
+ impl Step for BoltInstrument {
2042
+ type Output = PathBuf ;
2043
+
2044
+ const ONLY_HOSTS : bool = false ;
2045
+ const DEFAULT : bool = false ;
2046
+
2047
+ fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
2048
+ run. never ( )
2049
+ }
2050
+
2051
+ fn make_run ( _run : RunConfig < ' _ > ) { }
2052
+
2053
+ fn run ( self , builder : & Builder < ' _ > ) -> PathBuf {
2054
+ if builder. build . config . dry_run ( ) {
2055
+ return self . file . clone ( ) ;
2056
+ }
2057
+
2058
+ if builder. build . config . llvm_from_ci {
2059
+ println ! ( "warning: trying to use BOLT with LLVM from CI, this will probably not work" ) ;
2060
+ }
2061
+
2062
+ println ! ( "Instrumenting {} with BOLT" , self . file. display( ) ) ;
2063
+
2064
+ let output_path = create_bolt_output_path ( builder, & self . file , & self . hash ) ;
2065
+ if !output_path. is_file ( ) {
2066
+ instrument_with_bolt ( & self . file , & output_path) ;
2067
+ }
2068
+ output_path
2069
+ }
2070
+ }
2071
+
2072
+ /// Optimize the provided file with BOLT.
2073
+ /// Returns a path to the optimized artifact.
2074
+ ///
2075
+ /// The hash is stored in the step to make sure that we don't optimize the same file
2076
+ /// twice (even under different file paths).
2077
+ #[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
2078
+ pub struct BoltOptimize {
2079
+ file : PathBuf ,
2080
+ profile : PathBuf ,
2081
+ hash : String ,
2082
+ }
2083
+
2084
+ impl BoltOptimize {
2085
+ fn new ( file : PathBuf , profile : PathBuf ) -> Self {
2086
+ let mut hasher = sha2:: Sha256 :: new ( ) ;
2087
+ hasher. update ( t ! ( fs:: read( & file) ) ) ;
2088
+ hasher. update ( t ! ( fs:: read( & profile) ) ) ;
2089
+ let hash = hex:: encode ( hasher. finalize ( ) . as_slice ( ) ) ;
2090
+
2091
+ Self { file, profile, hash }
2092
+ }
2093
+ }
2094
+
2095
+ impl Step for BoltOptimize {
2096
+ type Output = PathBuf ;
2097
+
2098
+ const ONLY_HOSTS : bool = false ;
2099
+ const DEFAULT : bool = false ;
2100
+
2101
+ fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
2102
+ run. never ( )
2103
+ }
2104
+
2105
+ fn make_run ( _run : RunConfig < ' _ > ) { }
2106
+
2107
+ fn run ( self , builder : & Builder < ' _ > ) -> PathBuf {
2108
+ if builder. build . config . dry_run ( ) {
2109
+ return self . file . clone ( ) ;
2110
+ }
2111
+
2112
+ if builder. build . config . llvm_from_ci {
2113
+ println ! ( "warning: trying to use BOLT with LLVM from CI, this will probably not work" ) ;
2114
+ }
2115
+
2116
+ println ! ( "Optimizing {} with BOLT" , self . file. display( ) ) ;
2117
+
2118
+ let output_path = create_bolt_output_path ( builder, & self . file , & self . hash ) ;
2119
+ if !output_path. is_file ( ) {
2120
+ optimize_with_bolt ( & self . file , & self . profile , & output_path) ;
2121
+ }
2122
+ output_path
2123
+ }
2124
+ }
2125
+
2010
2126
#[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
2011
2127
pub struct LlvmTools {
2012
2128
pub target : TargetSelection ,
0 commit comments