mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
* Add prefs to limit threadpool sizes Add preferences to control the size of threadpools, so that we can easily reduce the amount of runtime threads and test which pools benefit from more threads. Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com> * Add pref for Webrender threadpool Add a preference to limit the size of the webrender threadpool. Note: WebRender by default calls hooks which register the threads with a profiler instance that the embedder can register with webrender. Servo currently doesn't register such a profiler with webrender, but in the future we might also want to profile the webrender threadpool. Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com> --------- Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
650 lines
22 KiB
Rust
650 lines
22 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||
|
||
use std::borrow::ToOwned;
|
||
use std::collections::HashMap;
|
||
use std::convert::{TryFrom, TryInto};
|
||
use std::sync::LazyLock;
|
||
|
||
use embedder_traits::resources::{self, Resource};
|
||
use gen::Prefs;
|
||
use log::{error, warn};
|
||
use serde_json::{self, Value};
|
||
|
||
use crate::pref_util::Preferences;
|
||
pub use crate::pref_util::{PrefError, PrefValue};
|
||
|
||
static PREFS: LazyLock<Preferences<'static, Prefs>> = LazyLock::new(|| {
|
||
let def_prefs: Prefs = serde_json::from_str(&resources::read_string(Resource::Preferences))
|
||
.unwrap_or_else(|_| {
|
||
error!("Preference json file is invalid. Setting Preference to default values");
|
||
Prefs::default()
|
||
});
|
||
let result = Preferences::new(def_prefs, &gen::PREF_ACCESSORS);
|
||
for (key, value) in result.iter() {
|
||
set_stylo_pref_ref(&key, &value);
|
||
}
|
||
result
|
||
});
|
||
|
||
/// A convenience macro for accessing a preference value using its static path.
|
||
/// Passing an invalid path is a compile-time error.
|
||
#[macro_export]
|
||
macro_rules! pref {
|
||
($($segment: ident).+) => {{
|
||
let values = $crate::prefs::pref_map().values();
|
||
let lock = values.read()
|
||
.map(|prefs| prefs $(.$segment)+.clone());
|
||
lock.unwrap()
|
||
}};
|
||
}
|
||
|
||
/// A convenience macro for updating a preference value using its static path.
|
||
/// Passing an invalid path is a compile-time error.
|
||
#[macro_export]
|
||
macro_rules! set_pref {
|
||
($($segment: ident).+, $value: expr) => {{
|
||
let value = $value;
|
||
$crate::prefs::set_stylo_pref(stringify!($($segment).+), value);
|
||
let values = $crate::prefs::pref_map().values();
|
||
let mut lock = values.write().unwrap();
|
||
lock$ (.$segment)+ = value;
|
||
}};
|
||
}
|
||
|
||
/// Access preferences using their `String` keys. Note that the key may be different from the
|
||
/// static path because legacy keys contain hyphens, or because a preference name has been renamed.
|
||
///
|
||
/// When retrieving a preference, the value will always be a `PrefValue`. When setting a value, it
|
||
/// may be a `PrefValue` or the type that converts into the correct underlying value; one of `bool`,
|
||
/// `i64`, `f64` or `String`.
|
||
#[inline]
|
||
pub fn pref_map() -> &'static Preferences<'static, Prefs> {
|
||
&PREFS
|
||
}
|
||
|
||
pub fn add_user_prefs(prefs: HashMap<String, PrefValue>) {
|
||
for (key, value) in prefs.iter() {
|
||
set_stylo_pref_ref(key, value);
|
||
}
|
||
if let Err(error) = PREFS.set_all(prefs) {
|
||
panic!("Error setting preference: {:?}", error);
|
||
}
|
||
}
|
||
|
||
pub fn set_stylo_pref(key: &str, value: impl Into<PrefValue>) {
|
||
set_stylo_pref_ref(key, &value.into());
|
||
}
|
||
|
||
fn set_stylo_pref_ref(key: &str, value: &PrefValue) {
|
||
match value.try_into() {
|
||
Ok(StyloPrefValue::Bool(value)) => style_config::set_bool(key, value),
|
||
Ok(StyloPrefValue::Int(value)) => style_config::set_i32(key, value),
|
||
Err(TryFromPrefValueError::IntegerOverflow(value)) => {
|
||
// TODO: logging doesn’t actually work this early, so we should
|
||
// split PrefValue into i32 and i64 variants.
|
||
warn!("Pref value too big for Stylo: {} ({})", key, value);
|
||
},
|
||
Err(TryFromPrefValueError::UnmappedType) => {
|
||
// Most of Servo’s prefs will hit this. When adding a new pref type
|
||
// in Stylo, update TryFrom<&PrefValue> for StyloPrefValue as well.
|
||
},
|
||
}
|
||
}
|
||
|
||
enum StyloPrefValue {
|
||
Bool(bool),
|
||
Int(i32),
|
||
}
|
||
|
||
enum TryFromPrefValueError {
|
||
IntegerOverflow(i64),
|
||
UnmappedType,
|
||
}
|
||
|
||
impl TryFrom<&PrefValue> for StyloPrefValue {
|
||
type Error = TryFromPrefValueError;
|
||
|
||
fn try_from(value: &PrefValue) -> Result<Self, Self::Error> {
|
||
match *value {
|
||
PrefValue::Int(value) => {
|
||
if let Ok(value) = value.try_into() {
|
||
Ok(Self::Int(value))
|
||
} else {
|
||
Err(TryFromPrefValueError::IntegerOverflow(value))
|
||
}
|
||
},
|
||
PrefValue::Bool(value) => Ok(Self::Bool(value)),
|
||
_ => Err(TryFromPrefValueError::UnmappedType),
|
||
}
|
||
}
|
||
}
|
||
|
||
pub fn read_prefs_map(txt: &str) -> Result<HashMap<String, PrefValue>, PrefError> {
|
||
let prefs: HashMap<String, Value> =
|
||
serde_json::from_str(txt).map_err(PrefError::JsonParseErr)?;
|
||
prefs
|
||
.into_iter()
|
||
.map(|(k, pref_value)| {
|
||
Ok({
|
||
let v = match &pref_value {
|
||
Value::Bool(b) => PrefValue::Bool(*b),
|
||
Value::Number(n) if n.is_i64() => PrefValue::Int(n.as_i64().unwrap()),
|
||
Value::Number(n) if n.is_f64() => PrefValue::Float(n.as_f64().unwrap()),
|
||
Value::String(s) => PrefValue::Str(s.to_owned()),
|
||
Value::Array(v) => {
|
||
let mut array = v.iter().map(PrefValue::from_json_value);
|
||
if array.all(|v| v.is_some()) {
|
||
PrefValue::Array(array.flatten().collect())
|
||
} else {
|
||
return Err(PrefError::InvalidValue(format!(
|
||
"Invalid value: {}",
|
||
pref_value
|
||
)));
|
||
}
|
||
},
|
||
_ => {
|
||
return Err(PrefError::InvalidValue(format!(
|
||
"Invalid value: {}",
|
||
pref_value
|
||
)));
|
||
},
|
||
};
|
||
(k.to_owned(), v)
|
||
})
|
||
})
|
||
.collect()
|
||
}
|
||
|
||
mod gen {
|
||
use serde::{Deserialize, Serialize};
|
||
use servo_config_plugins::build_structs;
|
||
|
||
// The number of layout threads is calculated if it is not present in `prefs.json`.
|
||
fn default_layout_threads() -> i64 {
|
||
std::cmp::max(num_cpus::get() * 3 / 4, 1) as i64
|
||
}
|
||
|
||
fn default_font_size() -> i64 {
|
||
16
|
||
}
|
||
|
||
fn default_monospace_font_size() -> i64 {
|
||
13
|
||
}
|
||
|
||
build_structs! {
|
||
// type of the accessors
|
||
accessor_type = crate::pref_util::Accessor::<Prefs, crate::pref_util::PrefValue>,
|
||
// name of the constant, which will hold a HashMap of preference accessors
|
||
gen_accessors = PREF_ACCESSORS,
|
||
// tree of structs to generate
|
||
gen_types = Prefs {
|
||
fonts: {
|
||
#[serde(default)]
|
||
default: String,
|
||
#[serde(default)]
|
||
serif: String,
|
||
#[serde(default)]
|
||
#[serde(rename = "fonts.sans-serif")]
|
||
sans_serif: String,
|
||
#[serde(default)]
|
||
monospace: String,
|
||
#[serde(default = "default_font_size")]
|
||
#[serde(rename = "fonts.default-size")]
|
||
default_size: i64,
|
||
#[serde(default = "default_monospace_font_size")]
|
||
#[serde(rename = "fonts.default-monospace-size")]
|
||
default_monospace_size: i64,
|
||
},
|
||
/// Allows customizing the different threadpools used by servo
|
||
threadpools: {
|
||
/// Number of workers per threadpool, if we fail to detect how much
|
||
/// parallelism is available at runtime.
|
||
fallback_worker_num: i64,
|
||
image_cache_workers: {
|
||
/// Maximum number of workers for the Image Cache thread pool
|
||
max: i64,
|
||
},
|
||
async_runtime_workers: {
|
||
/// Maximum number of workers for the Networking async runtime thread pool
|
||
max: i64
|
||
},
|
||
resource_workers: {
|
||
/// Maximum number of workers for the Core Resource Manager
|
||
max: i64,
|
||
},
|
||
webrender_workers: {
|
||
/// Maximum number of workers for webrender
|
||
max: i64,
|
||
},
|
||
},
|
||
css: {
|
||
animations: {
|
||
testing: {
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
},
|
||
},
|
||
},
|
||
devtools: {
|
||
server: {
|
||
enabled: bool,
|
||
port: i64,
|
||
},
|
||
},
|
||
dom: {
|
||
webgpu: {
|
||
/// Enable WebGPU APIs.
|
||
enabled: bool,
|
||
/// List of comma-separated backends to be used by wgpu
|
||
wgpu_backend: String,
|
||
},
|
||
bluetooth: {
|
||
enabled: bool,
|
||
testing: {
|
||
enabled: bool,
|
||
}
|
||
},
|
||
allow_scripts_to_close_windows: bool,
|
||
canvas_capture: {
|
||
enabled: bool,
|
||
},
|
||
canvas_text: {
|
||
enabled: bool,
|
||
},
|
||
composition_event: {
|
||
#[serde(rename = "dom.compositionevent.enabled")]
|
||
enabled: bool,
|
||
},
|
||
crypto: {
|
||
subtle: {
|
||
enabled: bool,
|
||
}
|
||
},
|
||
custom_elements: {
|
||
#[serde(rename = "dom.customelements.enabled")]
|
||
enabled: bool,
|
||
},
|
||
document: {
|
||
dblclick_timeout: i64,
|
||
dblclick_dist: i64,
|
||
},
|
||
forcetouch: {
|
||
enabled: bool,
|
||
},
|
||
fullscreen: {
|
||
test: bool,
|
||
},
|
||
gamepad: {
|
||
enabled: bool,
|
||
},
|
||
imagebitmap: {
|
||
enabled: bool,
|
||
},
|
||
intersection_observer: {
|
||
enabled: bool,
|
||
},
|
||
microdata: {
|
||
testing: {
|
||
enabled: bool,
|
||
}
|
||
},
|
||
mouse_event: {
|
||
which: {
|
||
#[serde(rename = "dom.mouseevent.which.enabled")]
|
||
enabled: bool,
|
||
}
|
||
},
|
||
mutation_observer: {
|
||
enabled: bool,
|
||
},
|
||
offscreen_canvas: {
|
||
enabled: bool,
|
||
},
|
||
permissions: {
|
||
enabled: bool,
|
||
testing: {
|
||
allowed_in_nonsecure_contexts: bool,
|
||
}
|
||
},
|
||
resize_observer: {
|
||
enabled: bool,
|
||
},
|
||
script: {
|
||
asynch: bool,
|
||
},
|
||
serviceworker: {
|
||
enabled: bool,
|
||
timeout_seconds: i64,
|
||
},
|
||
servo_helpers: {
|
||
enabled: bool,
|
||
},
|
||
servoparser: {
|
||
async_html_tokenizer: {
|
||
enabled: bool,
|
||
}
|
||
},
|
||
shadowdom: {
|
||
enabled: bool,
|
||
},
|
||
svg: {
|
||
enabled: bool,
|
||
},
|
||
testable_crash: {
|
||
enabled: bool,
|
||
},
|
||
testbinding: {
|
||
enabled: bool,
|
||
prefcontrolled: {
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
},
|
||
prefcontrolled2: {
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
},
|
||
preference_value: {
|
||
#[serde(default)]
|
||
falsy: bool,
|
||
#[serde(default)]
|
||
quote_string_test: String,
|
||
#[serde(default)]
|
||
space_string_test: String,
|
||
#[serde(default)]
|
||
string_empty: String,
|
||
#[serde(default)]
|
||
string_test: String,
|
||
#[serde(default)]
|
||
truthy: bool,
|
||
},
|
||
},
|
||
testing: {
|
||
element: {
|
||
activation: {
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
}
|
||
},
|
||
html_input_element: {
|
||
select_files: {
|
||
#[serde(rename = "dom.testing.htmlinputelement.select_files.enabled")]
|
||
enabled: bool,
|
||
}
|
||
},
|
||
},
|
||
testperf: {
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
},
|
||
webgl2: {
|
||
/// Enable WebGL2 APIs.
|
||
enabled: bool,
|
||
},
|
||
webrtc: {
|
||
transceiver: {
|
||
enabled: bool,
|
||
},
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
},
|
||
webvtt: {
|
||
enabled: bool,
|
||
},
|
||
webxr: {
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
#[serde(default)]
|
||
test: bool,
|
||
first_person_observer_view: bool,
|
||
glwindow: {
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
#[serde(rename = "dom.webxr.glwindow.left-right")]
|
||
left_right: bool,
|
||
#[serde(rename = "dom.webxr.glwindow.red-cyan")]
|
||
red_cyan: bool,
|
||
spherical: bool,
|
||
cubemap: bool,
|
||
},
|
||
hands: {
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
},
|
||
layers: {
|
||
enabled: bool,
|
||
},
|
||
openxr: {
|
||
enabled: bool,
|
||
},
|
||
sessionavailable: bool,
|
||
#[serde(rename = "dom.webxr.unsafe-assume-user-intent")]
|
||
unsafe_assume_user_intent: bool,
|
||
},
|
||
worklet: {
|
||
blockingsleep: {
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
},
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
testing: {
|
||
#[serde(default)]
|
||
enabled: bool,
|
||
},
|
||
timeout_ms: i64,
|
||
},
|
||
},
|
||
gfx: {
|
||
subpixel_text_antialiasing: {
|
||
#[serde(rename = "gfx.subpixel-text-antialiasing.enabled")]
|
||
enabled: bool,
|
||
},
|
||
texture_swizzling: {
|
||
#[serde(rename = "gfx.texture-swizzling.enabled")]
|
||
enabled: bool,
|
||
},
|
||
},
|
||
js: {
|
||
asmjs: {
|
||
enabled: bool,
|
||
},
|
||
asyncstack: {
|
||
enabled: bool,
|
||
},
|
||
baseline_interpreter: {
|
||
enabled: bool,
|
||
},
|
||
/// Whether to disable the jit within SpiderMonkey
|
||
disable_jit: bool,
|
||
baseline_jit: {
|
||
enabled: bool,
|
||
unsafe_eager_compilation: {
|
||
enabled: bool,
|
||
},
|
||
},
|
||
discard_system_source: {
|
||
enabled: bool,
|
||
},
|
||
dump_stack_on_debuggee_would_run: {
|
||
enabled: bool,
|
||
},
|
||
ion: {
|
||
enabled: bool,
|
||
offthread_compilation: {
|
||
enabled: bool,
|
||
},
|
||
unsafe_eager_compilation: {
|
||
enabled: bool,
|
||
},
|
||
},
|
||
mem: {
|
||
gc: {
|
||
allocation_threshold_mb: i64,
|
||
allocation_threshold_factor: i64,
|
||
allocation_threshold_avoid_interrupt_factor: i64,
|
||
compacting: {
|
||
enabled: bool,
|
||
},
|
||
decommit_threshold_mb: i64,
|
||
dynamic_heap_growth: {
|
||
enabled: bool,
|
||
},
|
||
dynamic_mark_slice: {
|
||
enabled: bool,
|
||
},
|
||
empty_chunk_count_max: i64,
|
||
empty_chunk_count_min: i64,
|
||
high_frequency_heap_growth_max: i64,
|
||
high_frequency_heap_growth_min: i64,
|
||
high_frequency_high_limit_mb: i64,
|
||
high_frequency_low_limit_mb: i64,
|
||
high_frequency_time_limit_ms: i64,
|
||
incremental: {
|
||
enabled: bool,
|
||
slice_ms: i64,
|
||
},
|
||
low_frequency_heap_growth: i64,
|
||
per_zone: {
|
||
enabled: bool,
|
||
},
|
||
zeal: {
|
||
frequency: i64,
|
||
level: i64,
|
||
},
|
||
},
|
||
max: i64,
|
||
},
|
||
native_regex: {
|
||
enabled: bool,
|
||
},
|
||
offthread_compilation: {
|
||
enabled: bool,
|
||
},
|
||
parallel_parsing: {
|
||
enabled: bool,
|
||
},
|
||
shared_memory: {
|
||
enabled: bool,
|
||
},
|
||
throw_on_asmjs_validation_failure: {
|
||
enabled: bool,
|
||
},
|
||
throw_on_debuggee_would_run: {
|
||
enabled: bool,
|
||
},
|
||
timers: {
|
||
minimum_duration: i64,
|
||
},
|
||
wasm: {
|
||
baseline: {
|
||
enabled: bool,
|
||
},
|
||
enabled: bool,
|
||
ion: {
|
||
enabled: bool,
|
||
}
|
||
},
|
||
werror: {
|
||
enabled: bool,
|
||
},
|
||
},
|
||
layout: {
|
||
animations: {
|
||
test: {
|
||
enabled: bool,
|
||
}
|
||
},
|
||
columns: {
|
||
enabled: bool,
|
||
},
|
||
css: {
|
||
transition_behavior: {
|
||
#[serde(rename = "layout.css.transition-behavior.enabled")]
|
||
enabled: bool,
|
||
}
|
||
},
|
||
flexbox: {
|
||
enabled: bool,
|
||
},
|
||
grid: {
|
||
enabled: bool,
|
||
},
|
||
legacy_layout: bool,
|
||
#[serde(default = "default_layout_threads")]
|
||
threads: i64,
|
||
writing_mode: {
|
||
#[serde(rename = "layout.writing-mode.enabled")]
|
||
enabled: bool,
|
||
}
|
||
},
|
||
media: {
|
||
glvideo: {
|
||
/// Enable hardware acceleration for video playback.
|
||
enabled: bool,
|
||
},
|
||
testing: {
|
||
/// Enable a non-standard event handler for verifying behavior of media elements during tests.
|
||
enabled: bool,
|
||
}
|
||
},
|
||
network: {
|
||
enforce_tls: {
|
||
enabled: bool,
|
||
localhost: bool,
|
||
onion: bool,
|
||
},
|
||
http_cache: {
|
||
#[serde(rename = "network.http-cache.disabled")]
|
||
disabled: bool,
|
||
},
|
||
local_directory_listing: {
|
||
enabled: bool,
|
||
},
|
||
mime: {
|
||
sniff: bool,
|
||
},
|
||
tls: {
|
||
/// Ignore `std::io::Error` with `ErrorKind::UnexpectedEof` received when a TLS connection
|
||
/// is closed without a close_notify.
|
||
///
|
||
/// Used for tests because WPT server doesn't properly close the TLS connection.
|
||
// TODO: remove this when WPT server is updated to use a proper TLS implementation.
|
||
ignore_unexpected_eof: bool,
|
||
},
|
||
},
|
||
session_history: {
|
||
#[serde(rename = "session-history.max-length")]
|
||
max_length: i64,
|
||
},
|
||
shell: {
|
||
background_color: {
|
||
/// The background color of shell's viewport. This will be used by OpenGL's `glClearColor`.
|
||
#[serde(rename = "shell.background-color.rgba")]
|
||
rgba: [f64; 4],
|
||
},
|
||
crash_reporter: {
|
||
enabled: bool,
|
||
},
|
||
/// URL string of the homepage.
|
||
homepage: String,
|
||
#[serde(rename = "shell.native-orientation")]
|
||
native_orientation: String,
|
||
native_titlebar: {
|
||
/// Enable native window's titlebar and decorations.
|
||
#[serde(rename = "shell.native-titlebar.enabled")]
|
||
enabled: bool,
|
||
},
|
||
/// URL string of the search engine page (for example <https://google.com> or and <https://duckduckgo.com>.
|
||
searchpage: String,
|
||
},
|
||
webgl: {
|
||
testing: {
|
||
context_creation_error: bool,
|
||
}
|
||
},
|
||
}
|
||
}
|
||
}
|