Skip to content

Commit 06b95b2

Browse files
committed
unstable feature usage metrics
1 parent 17b322f commit 06b95b2

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

Cargo.lock

+2
Original file line numberDiff line numberDiff line change
@@ -3681,6 +3681,8 @@ version = "0.0.0"
36813681
dependencies = [
36823682
"rustc_data_structures",
36833683
"rustc_span",
3684+
"serde",
3685+
"serde_json",
36843686
]
36853687

36863688
[[package]]

compiler/rustc_driver_impl/src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,17 @@ fn run_compiler(
472472
eprintln!("Fuel used by {}: {}", fuel, sess.print_fuel.load(Ordering::SeqCst));
473473
}
474474

475+
// TODO: DECIDE where to put metrics in dump, for now I'm just shoving it in at the very
476+
// end, I don't know if it really matters but I don't have a preference
477+
if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
478+
compiler.enter(|queries| -> Result<(), ErrorGuaranteed> {
479+
queries
480+
.global_ctxt()?
481+
.enter(|tcxt| tcxt.features().dump_feature_usage_metrics(metrics_dir));
482+
Ok(())
483+
})?;
484+
}
485+
475486
Ok(())
476487
})
477488
}

compiler/rustc_feature/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ edition = "2021"
77
# tidy-alphabetical-start
88
rustc_data_structures = { path = "../rustc_data_structures" }
99
rustc_span = { path = "../rustc_span" }
10+
serde = { version = "1.0.125", features = [ "derive" ] }
11+
serde_json = "1.0.59"
1012
# tidy-alphabetical-end

compiler/rustc_feature/src/unstable.rs

+56
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! List of the unstable feature gates.
22
3+
use std::path::Path;
4+
35
use rustc_data_structures::fx::FxHashSet;
46
use rustc_span::symbol::{sym, Symbol};
57
use rustc_span::Span;
@@ -649,6 +651,60 @@ declare_features! (
649651
// -------------------------------------------------------------------------
650652
);
651653

654+
impl Features {
655+
pub fn dump_feature_usage_metrics(&self, metrics_dir: &Path) {
656+
#[derive(serde::Serialize)]
657+
struct LibFeature {
658+
symbol: String,
659+
}
660+
661+
#[derive(serde::Serialize)]
662+
struct LangFeature {
663+
symbol: String,
664+
since: Option<String>,
665+
}
666+
667+
#[derive(serde::Serialize)]
668+
struct FeatureUsage {
669+
lib_features: Vec<LibFeature>,
670+
lang_features: Vec<LangFeature>,
671+
}
672+
673+
// TODO (DECIDE): How fine grained do we want to track feature usage?
674+
// Jane Preference: i want to track usage for code that gets used, not code
675+
// that is in development, but I don't know how we'd hook into this for code
676+
// that doesn't participate in the crates.io ecosystem, those crates won't even
677+
// necessarily have releases or versioning norms that match other crates, so we
678+
// may have to just track per compilation and aggressively collapse metrics to
679+
// avoid unnecessary disk usage.
680+
// TODO avoid filename collisions between runs
681+
let feature_metrics_file = metrics_dir.join("unstable_feature_usage.json");
682+
let Ok(feature_metrics_file) = std::fs::File::create(feature_metrics_file) else {
683+
return;
684+
};
685+
let feature_metrics_file = std::io::BufWriter::new(feature_metrics_file);
686+
687+
let lib_features = self
688+
.declared_lib_features
689+
.iter()
690+
.map(|(symbol, _)| LibFeature { symbol: symbol.to_string() })
691+
.collect();
692+
693+
let lang_features = self
694+
.declared_lang_features
695+
.iter()
696+
.map(|(symbol, _, since)| LangFeature {
697+
symbol: symbol.to_string(),
698+
since: since.map(|since| since.to_string()),
699+
})
700+
.collect();
701+
702+
let feature_usage = FeatureUsage { lib_features, lang_features };
703+
704+
let _ = serde_json::to_writer(feature_metrics_file, &feature_usage);
705+
}
706+
}
707+
652708
/// Some features are not allowed to be used together at the same time, if
653709
/// the two are present, produce an error.
654710
///

0 commit comments

Comments
 (0)