Il s'avère que les performances extrêmement variables étaient liées à la collecte des ordures. Chaque appel à la fonction deviendrait plus lent jusqu'à ce qu'une récupération de place soit exécutée. Avec emacs stock, gc était exécuté toutes les deux secondes, mais j'avais une ligne dans mon init.el pour améliorer le temps de démarrage qui définissait gc-cons-threshold à 20 Mo, et cela signifiait que gc était exécuté beaucoup plus rarement, ce qui provoquait signaler un chronométrage de plus en plus lent jusqu'à ce qu'un GC soit exécuté après quelques minutes, puis les temps chuteraient et seraient à nouveau rapides.
Après être revenu à gc-cons-threshhold par défaut, l'analyse comparative est devenue plus facile.
J'ai ensuite profilé la mémoire avec le profiler ( M-x profiler-start
) intégré et découvert que les appels à syntax-ppss causaient le plus d'allocations, donc après une optimisation pour appeler syntax-ppss moins souvent, j'ai atteint des performances acceptables.
Utiliser le mode jit-lock (ajouter une fonction via jit-lock-register) semble être le moyen le plus simple pour que le verrouillage de police multi-lignes fonctionne de manière fiable, c'est donc la méthode que j'ai choisie.
Edit: Après avoir découvert que les performances n'étaient toujours pas assez bonnes dans les très gros tampons, j'ai passé beaucoup de temps à optimiser l'utilisation et l'allocation des processeurs, à mesurer les améliorations des performances avec le profileur Emacs intégré ( M-x profiler-start
). Cependant, Emacs bégayait toujours et se bloquait lors du défilement rapide à travers de très grands tampons. La suppression de la fonction jit-lock avec laquelle je me suis inscrit jit-lock-register
supprimerait le bégaiement et les blocages, mais le profilage a montré que la fonction jit-lock se terminait en environ 8 ms, ce qui devrait être assez rapide pour un défilement fluide. La suppression de l'appel à jit-lock-register
et à la place à l'aide d'un correcteur de police-verrouillage-mots-clés standard a résolu le problème.
TLDR: Faire cela était lent et bégayerait:
(defun my-font-lock-function (start end)
"Set faces for font-lock between START and END.")
(jit-lock-register 'my-font-lock-function)
Faire cela était rapide et ne bégayerait pas:
(defun my-font-lock-function (start end)
"Set faces for font-lock between START and END.")
(defun my-font-lock-matcher (limit)
(my-font-lock-function (point) limit)
nil)
(setq font-lock-defaults
(list
...
;; Note that the face specified here doesn't matter since
;; my-font-lock-matcher always returns nil and sets the face on
;; its own.
`(my-font-lock-matcher (1 font-lock-keyword-face nil))))