Skip to content

Commit

Permalink
Rollup merge of rust-lang#82535 - wesleywiser:wip_codegen_thread_name…
Browse files Browse the repository at this point in the history
…s, r=nagisa

Set codegen thread names

Set names on threads spawned during codegen. Various debugging and profiling tools can take advantage of this to show a more useful identifier for threads.

For example, gdb will show thread names in `info threads`:

```
(gdb) info threads
  Id   Target Id                                          Frame
  1    Thread 0x7fffefa7ec40 (LWP 2905) "rustc"           __pthread_clockjoin_ex (threadid=140737214134016, thread_return=0x0, clockid=<optimized out>, abstime=<optimized out>, block=<optimized out>)
    at pthread_join_common.c:145
  2    Thread 0x7fffefa7b700 (LWP 2957) "rustc"           0x00007ffff125eaa8 in llvm::X86_MC::initLLVMToSEHAndCVRegMapping(llvm::MCRegisterInfo*) ()
   from /home/wesley/.rustup/toolchains/stage1/lib/librustc_driver-f866439e29074957.so
  3    Thread 0x7fffeef0f700 (LWP 3116) "rustc"           futex_wait_cancelable (private=0, expected=0, futex_word=0x7fffe8602ac8) at ../sysdeps/nptl/futex-internal.h:183
* 4    Thread 0x7fffeed0e700 (LWP 3123) "rustc"           rustc_codegen_ssa::back::write::spawn_work (cgcx=..., work=...) at /home/wesley/code/rust/rust/compiler/rustc_codegen_ssa/src/back/write.rs:1573
  6    Thread 0x7fffe113b700 (LWP 3150) "opt foof.7rcbfp" 0x00007ffff2940e62 in llvm::CallGraph::populateCallGraphNode(llvm::CallGraphNode*) ()
   from /home/wesley/.rustup/toolchains/stage1/lib/librustc_driver-f866439e29074957.so
  8    Thread 0x7fffe0d39700 (LWP 3158) "opt foof.7rcbfp" 0x00007fffefe8998e in malloc_consolidate (av=av@entry=0x7ffe2c000020) at malloc.c:4492
  9    Thread 0x7fffe0f3a700 (LWP 3162) "opt foof.7rcbfp" 0x00007fffefef27c4 in __libc_open64 (file=0x7fffe0f38608 "foof.foof.7rcbfp3g-cgu.6.rcgu.o", oflag=524865) at ../sysdeps/unix/sysv/linux/open64.c:48
(gdb)
```

and Windows Performance Analyzer will also show this information when profiling:

![image](https://user-images.githubusercontent.com/831192/109231017-d311f780-7793-11eb-8072-ab836a830e90.png)
  • Loading branch information
GuillaumeGomez authored Feb 26, 2021
2 parents c21341b + 9d3739d commit 0d7f5a0
Showing 1 changed file with 77 additions and 47 deletions.
124 changes: 77 additions & 47 deletions compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,33 @@ impl<B: WriteBackendMethods> WorkItem<B> {
}
}
}

/// Generate a short description of this work item suitable for use as a thread name.
fn short_description(&self) -> String {
// `pthread_setname()` on *nix is limited to 15 characters and longer names are ignored.
// Use very short descriptions in this case to maximize the space available for the module name.
// Windows does not have that limitation so use slightly more descriptive names there.
match self {
WorkItem::Optimize(m) => {
#[cfg(windows)]
return format!("optimize module {}", m.name);
#[cfg(not(windows))]
return format!("opt {}", m.name);
}
WorkItem::CopyPostLtoArtifacts(m) => {
#[cfg(windows)]
return format!("copy LTO artifacts for {}", m.name);
#[cfg(not(windows))]
return format!("copy {}", m.name);
}
WorkItem::LTO(m) => {
#[cfg(windows)]
return format!("LTO module {}", m.name());
#[cfg(not(windows))]
return format!("LTO {}", m.name());
}
}
}
}

enum WorkItemResult<B: WriteBackendMethods> {
Expand Down Expand Up @@ -1609,56 +1636,59 @@ fn start_executing_work<B: ExtraBackendMethods>(
pub struct WorkerFatalError;

fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>) {
thread::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)));
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)));
}
}
}

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))
};
});
// 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 {
Expand Down

0 comments on commit 0d7f5a0

Please sign in to comment.