Only build the RTTI hashmap once per thread (#6617)

This removes a lot of temporary allocations, note e.g. how this
was called once per component previously yet the data contained
in the map was always the same!

Before:
```
Benchmark 1: ./target/release/slint-viewer ../slint-perf/app.slint
  Time (mean ± σ):     636.2 ms ±  20.0 ms    [User: 563.4 ms, System: 71.8 ms]
  Range (min … max):   615.2 ms … 657.9 ms    10 runs

        allocations:            3371939
```

After:
```
Benchmark 1: ./target/release/slint-viewer ../slint-perf/app.slint
  Time (mean ± σ):     600.6 ms ±   2.9 ms    [User: 522.0 ms, System: 74.4 ms]
  Range (min … max):   596.3 ms … 605.2 ms    10 runs

        allocations:            2917930
```
This commit is contained in:
Milian Wolff 2024-10-22 18:01:33 +02:00 committed by GitHub
parent 10de1e664b
commit e3741a87f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -36,7 +36,7 @@ use i_slint_core::window::{WindowAdapterRc, WindowInner};
use i_slint_core::{Brush, Color, Property, SharedString, SharedVector};
#[cfg(feature = "internal")]
use itertools::Either;
use once_cell::unsync::OnceCell;
use once_cell::unsync::{Lazy, OnceCell};
use smol_str::{SmolStr, ToSmolStr};
use std::collections::BTreeMap;
use std::collections::HashMap;
@ -935,14 +935,8 @@ pub async fn load(
}
}
pub(crate) fn generate_item_tree<'id>(
component: &Rc<object_tree::Component>,
compiled_globals: Option<Rc<CompiledGlobalCollection>>,
guard: generativity::Guard<'id>,
) -> Rc<ItemTreeDescription<'id>> {
//dbg!(&*component.root_element.borrow());
fn generate_rtti() -> HashMap<&'static str, Rc<ItemRTTI>> {
let mut rtti = HashMap::new();
{
use i_slint_core::items::*;
rtti.extend(
[
@ -990,6 +984,19 @@ pub(crate) fn generate_item_tree<'id>(
}
}
i_slint_backend_selector::NativeWidgets::push(&mut rtti);
rtti
}
pub(crate) fn generate_item_tree<'id>(
component: &Rc<object_tree::Component>,
compiled_globals: Option<Rc<CompiledGlobalCollection>>,
guard: generativity::Guard<'id>,
) -> Rc<ItemTreeDescription<'id>> {
//dbg!(&*component.root_element.borrow());
thread_local! {
static RTTI: Lazy<HashMap<&'static str, Rc<ItemRTTI>>> = Lazy::new(|| generate_rtti());
}
struct TreeBuilder<'id> {
@ -1001,7 +1008,6 @@ pub(crate) fn generate_item_tree<'id>(
type_builder: dynamic_type::TypeBuilder<'id>,
repeater: Vec<ErasedRepeaterWithinComponent<'id>>,
repeater_names: HashMap<SmolStr, usize>,
rtti: Rc<HashMap<&'static str, Rc<ItemRTTI>>>,
change_callbacks: Vec<(NamedReference, Expression)>,
}
impl<'id> generator::ItemTreeBuilder for TreeBuilder<'id> {
@ -1050,8 +1056,15 @@ pub(crate) fn generate_item_tree<'id>(
_component_state: &Self::SubComponentState,
) {
let item = rc_item.borrow();
let rt = self.rtti.get(&*item.base_type.as_native().class_name).unwrap_or_else(|| {
panic!("Native type not registered: {}", item.base_type.as_native().class_name)
let rt = RTTI.with(|rtti| {
rtti.get(&*item.base_type.as_native().class_name)
.unwrap_or_else(|| {
panic!(
"Native type not registered: {}",
item.base_type.as_native().class_name
)
})
.clone()
});
let offset = self.type_builder.add_field(rt.type_info);
@ -1068,7 +1081,7 @@ pub(crate) fn generate_item_tree<'id>(
debug_assert_eq!(self.original_elements.len(), self.tree_array.len());
self.items_types.insert(
item.id.clone(),
ItemWithinItemTree { offset, rtti: rt.clone(), elem: rc_item.clone() },
ItemWithinItemTree { offset, rtti: rt, elem: rc_item.clone() },
);
for (prop, expr) in &item.change_callbacks {
self.change_callbacks.push((
@ -1107,7 +1120,6 @@ pub(crate) fn generate_item_tree<'id>(
type_builder: dynamic_type::TypeBuilder::new(guard),
repeater: vec![],
repeater_names: HashMap::new(),
rtti: Rc::new(rtti),
change_callbacks: vec![],
};