@@ -18,6 +18,7 @@ use std::process::Command;
1818
1919use object:: read:: archive:: ArchiveFile ;
2020use object:: BinaryFormat ;
21+ use sha2:: Digest ;
2122
2223use crate :: bolt:: { instrument_with_bolt, optimize_with_bolt} ;
2324use crate :: builder:: { Builder , Kind , RunConfig , ShouldRun , Step } ;
@@ -1915,9 +1916,9 @@ fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
19151916 // We perform the instrumentation/optimization here, on the fly, just before they are being
19161917 // packaged into some destination directory.
19171918 let postprocessed = if builder. config . llvm_bolt_profile_generate {
1918- instrument_with_bolt ( source)
1919+ builder . ensure ( BoltInstrument :: new ( source. to_path_buf ( ) ) )
19191920 } 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 ( ) ) )
19211922 } else {
19221923 source. to_path_buf ( )
19231924 } ;
@@ -2007,6 +2008,121 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection
20072008 }
20082009}
20092010
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+
20102126#[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
20112127pub struct LlvmTools {
20122128 pub target : TargetSelection ,
0 commit comments