Package: emacs;
Reported by: Aaron Zeng <azeng <at> janestreet.com>
Date: Thu, 29 May 2025 20:58:02 UTC
Severity: normal
Found in version 30.1.90
To reply to this bug, email your comments to 78637 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Thu, 29 May 2025 20:58:02 GMT) Full text and rfc822 format available.Aaron Zeng <azeng <at> janestreet.com>
:bug-gnu-emacs <at> gnu.org
.
(Thu, 29 May 2025 20:58:02 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Aaron Zeng <azeng <at> janestreet.com> To: bug-gnu-emacs <at> gnu.org Cc: app-emacs-dev <at> janestreet.com Subject: 30.1.90; Calling setopt during init loads cus-start over and over Date: Thu, 29 May 2025 16:57:22 -0400
Hello, While trying to improve Emacs startup time at my site, I noticed that cus-start was being loaded repeatedly, each time setopt was called. It seems that, when called during site-start or loading the user's init file, setopt (which eventually calls custom-load-symbol) requires cus-start, ignoring errors---and loading cus-start at that moment does indeed error. As a result of this ignored error, cus-start is loaded from scratch each time (require 'cus-start) is evaluated. This adds something like 12ms of startup time to Emacs batch commands at my site, since we have about 25 setopt calls in site-start, and each one takes an extra 500us or so. I performed a quick experiment, with: emacs -Q --batch --init-directory=example-init --user "" where example-init/init.el contains just: (dotimes (_ 25) (setopt make-backup-files nil)) Running the above command under hyperfine shows that the runtime is about 82ms on my machine. Prepending this code to example-init/init.el: (ignore-errors (require 'cus-start)) (push 'cus-start features) drops the runtime of the command to 75ms. (I believe this experiment might underestimate the true impact of repeatedly loading cus-start due to caching effects.) I believe this can be fixed with the following patch. On my machine, this patch reduces the runtime of the original init file to 75ms and causes the prepended code to make no difference to the runtime. diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 91cc6e22152..e82e97e87ca 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -934,7 +934,7 @@ minibuffer-prompt-properties--setter ;; This is used by describe-variable. (if version (put symbol 'custom-version version)) ;; Don't re-add to custom-delayed-init-variables post-startup. - (unless after-init-time + (when (listp custom-delayed-init-variables) ;; Note this is the _only_ initialize property we handle. (if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay) ;; These vars are defined early and should hence be initialized In GNU Emacs 30.1.90 (build 2, x86_64-pc-linux-gnu, X toolkit, cairo version 1.15.12, Xaw scroll bars) of 2025-05-29 built on igm-qws-u12685a Repository revision: 3e57c35323abe0782ba6a70adeecf99c27497e48 Repository branch: HEAD Windowing system distributor 'The X.Org Foundation', version 11.0.12011000 System Description: Rocky Linux 8.10 (Green Obsidian) Configured using: 'configure --config-cache --with-x-toolkit=lucid --without-gpm --without-gconf --without-selinux --without-imagemagick --with-modules --with-gif=no --with-cairo --with-rsvg --without-compress-install --with-tree-sitter --with-native-compilation=aot --prefix=' Configured features: CAIRO DBUS FREETYPE GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG LIBSYSTEMD LIBXML2 MODULES NATIVE_COMP NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER X11 XDBE XIM XINPUT2 XPM LUCID ZLIB Important settings: value of $LANG: en_US.utf8 locale-coding-system: utf-8-unix Major mode: Lisp Interaction Minor modes in effect: tooltip-mode: t global-eldoc-mode: t eldoc-mode: t show-paren-mode: t electric-indent-mode: t mouse-wheel-mode: t tool-bar-mode: t menu-bar-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t minibuffer-regexp-mode: t line-number-mode: t indent-tabs-mode: t transient-mark-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t Load-path shadows: None found. Features: (shadow sort mail-extr emacsbug message mailcap yank-media puny dired dired-loaddefs rfc822 mml mml-sec password-cache epa derived epg rfc6068 epg-config gnus-util text-property-search time-date subr-x mm-decode mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader cl-loaddefs cl-lib sendmail rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils rmc iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win term/common-win x-dnd touch-screen tool-bar dnd fontset image regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic indonesian philippine cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp files window text-properties overlay sha1 md5 base64 format env code-pages mule custom widget keymap hashtable-print-readable backquote threads dbusbind inotify dynamic-setting system-font-setting font-render-setting cairo x-toolkit xinput2 x multi-tty move-toolbar make-network-process native-compile emacs) Memory information: ((conses 16 50339 9279) (symbols 48 5372 0) (strings 32 15703 2215) (string-bytes 1 493685) (vectors 16 9036) (vector-slots 8 126107 9764) (floats 8 24 2) (intervals 56 274 0) (buffers 992 10))
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Fri, 30 May 2025 07:25:02 GMT) Full text and rfc822 format available.Message #8 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Aaron Zeng <azeng <at> janestreet.com> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Fri, 30 May 2025 10:24:08 +0300
> Cc: app-emacs-dev <at> janestreet.com > Date: Thu, 29 May 2025 16:57:22 -0400 > From: Aaron Zeng via "Bug reports for GNU Emacs, > the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org> > > While trying to improve Emacs startup time at my site, I noticed that > cus-start was being loaded repeatedly, each time setopt was called. > It seems that, when called during site-start or loading the user's > init file, setopt (which eventually calls custom-load-symbol) requires > cus-start, ignoring errors---and loading cus-start at that moment does > indeed error. > > As a result of this ignored error, cus-start is loaded from scratch > each time (require 'cus-start) is evaluated. This adds something like > 12ms of startup time to Emacs batch commands at my site, since we have > about 25 setopt calls in site-start, and each one takes an extra 500us > or so. > > I performed a quick experiment, with: > > emacs -Q --batch --init-directory=example-init --user "" > > where example-init/init.el contains just: > > (dotimes (_ 25) > (setopt make-backup-files nil)) > > Running the above command under hyperfine shows that the runtime is > about 82ms on my machine. > > Prepending this code to example-init/init.el: > > (ignore-errors > (require 'cus-start)) > (push 'cus-start features) > > drops the runtime of the command to 75ms. (I believe this experiment > might underestimate the true impact of repeatedly loading cus-start > due to caching effects.) I don't understand: cus-start is preloaded (see lisp/loadup.el), so "(require 'cus-start)" should be (almost) a no-op. Do you have any evidence that cus-start.el is indeed being loaded under this recipe? If so, can you present that evidence? (And no, the fact that startup time goes down doesn't mean that loading cus-start is the reason, it could be something else.) > I believe this can be fixed with the following patch. On my machine, > this patch reduces the runtime of the original init file to 75ms and > causes the prepended code to make no difference to the runtime. > > diff --git a/lisp/cus-start.el b/lisp/cus-start.el > index 91cc6e22152..e82e97e87ca 100644 > --- a/lisp/cus-start.el > +++ b/lisp/cus-start.el > @@ -934,7 +934,7 @@ minibuffer-prompt-properties--setter > ;; This is used by describe-variable. > (if version (put symbol 'custom-version version)) > ;; Don't re-add to custom-delayed-init-variables post-startup. > - (unless after-init-time > + (when (listp custom-delayed-init-variables) > ;; Note this is the _only_ initialize property we handle. > (if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay) > ;; These vars are defined early and should hence be initialized I think this patch changes behavior, so it is not TRT. But before we discuss how to fix the problem, let's be sure we understand the problem and its reason(s).
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Fri, 30 May 2025 15:29:02 GMT) Full text and rfc822 format available.Message #11 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Aaron Zeng <azeng <at> janestreet.com> To: Eli Zaretskii <eliz <at> gnu.org> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Fri, 30 May 2025 11:27:44 -0400
On Fri, May 30, 2025 at 3:24 AM Eli Zaretskii <eliz <at> gnu.org> wrote: > > I don't understand: cus-start is preloaded (see lisp/loadup.el), so > "(require 'cus-start)" should be (almost) a no-op. Do you have any > evidence that cus-start.el is indeed being loaded under this recipe? > If so, can you present that evidence? (And no, the fact that startup > time goes down doesn't mean that loading cus-start is the reason, it > could be something else.) Yes, if you add (setq force-load-messages t) to the init file I provided, you can see that "Loading cus-start..." is messaged repeatedly, once for each time setopt runs. Also, you can see that "Loading cus-start...done" never gets messaged, indicating that something failed while loading cus-start. I also observe that just calling (require 'cus-start) in that file triggers an error. > > diff --git a/lisp/cus-start.el b/lisp/cus-start.el > > index 91cc6e22152..e82e97e87ca 100644 > > --- a/lisp/cus-start.el > > +++ b/lisp/cus-start.el > > @@ -934,7 +934,7 @@ minibuffer-prompt-properties--setter > > ;; This is used by describe-variable. > > (if version (put symbol 'custom-version version)) > > ;; Don't re-add to custom-delayed-init-variables post-startup. > > - (unless after-init-time > > + (when (listp custom-delayed-init-variables) > > ;; Note this is the _only_ initialize property we handle. > > (if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay) > > ;; These vars are defined early and should hence be initialized > > I think this patch changes behavior, so it is not TRT. But before we > discuss how to fix the problem, let's be sure we understand the > problem and its reason(s). Sorry, I skipped a few steps in reasoning here. What I am observing from the backtrace of the load error mentioned above, is that custom-delayed-init-variables is set to t when add-to-list runs (on the line following the context from the above patch). This is, of course, a type error. The docstring of custom-delayed-init-variables claims that it is set to a non-list value when the list has already been processed---so, my reasoning was that if it is already set to a non-list value that means there is no point adding anything to it. I am happy to consider different ways of solving this issue.
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Fri, 30 May 2025 16:12:02 GMT) Full text and rfc822 format available.Message #14 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Aaron Zeng <azeng <at> janestreet.com>, Stefan Monnier <monnier <at> iro.umontreal.ca> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Fri, 30 May 2025 19:11:01 +0300
> From: Aaron Zeng <azeng <at> janestreet.com> > Date: Fri, 30 May 2025 11:27:44 -0400 > Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com > > On Fri, May 30, 2025 at 3:24 AM Eli Zaretskii <eliz <at> gnu.org> wrote: > > > > I don't understand: cus-start is preloaded (see lisp/loadup.el), so > > "(require 'cus-start)" should be (almost) a no-op. Do you have any > > evidence that cus-start.el is indeed being loaded under this recipe? > > If so, can you present that evidence? (And no, the fact that startup > > time goes down doesn't mean that loading cus-start is the reason, it > > could be something else.) > > > Yes, if you add (setq force-load-messages t) to the init file I provided, > you can see that "Loading cus-start..." is messaged repeatedly, once > for each time setopt runs. Also, you can see that "Loading cus-start...done" > never gets messaged, indicating that something failed while loading > cus-start. I also observe that just calling (require 'cus-start) in that file > triggers an error. This is because: . custom.el and cus-edit.el say (require 'cus-start), something they don't need to do . for some reason, 'require' doesn't avoid loading cus-start even if it is already loaded; the simple patch below reduces the number of loads of cus-start to just 1 in this scenario Stefan, why does this happen? It sounds like when 'require' is called from bytecode, it always loads the file? Or is this something special for cus-start? Or something else? Further, that single load of cus-start that is left is also strange: it comes from cus-load, and stepping with a debugger into Frequire, I see that cus-start is not in the Vfeatures list? Why? > > I think this patch changes behavior, so it is not TRT. But before we > > discuss how to fix the problem, let's be sure we understand the > > problem and its reason(s). > > Sorry, I skipped a few steps in reasoning here. What I am observing from the > backtrace of the load error mentioned above, is that > custom-delayed-init-variables > is set to t when add-to-list runs (on the line following the context > from the above patch). This is, of course, a type error. > > The docstring of custom-delayed-init-variables claims that it is set > to a non-list > value when the list has already been processed---so, my reasoning was that > if it is already set to a non-list value that means there is no point > adding anything > to it. > > I am happy to consider different ways of solving this issue. The way to solve this is to understand why 'require' insists on loading cus-start although it's preloaded. I hope Stefan will help us understand why this happens. Here's the patch which reduces the number of loads to 1 (and which I hoped will reduce it to zero): diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 2ecae54..510c0b9 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -149,7 +149,8 @@ recentf-exclude (error nil)) (condition-case nil - (require 'cus-start) + (unless (featurep 'cus-start) + (require 'cus-start)) (error nil)) (put 'custom-define-hook 'custom-type 'hook) diff --git a/lisp/custom.el b/lisp/custom.el index a0dc194..e5ceda8 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -699,7 +699,8 @@ custom-load-symbol (ignore-errors (require 'cus-load)) (ignore-errors - (require 'cus-start)) + (unless (featurep 'cus-start) + (require 'cus-start))) (dolist (load (get symbol 'custom-loads)) (cond ((symbolp load) (ignore-errors (require load))) ;; This is subsumed by the test below, but it's much faster.
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Fri, 30 May 2025 17:10:02 GMT) Full text and rfc822 format available.Message #17 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Aaron Zeng <azeng <at> janestreet.com> To: Eli Zaretskii <eliz <at> gnu.org> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com, Stefan Monnier <monnier <at> iro.umontreal.ca> Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Fri, 30 May 2025 13:09:12 -0400
On Fri, May 30, 2025 at 12:11 PM Eli Zaretskii <eliz <at> gnu.org> wrote: > . for some reason, 'require' doesn't avoid loading cus-start even if > it is already loaded; the simple patch below reduces the number of > loads of cus-start to just 1 in this scenario Maybe I am misunderstanding, but I think this is deliberate. cus-start.el does not provide the 'cus-start' feature when Emacs is dumping. > Further, that single load of cus-start that is left is also strange: > it comes from cus-load, and stepping with a debugger into Frequire, I > see that cus-start is not in the Vfeatures list? Why? If I understand correctly, this is because loading cus-start signals an error, and therefore the (provide 'cus-start) line is never executed and the feature never gets added to the list. > Here's the patch which reduces the number of loads to 1 (and which I > hoped will reduce it to zero): I don't think this patch worked on my machine. I still see that cus-start is loaded once each time setopt runs, when setting force-load-messages to t.
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Sat, 31 May 2025 06:22:01 GMT) Full text and rfc822 format available.Message #20 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Aaron Zeng <azeng <at> janestreet.com> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com, monnier <at> iro.umontreal.ca Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Sat, 31 May 2025 09:21:16 +0300
> From: Aaron Zeng <azeng <at> janestreet.com> > Date: Fri, 30 May 2025 13:09:12 -0400 > Cc: Stefan Monnier <monnier <at> iro.umontreal.ca>, 78637 <at> debbugs.gnu.org, > app-emacs-dev <at> janestreet.com > > On Fri, May 30, 2025 at 12:11 PM Eli Zaretskii <eliz <at> gnu.org> wrote: > > . for some reason, 'require' doesn't avoid loading cus-start even if > > it is already loaded; the simple patch below reduces the number of > > loads of cus-start to just 1 in this scenario > > Maybe I am misunderstanding, but I think this is deliberate. cus-start.el > does not provide the 'cus-start' feature when Emacs is dumping. > > > Further, that single load of cus-start that is left is also strange: > > it comes from cus-load, and stepping with a debugger into Frequire, I > > see that cus-start is not in the Vfeatures list? Why? > > If I understand correctly, this is because loading cus-start signals an error, > and therefore the (provide 'cus-start) line is never executed and the feature > never gets added to the list. That might explain the single load that is still left after the patch I sent, but it cannot explain the rest, because cus-start does provide its feature after dumping. > > Here's the patch which reduces the number of loads to 1 (and which I > > hoped will reduce it to zero): > > I don't think this patch worked on my machine. I still see that > cus-start is loaded > once each time setopt runs, when setting force-load-messages to t. Doesn't happen here. I see only one "Loading cus-start" message in *Messages*, not 20+ I saw before. Maybe you haven't fully re-built Emacs after patching it?
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Sat, 31 May 2025 15:18:01 GMT) Full text and rfc822 format available.Message #23 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Stefan Monnier <monnier <at> iro.umontreal.ca> To: Aaron Zeng <azeng <at> janestreet.com> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Sat, 31 May 2025 11:17:04 -0400
> While trying to improve Emacs startup time at my site, I noticed that > cus-start was being loaded repeatedly, each time setopt was called. I don't see this, but I do see `cus-start` being (re)loaded when the first `setopt` is executed. This comes from the weird conditional below: (unless dump-mode (provide 'cus-start)) This dates back to commit 4883633e7b4416a0da1a63bc7fd0c4081bdc7837 Author: Richard M. Stallman <rms <at> gnu.org> Date: Sat May 31 00:54:10 1997 +0000 Arrange to load it once during dumping, and again if needed by cus-edit.el. (custom-start-quote): Don't define as separate function. (load-path): Improve the :type. (delete-exited-processes): Fix group to processes-basics. I have no idea why, but it's not a new problem. Maybe the repeated-loading you're seeing is due to `dump-mode` being non-nil in your Emacs build? If that's the case, do you have any idea why that would be the case (it's rather unusual). Stefan
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Sat, 31 May 2025 16:39:05 GMT) Full text and rfc822 format available.Message #26 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Stefan Monnier <monnier <at> iro.umontreal.ca> To: Aaron Zeng <azeng <at> janestreet.com> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Sat, 31 May 2025 12:37:54 -0400
> This dates back to > > commit 4883633e7b4416a0da1a63bc7fd0c4081bdc7837 > Author: Richard M. Stallman <rms <at> gnu.org> > Date: Sat May 31 00:54:10 1997 +0000 > > Arrange to load it once during dumping, > and again if needed by cus-edit.el. [...] > I have no idea why, but it's not a new problem. The why is a bit further up in the file: (unless dump-mode ;; Add it to the right group(s). (if (listp group) (dolist (g group) (custom-add-to-group g symbol 'custom-variable)) (custom-add-to-group group symbol 'custom-variable)) ;; Set the type. (put symbol 'custom-type type) (while rest (setq prop (car rest) propval (cadr rest) rest (nthcdr 2 rest)) (cond ((memq prop '(:standard :risky :safe :set))) ; handled above ((eq prop :tag) (put symbol 'custom-tag propval)))))))) IOW, the dump-time load of `cus-start.el` only sets up part of the info (to try and keep the dumped executable a bit smaller), which is why we need to *re*load it later. So the remaining question is why/when it may be reloaded multiple times rather than once. I personally don't see this behavior here, so I think we need a more detailed recipe to investigate the origin. Stefan
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Sat, 31 May 2025 17:24:03 GMT) Full text and rfc822 format available.Message #29 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Stefan Monnier <monnier <at> iro.umontreal.ca> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com, azeng <at> janestreet.com Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Sat, 31 May 2025 20:23:39 +0300
> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com > Date: Sat, 31 May 2025 11:17:04 -0400 > From: Stefan Monnier via "Bug reports for GNU Emacs, > the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org> > > > While trying to improve Emacs startup time at my site, I noticed that > > cus-start was being loaded repeatedly, each time setopt was called. > > I don't see this, but I do see `cus-start` being (re)loaded when the > first `setopt` is executed. > > This comes from the weird conditional below: > > (unless dump-mode > (provide 'cus-start)) > > This dates back to > > commit 4883633e7b4416a0da1a63bc7fd0c4081bdc7837 > Author: Richard M. Stallman <rms <at> gnu.org> > Date: Sat May 31 00:54:10 1997 +0000 > > Arrange to load it once during dumping, > and again if needed by cus-edit.el. > (custom-start-quote): Don't define as separate function. > (load-path): Improve the :type. > (delete-exited-processes): Fix group to processes-basics. > > I have no idea why, but it's not a new problem. > > Maybe the repeated-loading you're seeing is due to `dump-mode` being > non-nil in your Emacs build? If that's the case, do you have any idea > why that would be the case (it's rather unusual). No dump-mode is nil at this stage. I think I'm beginning to understand why this happens: somehow loading cus-start signals an error, so we never get to the provide part. E.g., if I change the init file to say this: (setq force-load-messages t) (require 'cus-start) (dotimes (_ 25) (setopt make-backup-files nil)) then starting "emacs" shows the *Warnings* buffer with this text: Wrong type argument: listp, t To ensure normal operation, you should investigate and remove the cause of the error in your initialization file. Start Emacs with the ‘--debug-init’ option to view a complete error backtrace. I also see that wrong-type-argument error signaled if I run the recipe under GDB with a breakpoint on Fsignal. The backtrace is below, if it helps. It seems Emacs is trying to do the equivalent of (member transient-mark-mode t) But I cannot figure out which part of cus-start causes this. Any ideas? Here's the backtrace from the error Emacs signals and some additional data from snooping around: (gdb) bt #0 Fsignal (error_symbol=85536, data=-4611686018187727616) at eval.c:1820 #1 0x00955a95 in xsignal (error_symbol=85536, data=-4611686018187727616) at lisp.h:4845 #2 0x0095bb1a in xsignal2 (error_symbol=85536, arg1=49488, arg2=48) at eval.c:1988 #3 0x0092e545 in wrong_type_argument (predicate=49488, value=48) at data.c:135 #4 0x00967a07 in CHECK_LIST_END (x=48, y=48) at lisp.h:3368 #5 0x0096eef5 in Fmemq (elt=138077904, list=48) at fns.c:1923 #6 0x0096ebeb in Fmember (elt=138077904, list=48) at fns.c:1905 #7 0x009d14c6 in exec_byte_code (fun=-6917529027483966176, args_template=1026, nargs=3, args=0xa020440) at bytecode.c:1604 #8 0x009cc8d7 in Fbyte_code (bytestr=-9223372036650939888, vector=-6917529027437457712, maxdepth=4611686018427387933) at bytecode.c:329 #9 0x0095dff5 in eval_sub (form=-4611686018187654016) at eval.c:2604 #10 0x009afade in readevalloop (readcharfun=37056, infile0=0x628cb04, sourcename=-9223372036650939824, printflag=false, unibyte=0, readfun=0, start=0, end=0) at lread.c:2543 #11 0x009acdba in Fload (file=-9223372036698239704, noerror=0, nomessage=48, nosuffix=0, must_suffix=48) at lread.c:1731 #12 0x009ad1c0 in save_match_data_load (file=-9223372036698239704, noerror=0, nomessage=48, nosuffix=0, must_suffix=48) at lread.c:1783 #13 0x0095d0c9 in load_with_autoload_queue (file=-9223372036698239704, noerror=0, nomessage=48, nosuffix=0, must_suffix=48) at eval.c:2382 #14 0x00977eb5 in Frequire (feature=138111896, filename=0, noerror=0) at fns.c:3771 #15 0x009600d3 in funcall_subr (subr=0x105bc40 <Srequire>, numargs=1, args=0xa020320) at eval.c:3165 #16 0x009cd90d in exec_byte_code (fun=-6917529027484546136, args_template=257, nargs=1, args=0xa0202e0) at bytecode.c:812 #17 0x0096094f in funcall_lambda (fun=-6917529027438039424, nargs=2, arg_vector=0x628d470) at eval.c:3252 #18 0x0096076a in apply_lambda (fun=-6917529027438039424, args=-4611686018298105856, count=1280) at eval.c:3215 #19 0x0095e517 in eval_sub (form=-4611686018298105872) at eval.c:2645 #20 0x00956ba6 in Fprogn (body=0) at eval.c:439 #21 0x00959483 in Flet (args=-4611686018298106016) at eval.c:1109 #22 0x0095dbc3 in eval_sub (form=-4611686018298106032) at eval.c:2549 #23 0x00956ba6 in Fprogn (body=-4611686018298006720) at eval.c:439 #24 0x00956bf2 in prog_ignore (body=-4611686018298106080) at eval.c:450 #25 0x0095951a in Fwhile (args=-4611686018298106064) at eval.c:1130 #26 0x0095dbc3 in eval_sub (form=-4611686018298106048) at eval.c:2549 #27 0x00956ba6 in Fprogn (body=0) at eval.c:439 #28 0x00959483 in Flet (args=-4611686018298106288) at eval.c:1109 #29 0x0095dbc3 in eval_sub (form=-4611686018298106304) at eval.c:2549 #30 0x009aee16 in readevalloop_eager_expand_eval (val=-4611686018298006624, macroexpand=44400) at lread.c:2359 #31 0x009afac4 in readevalloop (readcharfun=-6917529027437162840, infile0=0x0, sourcename=-9223372036650853472, printflag=false, unibyte=0, readfun=0, start=0, end=0) at lread.c:2541 #32 0x009affc2 in Feval_buffer (buffer=-6917529027437162840, printflag=0, filename=-9223372036650853472, unibyte=0, do_allow_print=48) at lread.c:2616 #33 0x009601c0 in funcall_subr (subr=0x105d040 <Seval_buffer>, numargs=5, args=0xa020280) at eval.c:3169 #34 0x009cd90d in exec_byte_code (fun=-6917529027484017368, args_template=257, nargs=1, args=0xa020288) at bytecode.c:812 #35 0x0096094f in funcall_lambda (fun=-6917529027483359632, nargs=4, arg_vector=0x628eb88) at eval.c:3252 #36 0x0095fa15 in funcall_general (fun=-6917529027483359632, numargs=4, args=0x628eb88) at eval.c:3044 #37 0x0095fd3e in Ffuncall (nargs=5, args=0x628eb80) at eval.c:3093 #38 0x009ac862 in Fload (file=-9223372036698322936, noerror=138689728, nomessage=138689664, nosuffix=0, must_suffix=0) at lread.c:1619 #39 0x009601c0 in funcall_subr (subr=0x105cfc0 <Sload>, numargs=3, args=0xa0201d8) at eval.c:3169 #40 0x009cd90d in exec_byte_code (fun=-6917529027484481064, args_template=513, nargs=1, args=0xa020238) at bytecode.c:812 #41 0x0096094f in funcall_lambda (fun=-6917529027478952400, nargs=0, arg_vector=0x628f5a0) at eval.c:3252 #42 0x0096076a in apply_lambda (fun=-6917529027478952400, args=0, count=128) at eval.c:3215 #43 0x0095e517 in eval_sub (form=-4611686018263554520) at eval.c:2645 #44 0x0095d5f0 in Feval (form=-4611686018263554520, lexical=48) at eval.c:2462 #45 0x008646d7 in top_level_2 () at keyboard.c:1184 #46 0x0095aa2d in internal_condition_case (bfun=0x86464e <top_level_2>, handlers=144, hfun=0x863c02 <cmd_error>) at eval.c:1613 #47 0x0086476a in top_level_1 (ignore=0) at keyboard.c:1196 #48 0x00959ab2 in internal_catch (tag=75552, func=0x8646f6 <top_level_1>, arg=0) at eval.c:1292 #49 0x00864541 in command_loop () at keyboard.c:1145 #50 0x00863662 in recursive_edit_1 () at keyboard.c:754 #51 0x00863900 in Frecursive_edit () at keyboard.c:837 #52 0x0085ea23 in main (argc=1, argv=0x7bf25c0) at emacs.c:2646 Lisp Backtrace: "add-to-list" (0xa020428) "byte-code" (0x628c270) "require" (0xa020320) "custom-load-symbol" (0xa0202d8) "setopt--set" (0x628d470) "let" (0x628d840) "while" (0x628da80) "let" (0x628dd10) "eval-buffer" (0xa020280) "load-with-code-conversion" (0x628eb88) "load" (0xa0201d8) 0xc2418f8 PVEC_CLOSURE "startup--load-user-init-file" (0xa0200c8) "command-line" (0xa020048) "normal-top-level" (0x628f5a0) (gdb) fr 7 #7 0x009d14c6 in exec_byte_code (fun=-6917529027483966176, args_template=1026, nargs=3, args=0xa020440) at bytecode.c:1604 1604 TOP = Fmember (TOP, v1); (gdb) pp TOP transient-mark-mode (gdb) pp v1 t (gdb) fr 9 #9 0x0095dff5 in eval_sub (form=-4611686018187654016) at eval.c:2604 2604 val = (XSUBR (fun)->function.a3 (gdb) p form $12 = -4611686018187654016 (gdb) xcar $13 = 0x83ad218 (gdb) xtype Lisp_Symbol (gdb) xsymbol $14 = (struct Lisp_Symbol *) 0x953f378 "byte-code" (gdb) p form $15 = -4611686018187654016 (gdb) xcdr $16 = 0xc00000000e4a0c70 (gdb) xcar $17 = 0x800000000c264a10 (gdb) xtype Lisp_String (gdb) xprintbytestr $17->u.s Bytecode: Non-integral right operand for "@" operator.
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Sat, 31 May 2025 18:05:04 GMT) Full text and rfc822 format available.Message #32 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Stefan Monnier <monnier <at> iro.umontreal.ca> To: Eli Zaretskii <eliz <at> gnu.org> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com, Aaron Zeng <azeng <at> janestreet.com> Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Sat, 31 May 2025 14:04:39 -0400
>> I believe this can be fixed with the following patch. On my machine, >> this patch reduces the runtime of the original init file to 75ms and >> causes the prepended code to make no difference to the runtime. >> >> diff --git a/lisp/cus-start.el b/lisp/cus-start.el >> index 91cc6e22152..e82e97e87ca 100644 >> --- a/lisp/cus-start.el >> +++ b/lisp/cus-start.el >> @@ -934,7 +934,7 @@ minibuffer-prompt-properties--setter >> ;; This is used by describe-variable. >> (if version (put symbol 'custom-version version)) >> ;; Don't re-add to custom-delayed-init-variables post-startup. >> - (unless after-init-time >> + (when (listp custom-delayed-init-variables) >> ;; Note this is the _only_ initialize property we handle. >> (if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay) >> ;; These vars are defined early and should hence be initialized I'm sorry I was dense, but yes it looks like you found the culprit. > I think this patch changes behavior, so it is not TRT. But before we > discuss how to fix the problem, let's be sure we understand the > problem and its reason(s). I think the patch below is a cleaner version of the patch above and I think it does do TRT: `custom-delayed-init-variables` is used only at early startup to force re-evaluation of some of the preloaded (a.k.a dumped) variables; after that it should simply not be used and adding entries to it is pointless. I think this problem comes originally from my lack of understanding when I added that `custom-delayed-init-variables` thingy here: if I had understood what the `(unless purify-flag` was doing there I would have used that test right from the start instead of `after-init-time`. startup.el sets `custom-delayed-init-variables` to t after using it, so as to try and catch cases where we mistakenly register vars on this list "too late". The `after-init-time` avoided the problem only as long as `cus-start` was loaded late enough. Stefan diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 09364b68e11..7e07e055015 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -946,19 +946,18 @@ minibuffer-prompt-properties--setter (put symbol 'custom-set (cadr prop))) ;; This is used by describe-variable. (if version (put symbol 'custom-version version)) - ;; Don't re-add to custom-delayed-init-variables post-startup. - (unless after-init-time - ;; Note this is the _only_ initialize property we handle. - (if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay) - ;; These vars are defined early and should hence be initialized - ;; early, even if this file happens to be loaded late. so add them - ;; to the end of custom-delayed-init-variables. Otherwise, - ;; auto-save-file-name-transforms will appear in customize-rogue. - (add-to-list 'custom-delayed-init-variables symbol 'append))) ;; If this is NOT while dumping Emacs, set up the rest of the ;; customization info. This is the stuff that is not needed ;; until someone does M-x customize etc. - (unless dump-mode + (if dump-mode + ;; Don't re-add to custom-delayed-init-variables post-startup. + ;; Note this is the _only_ initialize property we handle. + (if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay) + ;; These vars are defined early and should hence be initialized + ;; early, even if this file happens to be loaded late. so add + ;; them to the end of custom-delayed-init-variables. Otherwise, + ;; auto-save-file-name-transforms will appear in customize-rogue. + (add-to-list 'custom-delayed-init-variables symbol 'append)) ;; Add it to the right group(s). (if (listp group) (dolist (g group)
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Sun, 01 Jun 2025 09:41:02 GMT) Full text and rfc822 format available.Message #35 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Stefan Monnier <monnier <at> iro.umontreal.ca> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com, azeng <at> janestreet.com Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Sun, 01 Jun 2025 12:40:16 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca> > Cc: Aaron Zeng <azeng <at> janestreet.com>, 78637 <at> debbugs.gnu.org, > app-emacs-dev <at> janestreet.com > Date: Sat, 31 May 2025 14:04:39 -0400 > > >> I believe this can be fixed with the following patch. On my machine, > >> this patch reduces the runtime of the original init file to 75ms and > >> causes the prepended code to make no difference to the runtime. > >> > >> diff --git a/lisp/cus-start.el b/lisp/cus-start.el > >> index 91cc6e22152..e82e97e87ca 100644 > >> --- a/lisp/cus-start.el > >> +++ b/lisp/cus-start.el > >> @@ -934,7 +934,7 @@ minibuffer-prompt-properties--setter > >> ;; This is used by describe-variable. > >> (if version (put symbol 'custom-version version)) > >> ;; Don't re-add to custom-delayed-init-variables post-startup. > >> - (unless after-init-time > >> + (when (listp custom-delayed-init-variables) > >> ;; Note this is the _only_ initialize property we handle. > >> (if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay) > >> ;; These vars are defined early and should hence be initialized > > I'm sorry I was dense, but yes it looks like you found the culprit. > > > I think this patch changes behavior, so it is not TRT. But before we > > discuss how to fix the problem, let's be sure we understand the > > problem and its reason(s). > > I think the patch below is a cleaner version of the patch above and > I think it does do TRT: `custom-delayed-init-variables` is used only at > early startup to force re-evaluation of some of the preloaded (a.k.a > dumped) variables; after that it should simply not be used and adding > entries to it is pointless. Does this explain what I see: that loading cus-start via 'require' during processing of the init file signals an error, like I show in my previous message? If so, could you explain why do we signal an error in that case?
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Sun, 01 Jun 2025 16:32:05 GMT) Full text and rfc822 format available.Message #38 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Stefan Monnier <monnier <at> iro.umontreal.ca> To: Eli Zaretskii <eliz <at> gnu.org> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com, azeng <at> janestreet.com Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Sun, 01 Jun 2025 12:30:54 -0400
> Does this explain what I see: that loading cus-start via 'require' > during processing of the init file signals an error, like I show in my > previous message? Yes. > If so, could you explain why do we signal an error in that case? We don't do it on purpose, of course, but the code protected by the `(unless after-init-time` test presumes that `custom-delayed-init-variables` contains a list whereas this assumption is true only while dumping and at the very beginning of the startup sequence. So the code work fine if run: - during dump or very early startup, when `custom-delayed-init-variables` still contains a list. - after loading the init file, thanks to the `(unless after-init-time` test. But not between those two (i.e. not from within the init file). The effect of that code is to fill `custom-delayed-init-variables` during the dump for subsequent use in the very early startup, hence my patch replaces the `(unless after-init-time` by `(if dump-mode. Stefan
bug-gnu-emacs <at> gnu.org
:bug#78637
; Package emacs
.
(Sat, 07 Jun 2025 09:26:01 GMT) Full text and rfc822 format available.Message #41 received at 78637 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Stefan Monnier <monnier <at> iro.umontreal.ca> Cc: 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com, azeng <at> janestreet.com Subject: Re: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over Date: Sat, 07 Jun 2025 12:25:36 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca> > Cc: azeng <at> janestreet.com, 78637 <at> debbugs.gnu.org, app-emacs-dev <at> janestreet.com > Date: Sun, 01 Jun 2025 12:30:54 -0400 > > > Does this explain what I see: that loading cus-start via 'require' > > during processing of the init file signals an error, like I show in my > > previous message? > > Yes. > > > If so, could you explain why do we signal an error in that case? > > We don't do it on purpose, of course, but the code protected by the > `(unless after-init-time` test presumes that > `custom-delayed-init-variables` contains a list whereas this assumption > is true only while dumping and at the very beginning of the > startup sequence. > > So the code work fine if run: > > - during dump or very early startup, when > `custom-delayed-init-variables` still contains a list. > - after loading the init file, thanks to the `(unless after-init-time` test. > > But not between those two (i.e. not from within the init file). > The effect of that code is to fill `custom-delayed-init-variables` > during the dump for subsequent use in the very early startup, hence my > patch replaces the `(unless after-init-time` by `(if dump-mode. Thanks, feel free to install your changes and close the bug.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.