Comment puis-je améliorer le temps de démarrage malgré de nombreux packages?


19

TL; DR J'ai une telle quantité de paquets que ça me fait mal au démarrage. Si vous ne pensez pas que cela pourrait être le cas, lisez la suite.


Mon temps de démarrage Emacs est assez petit. Je ne l'utilise pas use-package, je mets juste des tonnes de hooks et autoloads pour que presque tout le code soit différé. En réalité, le tout est chargé en généralement moins d'une demi-seconde, même si cela semble être un gâchis fou.

Cependant, au fil du temps, j'ai remarqué que mon temps de démarrage était extrêmement lent, inexplicablement. Ceci est finalement arrivé au point où le temps de démarrage est ≥ 1 seconde. J'en ai finalement eu assez et j'ai creusé à la racine du problème. J'ai finalement commenté tout mon ~/.emacsfichier et constaté que le temps de démarrage était toujours ≥ 1 seconde. En fait, il ne s'était rasé qu'environ 0.2quelques secondes, parfois même moins. Ensuite, j'ai essayé emacs -qet constaté que le temps de démarrage était de ~ 0.1secondes.

En examinant cette section du manuel Elisp, j'ai découvert pourquoi emacs -qle temps de démarrage était tellement réduit. Apparemment emacs -q, Emacs empêche trois choses au démarrage:

  1. chargement de votre fichier init
  2. chargement de votre default.elfichier
  3. appel package-initialize

Nous avons déjà exclu mon fichier init, car commenter mon tout ~/.emacsne fait presque rien. Je n'utilise pas de default.elfichier, ce qui est également exclu. Ce qui laisse package-initializele coupable du succès de la performance.

Pourquoi prendrait package-initializeautant de temps de démarrage? C'était la première question que je me posais. Ne suis-je pas en train de tout charger automatiquement? Hé bien oui. Mais c'est précisément le problème.

J'ai trouvé ce post qui explique que "l'activation" des packages consiste à lire des fichiers de chargement automatique et à définir des chemins de chargement. Cela entraîne évidemment une pénalité d'E / S lorsque vous avez plusieurs packages car vous avez de nombreux fichiers à chargement automatique à lire et de nombreux chemins à définir. Malheureusement, sans cela, la tâche de gérer les chargements automatiques incombe à l'utilisateur. En d'autres termes, sans laisser package.elexplorer le système de fichiers pour les fichiers et les chemins de chargement automatique, je devrais gérer moi-même ce qui pourrait être un processus fastidieux et sujet aux erreurs.

Je préférerais ne pas emprunter cette voie. J'ai actuellement 116 packages, dont 107 d'ELPA et 25 de dépendances. Je suis sûr que ce nombre énorme est ce qui dégrade si gravement mes performances. Mais je suis dans un dilemme car je ne veux supprimer aucun de mes packages.

Existe-t-il un remède dans une telle situation pour récupérer mon temps de démarrage de la foudre?


Mise à jour:

Nous avons commencé un nouveau fil sur la emacs-develliste de diffusion sur certains correctifs par Stefan Monnier (une description de ces correctifs est ici ) pour résoudre ce problème. Tout le monde est invité à tester ses correctifs et à donner son avis.

Une autre mise à jour:

Il semble que Stefan Monnier ne soit plus intéressé par ce problème ou qu'il ne reçoive pas mes messages. Je suis enclin à croire le premier, ce qui est bien, mais j'apprécierais une sorte de réponse de sa part si tel est le cas. Quoi qu'il en soit, le code qu'il a produit jusqu'à présent pour ce numéro fonctionne assez bien. Les patchs les plus récents sont disponibles ici (pour Emacs 25.3) et ici (pour Emacs master branch).J'ai vu de bonnes améliorations sur mon temps de démarrage grâce à ses correctifs et je suis à un point où je suis à l'aise avec mon temps de démarrage dans la mesure où il est aussi optimisé que possible sans couper les fonctionnalités de ma personnalisation. J'espérais que ces correctifs arriveraient dans la ligne principale d'Emacs à un moment donné, mais je suppose que moi (ou quelqu'un d'autre) devrais reprendre le flambeau maintenant, au lieu de Stefan. Nous avions un peu de spar sur la liste de diffusion sur l'attribution des droits d'auteur et les licences. J'étais initialement mal à l'aise de le faire, mais en raison de certains commentaires de Richard Stallman et d'autres, la cession des droits d'auteur peut ne pas être aussi restrictive que je le pensais à l'origine. De plus, il peut être possible pour moi de placer mes œuvres dans le domaine public comme alternative à la cession du droit d'auteur.

En tout cas, merci Stefan pour les patchs à ce jour! J'espère que vous continuerez à développer ces changements, mais sinon, ça va et je pourrai continuer à les développer à un moment donné. Je remercie également toutes les autres personnes qui ont offert leur avis et leur contribution à la résolution de ce problème.

Encore une autre mise à jour:

Wow, on dirait que cette fonctionnalité a finalement atterri et sera dans Emacs 27. Merci à Stefan Monnier!


Grande question.
Drew

use-packageest la voie à suivre pour cela.
Dodgie

N'essayez pas de minimiser le problème (la latence de démarrage est importante!), Mais envisagez d'exécuter emacs en tant que démon / serveur afin de ne payer qu'une seule fois le coût de démarrage.
GManNickG

1
@GManNickG J'exécute Emacs en tant que serveur. Malheureusement, de temps en temps, je pousse Emacs trop fort ou bricoler trop et un redémarrage est le meilleur moyen de nettoyer les choses. Lorsque cela se produit, j'aime que mon temps de démarrage soit optimal.
GDP2

Réponses:


13

L'un des choix de conception de package.el était d'essayer de simplifier les choses. Cela consiste en partie à package-initializerechercher tous les packages installés, puis à essayer de déterminer lesquels doivent être activés (en fonction de l'épinglage et de la récence des versions dans le cas où plusieurs versions du même package sont disponibles), puis à charger chacun active le <pkg>-autoloads.elfichier du package .

Donc, pour N packages installés, cela signifie essentiellement lire N <pkg>-pkg.elfichiers de description de package et N <pkg>-autoloads.elfichiers. Pour les grands N, cela peut devenir un problème grave. Un autre problème de performance potentiel est qu'il ajoutera N éléments load-path, donc à chaque fois que vous loadEmacs recherchera dans N répertoires, chacun loadsera donc ralenti.

Nous pouvons essayer d'accélérer cela de différentes manières:

  • Fournir un moyen de précalculer un ~/.emacs.d/elpa/package-initialize.el(c)fichier qui résulterait de la concaténation de tous les droits <pkg>-autoloads.eldans le bon ordre. Ensuite, package-initializepourrait simplement charger ce fichier lorsqu'il est présent et ignorer tout le reste. Vous auriez alors besoin d'un moyen d'actualiser / vider le package-initialize.el(c)fichier lorsque des packages sont ajoutés / mis à jour / supprimés ou lorsque vous modifiez votre package-pinned-packagesou votre package-load-list. Je pense que cela peut être fait avec assez peu de modifications du système (la seule chose qui aurait vraiment besoin d'être modifiée, je pense package-initialize, c'est qu'on puisse lui dire de "n'activer que" sans charger les métadonnées sur les packages disponibles).

  • Fournir un moyen de construire / manipuler des super-packages, c'est-à-dire des packages qui combinent plusieurs packages en un (donc il n'y a qu'un seul élément ajouté load-path, un <pkg>-pkg.elet un <pkg>-autoloads.elchargé). Cela peut être plus difficile à faire (car vous ne pouvez alors activer qu'une partie des packages contenus dans ces super-packages, donc l'analyse de dépendance / version peut être délicate).

La première option ci-dessus devrait être assez facile à implémenter et serait package-initialize beaucoup plus rapide lorsque de nombreux packages sont installés. Si cela vous intéresse, n'hésitez pas à me demander de l'aide.

FWIW, je viens d'essayer de construire un tel fichier méga-autoloads "à la main" sur ma configuration de test. Résultats: alors que cela package-initializeprend environ 0,9s, le chargement du mega-autoloads.elfichier prend 0,3s que je peux ramener à 0,2s en laissant la liaison load-source-file-functionà zéro et à 0,1s en compilant le fichier en octets. Je m'attendais à une meilleure accélération, pour être honnête, mais cela en vaut toujours la peine.

[EDIT] Cette approche de "méga autochargements" est maintenant disponible dans la branche principale d'Emacs (pour devenir Emacs-27 dans un futur lointain). Il est contrôlé par la nouvelle package-quickstartvariable.


Ce sont des idées très intéressantes. Le premier sonne plus terre-à-terre et moins difficile. Le second est assez intéressant, mais cela ressemble à un travail pour les package.eldéveloppeurs. Quel type de conseils avez-vous pour commencer avec cette première option? J'aimerais voir ce que je peux marteler avec, car il semble beaucoup plus réalisable.
GDP2

el-get utilise l'approche du fichier de chargement automatique unique, il fonctionne essentiellement la plupart du temps. Il y a des problèmes avec certains packages dont les chargements automatiques dépendent de l'emplacement dans le système de fichiers dans lequel ils sont évalués. Je ne comprends pas ce que vous entendez par "dans le bon ordre" cependant, pourquoi l'ordre de chargement automatique importerait-il jamais (je n'ai pas pense que c'était même déterministe pour package.el actuel)?
npostavs

@Stefan, veuillez partager la solution ici, si possible.
Manuel Uberti

1
@npostavs: la plupart des <pkg>-autoloads.elfichiers ne configurent que les chargements automatiques et ne se soucient pas de la commande, mais rien ne les empêche de faire d'autres choses au hasard, et package.el garantit que le package dont il <pkg>dépend sera activé avant <pkg>lui-même.
Stefan

1
Une autre mise à jour sur ce problème: nous avons commencé un nouveau sujet sur la liste de diffusion ici et tout le monde est libre de commenter ou de tester les modifications de Stefan.
GDP2

6

Le problème que vous décrivez au sujet de package-initializeprendre autant de temps à charger est un problème bien connu. C'est également l'un des problèmes que certains frameworks emacs tentent de résoudre en chargeant les chargements automatiques manuellement.

Je vois deux solutions à votre problème.

  1. Écrivez (ou extrayez d'un framework) la fonctionnalité pour définir les chemins et charger les chargements automatiques des packages qui vous intéressent.
  2. Utilisez un cadre qui cible explicitement la vitesse. Je recommande personnellement les emacs DOOM . Avec ce cadre, je charge plus de 200 paquets en environ 1 seconde.

L'une des principales raisons de recommander emacs DOOM est que le framework place la gestion des packages en dehors d'emacs. Ne vous méprenez pas, c'est toujours emacs qui fait la gestion des packages, c'est juste que la gestion des packages se fait en dehors d'une session utilisateur standard. La philosophie est la suivante: lors du démarrage normal d'emacs, nous devrions pouvoir supposer que tous les packages sont présents et peuvent déjà être chargés. Cela fait gagner beaucoup de temps. DOOM emacs fournit une sorte d'équivalent de apt-getou pacmanpour emacs. Une fois qu'un paquet est installé, chaque fois qu'emacs démarre, il est supposé être déjà installé; pas de questions posées.


Ouf, content de savoir que ce problème ne m'affecte pas seulement. Merci de me diriger vers DOOM Emacs. Je vais devoir y regarder de plus près et voir ce que je peux adapter à ma propre configuration.
GDP2

Je joue avec les emacs DOOM (et je contribue quand je le peux) depuis un certain temps maintenant. Si vous rencontrez des problèmes, n'hésitez pas à me contacter.
UndeadKernel
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.