-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Build instruction profiler runtime as part of compiler-rt #38608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# `profile` | ||
|
||
The tracking issue for this feature is: None | ||
|
||
------------------------ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# `profiler_runtime` | ||
|
||
The tracking issue for this feature is: None. | ||
|
||
------------------------ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# `profiler_runtime_lib` | ||
|
||
This feature is internal to the Rust compiler and is not intended for general use. | ||
|
||
------------------------ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
[package] | ||
authors = ["The Rust Project Developers"] | ||
build = "build.rs" | ||
name = "profiler_builtins" | ||
version = "0.0.0" | ||
|
||
[lib] | ||
name = "profiler_builtins" | ||
path = "lib.rs" | ||
test = false | ||
bench = false | ||
doc = false | ||
|
||
[dependencies] | ||
core = { path = "../libcore" } | ||
|
||
[build-dependencies] | ||
gcc = "0.3.27" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
//! Compiles the profiler part of the `compiler-rt` library. | ||
//! | ||
//! See the build.rs for libcompiler_builtins crate for details. | ||
|
||
extern crate gcc; | ||
|
||
use std::env; | ||
use std::path::Path; | ||
|
||
fn main() { | ||
let target = env::var("TARGET").expect("TARGET was not set"); | ||
let cfg = &mut gcc::Config::new(); | ||
|
||
if target.contains("msvc") { | ||
// Don't pull in extra libraries on MSVC | ||
cfg.flag("/Zl"); | ||
} else { | ||
// Turn off various features of gcc and such, mostly copying | ||
// compiler-rt's build system already | ||
cfg.flag("-fno-builtin"); | ||
cfg.flag("-fvisibility=hidden"); | ||
cfg.flag("-fomit-frame-pointer"); | ||
cfg.flag("-ffreestanding"); | ||
cfg.define("VISIBILITY_HIDDEN", None); | ||
} | ||
|
||
let profile_sources = &["GCDAProfiling.c", | ||
"InstrProfiling.c", | ||
"InstrProfilingBuffer.c", | ||
"InstrProfilingFile.c", | ||
"InstrProfilingMerge.c", | ||
"InstrProfilingMergeFile.c", | ||
"InstrProfilingPlatformDarwin.c", | ||
"InstrProfilingPlatformLinux.c", | ||
"InstrProfilingPlatformOther.c", | ||
"InstrProfilingRuntime.cc", | ||
"InstrProfilingUtil.c", | ||
"InstrProfilingValue.c", | ||
"InstrProfilingWriter.c"]; | ||
|
||
for src in profile_sources { | ||
cfg.file(Path::new("../compiler-rt/lib/profile").join(src)); | ||
} | ||
|
||
cfg.compile("libprofiler-rt.a"); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
#![no_std] | ||
#![cfg_attr(not(stage0), feature(profiler_runtime))] | ||
#![cfg_attr(not(stage0), profiler_runtime)] | ||
#![unstable(feature = "profiler_runtime_lib", | ||
reason = "internal implementation detail of rustc right now", | ||
issue = "0")] | ||
#![crate_name = "profiler_builtins"] | ||
#![crate_type = "rlib"] | ||
#![allow(unused_features)] | ||
#![feature(staged_api)] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -870,6 +870,33 @@ impl<'a> CrateLoader<'a> { | |
} | ||
} | ||
|
||
fn inject_profiler_runtime(&mut self) { | ||
if self.sess.opts.debugging_opts.profile { | ||
let mut uses_std = false; | ||
self.cstore.iter_crate_data(|_, data| { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @japaric can you remind me why this is needed? Naively I'd expect that a crate would require the profiler runtime regardless of whether it links to std or not, but I forget why this clause is above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I orignially copied that over from compiler_builtins. I think it's useful because a no_std crate may want to supply their own profiler builtins, e.g. to submit the results somewhere in a semihosting implementation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alexcrichton iirc, because the sanitizers only work with But since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah ok. @whitequark perhaps this clause (checking Is it really feasible for someone to write their own profiler builtins? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alexcrichton Sure, I'll remove it. I imagine someone would replace the libc calls in the stock profiler builtins with something else and then link to that, not write them from scratch. I am thinking of doing this for my embedded system work, incidentally. |
||
if data.name == "std" { | ||
uses_std = true; | ||
} | ||
}); | ||
|
||
if uses_std { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mentioned above, we can remove this clause, right? (just execute the code below if |
||
info!("loading profiler"); | ||
|
||
let symbol = Symbol::intern("profiler_builtins"); | ||
let dep_kind = DepKind::Implicit; | ||
let (_, data) = | ||
self.resolve_crate(&None, symbol, symbol, None, DUMMY_SP, | ||
PathKind::Crate, dep_kind); | ||
|
||
// Sanity check the loaded crate to ensure it is indeed a profiler runtime | ||
if !data.is_profiler_runtime() { | ||
self.sess.err(&format!("the crate `profiler_builtins` is not \ | ||
a profiler runtime")); | ||
} | ||
} | ||
} | ||
} | ||
|
||
fn inject_allocator_crate(&mut self) { | ||
// Make sure that we actually need an allocator, if none of our | ||
// dependencies need one then we definitely don't! | ||
|
@@ -1071,6 +1098,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { | |
// inject the sanitizer runtime before the allocator runtime because all | ||
// sanitizers force the use of the `alloc_system` allocator | ||
self.inject_sanitizer_runtime(); | ||
self.inject_profiler_runtime(); | ||
self.inject_allocator_crate(); | ||
self.inject_panic_runtime(krate); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,10 +39,12 @@ use rustc::ty::{self, AdtKind, Ty}; | |
use rustc::ty::layout::{self, LayoutTyper}; | ||
use session::config; | ||
use util::nodemap::FxHashMap; | ||
use rustc::util::common::path2cstr; | ||
|
||
use libc::{c_uint, c_longlong}; | ||
use std::ffi::CString; | ||
use std::ptr; | ||
use std::path::Path; | ||
use syntax::ast; | ||
use syntax::symbol::{Interner, InternedString, Symbol}; | ||
use syntax_pos::{self, Span}; | ||
|
@@ -788,20 +790,54 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, | |
let file_metadata = llvm::LLVMRustDIBuilderCreateFile( | ||
debug_context.builder, compile_unit_name, work_dir.as_ptr()); | ||
|
||
return llvm::LLVMRustDIBuilderCreateCompileUnit( | ||
let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( | ||
debug_context.builder, | ||
DW_LANG_RUST, | ||
file_metadata, | ||
producer.as_ptr(), | ||
sess.opts.optimize != config::OptLevel::No, | ||
flags.as_ptr() as *const _, | ||
0, | ||
split_name.as_ptr() as *const _) | ||
split_name.as_ptr() as *const _); | ||
|
||
let cu_desc_metadata = llvm::LLVMRustMetadataAsValue(debug_context.llcontext, | ||
unit_metadata); | ||
|
||
let gcov_cu_info = [ | ||
// Ideally we would be using the three-element form of !llvm.gcov metadata, | ||
// which allows us to specify gcno/gcda files explicitly, but that's only | ||
// available in LLVM 3.9+; so we rely on LLVM chopping off the extension | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should be using 3.9+, right? (and soon 4.0!) Is this using a different form for compatibility with older llvm version? (if so, I wouldn't worry about that and just use the newer version) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Is that really the case? The HEAD in the LLVM submodule is pre-3.9 isn't it? (Or at least it did not have the functionality I tried to rely on here.) Also, it is my understanding that the LLVM version check only rejects LLVM <3.7, so someone could still make their own build with that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes someone can make their own build, but we're not obligated to support literally everything on all LLVM versions, it's fine if profiling just doesn't work on previous LLVM versions (no one will slight us) |
||
// and replacing it with gcno/gcda, instead. | ||
path_to_mdstring(debug_context.llcontext, | ||
&scc.output_filenames().with_extension("gcno")), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this all happen conditionally? Only if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm perhaps this could be behind a guard for clarity? I'd be wary of an update to LLVM randomly starting to read this by accident... |
||
// path_to_mdstring(debug_context.llcontext, | ||
// &scc.output_filenames().with_extension("gcda")), | ||
cu_desc_metadata, | ||
]; | ||
let gcov_metadata = llvm::LLVMMDNodeInContext(debug_context.llcontext, | ||
gcov_cu_info.as_ptr(), | ||
gcov_cu_info.len() as c_uint); | ||
|
||
let llvm_gcov_ident = CString::new("llvm.gcov").unwrap(); | ||
llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, | ||
llvm_gcov_ident.as_ptr(), | ||
gcov_metadata); | ||
|
||
return unit_metadata; | ||
}; | ||
|
||
fn fallback_path(scc: &SharedCrateContext) -> CString { | ||
CString::new(scc.tcx().crate_name(LOCAL_CRATE).to_string()).unwrap() | ||
} | ||
|
||
fn path_to_mdstring(llcx: llvm::ContextRef, path: &Path) -> llvm::ValueRef { | ||
let path_str = path2cstr(path); | ||
unsafe { | ||
llvm::LLVMMDStringInContext(llcx, | ||
path_str.as_ptr(), | ||
path_str.as_bytes().len() as c_uint) | ||
} | ||
} | ||
} | ||
|
||
struct MetadataCreationResult { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
#![profiler_runtime] //~ ERROR the `#[profiler_runtime]` attribute is | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
-include ../tools.mk | ||
|
||
all: | ||
$(RUSTC) -g -Z profile test.rs | ||
$(call RUN,test) || exit 1 | ||
[ -e "$(TMPDIR)/test.gcno" ] || (echo "No .gcno file"; exit 1) | ||
[ -e "$(TMPDIR)/test.gcda" ] || (echo "No .gcda file"; exit 1) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
fn main() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that this is ever read, is it still needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's needed for a test. That's yet to be written.