1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-08 23:40:24 -08:00

Call igc--on-idle multiple times per idle period

This makes the exact value of igc--idle-delay less import because
igc--on-idle is now called after igc--idle-delay then after
igc--idle-delay * 2, then igc--idle-delay * 4, and so on.

* lisp/emacs-lisp/igc.el (igc--on-idle): Start a second timer until
igc--idle-repetitions is reached.
(igc--idle-delay): Use 1.0 as default.
(igc--idle-repetitions): New.
(igc--current-idle-time): New helper.
(igc--predict-idle-time): Use it.
This commit is contained in:
Helmut Eller 2025-09-18 09:13:25 +02:00
parent 2e76caa312
commit d37f079bad

View file

@ -394,33 +394,64 @@ Used in calls to `format-time-string'.")
(defvar igc--idle-timer nil
"Idle timer to trigger oppurtunistic GC.")
(defvar igc--idle-delay 2.0
(defvar igc--idle-delay 1.0
"Time, in seconds, to wait for `igc--idle-timer'.")
(defvar igc--idle-repetitions 6
"How many times to wait.")
(defvar igc--step-interval 0.01
"Time, in seconds, MPS is allowed to use for one step.")
;;;###autoload
(defun igc-start-idle-timer ()
"Start a timer to do GC work while Emacs is idle."
(cl-assert (< igc--step-interval igc--idle-delay))
(when igc--idle-timer
(cancel-timer igc--idle-timer))
(setq igc--idle-timer
(run-with-idle-timer igc--idle-delay t #'igc--on-idle)))
(run-with-idle-timer igc--idle-delay t
#'igc--on-idle (vector nil) 0)))
(defun igc--current-idle-time ()
(let ((idle-time (current-idle-time)))
(if idle-time (float-time idle-time) 0)))
(defun igc--predict-idle-time ()
(* igc--idle-delay 0.66))
(* (igc--current-idle-time) 0.80))
(defun igc--on-idle ()
;; The igc-idle-timer works a bit like the blink-cursor-timer. It can
;; call 'gc--on-idle' multiple times per idle cycle either until some GC
;; work is done or until `igc--idle-repetitions' is reached. We do this
;; because our idle time prediction primarily depends on the
;; `current-idle-time', i.e. our predicted idle time gets larger the
;; larger `current-idle-time' gets.
;;
;; We try to recover from too optimistic predictions quicky, by calling
;; `igc--arena-step' with a relatively short `igc--step-interval' and
;; use `accept-process-output' to check if some output arrived, before
;; calling 'igc--arena-step' again.
(defun igc--on-idle (state repetition)
(let ((timer2 (aref state 0)))
(when timer2
(cancel-timer timer2)))
(let* ((available-time (igc--predict-idle-time))
(interval igc--step-interval)
(multiplier (floor (/ available-time interval))))
(named-let step ((n multiplier))
(let* ((work-to-do (igc--arena-step interval n)))
(when (and work-to-do
(> n 0)
(not (accept-process-output nil 0)))
(step (1- n)))))))
(cond ((and work-to-do
(> n 0)
(not (accept-process-output nil 0)))
(step (1- n)))
((and (not work-to-do)
(= n multiplier)
(< repetition igc--idle-repetitions))
(aset state 0 (run-with-idle-timer
(+ (igc--current-idle-time)
(* igc--idle-delay (ash 1 repetition)))
nil #'igc--on-idle state (1+ repetition)))))))))
(provide 'igc)