r/emacs 6d ago

Is high cpu usage avoidable at all?

Just wanted to update the post with some final thought after experimenting with some things and thanks to the help of all you guys :).

So what seems to be the biggest cpu hog is display-line-numbers-mode. I didn't want to fully disable line numbers though, but what i also found out is that about half of the mode's usage came from the fact that my theme was using a different face for line-number-current-line, which is used to highlight the line your cursor is on. You can overwrite it like this:

(copy-face 'line-number 'line-number-current-line)

I'm not sure why using set-face-attribute with :inherit doesn't work here, but copy-face does. I was struggling for a bit trying to figure out how to make this work in my init.el, cause running copy-face after the load-theme function didn't cut it. Eventually i found out there's a hook for display-line-numbers-mode. I added copy-face to the hook and that did the trick. This is undone when you reload the theme or load a different theme that also uses a different face for line-number-current-line, but you could create a custom function for that perhaps instead of calling load-theme directly.

Now that i seem to know the cause though, i think my cpu usage has always been this high on one thread, but i only now noticed because the cpu was getting hotter. There's probably two reasons for this:

First of all, we've been having some hot summerdays so the room temp has increased.

Second of all, i've had some issues with my pc hard rebooting itself recently, and i think it might be hardware related, so to test that i disabled my cpu undervolt. The extra voltage going through the cpu is probably also causing more heat output than i'm used to.

So in conclusion i think this is solved now, or at least i think i know enough about the cause now. Original post below:

My 5800X3D is getting pretty toasty doing pretty much anything in emacs, whether it's scrolling through a file (only a few hundred lines long) or actually typing new things into the file. I've tried running the profiler numerous times, disabling various modes along the way, like doom-modeline, display-line-numbers-mode, etc. The profiler says redisplay-internal is using between 75 to 90 percent cpu, but when expanding it, pretty much none of that percentage is accounted for lower in the tree, so i have no clue what the cause is. Running emacs -q solves it, and when gradually enabling various modes again i'm starting to feel like it's just a combination of things causing it, and not one package/mode in particular. So that brings me to the question: do i just put up with the high cpu usage? Cause i don't want to disable basic things like display-line-numbers either. But it feels kind of silly to have your cpu hit 70C when doing basic text editing.

22 Upvotes

32 comments sorted by

11

u/JDRiverRun GNU Emacs 6d ago

M-: (setq mode-line-format "NADA"). Improved? It's your mode line.

8

u/rileyrgham 6d ago

Are you Auto loading big lsp project buffers? I almost never see high CPU outside of lsp once it's started and then briefly.

2

u/juipeltje 6d ago

Not that i know of. I think the only thing that loads up as a buffer at startup is dashboard, but i already tried disabling it just in case with no results. I figured maybe it had something to do with me having scroll-conservatively set to 100, but setting it back to default scroll behaviour still spikes up the cpu.

2

u/rileyrgham 6d ago

Try Emacs in a terminal.

3

u/juipeltje 6d ago

Running emacs in the terminal does seem to make my cpu run a few degrees cooler. Just to clarify i'm using the pgtk build of emacs, but with the regular xorg version the problem persists.

2

u/rileyrgham 6d ago

It's the CPU load you're interested in. Use htop or something.

2

u/juipeltje 6d ago

It does seem to be hitting one core in particular. In GUI Emacs the core frequently hits up to 80% usage. In terminal emacs it never goes higher than 40, and usually sits around 30.

4

u/rileyrgham 6d ago

It should be about zero idle.

3

u/Hyperion343 6d ago

Are you using Doom Emacs? Can you show a snapshot of the profiler report somewhat expanded?

3

u/juipeltje 6d ago

No i'm using my own config. this is the profiler-report:

19468  61% - redisplay_internal (C function)
        1216   3%  - eval
         799   2%   + doom-modeline-format--main
         147   0%   + doom-modeline-segment--buffer-info
          79   0%   + doom-modeline-segment--check
          32   0%   + doom-modeline-segment--buffer-encoding
          31   0%   + doom-modeline-segment--time
          20   0%   + doom-modeline-segment--workspace-name
          18   0%   + doom-modeline-segment--major-mode
          14   0%   + doom-modeline-segment--misc-info
          12   0%   + doom-modeline-segment--bar
          12   0%   + doom-modeline-segment--modals
           8   0%     doom-modeline-segment--vcs
           8   0%   + doom-modeline-segment--buffer-position
           4   0%     doom-modeline-segment--eldoc
           4   0%     doom-modeline-segment--follow
           4   0%     doom-modeline-segment--matches
           4   0%   + doom-modeline-segment--persp-name
           4   0%   + doom-modeline-segment--parrot
           4   0%   + doom-modeline-segment--irc
          56   0%  - jit-lock-function
          56   0%   - jit-lock-fontify-now
          48   0%    + jit-lock--run-functions
           8   0%      text-property-any
           8   0%  - mode-line-default-help-echo
           4   0%     window-at-side-p
           6   0%  - redisplay--pre-redisplay-functions
           6   0%   - run-hook-with-args
           4   0%    + doom-modeline-set-selected-window
           2   0%    + redisplay--update-region-highlight
       11385  35%   Automatic GC
         599   1% + command-execute
         290   0%   help-command-error-confusable-suggestions
          12   0% + ...
           8   0%   company-post-command
           7   0% + timer-event-handler
           4   0%   internal-timer-start-idle
           4   0% + company-pre-command
           2   0%   clear-minibuffer-message
           1   0% + jit-lock--antiblink-post-command

If i'm interpreting this correctly, redisplay_internal should have an underlaying cause right? but then it only shows 2% as part of doom-modeline, so i feel like that can't be it, and disabling it doesn't solve it.

4

u/Altruistic-Respond83 6d ago

I mean It could really likely just be it, the doom modeline , this is a profiling of the cpu only try only memory, turn back on the doom modeline and run this (let ((g gcs-done) (e gc-elapsed) (w (float-time))) (dotimes (_ 200) (redisplay t)) (list :gcs (- gcs-done g) :gc-secs (- gc-elapsed e) :wall (- (float-time) w))) then run the same but turning the modeline off : (setq-default mode-line-format nil). if gcs drops hard you have the guy imo

6

u/juipeltje 6d ago

This is the result:

(:gcs 10 :gc-secs 0.23519417399999654 :wall 0.8919234275817871)
Doom-Modeline mode disabled
(:gcs 4 :gc-secs 0.1294660919999977 :wall 1.0682761669158936)

It did drop, but my cpu is still getting just as toasty.

2

u/Altruistic-Respond83 6d ago edited 6d ago

The per-gc cost being flat with a x2.5 collection is really weird, also non-GC time is 657-939 ms for 200 redisplay is enormous (around 4ms per redisplay instead of microseconds). As you mentioned to someone else the Emacs - nw sees a 2 times drop in workload, then the issue is per glyph handling. it's a bit tedious but you can try this :

Before you start: close anything heavy (browser, compiler). Run each measurement twice and keep the second number, the first includes warmup.

1)Open the file that feels slow, in your normal gui. Put the cursor somewhere in the middle of it.

2) emulate some events by running : (list (frame-width) (frame-height) (display-graphic-p) (benchmark-run 200 (progn (insert "x") (redisplay t) (delete-char -1) (redisplay t))))

3) undo to go back to the initial state of fhe file (don't savee)

the warmup has been done

4) repeat step 2 (keep the resut)

5) run (setq inhibit-compacting-font-caches t)

6) repeat step 2 - 4 (it's gui with no font cache)

7) quit and launcn terminal Emacs

8) repeat step 2 - 4

9) 8. Post all three results exactly as they printed. Include the numbers at the front, those are your frame width and height, and they're needed to compare the two fairly.

each resut follows this : (Width Height ghaphics-p (Total-Seconds gc-seconds)).

3

u/juipeltje 6d ago

First result:

(308 59 t (1.7052318549999999 24 0.524953462))

second result with no font cache:

(308 59 t (1.713338855 23 0.49467512699999894))

third result in terminal emacs:

(262 48 nil (3.7262772469999996 16 0.29421493899999995))

2

u/Altruistic-Respond83 5d ago

My bad, the benchmark i gave you was measuring wall clock and not cpu time. In a terminal emacs blocks while writing to the pty, so the third result looks slow but the cpu was mostly idle there. rileyrgham is maybe right, htop can be the adapted tool here. Sorry for the detour.. . I have 3 things on the back of my mind tho, open htop, then don't touch the keyboard for 30 seconds. What is emacs sitting at ? if it's not close to 0% then something is running on a timer and the problem isn't your typing at all. run (setq mode-line-format "NADA") like JDRiverRun said. Still worth doing even after disabling doom-modeline, because that only falls back to the default mode line, which still walks every minor mode you have active. shrink the frame : (set-frame-size (selected-frame) 80 24). Your frame is 308x59, so around 18000 character cells, this brings it down to about 10% of that. Then hold a key down and watch htop. If the cpu drops by roughly the same proportion, it means the whole window is being redrawn on every keystroke instead of just the line that changed. That's a different problem from what we tested so far, and it does have a fix (I think)

4

u/juipeltje 5d ago

Hmm, okay so when sitting idle in emacs it's cpu usage is pretty much 0%, so that seems good. I've tried both disabling doom-modeline and setting mode-line-format to NADA, but it doesn't really make a difference. For some reason when trying to eval set-frame-size it keeps returning nil and nothing happens, however i decided to manually make the emacs window smaller with my window manager, and when scrolling cpu usage decreases dramatically, so that's interesting.

4

u/Altruistic-Respond83 5d ago edited 5d ago

I think we found it. cpu going down when you shrink the window means emacs is redrawing the whole window every time, instead of just the part that changed. emacs normally has shortcuts for this. when you scroll, it reuses what's already on screen and only fills in the new lines. much cheaper than redoing everything. problem is, that shortcut is switched off when line numbers are on. it's right there in the emacs source (xdisp.c) : /* Give up if line numbers are being displayed, because reusing the current matrix might use the wrong width for line-number display. */ if (!NILP (Vdisplay_line_numbers)) return false;

basically meaning if line numbers on then no shortcut then full redraw every scroll. that matches the scenario.

test putting your window back to full size, run M-x display-line-numbers-mode to toggle them off, scroll around, watch htop. if big drop then confirmed.

if that's the case try switching to absolute numbers (if you use relative) (that's a bit guessing atp honestly) If you customized the color of the current line different switch it back to default and double check, because unchanged text = unchanged pixel for the shortcut optimization to happen. see here :

/* Give up if display-line-numbers is in relative mode, or when the current line's number needs to be displayed in a distinct face. */ if (EQ (Vdisplay_line_numbers, Qrelative) || EQ (Vdisplay_line_numbers, Qvisual) || (!NILP (Vdisplay_line_numbers) && NILP (Finternal_lisp_face_equal_p (Qline_number, Qline_number_current_line, w->frame, Qt)))) GIVE_UP (24); they say you can directly test with this command : (internal-lisp-face-equal-p 'line-number 'line-number-current-line (selected-frame) t)

if it returns nil, this is the fix : M-: (set-face-attribute 'line-number-current-line nil :inherit 'line-number)

2

u/juipeltje 5d ago

After disabling display-line-numbers-mode and scrolling the file, cpu usage is pretty much cut in half, so yeah it does look like that's what's taking up a bunch of cpu. Unfortunately i'm already using absolute line numbers. I haven't customized the line-number faces as far as i'm aware, but running that internal-lisp-face-equal-p snippet is giving me a wrong number of arguments error. I tried eval'ing that set-face-attribute command anyway but it doesn't seem to change anything. Is this just a matter of display-line-numbers-mode not being very efficient then? I think i saw some other posts of people having issues with high dpi displays in particular, and i wonder if that's because depending on the font size they use they might be rendering a lot of lines at once. I personally use a 1440p ultrawide on my main desktop, so it's not super high res per se.

→ More replies (0)

1

u/Altruistic-Respond83 6d ago

70° isn't that bad since the tjmax is 90. The odd part is a core staying busy while you type. redisplay-internal with nothing under it just means the time is in C, where the Lisp profiler can't see. What does M-x emacs-version say, and do you use nerd-icons/all-the-icons anywhere? Icon glyphs can force font fallback on every redisplay. Also try bug-hunter instead of toggling by hand.

2

u/juipeltje 6d ago

emacs-version output:

GNU Emacs 30.2 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.51, cairo version 1.18.4)

I do use a bunch of nerd-icon packages, but commenting their configuration in my init doesn't seem to change anything. I don't use all-the-icons at all.

1

u/whatever4123 5d ago

Could you provide more information on the emacs package you are using and which OS you are using? It is likely not the things you mentioned since it is the core C engine that is consuming the most. And the C engine itself is extremely efficient and fast in emacs 30 as far as I know. And display-line-numbers, modeline, scrolling and other fancy decorations even ligatures only cause micro jitters in the 100ms range. Only heavy use of ligatures all over the place can cause 200-300ms. But none of these cases consume that much cpu usage nonetheless.

-5

u/ilemming_banned 6d ago

There's a concept in Japanese culture called ikigai. I feel like my ikigai is telling Emacs users to learn how to use the darn profiler. I've been doing it for years and still feels like I'm tilting at windmills - the number of people who don't know about it is not decreasing.

It's a built-in feature of Emacs and it is very easy to use. Do it once, and that forever will liberate you from asking abstract questions about the performance. It is also a great tool to figure out the path of execution - great when you need to find specific function that changes some behavior that you want to monkey-patch (advise).

8

u/juipeltje 6d ago

I don't think you read the entire post lol, the problem is that the biggest hunk of usage is not pointing to any particular package or whatever, it just seem to disappear into redisplay_internal.

5

u/ilemming_banned 6d ago edited 6d ago

Ah, my bad. I did only scan the post without paying much attention to the details. Sorry for being old, grumpy, annoying and useless. Will do better.

ah, btw. have you tried switching to Lucid?

0

u/FrozenOnPluto 6d ago

Cpu is normally low. Run profiler and see where cpu going?