1
1
mirror of https://github.com/wez/wezterm.git synced 2024-09-20 11:17:15 +03:00

Add config options to control various cache sizes

These are more for low level testing than they are intended
for users to play with, so they are deliberately undocumented
at this time.
This commit is contained in:
Wez Furlong 2022-09-09 07:28:49 -07:00
parent 25cd05a80a
commit 39dd4cdd82
5 changed files with 112 additions and 13 deletions

View File

@ -644,6 +644,17 @@ pub struct Config {
#[dynamic(default = "default_max_fps")]
pub max_fps: u8,
#[dynamic(default = "default_shape_cache_size")]
pub shape_cache_size: usize,
#[dynamic(default = "default_line_state_cache_size")]
pub line_state_cache_size: usize,
#[dynamic(default = "default_line_quad_cache_size")]
pub line_quad_cache_size: usize,
#[dynamic(default = "default_line_to_ele_shape_cache_size")]
pub line_to_ele_shape_cache_size: usize,
#[dynamic(default = "default_glyph_cache_image_cache_size")]
pub glyph_cache_image_cache_size: usize,
#[dynamic(default)]
pub visual_bell: VisualBell,
@ -1598,6 +1609,26 @@ impl DroppedFileQuoting {
}
}
fn default_glyph_cache_image_cache_size() -> usize {
256
}
fn default_shape_cache_size() -> usize {
1024
}
fn default_line_state_cache_size() -> usize {
1024
}
fn default_line_quad_cache_size() -> usize {
1024
}
fn default_line_to_ele_shape_cache_size() -> usize {
1024
}
#[derive(Debug, FromDynamic, ToDynamic, Clone, Copy, PartialEq, Eq)]
pub enum ImePreeditRendering {
/// IME preedit is rendered by WezTerm itself

View File

@ -1,5 +1,6 @@
#![allow(dead_code)]
use cache_advisor::CacheAdvisor;
use config::ConfigHandle;
use fnv::FnvHashMap;
use std::borrow::Borrow;
use std::cmp::Eq;
@ -11,6 +12,8 @@ use std::hash::Hash;
/// Frequently used items are promoted from temporary to main cache.
const ENTRY_PERCENT: u8 = 20;
pub type CapFunc = fn(&ConfigHandle) -> usize;
/// A cache using a Least-Frequently-Used eviction policy.
/// If K is u64 you should use LfuCacheU64 instead as it has
/// less overhead.
@ -22,10 +25,17 @@ pub struct LfuCache<K, V> {
next_id: u64,
advisor: CacheAdvisor,
cap: usize,
cap_func: CapFunc,
}
impl<K: Hash + Eq + Clone, V> LfuCache<K, V> {
pub fn new(hit: &'static str, miss: &'static str, cap: usize) -> Self {
pub fn new(
hit: &'static str,
miss: &'static str,
cap_func: CapFunc,
config: &ConfigHandle,
) -> Self {
let cap = cap_func(config);
Self {
hit,
miss,
@ -34,6 +44,7 @@ impl<K: Hash + Eq + Clone, V> LfuCache<K, V> {
advisor: CacheAdvisor::new(cap, ENTRY_PERCENT),
next_id: 0,
cap,
cap_func,
}
}
@ -41,8 +52,17 @@ impl<K: Hash + Eq + Clone, V> LfuCache<K, V> {
self.map.len()
}
pub fn update_config(&mut self, config: &ConfigHandle) {
let new_cap = (self.cap_func)(config);
if new_cap != self.cap {
self.cap = new_cap;
self.clear();
}
}
pub fn clear(&mut self) {
self.map.clear();
self.key_to_id.clear();
self.advisor = CacheAdvisor::new(self.cap, ENTRY_PERCENT);
}
@ -101,16 +121,24 @@ pub struct LfuCacheU64<V> {
map: FnvHashMap<u64, V>,
advisor: CacheAdvisor,
cap: usize,
cap_func: CapFunc,
}
impl<V> LfuCacheU64<V> {
pub fn new(hit: &'static str, miss: &'static str, cap: usize) -> Self {
pub fn new(
hit: &'static str,
miss: &'static str,
cap_func: CapFunc,
config: &ConfigHandle,
) -> Self {
let cap = cap_func(config);
Self {
hit,
miss,
map: FnvHashMap::default(),
advisor: CacheAdvisor::new(cap, ENTRY_PERCENT),
cap,
cap_func,
}
}
@ -118,6 +146,14 @@ impl<V> LfuCacheU64<V> {
self.map.len()
}
pub fn update_config(&mut self, config: &ConfigHandle) {
let new_cap = (self.cap_func)(config);
if new_cap != self.cap {
self.cap = new_cap;
self.clear();
}
}
pub fn clear(&mut self) {
self.map.clear();
self.advisor = CacheAdvisor::new(self.cap, ENTRY_PERCENT);

View File

@ -243,6 +243,8 @@ impl DecodedImage {
}
}
/// A number of items here are HashMaps rather than LfuCaches;
/// eviction is managed by recreating Self when the Atlas is filled
pub struct GlyphCache<T: Texture2d> {
glyph_cache: HashMap<GlyphKey, Rc<CachedGlyph<T>>>,
pub atlas: Atlas<T>,
@ -266,7 +268,8 @@ impl GlyphCache<ImageTexture> {
image_cache: LfuCacheU64::new(
"glyph_cache.image_cache.hit.rate",
"glyph_cache.image_cache.miss.rate",
256,
|config| config.glyph_cache_image_cache_size,
&fonts.config(),
),
frame_cache: HashMap::new(),
atlas,
@ -316,7 +319,8 @@ impl GlyphCache<SrgbTexture2d> {
image_cache: LfuCacheU64::new(
"glyph_cache.image_cache.hit.rate",
"glyph_cache.image_cache.miss.rate",
256, // FIXME: make configurable
|config| config.glyph_cache_image_cache_size,
&fonts.config(),
),
frame_cache: HashMap::new(),
atlas,
@ -395,6 +399,11 @@ impl<T: Texture2d> GlyphCache<T> {
Ok(glyph)
}
pub fn config_changed(&mut self) {
let config = self.fonts.config();
self.image_cache.update_config(&config);
}
/// Perform the load and render of a glyph
#[allow(clippy::float_cmp)]
fn load_glyph(

View File

@ -129,9 +129,9 @@ pub struct RenderLayer {
impl RenderLayer {
pub fn new(context: &Rc<GliumContext>, num_quads: usize, zindex: i8) -> anyhow::Result<Self> {
let vb = [
Self::compute_vertices(context, 128)?,
Self::compute_vertices(context, 32)?,
Self::compute_vertices(context, num_quads)?,
Self::compute_vertices(context, 128)?,
Self::compute_vertices(context, 32)?,
];
Ok(Self {
@ -168,6 +168,11 @@ impl RenderLayer {
num_quads: usize,
) -> anyhow::Result<TripleVertexBuffer> {
let verts = vec![Vertex::default(); num_quads * VERTICES_PER_CELL];
log::trace!(
"compute_vertices num_quads={}, allocated {} bytes",
num_quads,
verts.len() * std::mem::size_of::<Vertex>()
);
let mut indices = vec![];
indices.reserve(num_quads * INDICES_PER_CELL);
@ -294,9 +299,9 @@ impl RenderState {
for layer in self.layers.borrow().iter() {
for vb_idx in 0..3 {
if let Some(need_quads) = layer.need_more_quads(vb_idx) {
// Round up to next multiple of 1024 that is >=
// Round up to next multiple of 128 that is >=
// the number of needed quads for this frame
let num_quads = (need_quads + 1023) & !1023;
let num_quads = (need_quads + 127) & !127;
layer.reallocate_quads(vb_idx, num_quads).with_context(|| {
format!(
"Failed to allocate {} quads (needed {})",
@ -355,6 +360,10 @@ impl RenderState {
)
}
pub fn config_changed(&mut self) {
self.glyph_cache.borrow_mut().config_changed();
}
pub fn recreate_texture_atlas(
&mut self,
fonts: &Rc<FontConfiguration>,

View File

@ -703,23 +703,27 @@ impl TermWindow {
shape_cache: RefCell::new(LfuCache::new(
"shape_cache.hit.rate",
"shape_cache.miss.rate",
1024,
|config| config.shape_cache_size,
&config,
)),
line_state_cache: RefCell::new(LfuCacheU64::new(
"line_state_cache.hit.rate",
"line_state_cache.miss.rate",
1024,
|config| config.line_state_cache_size,
&config,
)),
next_line_state_id: 0,
line_quad_cache: RefCell::new(LfuCache::new(
"line_quad_cache.hit.rate",
"line_quad_cache.miss.rate",
1024,
|config| config.line_quad_cache_size,
&config,
)),
line_to_ele_shape_cache: RefCell::new(LfuCache::new(
"line_to_ele_shape_cache.hit.rate",
"line_to_ele_shape_cache.miss.rate",
1024,
|config| config.line_to_ele_shape_cache_size,
&config,
)),
last_status_call: Instant::now(),
cursor_blink_state: RefCell::new(ColorEase::new(
@ -1536,12 +1540,22 @@ impl TermWindow {
self.show_scroll_bar = config.enable_scroll_bar;
self.shape_generation += 1;
self.shape_cache.borrow_mut().clear();
{
let mut shape_cache = self.shape_cache.borrow_mut();
shape_cache.update_config(&config);
shape_cache.clear();
}
self.line_state_cache.borrow_mut().update_config(&config);
self.line_quad_cache.borrow_mut().update_config(&config);
self.line_to_ele_shape_cache
.borrow_mut()
.update_config(&config);
self.fancy_tab_bar.take();
self.invalidate_fancy_tab_bar();
self.invalidate_modal();
self.input_map = InputMap::new(&config);
self.leader_is_down = None;
self.render_state.as_mut().map(|rs| rs.config_changed());
let dimensions = self.dimensions;
if let Err(err) = self.fonts.config_changed(&config) {