Metrics: How are nested templates counted?

Hugo can track metrics for each template’s durations (cumulative, average, max) and count. Pretend template A calls (only) template B. How are their contributions to build time counted?

  1. A’s duration includes B’s duration. If you added A’s and B’s durations, you would be double counting.
  2. A’s duration excludes B’s duration. If you added A’s and B’s durations, you would get the true time to render A.
  3. Or something else?

It’s 1).

If you look at the output of profilers out there (e.g. pprof), they often report both 1 and 2, but to identify the hot spots, I always start looking at the 1s.

This isn’t technically possible (or practical) to do with Go templates (I think). If you include template B in A, it gets parsed and executed as one (excluding the partials, which is a runtime evaluation; and these we also report on their own).

I suppose I should be more clear with my terminology, then, as I think I’ve set up the conversation for more confusion. I was using the word “template” as a catchall.

Layout /layouts/A.html calls partial /layouts/partials/B.html, and A is the only caller of B other than B. In this case, B is recursive—hence the exceptional interest in knowing its duration.

     cumulative       average       maximum         
       duration      duration      duration  count  template
     ----------      --------      --------  -----  --------
  39.287540211s   62.262345ms   475.83875ms    631  partials/b.html
  14.620130211s    94.93591ms  476.215583ms    154  a.html
  13.534242993s   33.751229ms   87.357167ms    401  partials/c.html
   2.435468598s     313.404µs   30.277833ms   7771  partials/d.html
   1.699269206s   11.106334ms   21.254958ms    153  partials/e.html

(To be precise, A also calls E. B also calls, C and D. B, C, and D are only ever called as cached partials.)

I’m at risk of misinterpreting your answer, so please correct me. You seem to be saying that partials get treated differently than other layouts for metrics. So since B is a partial, it’s duration is excluded from A’s duration. Thus to get the true duration of A, I would need to sum its duration with those of every partial it calls.

What I’m saying is there are 2 ways to include template B in A:

  • Using the partial func.
  • Using the template keyword in Go.

When you do:

  • A => partial B, then both A and B’s execution will show up as entries in the report. The timing of A will include the timing of B.
  • A => template B, then B will be compiled into A and they will show up as 1 line in the metric report.