Skip to content

Commit e841f6f

Browse files
author
bors-servo
authored
Auto merge of rust-lang#938 - jhod0:time_phases, r=fitzgen
Time phases New module `time_phases` with an RAII timer which prints to stderr, and command-line flag `--time-phases` to enable it. Fixes rust-lang#933
2 parents 04fa978 + e3c31dd commit e841f6f

File tree

5 files changed

+107
-1
lines changed

5 files changed

+107
-1
lines changed

src/codegen/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3479,6 +3479,7 @@ impl CodeGenerator for ObjCInterface {
34793479

34803480
pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
34813481
context.gen(|context| {
3482+
let _t = context.timer("codegen");
34823483
let counter = Cell::new(0);
34833484
let mut result = CodegenResult::new(&counter);
34843485

src/ir/context.rs

+20
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use super::module::{Module, ModuleKind};
1515
use super::template::{TemplateInstantiation, TemplateParameters};
1616
use super::traversal::{self, Edge, ItemTraversal};
1717
use super::ty::{FloatKind, Type, TypeKind};
18+
use super::super::time::Timer;
1819
use BindgenOptions;
1920
use callbacks::ParseCallbacks;
2021
use cexpr;
@@ -406,6 +407,13 @@ impl<'ctx> BindgenContext<'ctx> {
406407
me
407408
}
408409

410+
/// Creates a timer for the current bindgen phase. If time_phases is `true`,
411+
/// the timer will print to stderr when it is dropped, otherwise it will do
412+
/// nothing.
413+
pub fn timer<'a>(&self, name: &'a str) -> Timer<'a> {
414+
Timer::new(name).with_output(self.options.time_phases)
415+
}
416+
409417
/// Get the stack of partially parsed types that we are in the middle of
410418
/// parsing.
411419
pub fn currently_parsed_types(&self) -> &[PartialType] {
@@ -731,6 +739,7 @@ impl<'ctx> BindgenContext<'ctx> {
731739
/// Iterate over all items and replace any item that has been named in a
732740
/// `replaces="SomeType"` annotation with the replacement type.
733741
fn process_replacements(&mut self) {
742+
let _t = self.timer("process_replacements");
734743
if self.replacements.is_empty() {
735744
debug!("No replacements to process");
736745
return;
@@ -993,6 +1002,7 @@ impl<'ctx> BindgenContext<'ctx> {
9931002

9941003
/// Compute whether the type has vtable.
9951004
fn compute_has_vtable(&mut self) {
1005+
let _t = self.timer("compute_has_vtable");
9961006
assert!(self.have_vtable.is_none());
9971007
self.have_vtable = Some(analyze::<HasVtableAnalysis>(self));
9981008
}
@@ -1011,6 +1021,7 @@ impl<'ctx> BindgenContext<'ctx> {
10111021

10121022
/// Compute whether the type has a destructor.
10131023
fn compute_has_destructor(&mut self) {
1024+
let _t = self.timer("compute_has_destructor");
10141025
assert!(self.have_destructor.is_none());
10151026
self.have_destructor = Some(analyze::<HasDestructorAnalysis>(self));
10161027
}
@@ -1026,6 +1037,7 @@ impl<'ctx> BindgenContext<'ctx> {
10261037
}
10271038

10281039
fn find_used_template_parameters(&mut self) {
1040+
let _t = self.timer("find_used_template_parameters");
10291041
if self.options.whitelist_recursively {
10301042
let used_params = analyze::<UsedTemplateParameters>(self);
10311043
self.used_template_parameters = Some(used_params);
@@ -1869,6 +1881,7 @@ impl<'ctx> BindgenContext<'ctx> {
18691881
assert!(self.in_codegen_phase());
18701882
assert!(self.current_module == self.root_module);
18711883
assert!(self.whitelisted.is_none());
1884+
let _t = self.timer("compute_whitelisted_and_codegen_items");
18721885

18731886
let roots = {
18741887
let mut roots = self.items()
@@ -1991,6 +2004,7 @@ impl<'ctx> BindgenContext<'ctx> {
19912004

19922005
/// Compute whether we can derive debug.
19932006
fn compute_cannot_derive_debug(&mut self) {
2007+
let _t = self.timer("compute_cannot_derive_debug");
19942008
assert!(self.cannot_derive_debug.is_none());
19952009
if self.options.derive_debug {
19962010
self.cannot_derive_debug = Some(analyze::<CannotDeriveDebug>(self));
@@ -2012,6 +2026,7 @@ impl<'ctx> BindgenContext<'ctx> {
20122026

20132027
/// Compute whether we can derive default.
20142028
fn compute_cannot_derive_default(&mut self) {
2029+
let _t = self.timer("compute_cannot_derive_default");
20152030
assert!(self.cannot_derive_default.is_none());
20162031
if self.options.derive_default {
20172032
self.cannot_derive_default =
@@ -2034,12 +2049,14 @@ impl<'ctx> BindgenContext<'ctx> {
20342049

20352050
/// Compute whether we can derive copy.
20362051
fn compute_cannot_derive_copy(&mut self) {
2052+
let _t = self.timer("compute_cannot_derive_copy");
20372053
assert!(self.cannot_derive_copy.is_none());
20382054
self.cannot_derive_copy = Some(analyze::<CannotDeriveCopy>(self));
20392055
}
20402056

20412057
/// Compute whether we can derive hash.
20422058
fn compute_cannot_derive_hash(&mut self) {
2059+
let _t = self.timer("compute_cannot_derive_hash");
20432060
assert!(self.cannot_derive_hash.is_none());
20442061
if self.options.derive_hash {
20452062
self.cannot_derive_hash = Some(analyze::<CannotDeriveHash>(self));
@@ -2062,6 +2079,7 @@ impl<'ctx> BindgenContext<'ctx> {
20622079
/// Compute whether we can derive PartialEq. This method is also used in calculating
20632080
/// whether we can derive Eq
20642081
fn compute_cannot_derive_partialeq_or_eq(&mut self) {
2082+
let _t = self.timer("compute_cannot_derive_partialeq_or_eq");
20652083
assert!(self.cannot_derive_partialeq.is_none());
20662084
if self.options.derive_partialeq || self.options.derive_eq {
20672085
self.cannot_derive_partialeq = Some(analyze::<CannotDerivePartialEq>(self));
@@ -2097,6 +2115,7 @@ impl<'ctx> BindgenContext<'ctx> {
20972115

20982116
/// Compute whether the type has type parameter in array.
20992117
fn compute_has_type_param_in_array(&mut self) {
2118+
let _t = self.timer("compute_has_type_param_in_array");
21002119
assert!(self.has_type_param_in_array.is_none());
21012120
self.has_type_param_in_array =
21022121
Some(analyze::<HasTypeParameterInArray>(self));
@@ -2116,6 +2135,7 @@ impl<'ctx> BindgenContext<'ctx> {
21162135

21172136
/// Compute whether the type has float.
21182137
fn compute_has_float(&mut self) {
2138+
let _t = self.timer("compute_has_float");
21192139
assert!(self.has_float.is_none());
21202140
if self.options.derive_eq {
21212141
self.has_float = Some(analyze::<HasFloat>(self));

src/lib.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ mod features;
6464
mod ir;
6565
mod parse;
6666
mod regex_set;
67+
mod time;
6768

6869
pub mod callbacks;
6970

@@ -278,6 +279,10 @@ impl Builder {
278279
output_vector.push("--with-derive-eq".into());
279280
}
280281

282+
if self.options.time_phases {
283+
output_vector.push("--time-phases".into());
284+
}
285+
281286
if !self.options.generate_comments {
282287
output_vector.push("--no-doc-comments".into());
283288
}
@@ -774,6 +779,13 @@ impl Builder {
774779
self
775780
}
776781

782+
/// Set whether or not to time bindgen phases, and print
783+
/// information to stderr.
784+
pub fn time_phases(mut self, doit: bool) -> Self {
785+
self.options.time_phases = doit;
786+
self
787+
}
788+
777789
/// Emit Clang AST.
778790
pub fn emit_clang_ast(mut self) -> Builder {
779791
self.options.emit_ast = true;
@@ -1122,6 +1134,9 @@ pub struct BindgenOptions {
11221134
/// An optional prefix for the "raw" types, like `c_int`, `c_void`...
11231135
pub ctypes_prefix: Option<String>,
11241136

1137+
/// Whether to time the bindgen phases.
1138+
pub time_phases: bool,
1139+
11251140
/// True if we should generate constant names that are **directly** under
11261141
/// namespaces.
11271142
pub namespaced_constants: bool,
@@ -1280,6 +1295,7 @@ impl Default for BindgenOptions {
12801295
objc_extern_crate: false,
12811296
enable_mangling: true,
12821297
prepend_enum_name: true,
1298+
time_phases: false,
12831299
rustfmt_bindings: false,
12841300
rustfmt_configuration_file: None,
12851301
}
@@ -1403,8 +1419,13 @@ impl<'ctx> Bindings<'ctx> {
14031419
options.clang_args.push(f.name.to_str().unwrap().to_owned())
14041420
}
14051421

1422+
let time_phases = options.time_phases;
14061423
let mut context = BindgenContext::new(options);
1407-
try!(parse(&mut context));
1424+
{
1425+
let _t = time::Timer::new("parse")
1426+
.with_output(time_phases);
1427+
try!(parse(&mut context));
1428+
}
14081429

14091430
let module = ast::Mod {
14101431
inner: span,

src/options.rs

+7
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ where
107107
::std::os::raw.")
108108
.value_name("prefix")
109109
.takes_value(true),
110+
Arg::with_name("time-phases")
111+
.long("time-phases")
112+
.help("Time the different bindgen phases and print to stderr"),
110113
// All positional arguments after the end of options marker, `--`
111114
Arg::with_name("clang-args")
112115
.multiple(true),
@@ -340,6 +343,10 @@ where
340343
builder = builder.prepend_enum_name(false);
341344
}
342345

346+
if matches.is_present("time-phases") {
347+
builder = builder.time_phases(true);
348+
}
349+
343350
if let Some(prefix) = matches.value_of("ctypes-prefix") {
344351
builder = builder.ctypes_prefix(prefix);
345352
}

src/time.rs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use std::io::{self, Write};
2+
use std::time::{Instant, Duration};
3+
4+
5+
/// RAII timer to measure how long phases take.
6+
#[derive(Debug)]
7+
pub struct Timer<'a> {
8+
output: bool,
9+
name: &'a str,
10+
start: Instant,
11+
}
12+
13+
14+
impl<'a> Timer<'a> {
15+
/// Creates a Timer with the given name, and starts it. By default,
16+
/// will print to stderr when it is `drop`'d
17+
pub fn new(name: &'a str) -> Self {
18+
Timer {
19+
output: true,
20+
name,
21+
start: Instant::now()
22+
}
23+
}
24+
25+
/// Sets whether or not the Timer will print a mesage
26+
/// when it is dropped.
27+
pub fn with_output(mut self, output: bool) -> Self {
28+
self.output = output;
29+
self
30+
}
31+
32+
/// Returns the time elapsed since the timer's creation
33+
pub fn elapsed(&self) -> Duration {
34+
Instant::now() - self.start
35+
}
36+
37+
fn print_elapsed(&mut self) {
38+
if self.output {
39+
let elapsed = self.elapsed();
40+
let time = (elapsed.as_secs() as f32)
41+
+ (elapsed.subsec_nanos() as f32) / 1e9;
42+
let stderr = io::stderr();
43+
// Arbitrary output format, subject to change.
44+
writeln!(stderr.lock(),
45+
" time: {:.3} ms.\t{}",
46+
time, self.name)
47+
.expect("timer write should not fail");
48+
}
49+
}
50+
}
51+
52+
53+
impl<'a> Drop for Timer<'a> {
54+
fn drop(&mut self) {
55+
self.print_elapsed();
56+
}
57+
}

0 commit comments

Comments
 (0)