Merge branch 'profiling' of github.com:whitequark/rust into profiling

This commit is contained in:
Marco Castelluccio 2017-06-04 15:54:39 +01:00
commit ecba8d6a23
32 changed files with 296 additions and 10 deletions

1
configure vendored
View File

@ -452,6 +452,7 @@ opt vendor 0 "enable usage of vendored Rust crates"
opt sanitizers 0 "build the sanitizer runtimes (asan, lsan, msan, tsan)" opt sanitizers 0 "build the sanitizer runtimes (asan, lsan, msan, tsan)"
opt dist-src 1 "when building tarballs enables building a source tarball" opt dist-src 1 "when building tarballs enables building a source tarball"
opt cargo-openssl-static 0 "static openssl in cargo" opt cargo-openssl-static 0 "static openssl in cargo"
opt profiler 0 "build the profiler runtime"
# Optimization and debugging options. These may be overridden by the release channel, etc. # Optimization and debugging options. These may be overridden by the release channel, etc.
opt_nosave optimize 1 "build optimized rust code" opt_nosave optimize 1 "build optimized rust code"

9
src/Cargo.lock generated
View File

@ -889,6 +889,14 @@ dependencies = [
"syntax_pos 0.0.0", "syntax_pos 0.0.0",
] ]
[[package]]
name = "profiler_builtins"
version = "0.0.0"
dependencies = [
"core 0.0.0",
"gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "psapi-sys" name = "psapi-sys"
version = "0.1.0" version = "0.1.0"
@ -1582,6 +1590,7 @@ dependencies = [
"libc 0.0.0", "libc 0.0.0",
"panic_abort 0.0.0", "panic_abort 0.0.0",
"panic_unwind 0.0.0", "panic_unwind 0.0.0",
"profiler_builtins 0.0.0",
"rand 0.0.0", "rand 0.0.0",
"rustc_asan 0.0.0", "rustc_asan 0.0.0",
"rustc_lsan 0.0.0", "rustc_lsan 0.0.0",

View File

@ -298,6 +298,10 @@ pub fn compiletest(build: &Build,
cmd.env("SANITIZER_SUPPORT", "1"); cmd.env("SANITIZER_SUPPORT", "1");
} }
if build.config.profiler {
cmd.env("PROFILER_SUPPORT", "1");
}
cmd.arg("--adb-path").arg("adb"); cmd.arg("--adb-path").arg("adb");
cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
if target.contains("android") { if target.contains("android") {

View File

@ -50,6 +50,7 @@ pub struct Config {
pub full_bootstrap: bool, pub full_bootstrap: bool,
pub extended: bool, pub extended: bool,
pub sanitizers: bool, pub sanitizers: bool,
pub profiler: bool,
// llvm codegen options // llvm codegen options
pub llvm_assertions: bool, pub llvm_assertions: bool,
@ -162,6 +163,7 @@ struct Build {
extended: Option<bool>, extended: Option<bool>,
verbose: Option<usize>, verbose: Option<usize>,
sanitizers: Option<bool>, sanitizers: Option<bool>,
profiler: Option<bool>,
openssl_static: Option<bool>, openssl_static: Option<bool>,
} }
@ -318,6 +320,7 @@ impl Config {
set(&mut config.extended, build.extended); set(&mut config.extended, build.extended);
set(&mut config.verbose, build.verbose); set(&mut config.verbose, build.verbose);
set(&mut config.sanitizers, build.sanitizers); set(&mut config.sanitizers, build.sanitizers);
set(&mut config.profiler, build.profiler);
set(&mut config.openssl_static, build.openssl_static); set(&mut config.openssl_static, build.openssl_static);
if let Some(ref install) = toml.install { if let Some(ref install) = toml.install {
@ -471,6 +474,7 @@ impl Config {
("FULL_BOOTSTRAP", self.full_bootstrap), ("FULL_BOOTSTRAP", self.full_bootstrap),
("EXTENDED", self.extended), ("EXTENDED", self.extended),
("SANITIZERS", self.sanitizers), ("SANITIZERS", self.sanitizers),
("PROFILER", self.profiler),
("DIST_SRC", self.rust_dist_src), ("DIST_SRC", self.rust_dist_src),
("CARGO_OPENSSL_STATIC", self.openssl_static), ("CARGO_OPENSSL_STATIC", self.openssl_static),
} }

View File

@ -147,6 +147,9 @@
# Build the sanitizer runtimes # Build the sanitizer runtimes
#sanitizers = false #sanitizers = false
# Build the profiler runtime
#profiler = false
# Indicates whether the OpenSSL linked into Cargo will be statically linked or # Indicates whether the OpenSSL linked into Cargo will be statically linked or
# not. If static linkage is specified then the build system will download a # not. If static linkage is specified then the build system will download a
# known-good version of OpenSSL, compile it, and link it to Cargo. # known-good version of OpenSSL, compile it, and link it to Cargo.

View File

@ -594,6 +594,9 @@ impl Build {
if self.config.backtrace { if self.config.backtrace {
features.push_str(" backtrace"); features.push_str(" backtrace");
} }
if self.config.profiler {
features.push_str(" profiler");
}
return features return features
} }

View File

@ -2,6 +2,7 @@
- [Compiler flags](compiler-flags.md) - [Compiler flags](compiler-flags.md)
- [linker_flavor](compiler-flags/linker-flavor.md) - [linker_flavor](compiler-flags/linker-flavor.md)
- [profile](compiler-flags/profile.md)
- [remap_path_prefix](compiler-flags/remap-path-prefix.md) - [remap_path_prefix](compiler-flags/remap-path-prefix.md)
- [Language features](language-features.md) - [Language features](language-features.md)
- [abi_msp430_interrupt](language-features/abi-msp430-interrupt.md) - [abi_msp430_interrupt](language-features/abi-msp430-interrupt.md)
@ -70,6 +71,7 @@
- [plugin_registrar](language-features/plugin-registrar.md) - [plugin_registrar](language-features/plugin-registrar.md)
- [prelude_import](language-features/prelude-import.md) - [prelude_import](language-features/prelude-import.md)
- [proc_macro](language-features/proc-macro.md) - [proc_macro](language-features/proc-macro.md)
- [profiler_runtime](language-features/profiler-runtime.md)
- [quote](language-features/quote.md) - [quote](language-features/quote.md)
- [repr_align](language-features/repr-align.md) - [repr_align](language-features/repr-align.md)
- [repr_simd](language-features/repr-simd.md) - [repr_simd](language-features/repr-simd.md)
@ -177,6 +179,7 @@
- [placement_new_protocol](library-features/placement-new-protocol.md) - [placement_new_protocol](library-features/placement-new-protocol.md)
- [print_internals](library-features/print-internals.md) - [print_internals](library-features/print-internals.md)
- [proc_macro_internals](library-features/proc-macro-internals.md) - [proc_macro_internals](library-features/proc-macro-internals.md)
- [profiler_runtime_lib](library-features/sanitizer-runtime-lib.md)
- [question_mark_carrier](library-features/question-mark-carrier.md) - [question_mark_carrier](library-features/question-mark-carrier.md)
- [rand](library-features/rand.md) - [rand](library-features/rand.md)
- [range_contains](library-features/range-contains.md) - [range_contains](library-features/range-contains.md)

View File

@ -0,0 +1,5 @@
# `profile`
The tracking issue for this feature is: None
------------------------

View File

@ -0,0 +1,5 @@
# `profiler_runtime`
The tracking issue for this feature is: None.
------------------------

View File

@ -0,0 +1,5 @@
# `profiler_runtime_lib`
This feature is internal to the Rust compiler and is not intended for general use.
------------------------

View File

@ -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"

View File

@ -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");
}

View File

@ -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)]

View File

@ -260,6 +260,7 @@ pub trait CrateStore {
fn is_panic_runtime(&self, cnum: CrateNum) -> bool; fn is_panic_runtime(&self, cnum: CrateNum) -> bool;
fn is_compiler_builtins(&self, cnum: CrateNum) -> bool; fn is_compiler_builtins(&self, cnum: CrateNum) -> bool;
fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool; fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool;
fn is_profiler_runtime(&self, cnum: CrateNum) -> bool;
fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy; fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy;
fn extern_crate(&self, cnum: CrateNum) -> Option<ExternCrate>; fn extern_crate(&self, cnum: CrateNum) -> Option<ExternCrate>;
/// The name of the crate as it is referred to in source code of the current /// The name of the crate as it is referred to in source code of the current
@ -381,6 +382,7 @@ impl CrateStore for DummyCrateStore {
fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") } fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") }
fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") } fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") }
fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") } fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") }
fn is_profiler_runtime(&self, cnum: CrateNum) -> bool { bug!("is_profiler_runtime") }
fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool { bug!("is_sanitizer_runtime") } fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool { bug!("is_sanitizer_runtime") }
fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy { fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy {
bug!("panic_strategy") bug!("panic_strategy")

View File

@ -1033,6 +1033,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"a single extra argument to prepend the linker invocation (can be used several times)"), "a single extra argument to prepend the linker invocation (can be used several times)"),
pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED], pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
"extra arguments to prepend to the linker invocation (space separated)"), "extra arguments to prepend to the linker invocation (space separated)"),
profile: bool = (false, parse_bool, [TRACKED],
"insert profiling code"),
} }
pub fn default_lib_output() -> CrateType { pub fn default_lib_output() -> CrateType {

View File

@ -204,7 +204,8 @@ pub fn compile_input(sess: &Session,
println!("Pre-trans"); println!("Pre-trans");
tcx.print_debug_stats(); tcx.print_debug_stats();
} }
let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map); let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map,
&outputs);
if log_enabled!(::log::LogLevel::Info) { if log_enabled!(::log::LogLevel::Info) {
println!("Post-trans"); println!("Post-trans");
@ -1042,7 +1043,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
/// be discarded. /// be discarded.
pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
analysis: ty::CrateAnalysis, analysis: ty::CrateAnalysis,
incremental_hashes_map: &IncrementalHashesMap) incremental_hashes_map: &IncrementalHashesMap,
output_filenames: &OutputFilenames)
-> trans::CrateTranslation { -> trans::CrateTranslation {
let time_passes = tcx.sess.time_passes(); let time_passes = tcx.sess.time_passes();
@ -1053,7 +1055,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let translation = let translation =
time(time_passes, time(time_passes,
"translation", "translation",
move || trans::trans_crate(tcx, analysis, &incremental_hashes_map)); move || trans::trans_crate(tcx, analysis, &incremental_hashes_map, output_filenames));
time(time_passes, time(time_passes,
"assert dep graph", "assert dep graph",

View File

@ -591,7 +591,9 @@ extern "C" {
pub fn LLVMIsUndef(Val: ValueRef) -> Bool; pub fn LLVMIsUndef(Val: ValueRef) -> Bool;
// Operations on metadata // Operations on metadata
pub fn LLVMMDStringInContext(C: ContextRef, Str: *const c_char, SLen: c_uint) -> ValueRef;
pub fn LLVMMDNodeInContext(C: ContextRef, Vals: *const ValueRef, Count: c_uint) -> ValueRef; pub fn LLVMMDNodeInContext(C: ContextRef, Vals: *const ValueRef, Count: c_uint) -> ValueRef;
pub fn LLVMAddNamedMetadataOperand(M: ModuleRef, Name: *const c_char, Val: ValueRef);
// Operations on scalar constants // Operations on scalar constants
pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) -> ValueRef; pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) -> ValueRef;
@ -1332,6 +1334,8 @@ extern "C" {
pub fn LLVMRustAddModuleFlag(M: ModuleRef, name: *const c_char, value: u32); pub fn LLVMRustAddModuleFlag(M: ModuleRef, name: *const c_char, value: u32);
pub fn LLVMRustMetadataAsValue(C: ContextRef, MD: MetadataRef) -> ValueRef;
pub fn LLVMRustDIBuilderCreate(M: ModuleRef) -> DIBuilderRef; pub fn LLVMRustDIBuilderCreate(M: ModuleRef) -> DIBuilderRef;
pub fn LLVMRustDIBuilderDispose(Builder: DIBuilderRef); pub fn LLVMRustDIBuilderDispose(Builder: DIBuilderRef);

View File

@ -906,6 +906,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| {
if data.name == "std" {
uses_std = true;
}
});
if uses_std {
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.dep_graph) {
self.sess.err(&format!("the crate `profiler_builtins` is not \
a profiler runtime"));
}
}
}
}
fn inject_allocator_crate(&mut self) { fn inject_allocator_crate(&mut self) {
// Make sure that we actually need an allocator, if none of our // Make sure that we actually need an allocator, if none of our
// dependencies need one then we definitely don't! // dependencies need one then we definitely don't!
@ -1108,6 +1135,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
// inject the sanitizer runtime before the allocator runtime because all // inject the sanitizer runtime before the allocator runtime because all
// sanitizers force the use of the `alloc_system` allocator // sanitizers force the use of the `alloc_system` allocator
self.inject_sanitizer_runtime(); self.inject_sanitizer_runtime();
self.inject_profiler_runtime();
self.inject_allocator_crate(); self.inject_allocator_crate();
self.inject_panic_runtime(krate); self.inject_panic_runtime(krate);

View File

@ -298,6 +298,11 @@ impl CrateMetadata {
attr::contains_name(&attrs, "sanitizer_runtime") attr::contains_name(&attrs, "sanitizer_runtime")
} }
pub fn is_profiler_runtime(&self, dep_graph: &DepGraph) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph);
attr::contains_name(&attrs, "profiler_runtime")
}
pub fn is_no_builtins(&self, dep_graph: &DepGraph) -> bool { pub fn is_no_builtins(&self, dep_graph: &DepGraph) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph); let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph);
attr::contains_name(&attrs, "no_builtins") attr::contains_name(&attrs, "no_builtins")

View File

@ -244,6 +244,10 @@ impl CrateStore for cstore::CStore {
self.get_crate_data(cnum).is_sanitizer_runtime(&self.dep_graph) self.get_crate_data(cnum).is_sanitizer_runtime(&self.dep_graph)
} }
fn is_profiler_runtime(&self, cnum: CrateNum) -> bool {
self.get_crate_data(cnum).is_profiler_runtime(&self.dep_graph)
}
fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy { fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy {
self.get_crate_data(cnum).panic_strategy(&self.dep_graph) self.get_crate_data(cnum).panic_strategy(&self.dep_graph)
} }

View File

@ -1098,6 +1098,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
// symbols from the dylib. // symbols from the dylib.
let src = sess.cstore.used_crate_source(cnum); let src = sess.cstore.used_crate_source(cnum);
match data[cnum.as_usize() - 1] { match data[cnum.as_usize() - 1] {
_ if sess.cstore.is_profiler_runtime(cnum) => {
add_static_crate(cmd, sess, tmpdir, crate_type, cnum);
}
_ if sess.cstore.is_sanitizer_runtime(cnum) => { _ if sess.cstore.is_sanitizer_runtime(cnum) => {
link_sanitizer_runtime(cmd, sess, tmpdir, cnum); link_sanitizer_runtime(cmd, sess, tmpdir, cnum);
} }

View File

@ -701,6 +701,10 @@ pub fn run_passes(sess: &Session,
} }
} }
if sess.opts.debugging_opts.profile {
modules_config.passes.push("insert-gcov-profiling".to_owned())
}
modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize)); modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize));
modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize)); modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize));

View File

@ -43,7 +43,7 @@ use rustc::dep_graph::AssertDepGraphSafe;
use rustc::middle::cstore::LinkMeta; use rustc::middle::cstore::LinkMeta;
use rustc::hir::map as hir_map; use rustc::hir::map as hir_map;
use rustc::util::common::time; use rustc::util::common::time;
use rustc::session::config::{self, NoDebugInfo}; use rustc::session::config::{self, NoDebugInfo, OutputFilenames};
use rustc::session::Session; use rustc::session::Session;
use rustc_incremental::IncrementalHashesMap; use rustc_incremental::IncrementalHashesMap;
use abi; use abi;
@ -1049,7 +1049,8 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet {
pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
analysis: ty::CrateAnalysis, analysis: ty::CrateAnalysis,
incremental_hashes_map: &IncrementalHashesMap) incremental_hashes_map: &IncrementalHashesMap,
output_filenames: &OutputFilenames)
-> CrateTranslation { -> CrateTranslation {
// Be careful with this krate: obviously it gives access to the // Be careful with this krate: obviously it gives access to the
// entire contents of the krate. So if you push any subtasks of // entire contents of the krate. So if you push any subtasks of
@ -1066,7 +1067,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let shared_ccx = SharedCrateContext::new(tcx, let shared_ccx = SharedCrateContext::new(tcx,
exported_symbols, exported_symbols,
check_overflow); check_overflow,
output_filenames);
// Translate the metadata. // Translate the metadata.
let (metadata_llcx, metadata_llmod, metadata) = let (metadata_llcx, metadata_llmod, metadata) =
time(tcx.sess.time_passes(), "write metadata", || { time(tcx.sess.time_passes(), "write metadata", || {

View File

@ -23,7 +23,7 @@ use monomorphize::Instance;
use partitioning::CodegenUnit; use partitioning::CodegenUnit;
use type_::Type; use type_::Type;
use rustc_data_structures::base_n; use rustc_data_structures::base_n;
use rustc::session::config::{self, NoDebugInfo}; use rustc::session::config::{self, NoDebugInfo, OutputFilenames};
use rustc::session::Session; use rustc::session::Session;
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
@ -81,6 +81,8 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
check_overflow: bool, check_overflow: bool,
use_dll_storage_attrs: bool, use_dll_storage_attrs: bool,
output_filenames: &'a OutputFilenames,
} }
/// The local portion of a `CrateContext`. There is one `LocalCrateContext` /// The local portion of a `CrateContext`. There is one `LocalCrateContext`
@ -264,7 +266,8 @@ pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (Cont
impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
exported_symbols: NodeSet, exported_symbols: NodeSet,
check_overflow: bool) check_overflow: bool,
output_filenames: &'b OutputFilenames)
-> SharedCrateContext<'b, 'tcx> { -> SharedCrateContext<'b, 'tcx> {
// An interesting part of Windows which MSVC forces our hand on (and // An interesting part of Windows which MSVC forces our hand on (and
// apparently MinGW didn't) is the usage of `dllimport` and `dllexport` // apparently MinGW didn't) is the usage of `dllimport` and `dllexport`
@ -316,6 +319,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
tcx: tcx, tcx: tcx,
check_overflow: check_overflow, check_overflow: check_overflow,
use_dll_storage_attrs: use_dll_storage_attrs, use_dll_storage_attrs: use_dll_storage_attrs,
output_filenames: output_filenames,
} }
} }
@ -350,6 +354,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
pub fn use_dll_storage_attrs(&self) -> bool { pub fn use_dll_storage_attrs(&self) -> bool {
self.use_dll_storage_attrs self.use_dll_storage_attrs
} }
pub fn output_filenames(&self) -> &OutputFilenames {
self.output_filenames
}
} }
impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {

View File

@ -38,10 +38,12 @@ use rustc::ty::{self, AdtKind, Ty};
use rustc::ty::layout::{self, LayoutTyper}; use rustc::ty::layout::{self, LayoutTyper};
use rustc::session::{Session, config}; use rustc::session::{Session, config};
use rustc::util::nodemap::FxHashMap; use rustc::util::nodemap::FxHashMap;
use rustc::util::common::path2cstr;
use libc::{c_uint, c_longlong}; use libc::{c_uint, c_longlong};
use std::ffi::CString; use std::ffi::CString;
use std::ptr; use std::ptr;
use std::path::Path;
use syntax::ast; use syntax::ast;
use syntax::symbol::{Interner, InternedString, Symbol}; use syntax::symbol::{Interner, InternedString, Symbol};
use syntax_pos::{self, Span}; use syntax_pos::{self, Span};
@ -794,7 +796,7 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
let file_metadata = llvm::LLVMRustDIBuilderCreateFile( let file_metadata = llvm::LLVMRustDIBuilderCreateFile(
debug_context.builder, name_in_debuginfo.as_ptr(), work_dir.as_ptr()); debug_context.builder, name_in_debuginfo.as_ptr(), work_dir.as_ptr());
return llvm::LLVMRustDIBuilderCreateCompileUnit( let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
debug_context.builder, debug_context.builder,
DW_LANG_RUST, DW_LANG_RUST,
file_metadata, file_metadata,
@ -802,8 +804,42 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
sess.opts.optimize != config::OptLevel::No, sess.opts.optimize != config::OptLevel::No,
flags.as_ptr() as *const _, flags.as_ptr() as *const _,
0, 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
// and replacing it with gcno/gcda, instead.
path_to_mdstring(debug_context.llcontext,
&scc.output_filenames().with_extension("gcno")),
// 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 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 { struct MetadataCreationResult {

View File

@ -67,6 +67,7 @@ const DW_TAG_arg_variable: c_uint = 0x101;
/// A context object for maintaining all state needed by the debuginfo module. /// A context object for maintaining all state needed by the debuginfo module.
pub struct CrateDebugContext<'tcx> { pub struct CrateDebugContext<'tcx> {
llcontext: ContextRef, llcontext: ContextRef,
llmod: ModuleRef,
builder: DIBuilderRef, builder: DIBuilderRef,
created_files: RefCell<FxHashMap<(Symbol, Symbol), DIFile>>, created_files: RefCell<FxHashMap<(Symbol, Symbol), DIFile>>,
created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Integer), DIType>>, created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Integer), DIType>>,
@ -87,6 +88,7 @@ impl<'tcx> CrateDebugContext<'tcx> {
let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
CrateDebugContext { CrateDebugContext {
llcontext: llcontext, llcontext: llcontext,
llmod: llmod,
builder: builder, builder: builder,
created_files: RefCell::new(FxHashMap()), created_files: RefCell::new(FxHashMap()),
created_enum_disr_types: RefCell::new(FxHashMap()), created_enum_disr_types: RefCell::new(FxHashMap()),

View File

@ -20,6 +20,7 @@ core = { path = "../libcore" }
libc = { path = "../rustc/libc_shim" } libc = { path = "../rustc/libc_shim" }
rand = { path = "../librand" } rand = { path = "../librand" }
compiler_builtins = { path = "../libcompiler_builtins" } compiler_builtins = { path = "../libcompiler_builtins" }
profiler_builtins = { path = "../libprofiler_builtins", optional = true }
std_unicode = { path = "../libstd_unicode" } std_unicode = { path = "../libstd_unicode" }
unwind = { path = "../libunwind" } unwind = { path = "../libunwind" }
@ -43,3 +44,4 @@ debug-jemalloc = ["alloc_jemalloc/debug"]
jemalloc = ["alloc_jemalloc"] jemalloc = ["alloc_jemalloc"]
force_alloc_system = [] force_alloc_system = []
panic-unwind = ["panic_unwind"] panic-unwind = ["panic_unwind"]
profiler = ["profiler_builtins"]

View File

@ -325,6 +325,10 @@ declare_features! (
// rustc internal // rustc internal
(active, sanitizer_runtime, "1.17.0", None), (active, sanitizer_runtime, "1.17.0", None),
// Used to identify crates that contain the profiler runtime
// rustc internal
(active, profiler_runtime, "1.18.0", None),
// `extern "x86-interrupt" fn()` // `extern "x86-interrupt" fn()`
(active, abi_x86_interrupt, "1.17.0", Some(40180)), (active, abi_x86_interrupt, "1.17.0", Some(40180)),
@ -691,6 +695,13 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
identify crates that contain the runtime of a \ identify crates that contain the runtime of a \
sanitizer and will never be stable", sanitizer and will never be stable",
cfg_fn!(sanitizer_runtime))), cfg_fn!(sanitizer_runtime))),
("profiler_runtime", Whitelisted, Gated(Stability::Unstable,
"profiler_runtime",
"the `#[profiler_runtime]` attribute is used to \
identify the `profiler_builtins` crate which \
contains the profiler runtime and will never be \
stable",
cfg_fn!(profiler_runtime))),
("allow_internal_unstable", Normal, Gated(Stability::Unstable, ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
"allow_internal_unstable", "allow_internal_unstable",

View File

@ -466,6 +466,10 @@ extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name,
unwrap(M)->addModuleFlag(Module::Warning, Name, Value); unwrap(M)->addModuleFlag(Module::Warning, Name, Value);
} }
extern "C" void LLVMRustMetadataAsValue(LLVMContextRef C, LLVMRustMetadataRef MD) {
wrap(MetadataAsValue::get(*unwrap(C), unwrap(MD)));
}
extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) { extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) {
return new DIBuilder(*unwrap(M)); return new DIBuilder(*unwrap(M));
} }

View File

@ -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() {}

View File

@ -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)

View File

@ -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() {}