mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
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:
parent
06fb4d2564
commit
42754ce710
1
configure
vendored
1
configure
vendored
@ -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 dist-src 1 "when building tarballs enables building a source tarball"
|
||||
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.
|
||||
opt_nosave optimize 1 "build optimized rust code"
|
||||
|
9
src/Cargo.lock
generated
9
src/Cargo.lock
generated
@ -355,6 +355,14 @@ dependencies = [
|
||||
"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]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.0.8"
|
||||
@ -833,6 +841,7 @@ dependencies = [
|
||||
"libc 0.0.0",
|
||||
"panic_abort 0.0.0",
|
||||
"panic_unwind 0.0.0",
|
||||
"profiler_builtins 0.0.0",
|
||||
"rand 0.0.0",
|
||||
"rustc_asan 0.0.0",
|
||||
"rustc_lsan 0.0.0",
|
||||
|
@ -268,6 +268,10 @@ pub fn compiletest(build: &Build,
|
||||
cmd.env("SANITIZER_SUPPORT", "1");
|
||||
}
|
||||
|
||||
if build.config.profiler {
|
||||
cmd.env("PROFILER_SUPPORT", "1");
|
||||
}
|
||||
|
||||
cmd.arg("--adb-path").arg("adb");
|
||||
cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
|
||||
if target.contains("android") {
|
||||
|
@ -50,6 +50,7 @@ pub struct Config {
|
||||
pub full_bootstrap: bool,
|
||||
pub extended: bool,
|
||||
pub sanitizers: bool,
|
||||
pub profiler: bool,
|
||||
|
||||
// llvm codegen options
|
||||
pub llvm_assertions: bool,
|
||||
@ -158,6 +159,7 @@ struct Build {
|
||||
extended: Option<bool>,
|
||||
verbose: Option<usize>,
|
||||
sanitizers: Option<bool>,
|
||||
profiler: Option<bool>,
|
||||
openssl_static: Option<bool>,
|
||||
}
|
||||
|
||||
@ -311,6 +313,7 @@ impl Config {
|
||||
set(&mut config.extended, build.extended);
|
||||
set(&mut config.verbose, build.verbose);
|
||||
set(&mut config.sanitizers, build.sanitizers);
|
||||
set(&mut config.profiler, build.profiler);
|
||||
set(&mut config.openssl_static, build.openssl_static);
|
||||
|
||||
if let Some(ref install) = toml.install {
|
||||
@ -462,6 +465,7 @@ impl Config {
|
||||
("FULL_BOOTSTRAP", self.full_bootstrap),
|
||||
("EXTENDED", self.extended),
|
||||
("SANITIZERS", self.sanitizers),
|
||||
("PROFILER", self.profiler),
|
||||
("DIST_SRC", self.rust_dist_src),
|
||||
("CARGO_OPENSSL_STATIC", self.openssl_static),
|
||||
}
|
||||
|
@ -147,6 +147,9 @@
|
||||
# Build the sanitizer runtimes
|
||||
#sanitizers = false
|
||||
|
||||
# Build the profiler runtime
|
||||
#profiler = false
|
||||
|
||||
# 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
|
||||
# known-good version of OpenSSL, compile it, and link it to Cargo.
|
||||
|
@ -667,6 +667,9 @@ impl Build {
|
||||
if self.config.backtrace {
|
||||
features.push_str(" backtrace");
|
||||
}
|
||||
if self.config.profiler {
|
||||
features.push_str(" profiler");
|
||||
}
|
||||
return features
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
- [Compiler flags](compiler-flags.md)
|
||||
- [linker_flavor](compiler-flags/linker-flavor.md)
|
||||
- [profile](compiler-flags/profile.md)
|
||||
- [remap_path_prefix](compiler-flags/remap-path-prefix.md)
|
||||
- [Language features](language-features.md)
|
||||
- [abi_msp430_interrupt](language-features/abi-msp430-interrupt.md)
|
||||
@ -71,6 +72,7 @@
|
||||
- [plugin_registrar](language-features/plugin-registrar.md)
|
||||
- [prelude_import](language-features/prelude-import.md)
|
||||
- [proc_macro](language-features/proc-macro.md)
|
||||
- [profiler_runtime](language-features/profiler-runtime.md)
|
||||
- [quote](language-features/quote.md)
|
||||
- [relaxed_adts](language-features/relaxed-adts.md)
|
||||
- [repr_align](language-features/repr-align.md)
|
||||
@ -180,6 +182,7 @@
|
||||
- [print](library-features/print.md)
|
||||
- [proc_macro_internals](library-features/proc-macro-internals.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)
|
||||
- [rand](library-features/rand.md)
|
||||
- [range_contains](library-features/range-contains.md)
|
||||
|
5
src/doc/unstable-book/src/compiler-flags/profile.md
Normal file
5
src/doc/unstable-book/src/compiler-flags/profile.md
Normal file
@ -0,0 +1,5 @@
|
||||
# `profile`
|
||||
|
||||
The tracking issue for this feature is: None
|
||||
|
||||
------------------------
|
@ -0,0 +1,5 @@
|
||||
# `profiler_runtime`
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
@ -0,0 +1,5 @@
|
||||
# `profiler_runtime_lib`
|
||||
|
||||
This feature is internal to the Rust compiler and is not intended for general use.
|
||||
|
||||
------------------------
|
18
src/libprofiler_builtins/Cargo.toml
Normal file
18
src/libprofiler_builtins/Cargo.toml
Normal 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"
|
56
src/libprofiler_builtins/build.rs
Normal file
56
src/libprofiler_builtins/build.rs
Normal 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");
|
||||
}
|
20
src/libprofiler_builtins/lib.rs
Normal file
20
src/libprofiler_builtins/lib.rs
Normal 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)]
|
@ -220,6 +220,7 @@ pub trait CrateStore {
|
||||
fn is_panic_runtime(&self, cnum: CrateNum) -> bool;
|
||||
fn is_compiler_builtins(&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 extern_crate(&self, cnum: CrateNum) -> Option<ExternCrate>;
|
||||
/// 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_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") }
|
||||
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 panic_strategy(&self, cnum: CrateNum) -> PanicStrategy {
|
||||
bug!("panic_strategy")
|
||||
|
@ -1025,6 +1025,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
"add a source pattern to the file path remapping config"),
|
||||
remap_path_prefix_to: Vec<String> = (vec![], parse_string_push, [TRACKED],
|
||||
"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 {
|
||||
|
@ -203,7 +203,8 @@ pub fn compile_input(sess: &Session,
|
||||
println!("Pre-trans");
|
||||
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) {
|
||||
println!("Post-trans");
|
||||
@ -1029,7 +1030,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
/// be discarded.
|
||||
pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
analysis: ty::CrateAnalysis,
|
||||
incremental_hashes_map: &IncrementalHashesMap)
|
||||
incremental_hashes_map: &IncrementalHashesMap,
|
||||
output_filenames: &OutputFilenames)
|
||||
-> trans::CrateTranslation {
|
||||
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 =
|
||||
time(time_passes,
|
||||
"translation",
|
||||
move || trans::trans_crate(tcx, analysis, &incremental_hashes_map));
|
||||
move || trans::trans_crate(tcx, analysis, &incremental_hashes_map, output_filenames));
|
||||
|
||||
time(time_passes,
|
||||
"assert dep graph",
|
||||
|
@ -587,7 +587,9 @@ extern "C" {
|
||||
pub fn LLVMIsUndef(Val: ValueRef) -> Bool;
|
||||
|
||||
// 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 LLVMAddNamedMetadataOperand(M: ModuleRef, Name: *const c_char, Val: ValueRef);
|
||||
|
||||
// Operations on scalar constants
|
||||
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 LLVMRustMetadataAsValue(C: ContextRef, MD: MetadataRef) -> ValueRef;
|
||||
|
||||
pub fn LLVMRustDIBuilderCreate(M: ModuleRef) -> DIBuilderRef;
|
||||
|
||||
pub fn LLVMRustDIBuilderDispose(Builder: DIBuilderRef);
|
||||
|
@ -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) {
|
||||
// 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);
|
||||
|
||||
|
@ -308,6 +308,11 @@ impl CrateMetadata {
|
||||
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 {
|
||||
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
|
||||
attr::contains_name(&attrs, "no_builtins")
|
||||
|
@ -275,6 +275,10 @@ impl CrateStore for cstore::CStore {
|
||||
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 {
|
||||
self.get_crate_data(cnum).panic_strategy()
|
||||
}
|
||||
|
@ -1074,6 +1074,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
|
||||
// symbols from the dylib.
|
||||
let src = sess.cstore.used_crate_source(cnum);
|
||||
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) => {
|
||||
link_sanitizer_runtime(cmd, sess, tmpdir, cnum);
|
||||
}
|
||||
|
@ -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_size = Some(get_llvm_opt_size(sess.opts.optimize));
|
||||
|
||||
|
@ -42,7 +42,7 @@ use rustc::dep_graph::AssertDepGraphSafe;
|
||||
use rustc::middle::cstore::LinkMeta;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::util::common::time;
|
||||
use session::config::{self, NoDebugInfo};
|
||||
use session::config::{self, NoDebugInfo, OutputFilenames};
|
||||
use rustc_incremental::IncrementalHashesMap;
|
||||
use session::{self, DataTypeKind, Session};
|
||||
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>,
|
||||
analysis: ty::CrateAnalysis,
|
||||
incremental_hashes_map: &IncrementalHashesMap)
|
||||
incremental_hashes_map: &IncrementalHashesMap,
|
||||
output_filenames: &OutputFilenames)
|
||||
-> CrateTranslation {
|
||||
// Be careful with this krate: obviously it gives access to the
|
||||
// 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,
|
||||
exported_symbols,
|
||||
check_overflow);
|
||||
check_overflow,
|
||||
output_filenames);
|
||||
// Translate the metadata.
|
||||
let (metadata_llcx, metadata_llmod, metadata) =
|
||||
time(tcx.sess.time_passes(), "write metadata", || {
|
||||
|
@ -27,6 +27,7 @@ use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::layout::{LayoutTyper, TyLayout};
|
||||
use session::config::NoDebugInfo;
|
||||
use session::config::OutputFilenames;
|
||||
use session::Session;
|
||||
use session::config;
|
||||
use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
|
||||
@ -83,6 +84,8 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
|
||||
check_overflow: bool,
|
||||
|
||||
use_dll_storage_attrs: bool,
|
||||
|
||||
output_filenames: &'a OutputFilenames,
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
|
||||
exported_symbols: NodeSet,
|
||||
check_overflow: bool)
|
||||
check_overflow: bool,
|
||||
output_filenames: &'b OutputFilenames)
|
||||
-> SharedCrateContext<'b, 'tcx> {
|
||||
// An interesting part of Windows which MSVC forces our hand on (and
|
||||
// apparently MinGW didn't) is the usage of `dllimport` and `dllexport`
|
||||
@ -319,6 +323,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
|
||||
tcx: tcx,
|
||||
check_overflow: check_overflow,
|
||||
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 {
|
||||
self.use_dll_storage_attrs
|
||||
}
|
||||
|
||||
pub fn output_filenames(&self) -> &OutputFilenames {
|
||||
self.output_filenames
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
|
||||
|
@ -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,7 +790,7 @@ 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,
|
||||
@ -796,12 +798,46 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
|
||||
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
|
||||
// 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 {
|
||||
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 {
|
||||
|
@ -67,6 +67,7 @@ const DW_TAG_arg_variable: c_uint = 0x101;
|
||||
/// A context object for maintaining all state needed by the debuginfo module.
|
||||
pub struct CrateDebugContext<'tcx> {
|
||||
llcontext: ContextRef,
|
||||
llmod: ModuleRef,
|
||||
builder: DIBuilderRef,
|
||||
created_files: RefCell<FxHashMap<(Symbol, Symbol), DIFile>>,
|
||||
created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Integer), DIType>>,
|
||||
@ -87,6 +88,7 @@ impl<'tcx> CrateDebugContext<'tcx> {
|
||||
let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
|
||||
CrateDebugContext {
|
||||
llcontext: llcontext,
|
||||
llmod: llmod,
|
||||
builder: builder,
|
||||
created_files: RefCell::new(FxHashMap()),
|
||||
created_enum_disr_types: RefCell::new(FxHashMap()),
|
||||
|
@ -20,6 +20,7 @@ core = { path = "../libcore" }
|
||||
libc = { path = "../rustc/libc_shim" }
|
||||
rand = { path = "../librand" }
|
||||
compiler_builtins = { path = "../libcompiler_builtins" }
|
||||
profiler_builtins = { path = "../libprofiler_builtins", optional = true }
|
||||
std_unicode = { path = "../libstd_unicode" }
|
||||
unwind = { path = "../libunwind" }
|
||||
|
||||
@ -43,3 +44,4 @@ debug-jemalloc = ["alloc_jemalloc/debug"]
|
||||
jemalloc = ["alloc_jemalloc"]
|
||||
force_alloc_system = []
|
||||
panic-unwind = ["panic_unwind"]
|
||||
profiler = ["profiler_builtins"]
|
||||
|
@ -331,6 +331,10 @@ declare_features! (
|
||||
// rustc internal
|
||||
(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()`
|
||||
(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 \
|
||||
sanitizer and will never be stable",
|
||||
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",
|
||||
|
@ -466,6 +466,10 @@ extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name,
|
||||
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) {
|
||||
return new DIBuilder(*unwrap(M));
|
||||
}
|
||||
|
13
src/test/compile-fail/feature-gate-profiler-runtime.rs
Normal file
13
src/test/compile-fail/feature-gate-profiler-runtime.rs
Normal 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() {}
|
7
src/test/run-make/profile/Makefile
Normal file
7
src/test/run-make/profile/Makefile
Normal 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)
|
11
src/test/run-make/profile/test.rs
Normal file
11
src/test/run-make/profile/test.rs
Normal 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() {}
|
Loading…
Reference in New Issue
Block a user