about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-11-06 09:55:50 +0000
committerbors <bors@rust-lang.org>2021-11-06 09:55:50 +0000
commit3cd3bbecc5e498465e89be8a33d2936aaebed0bf (patch)
tree8f46689d0f1f642c432677bb7eca074399e63fa7 /compiler/rustc_codegen_ssa/src
parent7276a6a11768634c1e7df5605a83a0f117302c50 (diff)
parent5a09e1213543fca0cbc9a0a61643e8d1bd4fccd8 (diff)
downloadrust-3cd3bbecc5e498465e89be8a33d2936aaebed0bf.tar.gz
rust-3cd3bbecc5e498465e89be8a33d2936aaebed0bf.zip
Auto merge of #90617 - tmiasko:time-trace-threads, r=wesleywiser
Initialize LLVM time trace profiler on each code generation thread

In https://reviews.llvm.org/D71059 LLVM 11, the time trace profiler was
extended to support multiple threads.

`timeTraceProfilerInitialize` creates a thread local profiler instance.
When a thread finishes `timeTraceProfilerFinishThread` moves a thread
local instance into a global collection of instances. Finally when all
codegen work is complete `timeTraceProfilerWrite` writes data from the
current thread local instance and the instances in global collection
of instances.

Previously, the profiler was intialized on a single thread only. Since
this thread performs no code generation on its own, the resulting
profile was empty.

Update LLVM codegen to initialize & finish time trace profiler on each
code generation thread.

cc `@tmandry`
r? `@wesleywiser`
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs102
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs22
2 files changed, 73 insertions, 51 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index da34612ce76..b2edc6c0183 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -310,6 +310,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub no_landing_pads: bool,
     pub save_temps: bool,
     pub fewer_names: bool,
+    pub time_trace: bool,
     pub exported_symbols: Option<Arc<ExportedSymbols>>,
     pub opts: Arc<config::Options>,
     pub crate_types: Vec<CrateType>,
@@ -1039,6 +1040,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         no_landing_pads: sess.panic_strategy() == PanicStrategy::Abort,
         fewer_names: sess.fewer_names(),
         save_temps: sess.opts.cg.save_temps,
+        time_trace: sess.opts.debugging_opts.llvm_time_trace,
         opts: Arc::new(sess.opts.clone()),
         prof: sess.prof.clone(),
         exported_symbols,
@@ -1198,7 +1200,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
     // Each LLVM module is automatically sent back to the coordinator for LTO if
     // necessary. There's already optimizations in place to avoid sending work
     // back to the coordinator if LTO isn't requested.
-    return thread::spawn(move || {
+    return B::spawn_thread(cgcx.time_trace, move || {
         let mut worker_id_counter = 0;
         let mut free_worker_ids = Vec::new();
         let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| {
@@ -1615,59 +1617,57 @@ fn start_executing_work<B: ExtraBackendMethods>(
 pub struct WorkerFatalError;
 
 fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>) {
-    let builder = thread::Builder::new().name(work.short_description());
-    builder
-        .spawn(move || {
-            // Set up a destructor which will fire off a message that we're done as
-            // we exit.
-            struct Bomb<B: ExtraBackendMethods> {
-                coordinator_send: Sender<Box<dyn Any + Send>>,
-                result: Option<Result<WorkItemResult<B>, FatalError>>,
-                worker_id: usize,
-            }
-            impl<B: ExtraBackendMethods> Drop for Bomb<B> {
-                fn drop(&mut self) {
-                    let worker_id = self.worker_id;
-                    let msg = match self.result.take() {
-                        Some(Ok(WorkItemResult::Compiled(m))) => {
-                            Message::Done::<B> { result: Ok(m), worker_id }
-                        }
-                        Some(Ok(WorkItemResult::NeedsLink(m))) => {
-                            Message::NeedsLink::<B> { module: m, worker_id }
-                        }
-                        Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
-                            Message::NeedsFatLTO::<B> { result: m, worker_id }
-                        }
-                        Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => {
-                            Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id }
-                        }
-                        Some(Err(FatalError)) => {
-                            Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id }
-                        }
-                        None => Message::Done::<B> { result: Err(None), worker_id },
-                    };
-                    drop(self.coordinator_send.send(Box::new(msg)));
-                }
+    B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
+        // Set up a destructor which will fire off a message that we're done as
+        // we exit.
+        struct Bomb<B: ExtraBackendMethods> {
+            coordinator_send: Sender<Box<dyn Any + Send>>,
+            result: Option<Result<WorkItemResult<B>, FatalError>>,
+            worker_id: usize,
+        }
+        impl<B: ExtraBackendMethods> Drop for Bomb<B> {
+            fn drop(&mut self) {
+                let worker_id = self.worker_id;
+                let msg = match self.result.take() {
+                    Some(Ok(WorkItemResult::Compiled(m))) => {
+                        Message::Done::<B> { result: Ok(m), worker_id }
+                    }
+                    Some(Ok(WorkItemResult::NeedsLink(m))) => {
+                        Message::NeedsLink::<B> { module: m, worker_id }
+                    }
+                    Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
+                        Message::NeedsFatLTO::<B> { result: m, worker_id }
+                    }
+                    Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => {
+                        Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id }
+                    }
+                    Some(Err(FatalError)) => {
+                        Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id }
+                    }
+                    None => Message::Done::<B> { result: Err(None), worker_id },
+                };
+                drop(self.coordinator_send.send(Box::new(msg)));
             }
+        }
 
-            let mut bomb = Bomb::<B> {
-                coordinator_send: cgcx.coordinator_send.clone(),
-                result: None,
-                worker_id: cgcx.worker,
-            };
+        let mut bomb = Bomb::<B> {
+            coordinator_send: cgcx.coordinator_send.clone(),
+            result: None,
+            worker_id: cgcx.worker,
+        };
 
-            // Execute the work itself, and if it finishes successfully then flag
-            // ourselves as a success as well.
-            //
-            // Note that we ignore any `FatalError` coming out of `execute_work_item`,
-            // as a diagnostic was already sent off to the main thread - just
-            // surface that there was an error in this worker.
-            bomb.result = {
-                let _prof_timer = work.start_profiling(&cgcx);
-                Some(execute_work_item(&cgcx, work))
-            };
-        })
-        .expect("failed to spawn thread");
+        // Execute the work itself, and if it finishes successfully then flag
+        // ourselves as a success as well.
+        //
+        // Note that we ignore any `FatalError` coming out of `execute_work_item`,
+        // as a diagnostic was already sent off to the main thread - just
+        // surface that there was an error in this worker.
+        bomb.result = {
+            let _prof_timer = work.start_profiling(&cgcx);
+            Some(execute_work_item(&cgcx, work))
+        };
+    })
+    .expect("failed to spawn thread");
 }
 
 enum SharedEmitterMessage {
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 8fef8314a5c..9c8bc3b2109 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -142,4 +142,26 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
     ) -> TargetMachineFactoryFn<Self>;
     fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
     fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>;
+
+    fn spawn_thread<F, T>(_time_trace: bool, f: F) -> std::thread::JoinHandle<T>
+    where
+        F: FnOnce() -> T,
+        F: Send + 'static,
+        T: Send + 'static,
+    {
+        std::thread::spawn(f)
+    }
+
+    fn spawn_named_thread<F, T>(
+        _time_trace: bool,
+        name: String,
+        f: F,
+    ) -> std::io::Result<std::thread::JoinHandle<T>>
+    where
+        F: FnOnce() -> T,
+        F: Send + 'static,
+        T: Send + 'static,
+    {
+        std::thread::Builder::new().name(name).spawn(f)
+    }
 }