Add profiling support, through the rustc -Z profile flag.

When -Z profile is passed, the GCDAProfiling LLVM pass is added
to the pipeline, which uses debug information to instrument the IR.
After compiling with -Z profile, the $(OUT_DIR)/$(CRATE_NAME).gcno
file is created, containing initial profiling information.
After running the program built, the $(OUT_DIR)/$(CRATE_NAME).gcda
file is created, containing branch counters.

The created *.gcno and *.gcda files can be processed using
the "llvm-cov gcov" and "lcov" tools. The profiling data LLVM
generates does not faithfully follow the GCC's format for *.gcno
and *.gcda files, and so it will probably not work with other tools
(such as gcov itself) that consume these files.
This commit is contained in:
whitequark 2017-02-13 09:57:50 +00:00
parent 06fb4d2564
commit 42754ce710
32 changed files with 296 additions and 9 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

@ -355,6 +355,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.45 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "pulldown-cmark" name = "pulldown-cmark"
version = "0.0.8" version = "0.0.8"
@ -833,6 +841,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

@ -268,6 +268,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,
@ -158,6 +159,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>,
} }
@ -311,6 +313,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 {
@ -462,6 +465,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

@ -667,6 +667,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)
@ -71,6 +72,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)
- [relaxed_adts](language-features/relaxed-adts.md) - [relaxed_adts](language-features/relaxed-adts.md)
- [repr_align](language-features/repr-align.md) - [repr_align](language-features/repr-align.md)
@ -180,6 +182,7 @@
- [print](library-features/print.md) - [print](library-features/print.md)
- [proc_macro_internals](library-features/proc-macro-internals.md) - [proc_macro_internals](library-features/proc-macro-internals.md)
- [process_try_wait](library-features/process-try-wait.md) - [process_try_wait](library-features/process-try-wait.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

@ -220,6 +220,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
@ -356,6 +357,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

@ -1025,6 +1025,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"add a source pattern to the file path remapping config"), "add a source pattern to the file path remapping config"),
remap_path_prefix_to: Vec<String> = (vec![], parse_string_push, [TRACKED], remap_path_prefix_to: Vec<String> = (vec![], parse_string_push, [TRACKED],
"add a mapping target to the file path remapping config"), "add a mapping target to the file path remapping config"),
profile: bool = (false, parse_bool, [TRACKED],
"insert profiling code"),
} }
pub fn default_lib_output() -> CrateType { pub fn default_lib_output() -> CrateType {

View File

@ -203,7 +203,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");
@ -1029,7 +1030,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();
@ -1077,7 +1079,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

@ -587,7 +587,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;
@ -1328,6 +1330,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

@ -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| {
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.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!
@ -1071,6 +1098,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

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

View File

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

View File

@ -1074,6 +1074,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

@ -699,6 +699,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

@ -42,7 +42,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 session::config::{self, NoDebugInfo}; use session::config::{self, NoDebugInfo, OutputFilenames};
use rustc_incremental::IncrementalHashesMap; use rustc_incremental::IncrementalHashesMap;
use session::{self, DataTypeKind, Session}; use session::{self, DataTypeKind, Session};
use abi; use abi;
@ -1053,7 +1053,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
@ -1070,7 +1071,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

@ -27,6 +27,7 @@ use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{LayoutTyper, TyLayout}; use rustc::ty::layout::{LayoutTyper, TyLayout};
use session::config::NoDebugInfo; use session::config::NoDebugInfo;
use session::config::OutputFilenames;
use session::Session; use session::Session;
use session::config; use session::config;
use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
@ -83,6 +84,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`
@ -266,7 +269,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`
@ -319,6 +323,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,
} }
} }
@ -353,6 +358,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

@ -39,10 +39,12 @@ use rustc::ty::{self, AdtKind, Ty};
use rustc::ty::layout::{self, LayoutTyper}; use rustc::ty::layout::{self, LayoutTyper};
use session::config; use session::config;
use util::nodemap::FxHashMap; use 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};
@ -788,7 +790,7 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
let file_metadata = llvm::LLVMRustDIBuilderCreateFile( let file_metadata = llvm::LLVMRustDIBuilderCreateFile(
debug_context.builder, compile_unit_name, work_dir.as_ptr()); debug_context.builder, compile_unit_name, 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,
@ -796,12 +798,46 @@ 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 fallback_path(scc: &SharedCrateContext) -> CString { fn fallback_path(scc: &SharedCrateContext) -> CString {
CString::new(scc.tcx().crate_name(LOCAL_CRATE).to_string()).unwrap() 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 { 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

@ -331,6 +331,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)),
@ -693,6 +697,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() {}