@@ -12,6 +12,7 @@ use time::OffsetDateTime;
1212use xshell:: { Cmd , Shell , cmd} ;
1313use zip:: { DateTime , ZipWriter , write:: SimpleFileOptions } ;
1414
15+ use crate :: flags:: PgoTrainingCrate ;
1516use crate :: {
1617 date_iso,
1718 flags:: { self , Malloc } ,
@@ -93,7 +94,7 @@ fn dist_server(
9394 target : & Target ,
9495 allocator : Malloc ,
9596 zig : bool ,
96- pgo : bool ,
97+ pgo : Option < PgoTrainingCrate > ,
9798) -> anyhow:: Result < ( ) > {
9899 let _e = sh. push_env ( "CFG_RELEASE" , release) ;
99100 let _e = sh. push_env ( "CARGO_PROFILE_RELEASE_LTO" , "thin" ) ;
@@ -111,11 +112,12 @@ fn dist_server(
111112 let features = allocator. to_features ( ) ;
112113 let command = if linux_target && zig { "zigbuild" } else { "build" } ;
113114
114- let pgo_profile = if pgo {
115+ let pgo_profile = if let Some ( train_crate ) = pgo {
115116 Some ( gather_pgo_profile (
116117 sh,
117118 build_command ( sh, command, & target_name, features) ,
118119 & target_name,
120+ train_crate,
119121 ) ?)
120122 } else {
121123 None
@@ -155,8 +157,9 @@ fn gather_pgo_profile<'a>(
155157 sh : & ' a Shell ,
156158 ra_build_cmd : Cmd < ' a > ,
157159 target : & str ,
160+ train_crate : PgoTrainingCrate ,
158161) -> anyhow:: Result < PathBuf > {
159- let pgo_dir = std:: path:: absolute ( "ra-pgo-profiles " ) ?;
162+ let pgo_dir = std:: path:: absolute ( "rust-analyzer-pgo " ) ?;
160163 // Clear out any stale profiles
161164 if pgo_dir. is_dir ( ) {
162165 std:: fs:: remove_dir_all ( & pgo_dir) ?;
@@ -175,12 +178,21 @@ fn gather_pgo_profile<'a>(
175178 ra_build_cmd. env ( "RUSTFLAGS" , format ! ( "-Cprofile-generate={}" , pgo_dir. to_str( ) . unwrap( ) ) ) ;
176179 cmd_gather. run ( ) . context ( "cannot build rust-analyzer with PGO instrumentation" ) ?;
177180
178- // Run RA on itself to gather profiles
179- let train_crate = "." ;
181+ let ( train_path, label) = match & train_crate {
182+ PgoTrainingCrate :: RustAnalyzer => ( PathBuf :: from ( "." ) , "itself" ) ,
183+ PgoTrainingCrate :: GitHub ( url) => {
184+ ( download_crate_for_training ( sh, & pgo_dir, url) ?, url. as_str ( ) )
185+ }
186+ } ;
187+
188+ // Run RA either on itself or on a downloaded crate
189+ eprintln ! ( "Training RA on {label}..." ) ;
180190 cmd ! (
181191 sh,
182- "target/{target}/release/rust-analyzer analysis-stats {train_crate} --run-all-ide-things"
192+ "target/{target}/release/rust-analyzer analysis-stats --run-all-ide-things {train_path} "
183193 )
194+ // analysis-stats produces an enormous amount of output on stdout
195+ . ignore_stdout ( )
184196 . run ( )
185197 . context ( "cannot generate PGO profiles" ) ?;
186198
@@ -201,6 +213,17 @@ fn gather_pgo_profile<'a>(
201213 Ok ( merged_profile)
202214}
203215
216+ /// Downloads a crate from GitHub, stores it into `pgo_dir` and returns a path to it.
217+ fn download_crate_for_training ( sh : & Shell , pgo_dir : & Path , url : & str ) -> anyhow:: Result < PathBuf > {
218+ let normalized_path = url. replace ( "/" , "-" ) ;
219+ let target_path = pgo_dir. join ( normalized_path) ;
220+ cmd ! ( sh, "git clone --depth 1 https://github.com/{url} {target_path}" )
221+ . run ( )
222+ . with_context ( || "cannot download PGO training crate from {url}" ) ?;
223+
224+ Ok ( target_path)
225+ }
226+
204227fn gzip ( src_path : & Path , dest_path : & Path ) -> anyhow:: Result < ( ) > {
205228 let mut encoder = GzEncoder :: new ( File :: create ( dest_path) ?, Compression :: best ( ) ) ;
206229 let mut input = io:: BufReader :: new ( File :: open ( src_path) ?) ;
0 commit comments