pub mod common;
pub mod ppaux;
pub mod nodemap;
- pub mod time_graph;
pub mod profiling;
pub mod bug;
}
+use std::borrow::Cow;
use std::fs;
use std::io::{BufWriter, Write};
use std::mem;
Other,
}
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ProfilerEvent {
QueryStart { query_name: &'static str, category: ProfileCategory, time: u64 },
QueryEnd { query_name: &'static str, category: ProfileCategory, time: u64 },
- GenericActivityStart { category: ProfileCategory, time: u64 },
- GenericActivityEnd { category: ProfileCategory, time: u64 },
+ GenericActivityStart { category: ProfileCategory, label: Cow<'static, str>, time: u64 },
+ GenericActivityEnd { category: ProfileCategory, label: Cow<'static, str>, time: u64 },
IncrementalLoadResultStart { query_name: &'static str, time: u64 },
IncrementalLoadResultEnd { query_name: &'static str, time: u64 },
QueryCacheHit { query_name: &'static str, category: ProfileCategory, time: u64 },
}
#[inline]
- pub fn start_activity(&mut self, category: ProfileCategory) {
+ pub fn start_activity(
+ &mut self,
+ category: ProfileCategory,
+ label: impl Into<Cow<'static, str>>,
+ ) {
self.record(ProfilerEvent::GenericActivityStart {
category,
+ label: label.into(),
time: self.get_time_from_start(),
})
}
#[inline]
- pub fn end_activity(&mut self, category: ProfileCategory) {
+ pub fn end_activity(
+ &mut self,
+ category: ProfileCategory,
+ label: impl Into<Cow<'static, str>>,
+ ) {
self.record(ProfilerEvent::GenericActivityEnd {
category,
+ label: label.into(),
time: self.get_time_from_start(),
})
}
nanos,
thread_id,
).unwrap(),
- GenericActivityStart { category, time: _ } =>
+ GenericActivityStart { category, label, time: _ } =>
write!(file,
"{{
\"GenericActivityStart\": {{\
\"category\": \"{:?}\",\
+ \"label\": \"{}\",\
\"time\": {{\
\"secs\": {},\
\"nanos\": {}\
}}\
}}",
category,
+ label,
secs,
nanos,
thread_id,
).unwrap(),
- GenericActivityEnd { category, time: _ } =>
+ GenericActivityEnd { category, label, time: _ } =>
write!(file,
"{{\
\"GenericActivityEnd\": {{\
\"category\": \"{:?}\",\
+ \"label\": \"{}\",\
\"time\": {{\
\"secs\": {},\
\"nanos\": {}\
}}\
}}",
category,
+ label,
secs,
nanos,
thread_id,
secs,
nanos,
thread_id,
- ).unwrap()
+ ).unwrap(),
}
}
}
+++ /dev/null
-use rustc_data_structures::fx::FxHashMap;
-use std::fs::File;
-use std::io::prelude::*;
-use std::marker::PhantomData;
-use std::mem;
-use std::sync::{Arc, Mutex};
-use std::time::Instant;
-
-const OUTPUT_WIDTH_IN_PX: u64 = 1000;
-const TIME_LINE_HEIGHT_IN_PX: u64 = 20;
-const TIME_LINE_HEIGHT_STRIDE_IN_PX: usize = 30;
-
-#[derive(Clone)]
-struct Timing {
- start: Instant,
- end: Instant,
- work_package_kind: WorkPackageKind,
- name: String,
- events: Vec<(String, Instant)>,
-}
-
-#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
-pub struct TimelineId(pub usize);
-
-#[derive(Clone)]
-struct PerThread {
- timings: Vec<Timing>,
- open_work_package: Option<(Instant, WorkPackageKind, String)>,
-}
-
-#[derive(Clone)]
-pub struct TimeGraph {
- data: Arc<Mutex<FxHashMap<TimelineId, PerThread>>>,
-}
-
-#[derive(Clone, Copy)]
-pub struct WorkPackageKind(pub &'static [&'static str]);
-
-pub struct Timeline {
- token: Option<RaiiToken>,
-}
-
-struct RaiiToken {
- graph: TimeGraph,
- timeline: TimelineId,
- events: Vec<(String, Instant)>,
- // The token must not be Send:
- _marker: PhantomData<*const ()>
-}
-
-
-impl Drop for RaiiToken {
- fn drop(&mut self) {
- self.graph.end(self.timeline, mem::replace(&mut self.events, Vec::new()));
- }
-}
-
-impl TimeGraph {
- pub fn new() -> TimeGraph {
- TimeGraph {
- data: Arc::new(Mutex::new(FxHashMap::default()))
- }
- }
-
- pub fn start(&self,
- timeline: TimelineId,
- work_package_kind: WorkPackageKind,
- name: &str) -> Timeline {
- {
- let mut table = self.data.lock().unwrap();
-
- let data = table.entry(timeline).or_insert(PerThread {
- timings: Vec::new(),
- open_work_package: None,
- });
-
- assert!(data.open_work_package.is_none());
- data.open_work_package = Some((Instant::now(), work_package_kind, name.to_string()));
- }
-
- Timeline {
- token: Some(RaiiToken {
- graph: self.clone(),
- timeline,
- events: Vec::new(),
- _marker: PhantomData,
- }),
- }
- }
-
- fn end(&self, timeline: TimelineId, events: Vec<(String, Instant)>) {
- let end = Instant::now();
-
- let mut table = self.data.lock().unwrap();
- let data = table.get_mut(&timeline).unwrap();
-
- if let Some((start, work_package_kind, name)) = data.open_work_package.take() {
- data.timings.push(Timing {
- start,
- end,
- work_package_kind,
- name,
- events,
- });
- } else {
- bug!("end timing without start?")
- }
- }
-
- pub fn dump(&self, output_filename: &str) {
- let table = self.data.lock().unwrap();
-
- for data in table.values() {
- assert!(data.open_work_package.is_none());
- }
-
- let mut threads: Vec<PerThread> =
- table.values().map(|data| data.clone()).collect();
-
- threads.sort_by_key(|timeline| timeline.timings[0].start);
-
- let earliest_instant = threads[0].timings[0].start;
- let latest_instant = threads.iter()
- .map(|timeline| timeline.timings
- .last()
- .unwrap()
- .end)
- .max()
- .unwrap();
- let max_distance = distance(earliest_instant, latest_instant);
-
- let mut file = File::create(format!("{}.html", output_filename)).unwrap();
-
- writeln!(file, "
- <html>
- <head>
- <style>
- #threads a {{
- position: absolute;
- overflow: hidden;
- }}
- #threads {{
- height: {total_height}px;
- width: {width}px;
- }}
-
- .timeline {{
- display: none;
- width: {width}px;
- position: relative;
- }}
-
- .timeline:target {{
- display: block;
- }}
-
- .event {{
- position: absolute;
- }}
- </style>
- </head>
- <body>
- <div id='threads'>
- ",
- total_height = threads.len() * TIME_LINE_HEIGHT_STRIDE_IN_PX,
- width = OUTPUT_WIDTH_IN_PX,
- ).unwrap();
-
- let mut color = 0;
- for (line_index, thread) in threads.iter().enumerate() {
- let line_top = line_index * TIME_LINE_HEIGHT_STRIDE_IN_PX;
-
- for span in &thread.timings {
- let start = distance(earliest_instant, span.start);
- let end = distance(earliest_instant, span.end);
-
- let start = normalize(start, max_distance, OUTPUT_WIDTH_IN_PX);
- let end = normalize(end, max_distance, OUTPUT_WIDTH_IN_PX);
-
- let colors = span.work_package_kind.0;
-
- writeln!(file, "<a href='#timing{}'
- style='top:{}px; \
- left:{}px; \
- width:{}px; \
- height:{}px; \
- background:{};'>{}</a>",
- color,
- line_top,
- start,
- end - start,
- TIME_LINE_HEIGHT_IN_PX,
- colors[color % colors.len()],
- span.name,
- ).unwrap();
-
- color += 1;
- }
- }
-
- writeln!(file, "
- </div>
- ").unwrap();
-
- let mut idx = 0;
- for thread in threads.iter() {
- for timing in &thread.timings {
- let colors = timing.work_package_kind.0;
- let height = TIME_LINE_HEIGHT_STRIDE_IN_PX * timing.events.len();
- writeln!(file, "<div class='timeline'
- id='timing{}'
- style='background:{};height:{}px;'>",
- idx,
- colors[idx % colors.len()],
- height).unwrap();
- idx += 1;
- let max = distance(timing.start, timing.end);
- for (i, &(ref event, time)) in timing.events.iter().enumerate() {
- let i = i as u64;
- let time = distance(timing.start, time);
- let at = normalize(time, max, OUTPUT_WIDTH_IN_PX);
- writeln!(file, "<span class='event'
- style='left:{}px;\
- top:{}px;'>{}</span>",
- at,
- TIME_LINE_HEIGHT_IN_PX * i,
- event).unwrap();
- }
- writeln!(file, "</div>").unwrap();
- }
- }
-
- writeln!(file, "
- </body>
- </html>
- ").unwrap();
- }
-}
-
-impl Timeline {
- pub fn noop() -> Timeline {
- Timeline { token: None }
- }
-
- /// Record an event which happened at this moment on this timeline.
- ///
- /// Events are displayed in the eventual HTML output where you can click on
- /// a particular timeline and it'll expand to all of the events that
- /// happened on that timeline. This can then be used to drill into a
- /// particular timeline and see what events are happening and taking the
- /// most time.
- pub fn record(&mut self, name: &str) {
- if let Some(ref mut token) = self.token {
- token.events.push((name.to_string(), Instant::now()));
- }
- }
-}
-
-fn distance(zero: Instant, x: Instant) -> u64 {
-
- let duration = x.duration_since(zero);
- (duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64) // / div
-}
-
-fn normalize(distance: u64, max: u64, max_pixels: u64) -> u64 {
- (max_pixels * distance) / max
-}
-
to_llvm_opt_settings};
use crate::llvm::archive_ro::ArchiveRO;
use crate::llvm::{self, True, False};
-use crate::time_graph::Timeline;
use crate::{ModuleLlvm, LlvmCodegenBackend};
use rustc_codegen_ssa::back::symbol_export;
use rustc_codegen_ssa::back::write::{ModuleConfig, CodegenContext, FatLTOInput};
use rustc::middle::exported_symbols::SymbolExportLevel;
use rustc::session::config::{self, Lto};
use rustc::util::common::time_ext;
+use rustc::util::profiling::ProfileCategory;
use rustc_data_structures::fx::FxHashMap;
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
}
fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
- timeline: &mut Timeline,
diag_handler: &Handler)
-> Result<(Vec<CString>, Vec<(SerializedModule<ModuleBuffer>, CString)>), FatalError>
{
.iter()
.filter_map(symbol_filter)
.collect::<Vec<CString>>();
- timeline.record("whitelist");
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
+ "generate_symbol_white_list_for_thinlto");
info!("{} symbols to preserve in this crate", symbol_white_list.len());
// If we're performing LTO for the entire crate graph, then for each of our
}
for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
+ format!("load: {}", path.display()));
let exported_symbols = cgcx.exported_symbols
.as_ref().expect("needs exported symbols for LTO");
symbol_white_list.extend(
let bc = SerializedModule::FromRlib(bc);
upstream_modules.push((bc, CString::new(id).unwrap()));
}
- timeline.record(&format!("load: {}", path.display()));
}
}
/// for further optimization.
pub(crate) fn run_fat(cgcx: &CodegenContext<LlvmCodegenBackend>,
modules: Vec<FatLTOInput<LlvmCodegenBackend>>,
- cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
- timeline: &mut Timeline)
+ cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>)
-> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError>
{
let diag_handler = cgcx.create_diag_handler();
- let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, timeline, &diag_handler)?;
+ let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, &diag_handler)?;
let symbol_white_list = symbol_white_list.iter()
.map(|c| c.as_ptr())
.collect::<Vec<_>>();
cached_modules,
upstream_modules,
&symbol_white_list,
- timeline,
)
}
/// can simply be copied over from the incr. comp. cache.
pub(crate) fn run_thin(cgcx: &CodegenContext<LlvmCodegenBackend>,
modules: Vec<(String, ThinBuffer)>,
- cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
- timeline: &mut Timeline)
+ cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>)
-> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError>
{
let diag_handler = cgcx.create_diag_handler();
- let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, timeline, &diag_handler)?;
+ let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, &diag_handler)?;
let symbol_white_list = symbol_white_list.iter()
.map(|c| c.as_ptr())
.collect::<Vec<_>>();
modules,
upstream_modules,
cached_modules,
- &symbol_white_list,
- timeline)
+ &symbol_white_list)
}
pub(crate) fn prepare_thin(
mut modules: Vec<FatLTOInput<LlvmCodegenBackend>>,
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
- symbol_white_list: &[*const libc::c_char],
- timeline: &mut Timeline)
+ symbol_white_list: &[*const libc::c_char])
-> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError>
{
info!("going for a fat lto");
write::llvm_err(&diag_handler, &msg)
})
})?;
- timeline.record(&format!("link {:?}", name));
serialized_bitcode.push(bc_decoded);
}
drop(linker);
}
save_temp_bitcode(&cgcx, &module, "lto.after-nounwind");
}
- timeline.record("passes");
}
Ok(LtoModuleCodegen::Fat {
modules: Vec<(String, ThinBuffer)>,
serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
- symbol_white_list: &[*const libc::c_char],
- timeline: &mut Timeline)
+ symbol_white_list: &[*const libc::c_char])
-> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError>
{
unsafe {
});
thin_buffers.push(buffer);
module_names.push(cname);
- timeline.record(&name);
}
// FIXME: All upstream crates are deserialized internally in the
})?;
info!("thin LTO data created");
- timeline.record("data");
let import_map = if cgcx.incr_comp_session_dir.is_some() {
ThinLTOImports::from_thin_lto_data(data)
ThinLTOImports::default()
};
info!("thin LTO import map loaded");
- timeline.record("import-map-loaded");
let data = ThinData(data);
pub unsafe fn optimize_thin_module(
thin_module: &mut ThinModule<LlvmCodegenBackend>,
cgcx: &CodegenContext<LlvmCodegenBackend>,
- timeline: &mut Timeline
) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
let diag_handler = cgcx.create_diag_handler();
let tm = (cgcx.tm_factory.0)().map_err(|e| {
// Like with "fat" LTO, get some better optimizations if landing pads
// are disabled by removing all landing pads.
if cgcx.no_landing_pads {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
+ "LLVM_remove_landing_pads");
llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind");
- timeline.record("nounwind");
}
// Up next comes the per-module local analyses that we do for Thin LTO.
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
- timeline.record("rename");
if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve");
- timeline.record("resolve");
if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize");
- timeline.record("internalize");
if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-import");
- timeline.record("import");
// Ok now this is a bit unfortunate. This is also something you won't
// find upstream in LLVM's ThinLTO passes! This is a hack for now to
// fixed in LLVM.
llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
save_temp_bitcode(cgcx, &module, "thin-lto-after-patch");
- timeline.record("patch");
// Alright now that we've done everything related to the ThinLTO
// analysis it's time to run some optimizations! Here we use the same
let config = cgcx.config(module.kind);
run_pass_manager(cgcx, &module, config, true);
save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
- timeline.record("thin-done");
}
Ok(module)
}
use crate::back::lto::ThinBuffer;
use crate::base;
use crate::consts;
-use crate::time_graph::Timeline;
use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
use crate::llvm_util;
use crate::ModuleLlvm;
use rustc::ty::TyCtxt;
use rustc_codegen_ssa::{ModuleCodegen, CompiledModule};
use rustc::util::common::time_ext;
+use rustc::util::profiling::ProfileCategory;
use rustc_fs_util::{path_to_c_string, link_or_copy};
use rustc_data_structures::small_c_str::SmallCStr;
use errors::{Handler, FatalError};
pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
module: &ModuleCodegen<ModuleLlvm>,
- config: &ModuleConfig,
- timeline: &mut Timeline)
+ config: &ModuleConfig)
-> Result<(), FatalError>
{
let llmod = module.module_llvm.llmod();
diag_handler.abort_if_errors();
// Finally, run the actual optimization passes
- time_ext(config.time_passes,
- None,
- &format!("llvm function passes [{}]", module_name.unwrap()),
- || {
- llvm::LLVMRustRunFunctionPassManager(fpm, llmod)
- });
- timeline.record("fpm");
- time_ext(config.time_passes,
- None,
- &format!("llvm module passes [{}]", module_name.unwrap()),
- || {
- llvm::LLVMRunPassManager(mpm, llmod)
- });
+ {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_function_passes");
+ time_ext(config.time_passes,
+ None,
+ &format!("llvm function passes [{}]", module_name.unwrap()),
+ || {
+ llvm::LLVMRustRunFunctionPassManager(fpm, llmod)
+ });
+ }
+ {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_module_passes");
+ time_ext(config.time_passes,
+ None,
+ &format!("llvm module passes [{}]", module_name.unwrap()),
+ || {
+ llvm::LLVMRunPassManager(mpm, llmod)
+ });
+ }
// Deallocate managers that we're now done with
llvm::LLVMDisposePassManager(fpm);
pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
module: ModuleCodegen<ModuleLlvm>,
- config: &ModuleConfig,
- timeline: &mut Timeline)
+ config: &ModuleConfig)
-> Result<CompiledModule, FatalError>
{
- timeline.record("codegen");
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "codegen");
{
let llmod = module.module_llvm.llmod();
let llcx = &*module.module_llvm.llcx;
if write_bc || config.emit_bc_compressed || config.embed_bitcode {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_make_bitcode");
let thin = ThinBuffer::new(llmod);
let data = thin.data();
- timeline.record("make-bc");
if write_bc {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_bitcode");
if let Err(e) = fs::write(&bc_out, data) {
diag_handler.err(&format!("failed to write bytecode: {}", e));
}
- timeline.record("write-bc");
}
if config.embed_bitcode {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_embed_bitcode");
embed_bitcode(cgcx, llcx, llmod, Some(data));
- timeline.record("embed-bc");
}
if config.emit_bc_compressed {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
+ "LLVM_compress_bitcode");
let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
let data = bytecode::encode(&module.name, data);
if let Err(e) = fs::write(&dst, data) {
diag_handler.err(&format!("failed to write bytecode: {}", e));
}
- timeline.record("compress-bc");
}
} else if config.embed_bitcode_marker {
embed_bitcode(cgcx, llcx, llmod, None);
time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()),
|| -> Result<(), FatalError> {
if config.emit_ir {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_ir");
let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
let out = path_to_c_string(&out);
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback);
llvm::LLVMDisposePassManager(cpm);
});
- timeline.record("ir");
}
if config.emit_asm || asm_to_obj {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_asm");
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
// We can't use the same module for asm and binary output, because that triggers
write_output_file(diag_handler, tm, cpm, llmod, &path,
llvm::FileType::AssemblyFile)
})?;
- timeline.record("asm");
}
if write_obj {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_obj");
with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
llvm::FileType::ObjectFile)
})?;
- timeline.record("obj");
} else if asm_to_obj {
+ let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_asm_to_obj");
let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
run_assembler(cgcx, diag_handler, &assembly, &obj_out);
- timeline.record("asm_to_obj");
if !config.emit_asm && !cgcx.save_temps {
drop(fs::remove_file(&assembly));
use rustc_codegen_ssa::CompiledModule;
use errors::{FatalError, Handler};
use rustc::dep_graph::WorkProduct;
-use rustc::util::time_graph::Timeline;
use syntax_pos::symbol::InternedString;
use rustc::mir::mono::Stats;
pub use llvm_util::target_features;
use rustc::session::Session;
use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel};
use rustc::ty::{self, TyCtxt};
-use rustc::util::time_graph;
use rustc::util::profiling::ProfileCategory;
use rustc::util::common::ErrorReported;
use rustc_mir::monomorphize;
cgcx: &CodegenContext<Self>,
modules: Vec<FatLTOInput<Self>>,
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
- timeline: &mut Timeline
) -> Result<LtoModuleCodegen<Self>, FatalError> {
- back::lto::run_fat(cgcx, modules, cached_modules, timeline)
+ back::lto::run_fat(cgcx, modules, cached_modules)
}
fn run_thin_lto(
cgcx: &CodegenContext<Self>,
modules: Vec<(String, Self::ThinBuffer)>,
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
- timeline: &mut Timeline
) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
- back::lto::run_thin(cgcx, modules, cached_modules, timeline)
+ back::lto::run_thin(cgcx, modules, cached_modules)
}
unsafe fn optimize(
cgcx: &CodegenContext<Self>,
diag_handler: &Handler,
module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
- timeline: &mut Timeline
) -> Result<(), FatalError> {
- back::write::optimize(cgcx, diag_handler, module, config, timeline)
+ back::write::optimize(cgcx, diag_handler, module, config)
}
unsafe fn optimize_thin(
cgcx: &CodegenContext<Self>,
thin: &mut ThinModule<Self>,
- timeline: &mut Timeline
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
- back::lto::optimize_thin_module(thin, cgcx, timeline)
+ back::lto::optimize_thin_module(thin, cgcx)
}
unsafe fn codegen(
cgcx: &CodegenContext<Self>,
diag_handler: &Handler,
module: ModuleCodegen<Self::Module>,
config: &ModuleConfig,
- timeline: &mut Timeline
) -> Result<CompiledModule, FatalError> {
- back::write::codegen(cgcx, diag_handler, module, config, timeline)
+ back::write::codegen(cgcx, diag_handler, module, config)
}
fn prepare_thin(
module: ModuleCodegen<Self::Module>
// Run the linker on any artifacts that resulted from the LLVM run.
// This should produce either a finished executable or library.
- sess.profiler(|p| p.start_activity(ProfileCategory::Linking));
+ sess.profiler(|p| p.start_activity(ProfileCategory::Linking, "link_crate"));
time(sess, "linking", || {
back::link::link_binary(sess, &codegen_results,
outputs, &codegen_results.crate_name.as_str());
});
- sess.profiler(|p| p.end_activity(ProfileCategory::Linking));
+ sess.profiler(|p| p.end_activity(ProfileCategory::Linking, "link_crate"));
// Now that we won't touch anything in the incremental compilation directory
// any more, we can finalize it (which involves renaming it)
use crate::traits::*;
use crate::ModuleCodegen;
-use rustc::util::time_graph::Timeline;
use rustc_errors::FatalError;
use std::sync::Arc;
pub unsafe fn optimize(
&mut self,
cgcx: &CodegenContext<B>,
- timeline: &mut Timeline
) -> Result<ModuleCodegen<B::Module>, FatalError> {
match *self {
LtoModuleCodegen::Fat { ref mut module, .. } => {
{
let config = cgcx.config(module.kind);
B::run_lto_pass_manager(cgcx, &module, config, false);
- timeline.record("fat-done");
}
Ok(module)
}
- LtoModuleCodegen::Thin(ref mut thin) => B::optimize_thin(cgcx, thin, timeline),
+ LtoModuleCodegen::Thin(ref mut thin) => B::optimize_thin(cgcx, thin),
}
}
use rustc::session::config::{self, OutputFilenames, OutputType, Passes, Sanitizer, Lto};
use rustc::session::Session;
use rustc::util::nodemap::FxHashMap;
-use rustc::util::time_graph::{self, TimeGraph, Timeline};
use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc::ty::TyCtxt;
use rustc::util::common::{time_depth, set_time_depth, print_time_passes_entry};
-use rustc::util::profiling::SelfProfiler;
+use rustc::util::profiling::{ProfileCategory, SelfProfiler};
use rustc_fs_util::link_or_copy;
use rustc_data_structures::svh::Svh;
use rustc_errors::{Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
use parking_lot::Mutex as PlMutex;
use std::any::Any;
+use std::borrow::Cow;
use std::fs;
use std::io;
use std::mem;
}
}
+pub struct ProfileGenericActivityTimer {
+ profiler: Option<Arc<PlMutex<SelfProfiler>>>,
+ category: ProfileCategory,
+ label: Cow<'static, str>,
+}
+
+impl ProfileGenericActivityTimer {
+ pub fn start(
+ profiler: Option<Arc<PlMutex<SelfProfiler>>>,
+ category: ProfileCategory,
+ label: Cow<'static, str>,
+ ) -> ProfileGenericActivityTimer {
+ if let Some(profiler) = &profiler {
+ let mut p = profiler.lock();
+ p.start_activity(category, label.clone());
+ }
+
+ ProfileGenericActivityTimer {
+ profiler,
+ category,
+ label,
+ }
+ }
+}
+
+impl Drop for ProfileGenericActivityTimer {
+ fn drop(&mut self) {
+ if let Some(profiler) = &self.profiler {
+ let mut p = profiler.lock();
+ p.end_activity(self.category, self.label.clone());
+ }
+ }
+}
+
/// Additional resources used by optimize_and_codegen (not module specific)
#[derive(Clone)]
pub struct CodegenContext<B: WriteBackendMethods> {
pub cgu_reuse_tracker: CguReuseTracker,
// Channel back to the main control thread to send messages to
pub coordinator_send: Sender<Box<dyn Any + Send>>,
- // A reference to the TimeGraph so we can register timings. None means that
- // measuring is disabled.
- pub time_graph: Option<TimeGraph>,
// The assembler command if no_integrated_as option is enabled, None otherwise
pub assembler_cmd: Option<Arc<AssemblerCommand>>
}
self.profiler_active(f)
}
}
+
+ pub fn profile_activity(
+ &self,
+ category: ProfileCategory,
+ label: impl Into<Cow<'static, str>>,
+ ) -> ProfileGenericActivityTimer {
+ ProfileGenericActivityTimer::start(self.profiler.clone(), category, label.into())
+ }
}
fn generate_lto_work<B: ExtraBackendMethods>(
needs_thin_lto: Vec<(String, B::ThinBuffer)>,
import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>
) -> Vec<(WorkItem<B>, u64)> {
- let mut timeline = cgcx.time_graph.as_ref().map(|tg| {
- tg.start(CODEGEN_WORKER_TIMELINE,
- CODEGEN_WORK_PACKAGE_KIND,
- "generate lto")
- }).unwrap_or(Timeline::noop());
+ cgcx.profile(|p| p.start_activity(ProfileCategory::Linking, "codegen_run_lto"));
let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() {
assert!(needs_thin_lto.is_empty());
cgcx,
needs_fat_lto,
import_only_modules,
- &mut timeline,
)
.unwrap_or_else(|e| e.raise());
(vec![lto_module], vec![])
} else {
assert!(needs_fat_lto.is_empty());
- B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules, &mut timeline)
+ B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules)
.unwrap_or_else(|e| e.raise())
};
- lto_modules.into_iter().map(|module| {
+ let result = lto_modules.into_iter().map(|module| {
let cost = module.cost();
(WorkItem::LTO(module), cost)
}).chain(copy_jobs.into_iter().map(|wp| {
name: wp.cgu_name.clone(),
source: wp,
}), 0)
- })).collect()
+ })).collect();
+
+ cgcx.profile(|p| p.end_activity(ProfileCategory::Linking, "codegen_run_lto"));
+
+ result
}
pub struct CompiledModules {
pub fn start_async_codegen<B: ExtraBackendMethods>(
backend: B,
tcx: TyCtxt<'_, '_, '_>,
- time_graph: Option<TimeGraph>,
metadata: EncodedMetadata,
coordinator_receive: Receiver<Box<dyn Any + Send>>,
total_cgus: usize
coordinator_receive,
total_cgus,
sess.jobserver.clone(),
- time_graph.clone(),
Arc::new(modules_config),
Arc::new(metadata_config),
Arc::new(allocator_config));
linker_info,
crate_info,
- time_graph,
coordinator_send: tcx.tx_to_llvm_workers.lock().clone(),
codegen_worker_receive,
shared_emitter_main,
fn execute_work_item<B: ExtraBackendMethods>(
cgcx: &CodegenContext<B>,
work_item: WorkItem<B>,
- timeline: &mut Timeline
) -> Result<WorkItemResult<B>, FatalError> {
let module_config = cgcx.config(work_item.module_kind());
match work_item {
WorkItem::Optimize(module) => {
- execute_optimize_work_item(cgcx, module, module_config, timeline)
+ execute_optimize_work_item(cgcx, module, module_config)
}
WorkItem::CopyPostLtoArtifacts(module) => {
- execute_copy_from_cache_work_item(cgcx, module, module_config, timeline)
+ execute_copy_from_cache_work_item(cgcx, module, module_config)
}
WorkItem::LTO(module) => {
- execute_lto_work_item(cgcx, module, module_config, timeline)
+ execute_lto_work_item(cgcx, module, module_config)
}
}
}
cgcx: &CodegenContext<B>,
module: ModuleCodegen<B::Module>,
module_config: &ModuleConfig,
- timeline: &mut Timeline
) -> Result<WorkItemResult<B>, FatalError> {
let diag_handler = cgcx.create_diag_handler();
unsafe {
- B::optimize(cgcx, &diag_handler, &module, module_config, timeline)?;
+ B::optimize(cgcx, &diag_handler, &module, module_config)?;
}
// After we've done the initial round of optimizations we need to
Ok(match lto_type {
ComputedLtoType::No => {
let module = unsafe {
- B::codegen(cgcx, &diag_handler, module, module_config, timeline)?
+ B::codegen(cgcx, &diag_handler, module, module_config)?
};
WorkItemResult::Compiled(module)
}
cgcx: &CodegenContext<B>,
module: CachedModuleCodegen,
module_config: &ModuleConfig,
- _: &mut Timeline
) -> Result<WorkItemResult<B>, FatalError> {
let incr_comp_session_dir = cgcx.incr_comp_session_dir
.as_ref()
cgcx: &CodegenContext<B>,
mut module: lto::LtoModuleCodegen<B>,
module_config: &ModuleConfig,
- timeline: &mut Timeline
) -> Result<WorkItemResult<B>, FatalError> {
let diag_handler = cgcx.create_diag_handler();
unsafe {
- let module = module.optimize(cgcx, timeline)?;
- let module = B::codegen(cgcx, &diag_handler, module, module_config, timeline)?;
+ let module = module.optimize(cgcx)?;
+ let module = B::codegen(cgcx, &diag_handler, module, module_config)?;
Ok(WorkItemResult::Compiled(module))
}
}
coordinator_receive: Receiver<Box<dyn Any + Send>>,
total_cgus: usize,
jobserver: Client,
- time_graph: Option<TimeGraph>,
modules_config: Arc<ModuleConfig>,
metadata_config: Arc<ModuleConfig>,
allocator_config: Arc<ModuleConfig>
cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(),
coordinator_send,
diag_emitter: shared_emitter.clone(),
- time_graph,
output_filenames: tcx.output_filenames(LOCAL_CRATE),
regular_module_config: modules_config,
metadata_module_config: metadata_config,
}
pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX;
-pub const CODEGEN_WORKER_TIMELINE: time_graph::TimelineId =
- time_graph::TimelineId(CODEGEN_WORKER_ID);
-pub const CODEGEN_WORK_PACKAGE_KIND: time_graph::WorkPackageKind =
- time_graph::WorkPackageKind(&["#DE9597", "#FED1D3", "#FDC5C7", "#B46668", "#88494B"]);
-const LLVM_WORK_PACKAGE_KIND: time_graph::WorkPackageKind =
- time_graph::WorkPackageKind(&["#7DB67A", "#C6EEC4", "#ACDAAA", "#579354", "#3E6F3C"]);
fn spawn_work<B: ExtraBackendMethods>(
cgcx: CodegenContext<B>,
// as a diagnostic was already sent off to the main thread - just
// surface that there was an error in this worker.
bomb.result = {
- let timeline = cgcx.time_graph.as_ref().map(|tg| {
- tg.start(time_graph::TimelineId(cgcx.worker),
- LLVM_WORK_PACKAGE_KIND,
- &work.name())
- });
- let mut timeline = timeline.unwrap_or(Timeline::noop());
- execute_work_item(&cgcx, work, &mut timeline).ok()
+ let label = work.name();
+ cgcx.profile(|p| p.start_activity(ProfileCategory::Codegen, label.clone()));
+ let result = execute_work_item(&cgcx, work).ok();
+ cgcx.profile(|p| p.end_activity(ProfileCategory::Codegen, label));
+
+ result
};
});
}
pub windows_subsystem: Option<String>,
pub linker_info: LinkerInfo,
pub crate_info: CrateInfo,
- pub time_graph: Option<TimeGraph>,
pub coordinator_send: Sender<Box<dyn Any + Send>>,
pub codegen_worker_receive: Receiver<Message<B>>,
pub shared_emitter_main: SharedEmitterMain,
sess.abort_if_errors();
- if let Some(time_graph) = self.time_graph {
- time_graph.dump(&format!("{}-timings", self.crate_name));
- }
-
let work_products =
copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
&compiled_modules);
use rustc::session::config::{self, EntryFnType, Lto};
use rustc::session::Session;
use rustc_mir::monomorphize::item::DefPathBasedNames;
-use rustc::util::time_graph;
use rustc_mir::monomorphize::Instance;
use rustc_mir::monomorphize::partitioning::{CodegenUnit, CodegenUnitExt};
use rustc::util::nodemap::FxHashMap;
}
pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX;
-pub const CODEGEN_WORKER_TIMELINE: time_graph::TimelineId =
- time_graph::TimelineId(CODEGEN_WORKER_ID);
-pub const CODEGEN_WORK_PACKAGE_KIND: time_graph::WorkPackageKind =
- time_graph::WorkPackageKind(&["#DE9597", "#FED1D3", "#FDC5C7", "#B46668", "#88494B"]);
-
pub fn codegen_crate<B: ExtraBackendMethods>(
backend: B,
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
// Codegen the metadata.
- tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen));
+ tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen, "codegen crate metadata"));
let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
&["crate"],
let metadata = time(tcx.sess, "write metadata", || {
backend.write_metadata(tcx, &mut metadata_llvm_module)
});
- tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
+ tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen, "codegen crate metadata"));
let metadata_module = ModuleCodegen {
name: metadata_cgu_name,
kind: ModuleKind::Metadata,
};
- let time_graph = if tcx.sess.opts.debugging_opts.codegen_time_graph {
- Some(time_graph::TimeGraph::new())
- } else {
- None
- };
-
// Skip crate items and just output metadata in -Z no-codegen mode.
if tcx.sess.opts.debugging_opts.no_codegen ||
!tcx.sess.opts.output_types.should_codegen() {
let ongoing_codegen = start_async_codegen(
backend,
tcx,
- time_graph,
metadata,
rx,
1);
let ongoing_codegen = start_async_codegen(
backend.clone(),
tcx,
- time_graph.clone(),
metadata,
rx,
codegen_units.len());
match cgu_reuse {
CguReuse::No => {
- let _timing_guard = time_graph.as_ref().map(|time_graph| {
- time_graph.start(CODEGEN_WORKER_TIMELINE,
- CODEGEN_WORK_PACKAGE_KIND,
- &format!("codegen {}", cgu.name()))
- });
+ tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen,
+ format!("codegen {}", cgu.name())));
let start_time = Instant::now();
let stats = backend.compile_codegen_unit(tcx, *cgu.name());
all_stats.extend(stats);
total_codegen_time += start_time.elapsed();
+ tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen,
+ format!("codegen {}", cgu.name())));
false
}
CguReuse::PreLto => {
use crate::{CompiledModule, ModuleCodegen};
use rustc::dep_graph::WorkProduct;
-use rustc::util::time_graph::Timeline;
use rustc_errors::{FatalError, Handler};
pub trait WriteBackendMethods: 'static + Sized + Clone {
cgcx: &CodegenContext<Self>,
modules: Vec<FatLTOInput<Self>>,
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
- timeline: &mut Timeline,
) -> Result<LtoModuleCodegen<Self>, FatalError>;
/// Performs thin LTO by performing necessary global analysis and returning two
/// lists, one of the modules that need optimization and another for modules that
cgcx: &CodegenContext<Self>,
modules: Vec<(String, Self::ThinBuffer)>,
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
- timeline: &mut Timeline,
) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError>;
fn print_pass_timings(&self);
unsafe fn optimize(
diag_handler: &Handler,
module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
- timeline: &mut Timeline,
) -> Result<(), FatalError>;
unsafe fn optimize_thin(
cgcx: &CodegenContext<Self>,
thin: &mut ThinModule<Self>,
- timeline: &mut Timeline,
) -> Result<ModuleCodegen<Self::Module>, FatalError>;
unsafe fn codegen(
cgcx: &CodegenContext<Self>,
diag_handler: &Handler,
module: ModuleCodegen<Self::Module>,
config: &ModuleConfig,
- timeline: &mut Timeline,
) -> Result<CompiledModule, FatalError>;
fn prepare_thin(
module: ModuleCodegen<Self::Module>
.set_continue_after_error(sess.opts.debugging_opts.continue_parse_after_error);
hygiene::set_default_edition(sess.edition());
- sess.profiler(|p| p.start_activity(ProfileCategory::Parsing));
+ sess.profiler(|p| p.start_activity(ProfileCategory::Parsing, "parsing"));
let krate = time(sess, "parsing", || match *input {
Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess),
Input::Str {
ref name,
} => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess),
})?;
- sess.profiler(|p| p.end_activity(ProfileCategory::Parsing));
+ sess.profiler(|p| p.end_activity(ProfileCategory::Parsing, "parsing"));
sess.diagnostic().set_continue_after_error(true);
syntax_ext::register_builtins(&mut resolver, plugin_info.syntax_exts);
// Expand all macros
- sess.profiler(|p| p.start_activity(ProfileCategory::Expansion));
+ sess.profiler(|p| p.start_activity(ProfileCategory::Expansion, "macro expansion"));
krate = time(sess, "expansion", || {
// Windows dlls do not have rpaths, so they don't know how to find their
// dependencies. It's up to us to tell the system where to find all the
}
krate
});
- sess.profiler(|p| p.end_activity(ProfileCategory::Expansion));
+ sess.profiler(|p| p.end_activity(ProfileCategory::Expansion, "macro expansion"));
time(sess, "maybe building test harness", || {
syntax::test::modify_for_testing(
::rustc::middle::dependency_format::calculate(tcx)
});
- tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen));
+ tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen, "codegen crate"));
let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx));
- tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
+ tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen, "codegen crate"));
if log_enabled!(::log::Level::Info) {
println!("Post-codegen");
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> Result<(), ErrorReported>
{
- tcx.sess.profiler(|p| p.start_activity(ProfileCategory::TypeChecking));
+ tcx.sess.profiler(|p| p.start_activity(ProfileCategory::TypeChecking, "type-check crate"));
// this ensures that later parts of type checking can assume that items
// have valid types and not error
check_unused::check_crate(tcx);
check_for_entry_fn(tcx);
- tcx.sess.profiler(|p| p.end_activity(ProfileCategory::TypeChecking));
+ tcx.sess.profiler(|p| p.end_activity(ProfileCategory::TypeChecking, "type-check crate"));
if tcx.sess.err_count() == 0 {
Ok(())