From c5188c43883f73183ca0f4cb6597c75104722b63 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Mon, 12 Sep 2022 23:44:04 +0200 Subject: [PATCH] perf: cache module flags in symbol plists For small amounts of data, symbol plists are the most efficient (space and time wise) as data access gets in Emacs. Hash tables, though O(1), impose a minimum threshold of overhead before it becomes the efficient option, but this benefit won't be obvious for datasets of at least 60 or less. Since modulep! is used *a lot*, and used to determine a module's state (and state of its flags), there is a benefit to caching it. Still, this is only a read-only cache, and does not replace the `doom-modules` hash-table, which will always be the preferred interface for the rest of the module API. --- lisp/cli/autoloads.el | 6 ++++++ lisp/doom-modules.el | 18 +++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lisp/cli/autoloads.el b/lisp/cli/autoloads.el index 7c62ba9e8..66b77a46c 100644 --- a/lisp/cli/autoloads.el +++ b/lisp/cli/autoloads.el @@ -47,6 +47,12 @@ hoist buggy forms into autoloads.") (cl-loop for var in doom-autoloads-cached-vars when (boundp var) collect `(set ',var ',(symbol-value var))) + ;; Cache module state and flags in symbol plists for quick lookup by + ;; `modulep!' later. + (cl-loop for (category . modules) in (seq-group-by #'car (doom-module-list)) + collect `(setplist ',category + (quote ,(cl-loop for (_ . module) in modules + nconc `(,module ,(get category module)))))) (doom-autoloads--scan (append (doom-glob doom-core-dir "lib/*.el") (cl-loop for dir diff --git a/lisp/doom-modules.el b/lisp/doom-modules.el index 71fc3527e..edf8d994b 100644 --- a/lisp/doom-modules.el +++ b/lisp/doom-modules.el @@ -107,7 +107,7 @@ symbols, and that module's plist." (declare (pure t) (side-effect-free t)) (lambda (module plist) (let ((doom--current-module module) - (doom--current-flags (plist-get plist :flags)) + (doom--current-flags (cdr (get (car module) (cdr module)))) (inhibit-redisplay t)) (load! file (plist-get plist :path) t)))) @@ -178,6 +178,11 @@ following properties: Example: (doom-module-set :lang 'haskell :flags '(+lsp))" + ;; Doom caches flags and features using symbol plists for fast lookups in + ;; `modulep!'. plists lack the overhead, and are much faster for datasets this + ;; small. The format of this case is (cons FEATURES FLAGS) + (put category module (cons t (plist-get plist :flags))) + ;; But the hash table will always been Doom's formal storage for modules. (puthash (cons category module) plist doom-modules)) (defun doom-module-expand-path (category module &optional file) @@ -561,15 +566,14 @@ Module FLAGs are set in your config's `doom!' block, typically in CATEGORY and MODULE can be omitted When this macro is used from inside a module (except your DOOMDIR, which is a special module). e.g. (modulep! +flag)" - (and (cond (flag (memq flag (doom-module-get category module :flags))) - (module (doom-module-p category module)) + (and (cond (flag (memq flag (cdr (get category module)))) + (module (get category module)) (doom--current-flags (memq category doom--current-flags)) (doom--current-module - (memq category (doom-module-get (car doom--current-module) - (cdr doom--current-module) - :flags))) + (memq category (cdr (get (car doom--current-module) + (cdr doom--current-module))))) ((if-let (module (doom-module-from-path (macroexpand '(file!)))) - (memq category (doom-module-get (car module) (cdr module) :flags)) + (memq category (cdr (get (car module) (cdr module)))) (error "(modulep! %s %s %s) couldn't figure out what module it was called from (in %s)" category module flag (file!))))) t))