servo_config/opts.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Configuration options for a single run of the servo application. Created
6//! from command line arguments.
7
8use std::default::Default;
9use std::path::PathBuf;
10use std::process;
11use std::sync::OnceLock;
12
13use serde::{Deserialize, Serialize};
14
15/// Global flags for Servo, currently set on the command line.
16#[derive(Clone, Debug, Deserialize, Serialize)]
17pub struct Opts {
18 /// `None` to disable the time profiler or `Some` to enable it with:
19 ///
20 /// - an interval in seconds to cause it to produce output on that interval.
21 /// (`i.e. -p 5`).
22 /// - a file path to write profiling info to a TSV file upon Servo's termination.
23 /// (`i.e. -p out.tsv`).
24 pub time_profiling: Option<OutputOptions>,
25
26 /// When the profiler is enabled, this is an optional path to dump a self-contained HTML file
27 /// visualizing the traces as a timeline.
28 pub time_profiler_trace_path: Option<String>,
29
30 /// True to exit on thread failure instead of displaying about:failure.
31 pub hard_fail: bool,
32
33 /// Debug options that are used by developers to control Servo
34 /// behavior for debugging purposes.
35 pub debug: DiagnosticsLogging,
36
37 /// Whether we're running in multiprocess mode.
38 pub multiprocess: bool,
39
40 /// Whether to force using ipc_channel instead of crossbeam_channel in singleprocess mode. Does
41 /// nothing in multiprocess mode.
42 pub force_ipc: bool,
43
44 /// Whether we want background hang monitor enabled or not
45 pub background_hang_monitor: bool,
46
47 /// Whether we're running inside the sandbox.
48 pub sandbox: bool,
49
50 /// Probability of randomly closing a pipeline,
51 /// used for testing the hardening of the constellation.
52 pub random_pipeline_closure_probability: Option<f32>,
53
54 /// The seed for the RNG used to randomly close pipelines,
55 /// used for testing the hardening of the constellation.
56 pub random_pipeline_closure_seed: Option<usize>,
57
58 /// Load shaders from disk.
59 pub shaders_path: Option<PathBuf>,
60
61 /// Directory for a default config directory
62 pub config_dir: Option<PathBuf>,
63
64 /// Path to PEM encoded SSL CA certificate store.
65 pub certificate_path: Option<String>,
66
67 /// Whether or not to completely ignore SSL certificate validation errors.
68 /// TODO: We should see if we can eliminate the need for this by fixing
69 /// <https://github.com/servo/servo/issues/30080>.
70 pub ignore_certificate_errors: bool,
71
72 /// Unminify Javascript.
73 pub unminify_js: bool,
74
75 /// Directory path that was created with "unminify-js"
76 pub local_script_source: Option<String>,
77
78 /// Unminify Css.
79 pub unminify_css: bool,
80}
81
82/// Debug options for Servo, currently set on the command line with -Z
83#[derive(Clone, Debug, Default, Deserialize, Serialize)]
84pub struct DiagnosticsLogging {
85 /// List all the debug options.
86 pub help: bool,
87
88 /// Print the DOM after each restyle.
89 pub style_tree: bool,
90
91 /// Log the rule tree.
92 pub rule_tree: bool,
93
94 /// Log the fragment tree after each layout.
95 pub flow_tree: bool,
96
97 /// Log the stacking context tree after each layout.
98 pub stacking_context_tree: bool,
99
100 /// Log the scroll tree after each layout.
101 ///
102 /// Displays the hierarchy of scrollable areas and their properties.
103 pub scroll_tree: bool,
104
105 /// Log the display list after each layout.
106 pub display_list: bool,
107
108 /// Log notifications when a relayout occurs.
109 pub relayout_event: bool,
110
111 /// Periodically log on which events script threads spend their processing time.
112 pub profile_script_events: bool,
113
114 /// Log style sharing cache statistics to after each restyle.
115 ///
116 /// Shows hit/miss statistics for the style sharing cache
117 pub style_statistics: bool,
118
119 /// Log garbage collection passes and their durations.
120 pub gc_profile: bool,
121
122 /// Log Progressive Web Metrics.
123 pub progressive_web_metrics: bool,
124}
125
126impl DiagnosticsLogging {
127 /// Create a new DiagnosticsLogging configuration.
128 ///
129 /// In non-production builds, this will automatically read and parse the
130 /// SERVO_DIAGNOSTICS environment variable if it is set.
131 pub fn new() -> Self {
132 let mut config: DiagnosticsLogging = Default::default();
133
134 // Disabled for production builds
135 #[cfg(debug_assertions)]
136 {
137 if let Ok(diagnostics_var) = std::env::var("SERVO_DIAGNOSTICS") {
138 if let Err(error) = config.extend_from_string(&diagnostics_var) {
139 eprintln!("Could not parse debug logging option: {error}");
140 }
141 }
142 }
143
144 config
145 }
146
147 /// Print available diagnostic logging options and their descriptions.
148 fn print_debug_options_usage(app: &str) {
149 fn print_option(name: &str, description: &str) {
150 println!("\t{:<35} {}", name, description);
151 }
152
153 println!(
154 "Usage: {} debug option,[options,...]\n\twhere options include\n\nOptions:",
155 app
156 );
157 print_option("help", "Show this help message");
158 print_option("style-tree", "Log the style tree after each restyle");
159 print_option("rule-tree", "Log the rule tree");
160 print_option("flow-tree", "Log the fragment tree after each layout");
161 print_option(
162 "stacking-context-tree",
163 "Log the stacking context tree after each layout",
164 );
165 print_option("scroll-tree", "Log the scroll tree after each layout");
166 print_option("display-list", "Log the display list after each layout");
167 print_option("style-stats", "Log style sharing cache statistics");
168 print_option("relayout-event", "Log when relayout occurs");
169 print_option("profile-script-events", "Log script event processing time");
170 print_option("gc-profile", "Log garbage collection statistics");
171 print_option("progressive-web-metrics", "Log Progressive Web Metrics");
172 println!();
173
174 process::exit(0);
175 }
176
177 /// Extend the current configuration with additional options.
178 ///
179 /// Parses the string and merges any enabled options into the current configuration.
180 pub fn extend_from_string(&mut self, option_string: &str) -> Result<(), String> {
181 for option in option_string.split(',') {
182 let option = option.trim();
183 match option {
184 "help" => Self::print_debug_options_usage("servo"),
185 "display-list" => self.display_list = true,
186 "stacking-context-tree" => self.stacking_context_tree = true,
187 "flow-tree" => self.flow_tree = true,
188 "rule-tree" => self.rule_tree = true,
189 "style-tree" => self.style_tree = true,
190 "style-stats" => self.style_statistics = true,
191 "scroll-tree" => self.scroll_tree = true,
192 "gc-profile" => self.gc_profile = true,
193 "profile-script-events" => self.profile_script_events = true,
194 "relayout-event" => self.relayout_event = true,
195 "progressive-web-metrics" => self.progressive_web_metrics = true,
196 "" => {},
197 _ => return Err(format!("Unknown diagnostic option: {option}")),
198 };
199 }
200
201 Ok(())
202 }
203}
204
205#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
206pub enum OutputOptions {
207 /// Database connection config (hostname, name, user, pass)
208 FileName(String),
209 Stdout(f64),
210}
211
212impl Default for Opts {
213 fn default() -> Self {
214 Self {
215 time_profiling: None,
216 time_profiler_trace_path: None,
217 hard_fail: true,
218 multiprocess: false,
219 force_ipc: false,
220 background_hang_monitor: false,
221 random_pipeline_closure_probability: None,
222 random_pipeline_closure_seed: None,
223 sandbox: false,
224 debug: Default::default(),
225 config_dir: None,
226 shaders_path: None,
227 certificate_path: None,
228 ignore_certificate_errors: false,
229 unminify_js: false,
230 local_script_source: None,
231 unminify_css: false,
232 }
233 }
234}
235
236// Make Opts available globally. This saves having to clone and pass
237// opts everywhere it is used, which gets particularly cumbersome
238// when passing through the DOM structures.
239static OPTIONS: OnceLock<Opts> = OnceLock::new();
240
241/// Initialize options.
242///
243/// Should only be called once at process startup.
244/// Must be called before the first call to [get].
245pub fn initialize_options(opts: Opts) {
246 OPTIONS.set(opts).expect("Already initialized");
247}
248
249/// Get the servo options
250///
251/// If the servo options have not been initialized by calling [initialize_options], then the
252/// options will be initialized to default values. Outside of tests the options should
253/// be explicitly initialized.
254#[inline]
255pub fn get() -> &'static Opts {
256 // In unit-tests using default options reduces boilerplate.
257 // We can't use `cfg(test)` since that only is enabled when this crate
258 // is compiled in test mode.
259 // We rely on the `expect` in `initialize_options` to inform us if refactoring
260 // causes a `get` call to move before `initialize_options`.
261 OPTIONS.get_or_init(Default::default)
262}