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 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
9
src/Cargo.lock
generated
@ -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",
|
||||||
|
@ -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") {
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
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_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")
|
||||||
|
@ -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 {
|
||||||
|
@ -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",
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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")
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
@ -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", || {
|
||||||
|
@ -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> {
|
||||||
|
@ -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 {
|
||||||
|
@ -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()),
|
||||||
|
@ -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"]
|
||||||
|
@ -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",
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
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