Closed bgamari closed 9 years ago
Oh god, that's blech.
I noticed this timer since the addition of guide-key but did not see an impact on my MacBook Air. I remember finding it silly too and I watched a bit how I could fix it but did not find something that works.
I have the plan to make a custom guide-key for Spacemacs if guide-key does not allow to handle major-mode specific key bindings. I would also like to be able to put a short description for each binding (huge work but I don't fear this :-)).
@syl20bnr or just fork guide-key and start from there. Or start from scratch but copy-past liberally.
I was more for the second option and code just what we need for Spacemacs.
@syl20bnr is there a reasonably straightforward way to disable guide-key
until this is resolved? The problem may not be visible with a single emacs session but the time that the processor can remain in its low-power states scales non-linearly with the number of wakeup requests due to transition latency. I tend to have many emacs sessions open at once so the effect is quite pronounced.
One approach to reduce the effect of these wake-ups is to ensure the timers fire at the same time that other timers fire (typically on the second). This is the reason why glib
provides its timeout_add_seconds
function, for instance.
Guide-key has been removed in the develop branch, and is replaced by which-key in the upcoming release. Presumably this issue will be fixed and closed then. You may consider moving to develop or excluding guide-key
by adding it to the list dotspacemacs-excluded-packages
.
@TheBB great, thanks!
@bgamari which-key makes a couple of changes to the polling mechanism that should help. For example it disables any timers on the frame losing focus which should fix any issues with multiple sessions all simultaneously running their own timers.
Your suggestion about synchronizing the timers is interesting. I don't think it's possible to run multiple timers at once in which-key anyway but I'll see if maybe it's possible to take advantage of that idea.
I should say that it's also possible to run which-key with essentially no timer (or a timer with a very long delay) and triggering the popup through a key press.
@justbur indeed disabling the timers on loss of focus sounds like it should be a great improvement.
About synchronizing timers: note that it's not multiple timers within which-key
that you try to synchronize; you are trying to ensure that which-key
's timer fires at the same time as other timers on the system. In the optimal case, the CPU would only have to wake up once per second, service the relevant timers, and spend the rest of that second sleeping.
The worst possible case is timer events being randomly distributed throughout the second, preventing the CPU from ever sleeping long enough to reach the states where it can shut off large chunks of itself. Ensuring long periods of inactivity is the name of the game in modern CPU power management.
To accomplish this you would typically just round your desired wakeup time to the nearest second (or, if necessary, some nice fraction thereof, although it would be best not to poll that often).
That sounds even better but certainly having just four timers spread evenly across a second contributes to the problem, no?
Anyway off the top of my head I don't see a way for which-key to have multiple timers running at once.
@justbur well, four timers distributed across a second is certainly worse than four timers all firing at the beginning of that second. However, if the application needs to be notified four evenly-spaced times a second then you can't do much about that. Ultimately there is nothing special about the timescale of "one second"; placing timers evenly on the second is a convention which a few libraries use because it is a reasonable period for idle-task-like-things.
If you need to fire more often than once per second (say /n/ events per second) then ideally you would setup your timer such that at least one of your n events will occur on the second. this way the CPU will only need to do n-1 more wakeups than it would otherwise need to. Of course, for large /n/ this won't make much of a difference, but for /n=4/ you've reduced your wake-up count by 25%.
Obviously the best option here is to avoid repeated polling entirely.
I may be totally wrong but I believed that which-key did not poll anything, instead it triggered a timer when a key is pressed. If this reasoning is correct then no timer should be active when the computer does not process any keyboard input on a focused emacs instance.
@syl20bnr That's not true exactly, and I think trying to hook into a key press like that would be more intensive than what I'm doing with which-key right now. There are two ways to trigger which-key. The first is analogous to but less resource intensive than what guide-key does. The second doesn't require timers.
run-at-time
to check if you are in the middle of a key sequence (you've only pressed C-x
for example), which will then trigger the popup. run-at-time
is unnecessary because there's no reason to be checking IMO when emacs is not idle, so which-key uses run-with-idle-timer
to trigger the check (in both cases the check I'm referring to is very simple and uses C-based functions), so it only kicks in if you are idle for the given amount of time (e.g., you are thinking of which key you wanted to press next). The second significant change in which-key is to turn the timer off at appropriate times, mainly when the frame loses focus, so that the timers are not running in the background when they make no sense to run. There might be some other minor differences, but those are the two main improvements, and should address this issue btw.C-x C-h
will by default popup the which-key buffer for the prefix C-x
and pretend that only C-x
has been pressed (use can change to another trigger key of course). So you can do something like C-x C-h C-h C-x
which will call what you have bound to C-x C-x
. This method doesn't require idle timers, so if you use it exclusively you can set which-key-idle-delay
to a large number to effectively disable the timer (if there's interest in not having the timer run at all, file an issue at which-key and I'll add the option). It's not perfect, but this is the best I could come up with in designing which-key. I'm always happy to hear from someone who has a better method of triggering which-key when the current key sequence is a Prefix Key, which is the basic problem to be solved.
@bgamari Do you have an example of an elisp library that ties a function to run exactly on the second? That is, if I understand you correctly.
@justbur very cool, and to me this is just fine.
A pre-command-hook
to check for the pressed key and trigger a timer appropriatly should not impact the perfomance though, this is a just a cond
form. But then you should ask the user for a list of prefixes to watch which feels like a regression to me, I really like the work out of the box
feeling of which-key.
@justbur BTW, thank you for the explanation, I was really wrong :-)
@syl20bnr I looked into pre-command-hook
, but it won't work. It fires after a key sequence is completed (points to a command instead of a keymap) but before the command is executed. So this is too late because the which-key buffer needs to show before the key sequence is complete to be useful.
oh indeed, thank you for the info.
Labeling this as fixed since we've swapped out this package. Please report issues with which-key separately.
Recently I noticed that each of the dozen-or-so emacs processes running on my laptop were waking up 10 times a second, severely impacting my laptop's battery life.
helm-timers
revealed that the culprit isguide-key/polling-function
. I haven't get investigated whether this is due to spacemacs' configuration or inherent to the package but surely there is a better way to accomplish the goal of this timer than polling at 10 Hz.