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