Skip to content

Commit a7b35b5

Browse files
committed
Overhaul -Zmeta-stats output.
It's now much more like the `-Zhir-stats` output. - Each line is preceded with `meta-stats`, which makes the provenance clearer and allows filtering of the output. - Sections are now sorted in reverse order of size. - Column headings avoid the need to repeat the word "bytes" on every line. - Long numbers now have `_` separators for easier reading. - Consistent use of '-' within section labels, rather than a mix of '-', '_', and ' '. The code itself is shorter and easier to read thanks to: - the `stat` macro, which encapsulates each section's encoding, avoids some boilerplate, and removes the need for some low-value comments; - the `stats` vector, which replaces dozens of local variables.
1 parent b7dc934 commit a7b35b5

File tree

1 file changed

+142
-202
lines changed

1 file changed

+142
-202
lines changed

compiler/rustc_metadata/src/rmeta/encoder.rs

+142-202
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use rustc_middle::ty::codec::TyEncoder;
2828
use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
2929
use rustc_middle::ty::query::Providers;
3030
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
31+
use rustc_middle::util::common::to_readable_str;
3132
use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
3233
use rustc_session::config::CrateType;
3334
use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
@@ -554,78 +555,56 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
554555

555556
fn encode_crate_root(&mut self) -> LazyValue<CrateRoot> {
556557
let tcx = self.tcx;
557-
let mut i = 0;
558-
let preamble_bytes = self.position() - i;
559-
560-
// Encode the crate deps
561-
i = self.position();
562-
let crate_deps = self.encode_crate_deps();
563-
let dylib_dependency_formats = self.encode_dylib_dependency_formats();
564-
let dep_bytes = self.position() - i;
565-
566-
// Encode the lib features.
567-
i = self.position();
568-
let lib_features = self.encode_lib_features();
569-
let lib_feature_bytes = self.position() - i;
570-
571-
// Encode the stability implications.
572-
i = self.position();
573-
let stability_implications = self.encode_stability_implications();
574-
let stability_implications_bytes = self.position() - i;
575-
576-
// Encode the language items.
577-
i = self.position();
578-
let lang_items = self.encode_lang_items();
579-
let lang_items_missing = self.encode_lang_items_missing();
580-
let lang_item_bytes = self.position() - i;
581-
582-
// Encode the diagnostic items.
583-
i = self.position();
584-
let diagnostic_items = self.encode_diagnostic_items();
585-
let diagnostic_item_bytes = self.position() - i;
586-
587-
// Encode the native libraries used
588-
i = self.position();
589-
let native_libraries = self.encode_native_libraries();
590-
let native_lib_bytes = self.position() - i;
591-
592-
i = self.position();
593-
let foreign_modules = self.encode_foreign_modules();
594-
let foreign_modules_bytes = self.position() - i;
595-
596-
// Encode DefPathTable
597-
i = self.position();
598-
self.encode_def_path_table();
599-
let def_path_table_bytes = self.position() - i;
558+
let mut stats: Vec<(&'static str, usize)> = Vec::with_capacity(32);
559+
560+
macro_rules! stat {
561+
($label:literal, $f:expr) => {{
562+
let orig_pos = self.position();
563+
let res = $f();
564+
stats.push(($label, self.position() - orig_pos));
565+
res
566+
}};
567+
}
568+
569+
// We have already encoded some things. Get their combined size from the current position.
570+
stats.push(("preamble", self.position()));
571+
572+
let (crate_deps, dylib_dependency_formats) =
573+
stat!("dep", || (self.encode_crate_deps(), self.encode_dylib_dependency_formats()));
574+
575+
let lib_features = stat!("lib-features", || self.encode_lib_features());
576+
577+
let stability_implications =
578+
stat!("stability-implications", || self.encode_stability_implications());
579+
580+
let (lang_items, lang_items_missing) = stat!("lang-items", || {
581+
(self.encode_lang_items(), self.encode_lang_items_missing())
582+
});
583+
584+
let diagnostic_items = stat!("diagnostic-items", || self.encode_diagnostic_items());
585+
586+
let native_libraries = stat!("native-libs", || self.encode_native_libraries());
587+
588+
let foreign_modules = stat!("foreign-modules", || self.encode_foreign_modules());
589+
590+
_ = stat!("def-path-table", || self.encode_def_path_table());
600591

601592
// Encode the def IDs of traits, for rustdoc and diagnostics.
602-
i = self.position();
603-
let traits = self.encode_traits();
604-
let traits_bytes = self.position() - i;
593+
let traits = stat!("traits", || self.encode_traits());
605594

606595
// Encode the def IDs of impls, for coherence checking.
607-
i = self.position();
608-
let impls = self.encode_impls();
609-
let impls_bytes = self.position() - i;
610-
611-
i = self.position();
612-
let incoherent_impls = self.encode_incoherent_impls();
613-
let incoherent_impls_bytes = self.position() - i;
614-
615-
// Encode MIR.
616-
i = self.position();
617-
self.encode_mir();
618-
let mir_bytes = self.position() - i;
619-
620-
// Encode the items.
621-
i = self.position();
622-
self.encode_def_ids();
623-
self.encode_info_for_items();
624-
let item_bytes = self.position() - i;
625-
626-
// Encode the allocation index
627-
i = self.position();
628-
let interpret_alloc_index = {
596+
let impls = stat!("impls", || self.encode_impls());
597+
598+
let incoherent_impls = stat!("incoherent-impls", || self.encode_incoherent_impls());
599+
600+
_ = stat!("mir", || self.encode_mir());
601+
602+
_ = stat!("items", || {
603+
self.encode_def_ids();
604+
self.encode_info_for_items();
605+
});
606+
607+
let interpret_alloc_index = stat!("interpret-alloc-index", || {
629608
let mut interpret_alloc_index = Vec::new();
630609
let mut n = 0;
631610
trace!("beginning to encode alloc ids");
@@ -646,125 +625,90 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
646625
n = new_n;
647626
}
648627
self.lazy_array(interpret_alloc_index)
649-
};
650-
let interpret_alloc_index_bytes = self.position() - i;
628+
});
651629

652-
// Encode the proc macro data. This affects 'tables',
653-
// so we need to do this before we encode the tables.
654-
// This overwrites def_keys, so it must happen after encode_def_path_table.
655-
i = self.position();
656-
let proc_macro_data = self.encode_proc_macros();
657-
let proc_macro_data_bytes = self.position() - i;
630+
// Encode the proc macro data. This affects `tables`, so we need to do this before we
631+
// encode the tables. This overwrites def_keys, so it must happen after
632+
// encode_def_path_table.
633+
let proc_macro_data = stat!("proc-macro-data", || self.encode_proc_macros());
658634

659-
i = self.position();
660-
let tables = self.tables.encode(&mut self.opaque);
661-
let tables_bytes = self.position() - i;
635+
let tables = stat!("tables", || self.tables.encode(&mut self.opaque));
662636

663-
i = self.position();
664-
let debugger_visualizers = self.encode_debugger_visualizers();
665-
let debugger_visualizers_bytes = self.position() - i;
637+
let debugger_visualizers =
638+
stat!("debugger-visualizers", || self.encode_debugger_visualizers());
666639

667640
// Encode exported symbols info. This is prefetched in `encode_metadata` so we encode
668641
// this as late as possible to give the prefetching as much time as possible to complete.
669-
i = self.position();
670-
let exported_symbols = tcx.exported_symbols(LOCAL_CRATE);
671-
let exported_symbols = self.encode_exported_symbols(&exported_symbols);
672-
let exported_symbols_bytes = self.position() - i;
642+
let exported_symbols = stat!("exported-symbols", || {
643+
self.encode_exported_symbols(&tcx.exported_symbols(LOCAL_CRATE))
644+
});
673645

674-
// Encode the hygiene data,
646+
// Encode the hygiene data.
675647
// IMPORTANT: this *must* be the last thing that we encode (other than `SourceMap`). The
676648
// process of encoding other items (e.g. `optimized_mir`) may cause us to load data from
677649
// the incremental cache. If this causes us to deserialize a `Span`, then we may load
678650
// additional `SyntaxContext`s into the global `HygieneData`. Therefore, we need to encode
679651
// the hygiene data last to ensure that we encode any `SyntaxContext`s that might be used.
680-
i = self.position();
681-
let (syntax_contexts, expn_data, expn_hashes) = self.encode_hygiene();
682-
let hygiene_bytes = self.position() - i;
683-
684-
i = self.position();
685-
let def_path_hash_map = self.encode_def_path_hash_map();
686-
let def_path_hash_map_bytes = self.position() - i;
687-
688-
// Encode source_map. This needs to be done last,
689-
// since encoding `Span`s tells us which `SourceFiles` we actually
690-
// need to encode.
691-
i = self.position();
692-
let source_map = self.encode_source_map();
693-
let source_map_bytes = self.position() - i;
694-
695-
i = self.position();
696-
let attrs = tcx.hir().krate_attrs();
697-
let has_default_lib_allocator = tcx.sess.contains_name(&attrs, sym::default_lib_allocator);
698-
let root = self.lazy(CrateRoot {
699-
name: tcx.crate_name(LOCAL_CRATE),
700-
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
701-
triple: tcx.sess.opts.target_triple.clone(),
702-
hash: tcx.crate_hash(LOCAL_CRATE),
703-
stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
704-
required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE),
705-
panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
706-
edition: tcx.sess.edition(),
707-
has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
708-
has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
709-
has_default_lib_allocator,
710-
proc_macro_data,
711-
debugger_visualizers,
712-
compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins),
713-
needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator),
714-
needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime),
715-
no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
716-
panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
717-
profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
718-
symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
719-
720-
crate_deps,
721-
dylib_dependency_formats,
722-
lib_features,
723-
stability_implications,
724-
lang_items,
725-
diagnostic_items,
726-
lang_items_missing,
727-
native_libraries,
728-
foreign_modules,
729-
source_map,
730-
traits,
731-
impls,
732-
incoherent_impls,
733-
exported_symbols,
734-
interpret_alloc_index,
735-
tables,
736-
syntax_contexts,
737-
expn_data,
738-
expn_hashes,
739-
def_path_hash_map,
652+
let (syntax_contexts, expn_data, expn_hashes) = stat!("hygiene", || self.encode_hygiene());
653+
654+
let def_path_hash_map = stat!("def-path-hash-map", || self.encode_def_path_hash_map());
655+
656+
// Encode source_map. This needs to be done last, because encoding `Span`s tells us which
657+
// `SourceFiles` we actually need to encode.
658+
let source_map = stat!("source-map", || self.encode_source_map());
659+
660+
let root = stat!("final", || {
661+
let attrs = tcx.hir().krate_attrs();
662+
self.lazy(CrateRoot {
663+
name: tcx.crate_name(LOCAL_CRATE),
664+
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
665+
triple: tcx.sess.opts.target_triple.clone(),
666+
hash: tcx.crate_hash(LOCAL_CRATE),
667+
stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
668+
required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE),
669+
panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
670+
edition: tcx.sess.edition(),
671+
has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
672+
has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
673+
has_default_lib_allocator: tcx
674+
.sess
675+
.contains_name(&attrs, sym::default_lib_allocator),
676+
proc_macro_data,
677+
debugger_visualizers,
678+
compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins),
679+
needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator),
680+
needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime),
681+
no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
682+
panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
683+
profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
684+
symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
685+
686+
crate_deps,
687+
dylib_dependency_formats,
688+
lib_features,
689+
stability_implications,
690+
lang_items,
691+
diagnostic_items,
692+
lang_items_missing,
693+
native_libraries,
694+
foreign_modules,
695+
source_map,
696+
traits,
697+
impls,
698+
incoherent_impls,
699+
exported_symbols,
700+
interpret_alloc_index,
701+
tables,
702+
syntax_contexts,
703+
expn_data,
704+
expn_hashes,
705+
def_path_hash_map,
706+
})
740707
});
741-
let final_bytes = self.position() - i;
742708

743709
let total_bytes = self.position();
744710

745-
let computed_total_bytes = preamble_bytes
746-
+ dep_bytes
747-
+ lib_feature_bytes
748-
+ stability_implications_bytes
749-
+ lang_item_bytes
750-
+ diagnostic_item_bytes
751-
+ native_lib_bytes
752-
+ foreign_modules_bytes
753-
+ def_path_table_bytes
754-
+ traits_bytes
755-
+ impls_bytes
756-
+ incoherent_impls_bytes
757-
+ mir_bytes
758-
+ item_bytes
759-
+ interpret_alloc_index_bytes
760-
+ proc_macro_data_bytes
761-
+ tables_bytes
762-
+ debugger_visualizers_bytes
763-
+ exported_symbols_bytes
764-
+ hygiene_bytes
765-
+ def_path_hash_map_bytes
766-
+ source_map_bytes
767-
+ final_bytes;
711+
let computed_total_bytes: usize = stats.iter().map(|(_, size)| size).sum();
768712
assert_eq!(total_bytes, computed_total_bytes);
769713

770714
if tcx.sess.meta_stats() {
@@ -782,42 +726,38 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
782726
}
783727
assert_eq!(self.opaque.file().stream_position().unwrap(), pos_before_rewind);
784728

729+
stats.sort_by_key(|&(_, usize)| usize);
730+
731+
let prefix = "meta-stats";
785732
let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64;
786-
let p = |label, bytes| {
787-
eprintln!("{:>21}: {:>8} bytes ({:4.1}%)", label, bytes, perc(bytes));
788-
};
789733

790-
eprintln!("");
734+
eprintln!("{} METADATA STATS", prefix);
735+
eprintln!("{} {:<23}{:>10}", prefix, "Section", "Size");
736+
eprintln!(
737+
"{} ----------------------------------------------------------------",
738+
prefix
739+
);
740+
for (label, size) in stats {
741+
eprintln!(
742+
"{} {:<23}{:>10} ({:4.1}%)",
743+
prefix,
744+
label,
745+
to_readable_str(size),
746+
perc(size)
747+
);
748+
}
749+
eprintln!(
750+
"{} ----------------------------------------------------------------",
751+
prefix
752+
);
791753
eprintln!(
792-
"{} metadata bytes, of which {} bytes ({:.1}%) are zero",
793-
total_bytes,
794-
zero_bytes,
754+
"{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
755+
prefix,
756+
"Total",
757+
to_readable_str(total_bytes),
795758
perc(zero_bytes)
796759
);
797-
p("preamble", preamble_bytes);
798-
p("dep", dep_bytes);
799-
p("lib feature", lib_feature_bytes);
800-
p("stability_implications", stability_implications_bytes);
801-
p("lang item", lang_item_bytes);
802-
p("diagnostic item", diagnostic_item_bytes);
803-
p("native lib", native_lib_bytes);
804-
p("foreign modules", foreign_modules_bytes);
805-
p("def-path table", def_path_table_bytes);
806-
p("traits", traits_bytes);
807-
p("impls", impls_bytes);
808-
p("incoherent_impls", incoherent_impls_bytes);
809-
p("mir", mir_bytes);
810-
p("item", item_bytes);
811-
p("interpret_alloc_index", interpret_alloc_index_bytes);
812-
p("proc-macro-data", proc_macro_data_bytes);
813-
p("tables", tables_bytes);
814-
p("debugger visualizers", debugger_visualizers_bytes);
815-
p("exported symbols", exported_symbols_bytes);
816-
p("hygiene", hygiene_bytes);
817-
p("def-path hashes", def_path_hash_map_bytes);
818-
p("source_map", source_map_bytes);
819-
p("final", final_bytes);
820-
eprintln!("");
760+
eprintln!("{}", prefix);
821761
}
822762

823763
root

0 commit comments

Comments
 (0)