emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Loading a package applies automatically to future sessions?


From: Stefan Monnier
Subject: Re: Loading a package applies automatically to future sessions?
Date: Sun, 28 Jan 2018 17:11:07 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

>> This said, if a package's activation gets in the way of the user, I'd
>> generally consider it to be a bug in that package (similar to the fact
>> that if (require <foo>) has undesirable effects it's usually a bug in
>> <foo>).
> Activation of packages is a significant performance hit.
> It's therefore not a good idea to be activating superfluous packages.
> JW has told me that one of the reasons his Emacs configuration does
> not use package.el is that activating packages was too slow.

The performance impact is indeed something that probably deserves a bit
more work.  But we need to clarify what are the expected use cases and
sources of problems.  E.g.:

- In the case of JW, why does he have so many packages installed to slow
  down his startup, yet he doesn't want them activated?  Are these
  packages that he does use, but just rarely?  Or does he just have lots of
  packages installed that he doesn't use (e.g. that's my case: I always
  have all GNU ELPA packages installed, even though I use very few of
  them)?  If so, why does he have so many packages installed even tho he
  doesn't use them?

- In my case I have around 200 packages installed and I measured the
  startup cost of package-initialize to be 0.9s (with a warm cache).
  That's plenty fast for my use case (where I rarely start a new Emacs
  session), but I understand it may not be for people who like to use
  Emacs for quick one-off editing sessions.  Still, what kind of
  slowdown is JW talking about: is it also in the order of 1s?  more?
  If the slowdown is significant, could it be due to packages that do
  "too much work" in the <pkg>-autoloads.el or is it really just the
  sheer number of <pkg>-autoloads.el and <pkg>-pkg.el to process?

The issue came up recently on stackexchange and I whipped up
a quick&dirty patch to experiment (see below) which shows that my 0.9s
can be brought down to 0.3s by pre-computing a "big autoloads file",
which can then be brought down to 0.2s by loading it with
load-source-file-function bound to nil and can be reduced further to
0.1s by byte-compiling it.

Another thing we could do is add support for activating a package
without calling package-initialize beforehand (since just calling
(package-initialize t) can already take a non-negligible amount of time,
reading all the <pkg>-pkg.el files).  This way, a user could simply skip
package-initialize completely and just "manually" activate those few
packages he wants to activate.  It should be fairly easy to implement.


        Stefan


diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 71d1c41ec3..63ec6f40f7 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -676,6 +676,8 @@ package--activate-autoloads-and-load-path
 (defvar Info-directory-list)
 (declare-function info-initialize "info" ())
 
+(defvar package--fastpath-pkgs t)
+
 (defun package--load-files-for-activation (pkg-desc reload)
   "Load files for activating a package given by PKG-DESC.
 Load the autoloads file, and ensure `load-path' is setup.  If
@@ -718,16 +720,19 @@ package-activate-1
             (message "Unable to activate package `%s'.\nRequired package 
`%s-%s' is unavailable"
                      name (car req) (package-version-join (cadr req)))
             (throw 'exit nil))))
-      (package--load-files-for-activation pkg-desc reload)
-      ;; Add info node.
-      (when (file-exists-p (expand-file-name "dir" pkg-dir))
-        ;; FIXME: not the friendliest, but simple.
-        (require 'info)
-        (info-initialize)
-        (push pkg-dir Info-directory-list))
-      (push name package-activated-list)
-      ;; Don't return nil.
-      t)))
+      (if (listp package--fastpath-pkgs)
+          ;; We're only collecting the set of packages to activate!
+          (push pkg-desc package--fastpath-pkgs)
+        (package--load-files-for-activation pkg-desc reload)
+        ;; Add info node.
+        (when (file-exists-p (expand-file-name "dir" pkg-dir))
+          ;; FIXME: not the friendliest, but simple.
+          (require 'info)
+          (info-initialize)
+          (push pkg-dir Info-directory-list))
+        (push name package-activated-list)
+        ;; Don't return nil.
+        t))))
 
 (declare-function find-library-name "find-func" (library))
 
@@ -3468,6 +3473,49 @@ package-list-packages-no-fetch
   (interactive)
   (list-packages t))
 
+;;;; Fast-path for activation!
+
+(defcustom package-fastpath-file (locate-user-emacs-file "package-fastpath.el")
+  "Location of the file used to speed up activation of packages at startup."
+  :type 'file)
+
+(defun package-fastpath-refresh ()
+  "(Re)Generate the `package-fastpath-file'."
+  (interactive)
+  (package-initialize 'no-activate)
+  (let ((package--fastpath-pkgs ())
+        ;; Pretend we haven't activated anything yet!
+        (package-activated-list ()))
+    (dolist (elt package-alist)
+      (condition-case err
+          (package-activate (car elt))
+        ;; Don't let failure of activation of a package arbitrarily stop
+        ;; activation of further packages.
+        (error (message "%s" (error-message-string err)))))
+    (with-temp-file package-fastpath-file
+      (insert ";;; FastPath file to speed up package activation at startup  
-*- lexical-binding:t -*-\n")
+      (insert ";; ¡¡ This file is autogenerated, DO NOT EDIT !!\n\n")
+      (dolist (pkg package--fastpath-pkgs)
+        (let* ((file (locate-library (package--autoloads-file-name pkg)))
+               (pfile (prin1-to-string file)))
+          (insert "(let ((load-file-name " pfile "))\n")
+          (insert-file-contents file)
+          (while (search-forward "#$" nil 'move)
+            (replace-match pfile t t))
+          (unless (bolp) (insert "\n"))
+          (insert ")\n")))
+      (pp `(setq package-activated-list
+                 (append ',(mapcar #'package-desc-name package--fastpath-pkgs)
+                         package-activated-list))
+          (current-buffer))
+      (insert "
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: nil
+;; no-update-autoloads: t
+;; End:
+"))))
+
 (provide 'package)
 
 ;;; package.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]