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

[TwigComponents] [Question] Performance hit when passing content to nested component #2081

Open
Pechynho opened this issue Aug 18, 2024 · 14 comments
Labels
question Further information is requested Status: Waiting Feedback Needs feedback from the author TwigComponent

Comments

@Pechynho
Copy link

Hi,

I've noticed a significant performance hit when nesting components.

Here's a screenshot from the Profiler:

image

I understand that some level of performance trade-off is expected with this kind of abstraction in Twig, but almost one second for 70 elements seems excessively slow to me.

In Button.html.twig, I'm doing something like this:

<button class="{{ attributes.render('class') }}" {{ attributes }}>
    <twig:ButtonContent>
        {{ block(outerBlocks.content }}
    </twig:ButtonContent>
</button>

When I remove the {{ block(outerBlocks.content) }} call, the rendering is 10 times faster. Am I doing something wrong?

@carsonbot carsonbot added the question Further information is requested label Aug 18, 2024
@Pechynho
Copy link
Author

I've tried to rewrite the Button.html.twig component to avoid calling nested components, but it didn't help much. The main issue seems to be accessing and rendering blocks.

I rewrote it to store the content of the block in a variable and then use it based on different scenarios. However, the biggest problem is that block('content') is slow.

Button.html.twig

...other code
{% set content = block('content') %}
...outher code

@Kocal
Copy link
Collaborator

Kocal commented Aug 18, 2024

It's an issue I'm facing too with components being rendered inside other components.
Like you I've seen those timings in the Symfony profiler, but I don't know if it happens in non-debug mode/production as well.

Blackfire could really help us here!

Also, by any chance, do you have a reproduction repository? 🙏

@Kocal Kocal added Status: Waiting Feedback Needs feedback from the author TwigComponent labels Aug 18, 2024
@Pechynho
Copy link
Author

Pechynho commented Aug 18, 2024

It's an issue I'm facing too with components being rendered inside other components. Like you I've seen those timings in the Symfony profiler, but I don't know if it happens in non-debug mode/production as well.

Blackfire could really help us here!

Also, by any chance, do you have a reproduction repository? 🙏

I don't have a reproduction repository, but it seems the issue is related to nesting and block accessing. The more you nest, the slower the application becomes. The test below doesn't even complete on my PC, and it runs out of memory.

index.html.twig

{% for i in 0..1000 %}
    <twig:Level1>
        {{ i }}
    </twig:Level1>
{% endfor %}

Level1.html.twig

<twig:Level2>
    {{ block(outerBlocks.content) }}
</twig:Level2>

Level2.html.twig

<twig:Level3>
    {{ block(outerBlocks.content) }}
</twig:Level3>

Level3.html.twig

<twig:Level4>
    {{ block(outerBlocks.content) }}
</twig:Level4>

Level4.html.twig

<button type="button">
    {% block content %}{% endblock %}
</button>

@smnandre
Copy link
Collaborator

I believe the code example you gave here is not exactly like the IRL scenario you had performance problems with.

You render in this example "index.html.twig", right ?

{# index.html.twig #} 

{% for i in 0..1000 %}
    <twig:Level1>
        {{ i }}
    </twig:Level1>
{% endfor %}

In the loop you then call the component Level1 in the Level1.html.twig

But in the Level1.html.twig, you call .... Level1

{# Level1.html.twig #} 

<twig:Level1>
    {{ block(outerBlocks.content) }}
</twig:Level1>

So you have an infinite recursion here. You cannot call "yourself" in a template :)


Also, you do not seem to have a "content" block in your index.html.twig

But outerBlocks.content (called in Leve1.html.twig) mean exactly this: return the content of the block "content" in the parent content (so here: index.html.twig)


Some questions / leads to narrow down the problem

  • do you use up-to-date twig / twig-bridge / twig-component pacakges ?
  • are form involved in your irl case ?

Could you test (on your real example)

  • use Twig 3.8 (inferior to 3.9 anyway) (goal: see if this is related to yield)
  • try with embeds instead of components (goal: ensure this comes from twig component)

We know some specific usage may have an impact on performances, and i'd be very happy to investigate more and try to implement things, so if you can create a very minimal reproducer (or fix the example you gave) i promise we'll work on this!

@smnandre
Copy link
Collaborator

I've tried to rewrite the Button.html.twig component to avoid calling nested components, but it didn't help much. The main issue seems to be accessing and rendering blocks.

I rewrote it to store the content of the block in a variable and then use it based on different scenarios. However, the biggest problem is that block('content') is slow.

@Pechynho Could you show us what it looked like (the minimal example possible, but with the same needs you have) ?

That could help understand the difference / implications, compared to the component + outerBlocks method.

--

Also, could you try if disabling the TwigComponent profiler help ?

# config/packages/twig_component.yaml
twig_component:

    # ...
    
    profiler: false

@Pechynho
Copy link
Author

@smnandre

Yes, my problem occurs in a real-world application, and Symfony forms are used on the page that is particularly slow. I am using the latest version of the Twig Components package.

I can try to use Embeds construct instead of Twig Components, but that will take a lot of time to rewrite my application.

I've collected profiling information with the Xdebug profiler. If that's not sufficient, I will try to reproduce the issue in a separate repository.

https://fileport.io/n9AAhN6Nyz3B

@smnandre
Copy link
Collaborator

Yes, my problem occurs in a real-world application, and Symfony forms are used on the page that is particularly slow. I am using the latest version of the Twig Components package.

I then will be even more curious to know if downgrading Twig to 3.8 has any impact

I can try to use Embeds construct instead of Twig Components, but that will take a lot of time to rewrite my application.

I was not asking for the entire application, but the small test you made :)

I've collected profiling information with the Xdebug profiler. If that's not sufficient, I will try to reproduce the issue in a separate repository.

It can be interesting. But without a reproducer (or a simple description of how to reproduce -- as posted before, the one you posted is missing something to work), we cannot see if what we code / test would solve or improve things.

Did you have time to check if disabling the TwigComponent profiler has some effect ?

@Pechynho
Copy link
Author

@smnandre

I then will be even more curious to know if downgrading Twig to 3.8 has any impact

This has a huge impact on my scenario. I've gone from a 10-second page load to a 2-second page load with Xdebug and the Symfony development environment enabled. If I switch to the Symfony production environment and disable Xdebug, the load time is under one second.

However, I believe there's still something more...

To explain my scenario: I am building a form that consists of blocks of content. Users can add or remove these blocks. I'm using Twig Components with Live Components to achieve this. Every new block adds significant time to the response. I'm not sure if this can be explained simply by the fact that there's more HTML and more context for Symfony forms to handle, or if something else is at play.

image

image

It can be interesting. But without a reproducer (or a simple description of how to reproduce -- as posted before, the one you posted is missing something to work), we cannot see if what we code / test would solve or improve things.

I understand that. The problem I observed manifests itself in more complex form elements that contain dozens of Twig and Live components. Because of this, extracting the problematic code and replicating the behaviour in a reproduction repository is quite challenging.

I could give you access to the repository where I’m currently observing the problem, but the codebase is quite extensive, which might make it difficult to navigate. I hope to find some time to reproduce the issue in a simpler way so that I can share it with others in reproduction repository.

@Pechynho
Copy link
Author

Did you have time to check if disabling the TwigComponent profiler has some effect ?

This results in a 200-300 ms difference in the development scenario (Symfony dev mode with Xdebug enabled).

@smnandre
Copy link
Collaborator

There are been some issues with performances with Twig 3.9+ as it offers a great new feature to handle "yield" instead of "echo" (very simplified explanation), that cannot be imposed to existing code.

It seems a great solution has been implemented just two days ago, could you try it and see if that fixes all your problems here, or if we do need to fix something on the twig component side too (it's possible)

twigphp/Twig#4216

To test it you probably need to use 3.x-dev instead of the current version of Twig you're using.

@smnandre
Copy link
Collaborator

This results in a 200-300 ms difference in the development scenario (Symfony dev mode with Xdebug enabled).

This does not surprise me, but could deserve some warning/documentation.. or probably to re-implement the profiler another way.

@kbond
Copy link
Member

kbond commented Sep 15, 2024

@smnandre, #2167 helps?

@smnandre
Copy link
Collaborator

It's a start.. other things incoming soon

@Pechynho
Copy link
Author

Sorry I haven't posted in a while. I'm travelling at the moment and unfortunately I don't have time to work. I have reproducer half-finished. I'll post it here the first week of October.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested Status: Waiting Feedback Needs feedback from the author TwigComponent
Projects
None yet
Development

No branches or pull requests

5 participants