Also, in the meantime, here’s a link that gets rid of most of the dynamic elements on the page, and might avoid whatever issue is happening. I’d still like to know more about this though to prevent it.
There was an issue with the website related to service workers earlier. I just recently pushed a change that should fix it.
You may have to use incognito mode to force the browser to not use the old service worker.
In my experience, a lot of defaults / constants are picked more or less arbitrarily initially (speed and other priorities usually being the culprit), and it’s usually harder to argue to change them than to keep the status quo since they are currently working and there are other known priorities. This causes the values that worked reasonably at first tend to languish over time, so I definitely agree that there is a lot of opportunity in revisiting constants.
I haven’t profiled it much in that direction, so below is theoretical and not verified. Anecdotally, I’ve had multiple days of uptime with this change where memory stayed within reasonable boundaries.
It mainly impacts memory usage on the margins, in that the size of an empty block will be larger so it adds a larger constant overhead that doesn’t scale with memory usage. That overhead is pretty negligible though since it’s less than 64KB.
Have you tried smaller block alignments? What jumps out to me - an ignoramus in low level computing - is that 1<<10 sets the 11th bit which seems arbitrary but 1<<15 sets the 16th bit which is obviously a “nicer” number. I wonder if 1<<7 would also be “nice” for the branch predictor.
Yeah, the effect from having to walk more blocks is even more apparent with switching to a 1 << 7 buffer. There might still be some benefit from the number being “nicer”, but it’s hard to verify without finding out why 1 << 15 is the current limit.
Thanks! Yeah, I’ve signed over copyright to the GNU for it, but there’s still some work to be done to get it ready to be committed upstream.
I recently worked on making it so that writing to the subprocess is also handled with a background thread and just recently fixed a deadlock that arose from that. I haven’t observed any issues with the latest build, but my branch has some other changes that are a bit more idiosyncratic.
It was very noticeable to me because I have a lot of minor modes running that send requests and receive responses that are pretty large, so they create lots of temporary objects, and the slowdowns went from being noticeably distracting on my end to never noticing a GC pass. In practice, the real GCs are probably even faster than the benchmark implies because most regular GCs would fit inside a single block, and the experiment used a lot more conses than would fit in a single block.
Edit: I should add that I have gc-cons-threshold set a lot higher than the default as well, so that trades longer pauses for less GC passes. I like having as little friction as possible for typing, so I generally don’t want the GC running while in Evil insert mode.
I’m a heavy emacs user and excited to hear about this, but the page simply will not render for me.
I just archived it, so try this: https://archive.ph/GBoDb
That’s odd, which browser are you using?
Also, in the meantime, here’s a link that gets rid of most of the dynamic elements on the page, and might avoid whatever issue is happening. I’d still like to know more about this though to prevent it.
https://tdodge.consulting/blog/living-the-emacs-garbage-collection-dream-simple.html
There was an issue with the website related to service workers earlier. I just recently pushed a change that should fix it. You may have to use incognito mode to force the browser to not use the old service worker.
Yep, it’s fixed. I’m running Firefox on GNU/Linux, in case that’s still relevant.
Good article. I wonder how many other old constants (across all software) are still tuned for limited hardware?
In my experience, a lot of defaults / constants are picked more or less arbitrarily initially (speed and other priorities usually being the culprit), and it’s usually harder to argue to change them than to keep the status quo since they are currently working and there are other known priorities. This causes the values that worked reasonably at first tend to languish over time, so I definitely agree that there is a lot of opportunity in revisiting constants.
How does this change affect general memory usage?
I haven’t profiled it much in that direction, so below is theoretical and not verified. Anecdotally, I’ve had multiple days of uptime with this change where memory stayed within reasonable boundaries.
It mainly impacts memory usage on the margins, in that the size of an empty block will be larger so it adds a larger constant overhead that doesn’t scale with memory usage. That overhead is pretty negligible though since it’s less than 64KB.
Have you tried smaller block alignments? What jumps out to me - an ignoramus in low level computing - is that 1<<10 sets the 11th bit which seems arbitrary but 1<<15 sets the 16th bit which is obviously a “nicer” number. I wonder if 1<<7 would also be “nice” for the branch predictor.
That’s an interesting idea, I’m setting up a build now and I’ll post below a few times generated by the experiment.
Yeah, the effect from having to walk more blocks is even more apparent with switching to a 1 << 7 buffer. There might still be some benefit from the number being “nicer”, but it’s hard to verify without finding out why 1 << 15 is the current limit.
Are there fewer allocations/items to clean up with the bigger buffer?
It’s the same count from the test / did not run it differently than any of the other tests.
hey, this is rad; scrolling down to your background thread Io buffering for eshell, I’m wondering if your patches are headed upstream?
I’m really impressed, and checking out what else is in your fork, cheers!
Thanks! Yeah, I’ve signed over copyright to the GNU for it, but there’s still some work to be done to get it ready to be committed upstream. I recently worked on making it so that writing to the subprocess is also handled with a background thread and just recently fixed a deadlock that arose from that. I haven’t observed any issues with the latest build, but my branch has some other changes that are a bit more idiosyncratic.
I generally work on: https://github.com/tyler-dodge/emacs/tree/tyler-main-2
I also might push a branch with just the latest background output / input changes, if https://github.com/jimeh/build-emacs-for-macos/issues/77 gains traction.
How noticeable is this in “real life” usage? Are there modes or use-cases that run into GC problems?
I can believe it, I’m just curious what they are. I don’t recall it ever being a problem for me.
It was very noticeable to me because I have a lot of minor modes running that send requests and receive responses that are pretty large, so they create lots of temporary objects, and the slowdowns went from being noticeably distracting on my end to never noticing a GC pass. In practice, the real GCs are probably even faster than the benchmark implies because most regular GCs would fit inside a single block, and the experiment used a lot more conses than would fit in a single block.
Edit: I should add that I have gc-cons-threshold set a lot higher than the default as well, so that trades longer pauses for less GC passes. I like having as little friction as possible for typing, so I generally don’t want the GC running while in Evil insert mode.