Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/src/commands/settings.rs
1692 views
1
//! The module that implements the `wasmtime settings` command.
2
3
use anyhow::{Result, anyhow};
4
use clap::Parser;
5
use serde::{Serialize, ser::SerializeMap};
6
use std::collections::BTreeMap;
7
use std::str::FromStr;
8
use wasmtime_environ::{CompilerBuilder, FlagValue, Setting, SettingKind, Tunables};
9
10
/// Displays available Cranelift settings for a target.
11
#[derive(Parser, PartialEq)]
12
pub struct SettingsCommand {
13
/// The target triple to get the settings for; defaults to the host triple.
14
#[arg(long, value_name = "TARGET")]
15
target: Option<String>,
16
17
/// Switch output format to JSON
18
#[arg(long)]
19
json: bool,
20
}
21
22
struct SettingData(Setting);
23
24
impl Serialize for SettingData {
25
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
26
where
27
S: serde::Serializer,
28
{
29
let mut map = serializer.serialize_map(None)?;
30
map.serialize_entry("name", self.0.name)?;
31
map.serialize_entry("description", self.0.description)?;
32
map.serialize_entry("values", &self.0.values)?;
33
map.end()
34
}
35
}
36
37
// Gather together all of the setting data to displays
38
#[derive(serde_derive::Serialize)]
39
struct Settings {
40
triple: String,
41
42
enums: Vec<SettingData>,
43
nums: Vec<SettingData>,
44
bools: Vec<SettingData>,
45
presets: Vec<SettingData>,
46
47
inferred: Option<Vec<&'static str>>,
48
}
49
50
impl Settings {
51
fn from_builder(builder: &Box<dyn CompilerBuilder>) -> Settings {
52
let mut settings = Settings {
53
triple: builder.triple().to_string(),
54
enums: Vec::new(),
55
nums: Vec::new(),
56
bools: Vec::new(),
57
presets: Vec::new(),
58
inferred: None,
59
};
60
settings.add_settings(builder.settings());
61
settings
62
}
63
64
fn infer(&mut self, builder: &Box<dyn CompilerBuilder>) -> Result<()> {
65
let compiler = builder.build()?;
66
let values = compiler.isa_flags().into_iter().collect::<BTreeMap<_, _>>();
67
let mut result = Vec::new();
68
for (name, value) in values {
69
if let FlagValue::Bool(true) = value {
70
result.push(name);
71
}
72
}
73
74
self.inferred = Some(result);
75
76
Ok(())
77
}
78
79
fn add_setting(&mut self, setting: Setting) {
80
let collection = match setting.kind {
81
SettingKind::Enum => &mut self.enums,
82
SettingKind::Num => &mut self.nums,
83
SettingKind::Bool => &mut self.bools,
84
SettingKind::Preset => &mut self.presets,
85
};
86
collection.push(SettingData(setting));
87
}
88
89
fn add_settings<I>(&mut self, iterable: I)
90
where
91
I: IntoIterator<Item = Setting>,
92
{
93
for item in iterable.into_iter() {
94
self.add_setting(item);
95
}
96
}
97
98
fn is_empty(&self) -> bool {
99
self.enums.is_empty()
100
&& self.nums.is_empty()
101
&& self.bools.is_empty()
102
&& self.presets.is_empty()
103
}
104
}
105
106
impl SettingsCommand {
107
/// Executes the command.
108
pub fn execute(self) -> Result<()> {
109
// Gather settings from the cranelift compiler builder
110
let mut builder = wasmtime_cranelift::builder(None)?;
111
let tunables = if let Some(target) = &self.target {
112
let target = target_lexicon::Triple::from_str(target).map_err(|e| anyhow!(e))?;
113
let tunables = Tunables::default_for_target(&target)?;
114
builder.target(target)?;
115
tunables
116
} else {
117
Tunables::default_host()
118
};
119
120
builder.set_tunables(tunables)?;
121
let mut settings = Settings::from_builder(&builder);
122
123
// Add inferred settings if no target specified
124
if self.target.is_none() {
125
settings.infer(&builder)?;
126
}
127
128
// Print settings
129
if self.json {
130
self.print_json(settings)
131
} else {
132
self.print_human_readable(settings)
133
}
134
}
135
136
fn print_json(self, settings: Settings) -> Result<()> {
137
println!("{}", serde_json::to_string_pretty(&settings)?);
138
Ok(())
139
}
140
141
fn print_human_readable(self, settings: Settings) -> Result<()> {
142
if settings.is_empty() {
143
println!("Target '{}' has no settings.", settings.triple);
144
return Ok(());
145
}
146
147
println!("Cranelift settings for target '{}':", settings.triple);
148
149
Self::print_settings_human_readable("Boolean settings:", &settings.bools);
150
Self::print_settings_human_readable("Enum settings:", &settings.enums);
151
Self::print_settings_human_readable("Numerical settings:", &settings.nums);
152
Self::print_settings_human_readable("Presets:", &settings.presets);
153
154
if let Some(inferred) = settings.inferred {
155
println!();
156
println!("Settings inferred for the current host:");
157
158
for name in inferred {
159
println!(" {name}");
160
}
161
}
162
163
Ok(())
164
}
165
166
fn print_settings_human_readable(header: &str, settings: &[SettingData]) {
167
if settings.is_empty() {
168
return;
169
}
170
171
println!();
172
println!("{header}");
173
174
let width = settings.iter().map(|s| s.0.name.len()).max().unwrap_or(0);
175
176
for setting in settings {
177
println!(
178
" {:width$} {}{}",
179
setting.0.name,
180
setting.0.description,
181
setting
182
.0
183
.values
184
.map(|v| format!(" Supported values: {}.", v.join(", ")))
185
.unwrap_or("".to_string()),
186
width = width + 2
187
);
188
}
189
}
190
}
191
192