unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Stefan Monnier <monnier@iro.umontreal.ca>
To: Ihor Radchenko <yantar92@posteo.net>
Cc: Eli Zaretskii <eliz@gnu.org>,
	 Philip Kaludercic <philipk@posteo.net>,
	emacs-devel@gnu.org
Subject: Re: [ELPA] New package: emacs-gc-stats
Date: Sat, 10 Jun 2023 12:33:43 -0400	[thread overview]
Message-ID: <jwvjzwbxp4p.fsf-monnier+emacs@gnu.org> (raw)
In-Reply-To: <87sfaztyk9.fsf@localhost> (Ihor Radchenko's message of "Sat, 10 Jun 2023 10:13:26 +0000")

>> Let me know if you need help adding the package (I couldn't find a URL
>> for the code, so I have no opinion about it (yet :-))
> Oops... https://git.sr.ht/~yantar92/emacs-gc-stats

Thanks, added.

>> PS: In recent Emacsen, `gc-cons-percentage` is set to 1.0 when running in
>>     batch.  In non-batch I currently use 0.5 together with a timer that
>>     tries to opportunistically run the GC during idle time.
> This is yet another thing we can ask users to test, if we want to.
> My idea is have users set GC settings randomly in their init file,
> selecting from pre-configured set of alternatives we are yet to discuss.

FWIW, see below the code I'm using.  On my main Emacs instance,
`gc--opportunistic-score` tells me:

    ((jit 17 0 0)
     (cmd 22 3 7)
     (earlier-gcs . 76)
     (opportunistic-gcs . 1478)
     (noncmd 194 6 52)
     (commands . 109401))

IOW the majority of GCs happen "opportunistically" (i.e. during
idle time).  The `cmd/noncmd` distinction is supposed to distinguish
those GCs that happen while running timers and process filters, but I'm
not sure my code is careful enough to keep track of those correctly.


        Stefan


;;;; Opportunistic GC

(defvar gc--opportunistic-last-gcs gcs-done)
(defvar gc--opportunistic-state 'noncmd)
(defvar gc--opportunistic-counters nil)

(defun gc--check ()
  (let ((gcs-counted
         (+ (alist-get 'multi-gcs gc--opportunistic-counters 0)
                   (alist-get 'earlier-gcs gc--opportunistic-counters 0)
                   (alist-get 'single-gc-cmds gc--opportunistic-counters 0)
                   (alist-get 'noncmds-gcs gc--opportunistic-counters 0)
                   (alist-get 'opportunistic-gcs gc--opportunistic-counters 0)
                   (or (car (alist-get 'error-gcs gc--opportunistic-counters)) 0))))
    (unless (= gcs-done gcs-counted)
      (push (+ (- gcs-done gcs-counted)
               (or (car (alist-get 'error-gcs gc--opportunistic-counters)) 0))
            (alist-get 'error-gcs gc--opportunistic-counters)))))

(defun gc--opportunistic-record (nextstate)
  (let ((counts (alist-get gc--opportunistic-state gc--opportunistic-counters)))
    (unless counts
      (setf (alist-get gc--opportunistic-state gc--opportunistic-counters)
            (setq counts (list 0 0 0))))
    (pcase (prog1 (- gcs-done gc--opportunistic-last-gcs)
             (setq gc--opportunistic-last-gcs gcs-done))
      ((pred (>= 0)) nil)
      (1 (cl-incf (nth 0 counts)))
      (gcs (cl-incf (nth 1 counts))
           (cl-incf (nth 2 counts) gcs))))
  (setq gc--opportunistic-state nextstate))

(defun gc--opportunistic-postch ()
  (cl-incf (alist-get 'commands gc--opportunistic-counters 0))
  (gc--opportunistic-record 'noncmd))

(defun gc--opportunistic-prech ()
  (cl-callf identity
      (alist-get 'earlier-gcs gc--opportunistic-counters gcs-done))
  (gc--opportunistic-record 'cmd)
  ;; (gc--check)
  )

(defun gc--opportunistic-jitlock (orig-fun start)
  (if (eq gc--opportunistic-state 'cmd)
      ;; Count jit-lock execution which happens during a command as
      ;; being part of command execution rather than as part of jit-lock!
      (funcall orig-fun start)
    (let ((gc--opportunistic-state gc--opportunistic-state))
      (gc--opportunistic-record 'jit)
      (unwind-protect
          (funcall orig-fun start)
        (gc--opportunistic-record 'postjit)))))

(add-hook 'pre-command-hook #'gc--opportunistic-prech)
(add-hook 'post-command-hook #'gc--opportunistic-postch)
(advice-add 'jit-lock-function :around #'gc--opportunistic-jitlock)

(defun gc--opportunistic ()
  "Run the GC during idle time."
  ;; This is good for two reasons:
  ;; - It reduces the number of times we have to GC in the middle of
  ;;   an operation.
  ;; - It means we GC when the C stack is short, reducing the risk of false
  ;;   positives from the conservative stack scanning.
  (unless (> gc-cons-percentage 0.1)
    (setq gc-cons-percentage 0.5))
  (when (garbage-collect-maybe 10)
    (cl-incf (alist-get 'opportunistic-gcs gc--opportunistic-counters 0))
    ;; Don't double count this GC in other categories.
    (cl-incf gc--opportunistic-last-gcs)
    ;; Recalibrate the timer.
    (cancel-function-timers #'gc--opportunistic)
    (run-with-idle-timer
     ;; FIXME: Magic formula!
     (+ 1 (* 10 (/ gc-elapsed gcs-done))) t #'gc--opportunistic)))


(defun gc--opportunistic-score ()
  "Show the current counters's that keep track of GC behavior."
  (interactive)
  (message "%S" gc--opportunistic-counters))




  reply	other threads:[~2023-06-10 16:33 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-14 17:03 [ELPA] New package: emacs-gc-stats Ihor Radchenko
2023-06-09  9:14 ` Ihor Radchenko
2023-06-09 10:17   ` Eli Zaretskii
2023-06-09 16:19     ` Stefan Monnier
2023-06-10 10:13       ` Ihor Radchenko
2023-06-10 16:33         ` Stefan Monnier [this message]
2023-06-11  9:15           ` Ihor Radchenko
2023-06-11  9:12             ` Philip Kaludercic
2023-06-11  9:37               ` Ihor Radchenko
2023-06-11 15:51             ` Stefan Monnier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=jwvjzwbxp4p.fsf-monnier+emacs@gnu.org \
    --to=monnier@iro.umontreal.ca \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    --cc=philipk@posteo.net \
    --cc=yantar92@posteo.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).