Elpher rendering speed
----------------------
At the risk of continuing the inanity which has plagued the last few
posts, I've just made an update to Elpher that I feel deserves a post
on its own.
Several people have mentioned (eg [1]) that Elpher can be a bit.. laggy.
Some of this no-doubt has to do with its line-by-line approach to
inserting text into the buffer when displaying gopher directories and
text/gemini documents, which is not easily avoidable. Some of it is
also likely to do with performing regexps over the text to identify
URLs, which I consider a key feature of Elpher and one which I'm
absolutely willing to sacrifice a bit of performance for.
Over the past few weeks however I've started to _really_ notice it.
This is probably because I've been browsing a bit more gemini, and
there tends to be a bit more of a lag there anyway due to the TLS
handshake. Again, likely unavoidable, but it managed to bring the
situation to my attention again and make me start to wonder what the
_real_ problem here was. The situation seemed _particularly_ bad on
link-heavy pages, such as [2]. Hrm.
So finally I fired up the profiler.
Oh yes, did you know - emacs has a built-in profiler for elisp? I
mean, of course it does. But still.
The profiler reports its results as a hierarchy of function calls with
some estimate of the %age of CPU time spent in each. The top level
results seemed in line with my intuition. Yes, it's the document
rendering function (87%). Yes it's the line rendering function within
that (still 87%). Hrm, interesting, it's the button-insertion function
within that (STILL 87%). (Emacs calls clickable text in buffers
"buttons".)
Hold on, what's this though? Within the button-insertion function a
function is called to generate the mouseover help-text, and _this_ is
using 87% of the CPU time. WTF??
Within that function, it turns out a single library function call to
url-encode-url (in order to provide nice normalized URLs in the
mouseover text) is using almost all of the CPU time in rendering this
particular link-heavy page. How embarrassing!!
Of course the first thing I try is just replacing the mousover text
with an empty string. My test page loads in a snap - basically an
order of magnitude improvement. The profiler wasn't lying!
Side note: fixing bugs and squashing performance bottlenecks like
this is absolutely the best part of programming! This is _so much
fun_! :-)
Even though I would have been happy to dispense with mouseover help
text entirely for such a performance boost, it turned out I didn't
have to. It's a common (and awesome) pattern in the Emacs elisp API
for certain variables/properties to accept either a function or a
string. The help-echo text property used by buttons has this feature.
I'd previously been filling each link button with a pre-generated help
text, but what I now do is to just use a reference to a
help-text-generating function instead. Thus the help text is
generated when it's needed rather than when the page is rendered.
(It's currently generated _every_ time it's needed - there's no
caching - but this isn't an issue as you don't need to rapidly read
mouseover texts over and over again.)
SO! As of 2.7.9, rendering speed is _significantly_ improved. The
improvement is so major that there don't even have to be _that_ many
links on the page to notice it. (For instance, my bookmarks page only
contains about 50 links and there used to be a ~0.25s pause every time
I visited it. To good approximation this is completely gone.)
Yay for profiling! (And boo to url-encode-url! Seriously, wow - so slow!)
--
[1]: https://www.emacswiki.org/emacs/CategoryGopher
[2]: gopher://cosmic.voyage/1/log
Source