Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AddAnyAttr working with erase_components #3518

Merged
merged 2 commits into from
Jan 26, 2025
Merged

Conversation

zakstucke
Copy link
Contributor

@zakstucke zakstucke commented Jan 26, 2025

cc #3156 #3458 #3460 #3461 #3476

TLDR: this PR enables AddAnyAttr on AnyView when the--cfg erase_components feature flag is enabled. Made possible by further type erasing tuples of attrs types to Vec<AnyAttribute> before they even became tuples preventing generation of an exponential number of types. --cfg erase_components is now feature complete and provides up to 1.5-3x faster compilation speed. Yay!

Unfortunately this means the issues surrounding AddAnyAttr and AnyView without type erasure are most likely not an issue with rust or the compiler, but too many unique attribute tuple types, monorphisation and codegen, but importantly this missing feature is actually what is making stable leptos compile, by trimming the potential for futher attr types at each AnyView boundary and preventing further tuple types of that type being created, and why the feature cannot be enabled without reducing the number of unique types.

Arguably the above is an issue with rust/the compiler, but on further analysis it looks like the solution isn't "fix a bug in rust/compiler" it's "how do we reduce the number of unique types without hurting binary size or runtime too much because the current number seems to be insane".

As I've mentioned, the compile bottleneck is only surrounding the static typing of attributes, not the entire view tree, which makes sense considering these are the "leaves" whereas html elements are the "branches". Maybe erasing attributes is a worthwhile cost, whilst leaving the tree itself static (i.e splitting --cfg erase_components into 2 parts, the attr part being erased.

The main takeaway is that compiler issues, compile time, the AnyAttr feature not working on AnyView, are all down to the tuple impls that create an exponential number of types.

Using thaw's demo project, pointing leptos to this PR, you can see the effect of erasing the components with cargo-llvm-lines: llvm lines drop by 35% from 11million to 7million, still huge but it get's it down to something that seems manageable.

Without erasure:

cd demo
CARGO_PROFILE_RELEASE_LTO=fat cargo +stable llvm-lines --bin demo --release --features ssr | head -50
  11037943                245438                (TOTAL)
    753224 (6.8%,  6.8%)   14798 (6.0%,  6.0%)  core::ops::function::FnOnce::call_once
    344453 (3.1%,  9.9%)    3661 (1.5%,  7.5%)  <T as tachys::view::any_view::IntoAny>::into_any::{{closure}}
    344398 (3.1%, 13.1%)    1671 (0.7%,  8.2%)  <tachys::html::element::HtmlElement<E,At,Ch> as tachys::view::RenderHtml>::to_html_async_with_buf
    273222 (2.5%, 15.5%)    2868 (1.2%,  9.4%)  <futures_util::future::maybe_done::MaybeDone<Fut> as core::future::future::Future>::poll
    261056 (2.4%, 17.9%)    2191 (0.9%, 10.3%)  <T as tachys::view::any_view::IntoAny>::into_any::{{closure}}::{{closure}}
    210774 (1.9%, 19.8%)   13073 (5.3%, 15.6%)  core::ops::function::FnOnce::call_once{{vtable.shim}}
    167520 (1.5%, 21.3%)    1139 (0.5%, 16.1%)  reactive_graph::owner::Owner::with
    161694 (1.5%, 22.8%)    7963 (3.2%, 19.3%)  alloc::boxed::Box<T>::new
    146147 (1.3%, 24.1%)    1587 (0.6%, 19.9%)  <futures_util::future::poll_fn::PollFn<F> as core::future::future::Future>::poll
    130325 (1.2%, 25.3%)     878 (0.4%, 20.3%)  <tachys::html::element::HtmlElement<E,At,Ch> as tachys::view::RenderHtml>::to_html_with_buf
     96664 (0.9%, 26.2%)     470 (0.2%, 20.5%)  tachys::html::element::attributes_to_html
     95371 (0.9%, 27.0%)     139 (0.1%, 20.6%)  reactive_graph::computed::inner::<impl reactive_graph::graph::node::ReactiveNode for std::sync::rwlock::RwLock<reactive_graph::computed::inner::MemoInner<T,S>>>::update_if_necessary
     95137 (0.9%, 27.9%)     520 (0.2%, 20.8%)  <tachys::html::element::HtmlElement<E,At,Ch> as tachys::view::RenderHtml>::resolve::{{closure}}
     90507 (0.8%, 28.7%)    1026 (0.4%, 21.2%)  <futures_util::future::join::Join<Fut1,Fut2> as core::future::future::Future>::poll
     89915 (0.8%, 29.5%)    1106 (0.5%, 21.6%)  <T as tachys::view::any_view::IntoAny>::into_any
     82920 (0.8%, 30.3%)     794 (0.3%, 22.0%)  <tachys::html::element::HtmlElement<E,At,Ch> as tachys::view::Render>::build
     79087 (0.7%, 31.0%)    1623 (0.7%, 22.6%)  alloc::sync::Arc<T,A>::drop_slow
     78547 (0.7%, 31.7%)     788 (0.3%, 22.9%)  reactive_graph::owner::arena::Arena::with
     74110 (0.7%, 32.4%)    1193 (0.5%, 23.4%)  std::thread::local::LocalKey<T>::try_with
     67549 (0.6%, 33.0%)    1271 (0.5%, 23.9%)  futures_util::future::maybe_done::MaybeDone<Fut>::take_output
     64881 (0.6%, 33.6%)     290 (0.1%, 24.1%)  tachys::view::tuples::<impl tachys::view::RenderHtml for (A,B)>::resolve::{{closure}}
     61440 (0.6%, 34.1%)    1024 (0.4%, 24.5%)  reactive_graph::owner::Owner::with::{{closure}}
     58562 (0.5%, 34.7%)    1272 (0.5%, 25.0%)  core::pin::Pin<Ptr>::set
     56212 (0.5%, 35.2%)     771 (0.3%, 25.3%)  tachys::view::tuples::<impl tachys::view::RenderHtml for (A,B)>::to_html_async_with_buf
     55705 (0.5%, 35.7%)     550 (0.2%, 25.5%)  <T as reactive_graph::traits::Update>::try_maybe_update
     52200 (0.5%, 36.2%)     332 (0.1%, 25.7%)  reactive_graph::owner::Owner::with_cleanup
     44080 (0.4%, 36.6%)    1102 (0.4%, 26.1%)  <dyn core::any::Any>::is
     43997 (0.4%, 37.0%)     279 (0.1%, 26.2%)  reactive_graph::owner::Owner::on_cleanup
     43929 (0.4%, 37.4%)     114 (0.0%, 26.3%)  reactive_graph::effect::render_effect::RenderEffect<T>::new_with_value::erased::{{closure}}
     42502 (0.4%, 37.7%)     323 (0.1%, 26.4%)  <leptos::into_view::View<T> as tachys::view::RenderHtml>::resolve::{{closure}}
     42152 (0.4%, 38.1%)     767 (0.3%, 26.7%)  <tachys::html::element::HtmlElement<E,At,Ch> as tachys::view::Render>::rebuild
     39406 (0.4%, 38.5%)    1026 (0.4%, 27.1%)  tachys::view::tuples::<impl tachys::view::RenderHtml for (A,)>::to_html_async_with_buf
     36577 (0.3%, 38.8%)     286 (0.1%, 27.3%)  tachys::view::tuples::<impl tachys::view::RenderHtml for (A,B)>::resolve::{{closure}}::{{closure}}
     36469 (0.3%, 39.1%)     275 (0.1%, 27.4%)  tachys::view::tuples::<impl tachys::view::RenderHtml for (A,)>::resolve::{{closure}}
     36018 (0.3%, 39.5%)     413 (0.2%, 27.5%)  reactive_graph::owner::arena::Arena::with_mut
     34979 (0.3%, 39.8%)     499 (0.2%, 27.7%)  <tachys::html::element::ElementState<At,Ch> as tachys::view::Mountable>::insert_before_this
     32461 (0.3%, 40.1%)     516 (0.2%, 27.9%)  <reactive_graph::graph::subscriber::AnySubscriber as reactive_graph::graph::subscriber::WithObserver>::with_observer
     31836 (0.3%, 40.4%)     614 (0.3%, 28.2%)  <alloc::sync::Weak<T,A> as core::ops::drop::Drop>::drop
     31787 (0.3%, 40.7%)     664 (0.3%, 28.5%)  reactive_graph::effect::render_effect::RenderEffect<T>::new_with_value
     31451 (0.3%, 40.9%)     102 (0.0%, 28.5%)  tachys::view::tuples::<impl tachys::view::RenderHtml for (A,B,C)>::resolve::{{closure}}
     30857 (0.3%, 41.2%)     523 (0.2%, 28.7%)  alloc::boxed::convert::<impl alloc::boxed::Box<dyn core::any::Any,A>>::downcast
     30824 (0.3%, 41.5%)     808 (0.3%, 29.1%)  reactive_graph::graph::subscriber::untrack_with_diagnostics
     29347 (0.3%, 41.8%)     515 (0.2%, 29.3%)  tachys::view::tuples::<impl tachys::view::Render for (A,)>::build
     28308 (0.3%, 42.0%)     664 (0.3%, 29.5%)  core::result::Result<T,E>::expect
     28292 (0.3%, 42.3%)    5141 (2.1%, 31.6%)  <alloc::boxed::Box<dyn core::ops::function::FnOnce<()>+Output = tachys::view::any_view::AnyView+core::marker::Send> as leptos::children::ToChildren<F>>::to_children::{{closure}}
     26919 (0.2%, 42.5%)     411 (0.2%, 31.8%)  tachys::view::tuples::<impl tachys::view::RenderHtml for (A,B)>::to_html_with_buf
     25205 (0.2%, 42.8%)     198 (0.1%, 31.9%)  reactive_graph::traits::Get::get

With erasure:

RUSTFLAGS="--cfg erase_components" CARGO_PROFILE_RELEASE_LTO=fat cargo +stable llvm-lines --bin demo --release --features ssr | head -50`
  7164754                168452                (TOTAL)
   847252 (11.8%, 11.8%)  14887 (8.8%,  8.8%)  core::ops::function::FnOnce::call_once
   189182 (2.6%, 14.5%)   12341 (7.3%, 16.2%)  core::ops::function::FnOnce::call_once{{vtable.shim}}
   152782 (2.1%, 16.6%)    1081 (0.6%, 16.8%)  <T as tachys::view::any_view::IntoAny>::into_any::{{closure}}::{{closure}}
   150806 (2.1%, 18.7%)    1608 (1.0%, 17.8%)  <T as tachys::view::any_view::IntoAny>::into_any::{{closure}}
   129567 (1.8%, 20.5%)    6642 (3.9%, 21.7%)  alloc::boxed::Box<T>::new
   107322 (1.5%, 22.0%)     507 (0.3%, 22.0%)  <tachys::html::element::HtmlElement<E,At,Ch> as tachys::view::RenderHtml>::to_html_async_with_buf
    87836 (1.2%, 23.2%)     556 (0.3%, 22.3%)  <futures_util::future::maybe_done::MaybeDone<Fut> as core::future::future::Future>::poll
    74279 (1.0%, 24.3%)     431 (0.3%, 22.6%)  reactive_graph::owner::Owner::with
    73787 (1.0%, 25.3%)     102 (0.1%, 22.7%)  reactive_graph::computed::inner::<impl reactive_graph::graph::node::ReactiveNode for std::sync::rwlock::RwLock<reactive_graph::computed::inner::MemoInner<T,S>>>::update_if_necessary
    71172 (1.0%, 26.3%)    1444 (0.9%, 23.5%)  alloc::sync::Arc<T,A>::drop_slow
    67005 (0.9%, 27.2%)     658 (0.4%, 23.9%)  <T as tachys::html::attribute::any_attribute::IntoAnyAttribute>::into_any_attr::{{closure}}::{{closure}}
    55648 (0.8%, 28.0%)     592 (0.4%, 24.2%)  reactive_graph::owner::arena::Arena::with
    48538 (0.7%, 28.7%)     486 (0.3%, 24.5%)  <T as reactive_graph::traits::Update>::try_maybe_update
    43887 (0.6%, 29.3%)     619 (0.4%, 24.9%)  <T as tachys::view::any_view::IntoAny>::into_any
    42946 (0.6%, 29.9%)     243 (0.1%, 25.0%)  reactive_graph::owner::Owner::with_cleanup
    40953 (0.6%, 30.5%)     277 (0.2%, 25.2%)  <tachys::html::element::HtmlElement<E,At,Ch> as tachys::view::RenderHtml>::to_html_with_buf
    40163 (0.6%, 31.0%)     517 (0.3%, 25.5%)  <T as tachys::html::attribute::any_attribute::IntoAnyAttribute>::into_any_attr
    39664 (0.6%, 31.6%)     355 (0.2%, 25.7%)  <futures_util::future::poll_fn::PollFn<F> as core::future::future::Future>::poll
    32298 (0.5%, 32.0%)     480 (0.3%, 26.0%)  <T as tachys::html::attribute::any_attribute::IntoAnyAttribute>::into_any_attr::{{closure}}
    30591 (0.4%, 32.5%)      87 (0.1%, 26.1%)  reactive_graph::effect::render_effect::RenderEffect<T>::new_with_value::erased::{{closure}}
    30048 (0.4%, 32.9%)     793 (0.5%, 26.5%)  reactive_graph::graph::subscriber::untrack_with_diagnostics
    29254 (0.4%, 33.3%)     328 (0.2%, 26.7%)  tachys::view::tuples::<impl tachys::view::RenderHtml for (A,B)>::to_html_async_with_buf
    28263 (0.4%, 33.7%)    5137 (3.0%, 29.8%)  <alloc::boxed::Box<dyn core::ops::function::FnOnce<()>+Output = tachys::view::any_view::AnyView+core::marker::Send> as leptos::children::ToChildren<F>>::to_children::{{closure}}
    26464 (0.4%, 34.1%)     446 (0.3%, 30.0%)  <reactive_graph::graph::subscriber::AnySubscriber as reactive_graph::graph::subscriber::WithObserver>::with_observer
    26297 (0.4%, 34.4%)     316 (0.2%, 30.2%)  reactive_graph::owner::arena::Arena::with_mut
    25983 (0.4%, 34.8%)     290 (0.2%, 30.4%)  <futures_util::future::join::Join<Fut1,Fut2> as core::future::future::Future>::poll
    25591 (0.4%, 35.1%)     422 (0.3%, 30.7%)  std::thread::local::LocalKey<T>::try_with
    24230 (0.3%, 35.5%)     450 (0.3%, 30.9%)  <alloc::sync::Weak<T,A> as core::ops::drop::Drop>::drop
    24209 (0.3%, 35.8%)     161 (0.1%, 31.0%)  reactive_graph::traits::Get::get
    22697 (0.3%, 36.1%)      75 (0.0%, 31.1%)  reactive_graph::effect::render_effect::RenderEffect<T>::new_with_value::erased
    22681 (0.3%, 36.4%)     103 (0.1%, 31.1%)  tachys::view::tuples::<impl tachys::view::RenderHtml for (A,B)>::resolve::{{closure}}
    22128 (0.3%, 36.8%)     234 (0.1%, 31.3%)  <tachys::html::element::HtmlElement<E,At,Ch> as tachys::view::Render>::build
    22091 (0.3%, 37.1%)     401 (0.2%, 31.5%)  reactive_graph::owner::arena_item::ArenaItem<T,S>::new_with_storage
    21840 (0.3%, 37.4%)     263 (0.2%, 31.7%)  reactive_graph::signal::guards::Plain<T>::try_new
    20626 (0.3%, 37.7%)      87 (0.1%, 31.7%)  thaw_utils::class_list::ClassList::add
    19949 (0.3%, 37.9%)     114 (0.1%, 31.8%)  <tachys::html::element::HtmlElement<E,At,Ch> as tachys::view::RenderHtml>::resolve::{{closure}}
    19810 (0.3%, 38.2%)     402 (0.2%, 32.0%)  tachys::view::tuples::<impl tachys::view::RenderHtml for (A,)>::to_html_async_with_buf
    19356 (0.3%, 38.5%)     128 (0.1%, 32.1%)  tachys::view::tuples::<impl tachys::view::add_attr::AddAnyAttr for (A,B)>::add_any_attr
    18783 (0.3%, 38.7%)      65 (0.0%, 32.1%)  <leptos_router::matching::nested::NestedRoute<Segments,Children,Data,View> as leptos_router::matching::MatchNestedRoutes>::generate_routes
    18746 (0.3%, 39.0%)     405 (0.2%, 32.4%)  alloc::raw_vec::RawVec<T,A>::grow_one
    18392 (0.3%, 39.3%)     161 (0.1%, 32.5%)  <T as reactive_graph::traits::Track>::track
    18360 (0.3%, 39.5%)     459 (0.3%, 32.7%)  <dyn core::any::Any>::is
    18182 (0.3%, 39.8%)      65 (0.0%, 32.8%)  <leptos_router::matching::nested::NestedRoute<Segments,Children,Data,View> as leptos_router::matching::MatchNestedRoutes>::match_nested::{{closure}}
    17668 (0.2%, 40.0%)     781 (0.5%, 33.2%)  <tachys::html::element::HtmlElement<E,At,Ch> as tachys::view::add_attr::AddAnyAttr>::add_any_attr
    17453 (0.2%, 40.3%)     104 (0.1%, 33.3%)  reactive_graph::owner::Owner::on_cleanup
    16532 (0.2%, 40.5%)     202 (0.1%, 33.4%)  tachys::view::tuples::<impl tachys::view::Render for (A,)>::build
    16417 (0.2%, 40.7%)     127 (0.1%, 33.5%)  tachys::reactive_graph::<impl tachys::view::Render for F>::build::{{closure}}

@benwis
Copy link
Contributor

benwis commented Jan 26, 2025

Woah, that's some very nice work and something I've wanted for 0.7 for ages!

@benwis benwis merged commit 72f960a into leptos-rs:main Jan 26, 2025
72 of 74 checks passed
benwis pushed a commit that referenced this pull request Jan 26, 2025
* AddAnyAttr working with erase_components

* CI fixes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants