{
"$type": "site.standard.document",
"content": "---\ntitle: \"In-place XML tree mutation for Jekyll productivity\"\ndescription: \"Profiling a slow Jekyll build, finding the culprit in Nokogiri node copying,\n and getting a 20x speedup by switching to in-place tree mutation.\"\ntags:\n - dev\n---\n\nI wrote a [reveal.js](/blog/2018/09/28/another-revealjs-plugin-for-jekyll/)\nplugin for Jekyll so that I can make nice slides (especially for my\n[ANU](https://cs.anu.edu.au/courses/comp1720/lectures/)\n[courses](https://cs.anu.edu.au/courses/comp2300/lectures/)). Recently, though,\nI've been touching up the COMP1720 slides for 2019 and it's getting _really\nslow_ to build the website.\n\nI turned to Jekyll's built-in profiling command to see where the problem is.\nHere's the output of `jekyll build --profile` on this website, which (currently)\nbuilds in **7.2 seconds** on my machine.\n\n| Filename | Count | Bytes | Time |\n| ---------------------------------------- | ----- | ------- | ----- |\n| \\_layouts/reveal.html | 9 | 104.60K | 4.102 |\n| \\_layouts/default.html | 81 | 729.15K | 0.809 |\n| \\_includes/head.html | 90 | 266.90K | 0.702 |\n| research.md | 1 | 16.40K | 0.196 |\n| \\_includes/hljs.html | 90 | 29.44K | 0.192 |\n| \\_includes/slides/background-image.html | 9 | 31.94K | 0.154 |\n| \\_layouts/paginated.html | 21 | 70.29K | 0.078 |\n| \\_talks/u3a-world-since-google.md | 1 | 14.49K | 0.058 |\n| \\_includes/header.html | 81 | 85.88K | 0.042 |\n| \\_talks/ltc-stem-camp.md | 1 | 13.38K | 0.040 |\n| feed.xml | 1 | 105.55K | 0.038 |\n| ...more inconsequential stuff follows... | | | |\n\nClearly, the `reveal.html` layout is the problem, taking 4.1s (more than half\nthe total build time). I suspect that this is because my\n[reveal plugin](/blog/2018/09/28/another-revealjs-plugin-for-jekyll/) does a\nbunch of copying of (Nokogiri) XML nodes, because I wasn't worrying about\nperformance when I wrote it.\n\n### Re-parent all the nodes!\n\nLooking at the [Nokogiri API](https://nokogiri.org/rdoc/Nokogiri/XML/Node) and\nthe `revealify.rb` plugin code, there are a bunch of places where instead of\nduplicating & copying nodes, I can just re-parent them into the right places.\nI'm a big immutability fan usually, which is why I built the plugin based on\ncopying originally, but with a bit of careful re-parenting the `revealify.rb`\nplugin now looks like\n[this](https://github.com/benswift/benswift.github.io/blob/source/_plugins/revealify.rb)\n(see the\n[linked post above](/blog/2018/09/28/another-revealjs-plugin-for-jekyll/) to see\nwhat it looked like before).\n\nAnd the result? Total build time is down to **2.8 seconds**. Admittedly that was\nbecause it was _really inefficient_ before, but I'll take a 2.5x speedup anyday\nš. Here's the relevant profiler output with the updated plugin:\n\n| Filename | Count | Bytes | Time |\n| ---------------------------------------- | ----- | ------- | ----- |\n| \\_layouts/default.html | 82 | 741.77K | 0.873 |\n| \\_includes/head.html | 91 | 269.82K | 0.780 |\n| research.md | 1 | 16.40K | 0.198 |\n| \\_layouts/reveal.html | 9 | 105.65K | 0.182 |\n| \\_includes/hljs.html | 91 | 29.77K | 0.172 |\n| \\_includes/slides/background-image.html | 9 | 31.94K | 0.151 |\n| \\_layouts/paginated.html | 21 | 70.55K | 0.101 |\n| \\_talks/u3a-world-since-google.md | 1 | 14.50K | 0.058 |\n| \\_includes/header.html | 82 | 86.94K | 0.045 |\n| \\_talks/ltc-stem-camp.md | 1 | 13.39K | 0.041 |\n| feed.xml | 1 | 112.62K | 0.029 |\n| ...more inconsequential stuff follows... | | | |\n\nWow, the `reveal.html` layout has gone from 4.1s to 0.2s, a **20x speedup**!\n\nSo I guess the moral of the story is that profiling is important, and that\navoiding copies and writing filthy mutable code is helpful as long as you're\ncareful.\n\nNow that I've done procrastinating with this stuff, I can get back to writing my\nslides for the upcoming semester.\n",
"createdAt": "2026-05-13T23:14:59.462Z",
"description": "Profiling a slow Jekyll build, finding the culprit in Nokogiri node copying, and getting a 20x speedup by switching to in-place tree mutation.",
"path": "/blog/2019/07/17/in-place-xml-tree-mutation-for-jekyll-productivity",
"publishedAt": "2019-07-17T00:00:00.000Z",
"site": "at://did:plc:tevykrhi4kibtsipzci76d76/site.standard.publication/self",
"tags": [
"dev"
],
"textContent": "Profiling a slow Jekyll build, finding the culprit in Nokogiri node copying, and getting a 20x speedup by switching to in-place tree mutation.",
"title": "In-place XML tree mutation for Jekyll productivity"
}