Add link to the proposed wrapper generation patch
[ikiwiki] / doc / bugs / editing_gitbranch_template_is_really_slow.mdwn
1 On this wiki, editing `templates/gitbranch.mdwn` causes a really slow
2 refresh, orders of magnitude slower than a full rebuild: a large number of
3 pages depend on that template, or link to a page that embeds that template,
4 and so on.
5
6 I suspect that, as with my optimization pass for `album`'s benefit, the
7 costly thing is evaluating lots of pagespecs. I'm profiling it to see
8 whether the problem is there are any low-hanging fruit.
9
10 Easy to reproduce offline:
11
12 * comment out the `exclude` option in `docwiki.setup`
13 * `/usr/bin/perl -Iblib/lib ikiwiki.in -setup docwiki.setup -rebuild`
14 * `touch templates/gitbranch.mdwn`
15 * `/usr/bin/perl -Iblib/lib ikiwiki.in -setup docwiki.setup -refresh`
16
17 NYTProf says:
18
19     # spent 279s (237+41.8) within IkiWiki::bestlink which was called 13988949 times, avg 20µs/call:
20     # 13150827 times (222s+37.2s) by IkiWiki::PageSpec::match_link at line 2692, avg 20µs/call
21     # 829606 times (14.9s+4.51s) by IkiWiki::PageSpec::match_link at line 2687, avg 23µs/call
22     ...
23     sub bestlink ($$) {
24
25 which is about half the execution time (458s on my laptop).
26
27 Adding code to log each call to match_backlink indicates that a large part
28 of the problem is that it evaluates the pagespec
29 `backlink(plugins/goodstuff)` up to a million times, with various pages and locations.
30
31 --[[smcv]]
32
33 > [[!template id=gitbranch branch=smcv/ready/perf
34 author="[[Simon McVittie|smcv]]"
35 browse=http://git.pseudorandom.co.uk/smcv/ikiwiki.git/shortlog/refs/heads/ready/perf]]
36 > [[!tag patch users/smcv/ready]]
37 >
38 > Previously, if a page like `plugins/trail` contained a conditional like
39 >
40 >     \[[!if test="backlink(plugins/goodstuff)" all=no]]
41 >
42 > (which it gets via `templates/gitbranch`), then the
43 > [[plugins/conditional]] plugin would give `plugins/trail` a dependency on
44 > `(backlink(plugins/goodstuff)) and plugins/trail`. This dependency is
45 > useless: that pagespec can never match any page other than
46 > `plugins/trail`, but if `plugins/trail` has been modified or deleted,
47 > then it's going to be rendered or deleted *anyway*, so there's no point
48 > in spending time evaluating match_backlink for it.
49 >
50 > Conversely, the influences from the result were not taken into account,
51 > so `plugins/trail` did not have the
52 > `{ "plugins/goodstuff" => $DEPEND_LINKS }` dependency that it should.
53 >
54 > We should invert that, depending on the influences but not on the test.
55 >
56 > This is at least an order of magnitude faster: when I edit the docwiki
57 > as described above, a refresh takes 37s with nytprof overhead, compared
58 > with 458s with nytprof overhead before this change. Without nytprof,
59 > that refresh takes 14s, which is faster than the 24s rebuild again.
60 > I didn't record how long the refresh took without nytprof before this
61 > change, but it was something like 200s.
62 >
63 > `bestlink` is still the single most expensive function in this refresh
64 > at ~ 9.5s, with `match_glob` at ~ 5.2s as the runner-up.
65 > --[[smcv]]
66
67 >> [[merged|done]] --[[smcv]]