getzola / zola

A fast static site generator in a single binary with everything built-in. https://www.getzola.org
https://www.getzola.org
MIT License
12.99k stars 918 forks source link

Slow build #2508

Open faassen opened 1 month ago

faassen commented 1 month ago

As discussed here, I have a build that is rather slow and @Keats said somethign is likely wrong:

https://zola.discourse.group/t/incremental-rebuilds/2144/3

The repository is here:

https://github.com/faassen/secretweblog_zola

I'm building it with zola 0.18 compiled from source (from the tag) on Fedora Linux 39.

It takes about 7 to 8 seconds to build, for 233 pages. It uses the tabi theme.

Flamegraph

I've tried building with a flamegraph. It took me a while before I figured out that I should remove strip = true from Cargo.toml and not add debug = true (as constructing the flamegraph takes a very long time; I didn't wait for it to complete).

Here is the flamegraph:

flamegraph

Hopefully it's helpful in debugging this.

Keats commented 1 month ago

From a very quick look, 90+% of the time is spent in atom.xml and page.html. The template (mainly page.html) must be doing a lot of allocations in some ways.

faassen commented 1 month ago

I'm experimenting with a few things. Just recording a log here to see what could make a difference.

My first suspect is Tabi's translation system, which involves a function call to a macro_translate function. I replaced that function with the simplest possible version:

{% macro translate(key, number=-1, language_strings="", default="", replace=true) %}
    {{- default | safe -}}
{% endmacro %}

but this doesn't have a significant impact on build time.

faassen commented 1 month ago

Okay, it seems to be in Tabi's evaluate_setting_priority. I'll bring it up with the Tabi devs.

faassen commented 1 month ago

I'm trying to understand why evaluate_setting_priority is slow:

{% macro evaluate_setting_priority(setting, page, section="", default_global_value="") %}

{%- if section -%}
    {%- set current_section = section -%}
{%- elif page -%}
    {#- Retrieve last ancestor to determine current section, if applicable -#}
    {%- set last_ancestor = page.ancestors | slice(start=-1) %}
    {%- set current_section = get_section(path=last_ancestor.0) %}
{%- endif -%}

{%- set priority_order = [
    page.extra[setting] | default(value=""),
    current_section.extra[setting] | default(value=""),
    config.extra[setting] | default(value="")
] -%}

{%- set output = default_global_value -%}

{%- for value in priority_order -%}
    {%- if value != "" -%}
        {%- set_global output = value -%}
        {%- break -%}
    {%- endif -%}
{%- endfor -%}

{{- output -}}

{% endmacro %}

The bit that seems to trigger the slowdown is this:

   {%- set current_section = get_section(path=last_ancestor.0) %}

I don't understand why this is slow, but I'm going to try reading get_section next.

faassen commented 1 month ago

I'm ~getting~ suspecting locking contention in get_section somehow, but I'll leave it for now.

Keats commented 1 month ago

Try to change it to:

{%- set current_section = get_section(path=last_ancestor.0, metadata_only=true) %} it should already be much faster

faassen commented 1 month ago

Oh wow, that sped it to up drastically, it renders in less than a second now. Thank you! I'm going to suggest this modification to Tabi.