unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* A faster derived-mode-p
@ 2021-02-14 20:22 Lars Ingebrigtsen
  2021-02-14 22:25 ` Dmitry Gutov
  2021-02-14 23:51 ` Stefan Monnier
  0 siblings, 2 replies; 8+ messages in thread
From: Lars Ingebrigtsen @ 2021-02-14 20:22 UTC (permalink / raw)
  To: emacs-devel

There are only 11K commands in the Emacs tree, so I don't know whether
the current default completion predicate is going to turn out to be
problematically slow or not.

It basically calls `provided-mode-derived-p' for all annotated commands,
and this is a loop that chases mode parenthood back to its ultimate
ancestor.

It seems like this could done more efficiently by just resolving the
chain at `define-derived-mode' time.  That is, in addition to putting
`derived-mode-parent', it could put `derived-mode-parents', too, where
it chases the chain upwards.  Then we'd just have to look at a single
property list...

Does anybody see any disadvantages to doing it this way?  (This would
speed up `derived-mode-p', which we use all over Emacs, in general.)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: A faster derived-mode-p
  2021-02-14 20:22 A faster derived-mode-p Lars Ingebrigtsen
@ 2021-02-14 22:25 ` Dmitry Gutov
  2021-02-14 22:45   ` Basil L. Contovounesios
  2021-02-14 23:51 ` Stefan Monnier
  1 sibling, 1 reply; 8+ messages in thread
From: Dmitry Gutov @ 2021-02-14 22:25 UTC (permalink / raw)
  To: Lars Ingebrigtsen, emacs-devel

On 14.02.2021 22:22, Lars Ingebrigtsen wrote:
> There are only 11K commands in the Emacs tree, so I don't know whether
> the current default completion predicate is going to turn out to be
> problematically slow or not.

I just evaluated

   (length (cl-delete-if-not #'commandp obarray))

in a running Emacs session with a bunch of third-party packages 
installed and loaded, and that still evaluated only to 1083.

So if derived-mode-p only needs to run 1000 times or so, perhaps it can 
still be fast enough, however inefficient it might look. I'd also 
recommend benchmarking with both implementations, if it's really too slow.

Also see the whole other implementation approach I mentioned in another 
thread.



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: A faster derived-mode-p
  2021-02-14 22:25 ` Dmitry Gutov
@ 2021-02-14 22:45   ` Basil L. Contovounesios
  2021-02-14 23:03     ` Óscar Fuentes
  2021-02-15  2:34     ` Dmitry Gutov
  0 siblings, 2 replies; 8+ messages in thread
From: Basil L. Contovounesios @ 2021-02-14 22:45 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: Lars Ingebrigtsen, emacs-devel

Dmitry Gutov <dgutov@yandex.ru> writes:

> On 14.02.2021 22:22, Lars Ingebrigtsen wrote:
>> There are only 11K commands in the Emacs tree, so I don't know whether
>> the current default completion predicate is going to turn out to be
>> problematically slow or not.
>
> I just evaluated
>
>   (length (cl-delete-if-not #'commandp obarray))
>
> in a running Emacs session with a bunch of third-party packages installed and
> loaded, and that still evaluated only to 1083.

That's not counting the obarray's buckets.  I get ~6x as many results in
my session with (length (all-completions "" obarray #'commandp)).

-- 
Basil



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: A faster derived-mode-p
  2021-02-14 22:45   ` Basil L. Contovounesios
@ 2021-02-14 23:03     ` Óscar Fuentes
  2021-02-15  2:34     ` Dmitry Gutov
  1 sibling, 0 replies; 8+ messages in thread
From: Óscar Fuentes @ 2021-02-14 23:03 UTC (permalink / raw)
  To: emacs-devel

"Basil L. Contovounesios" <contovob@tcd.ie> writes:

> Dmitry Gutov <dgutov@yandex.ru> writes:
>
>> On 14.02.2021 22:22, Lars Ingebrigtsen wrote:
>>> There are only 11K commands in the Emacs tree, so I don't know whether
>>> the current default completion predicate is going to turn out to be
>>> problematically slow or not.
>>
>> I just evaluated
>>
>>   (length (cl-delete-if-not #'commandp obarray))
>>
>> in a running Emacs session with a bunch of third-party packages installed and
>> loaded, and that still evaluated only to 1083.
>
> That's not counting the obarray's buckets.  I get ~6x as many results in
> my session with (length (all-completions "" obarray #'commandp)).

~10000 here.

Can't we memoize derived-mode-p ? It doesn't look like something that
could take a lot of space.




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: A faster derived-mode-p
  2021-02-14 20:22 A faster derived-mode-p Lars Ingebrigtsen
  2021-02-14 22:25 ` Dmitry Gutov
@ 2021-02-14 23:51 ` Stefan Monnier
  2021-02-15  2:56   ` Lars Ingebrigtsen
  1 sibling, 1 reply; 8+ messages in thread
From: Stefan Monnier @ 2021-02-14 23:51 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: emacs-devel

> There are only 11K commands in the Emacs tree, so I don't know whether
> the current default completion predicate is going to turn out to be
> problematically slow or not.

Here's my suggestion:
Instead of trying to speed up those 10K predicates we're going to have
to evaluate, we could try to take advantage of the fact that there
should be a lot of redundancy there.

So we could do something like:

    (let ((cmds (make-hash-table :test #'equal)))
      (mapatom (lambda (sym)
                 (when (commandp sym)
                   (push sym (gethash (command-predicate sym) cmds)))))
      (let (active-cmds)
        (maphash (lambda (pred syms)
                   (when (funcall pred)
                     (cl-callf nconc active-cmds syms)))
                 cmds)
        active-cmds))

The only problem I can foresee here is that we have no guarantee that

    (equal (lambda () (derived-mode-p 'foo-mode))
           (lambda () (derived-mode-p 'foo-mode)))

To reduce the risk of such problems we could change the "predicate"
from being a function that takes 0 arguments, to being a list
a list (FUN . ARGS), so instead of

    (funcall pred)

we'd have to do:

    (apply pred)

So instead of

    (lambda () (derived-mode-p 'foo-mode))

the internal representation of the "predicate" would be

    (derived-mode-p foo-mode)

it should also make equality testing (within `gethash`) faster.

Of course, if we can arrange for the command predicates to be written
(in the source file) a single time for groups of commands (which would
also be beneficial to reduce the amount of redundancy in the source code
and the amount of work needed by authors), then we could even use `eq`
comparisons and still get most of the benefit.


        Stefan




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: A faster derived-mode-p
  2021-02-14 22:45   ` Basil L. Contovounesios
  2021-02-14 23:03     ` Óscar Fuentes
@ 2021-02-15  2:34     ` Dmitry Gutov
  2021-02-15  2:47       ` Lars Ingebrigtsen
  1 sibling, 1 reply; 8+ messages in thread
From: Dmitry Gutov @ 2021-02-15  2:34 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: Lars Ingebrigtsen, emacs-devel

On 15.02.2021 00:45, Basil L. Contovounesios wrote:
> That's not counting the obarray's buckets.  I get ~6x as many results in
> my session with (length (all-completions "" obarray #'commandp))

Oh, you're right, thanks. Still, that gives an estimate of how many 
times the function will be called in an average session.

And

   (benchmark 10000 '(derived-mode-p 'prog-mode))

prints ~0.01s here (unless caught in a GC).



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: A faster derived-mode-p
  2021-02-15  2:34     ` Dmitry Gutov
@ 2021-02-15  2:47       ` Lars Ingebrigtsen
  0 siblings, 0 replies; 8+ messages in thread
From: Lars Ingebrigtsen @ 2021-02-15  2:47 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: Basil L. Contovounesios, emacs-devel

Dmitry Gutov <dgutov@yandex.ru> writes:

> Oh, you're right, thanks. Still, that gives an estimate of how many
> times the function will be called in an average session.
>
> And
>
>   (benchmark 10000 '(derived-mode-p 'prog-mode))
>
> prints ~0.01s here (unless caught in a GC).

Oh, thanks.  Then I guess my worries about the speed of that bit, at
least, were premature.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: A faster derived-mode-p
  2021-02-14 23:51 ` Stefan Monnier
@ 2021-02-15  2:56   ` Lars Ingebrigtsen
  0 siblings, 0 replies; 8+ messages in thread
From: Lars Ingebrigtsen @ 2021-02-15  2:56 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> Here's my suggestion:
> Instead of trying to speed up those 10K predicates we're going to have
> to evaluate, we could try to take advantage of the fact that there
> should be a lot of redundancy there.
>
> So we could do something like:
>
>     (let ((cmds (make-hash-table :test #'equal)))
>       (mapatom (lambda (sym)
>                  (when (commandp sym)
>                    (push sym (gethash (command-predicate sym) cmds)))))
>       (let (active-cmds)
>         (maphash (lambda (pred syms)
>                    (when (funcall pred)
>                      (cl-callf nconc active-cmds syms)))
>                  cmds)
>         active-cmds))

Hm, right...  As Dmitry showed, my worries about the inefficiency of
derived-mode-p seem exaggerated, but if it turns out to be a problem (or
we have more complex predicates), then doing something like this seems
promising.

However, the vast, vast number of the predicates basically devolve to
this (on the happy path):

(or (derived-mode-p 'foo-mode)
    (memq 'foo-mode minor-modes)
    (memq 'foo-mode global-minor-modes))

The derived-mode-p is fast, `minor-modes' is typically less than four
elements, and the same with `global-minor-modes'.  I'm not sure that
it's likely that looping over the symbols and entering the predicates
into a hash table has much scope for improving the speed much -- it'll
already be quite speedy.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-02-15  2:56 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-14 20:22 A faster derived-mode-p Lars Ingebrigtsen
2021-02-14 22:25 ` Dmitry Gutov
2021-02-14 22:45   ` Basil L. Contovounesios
2021-02-14 23:03     ` Óscar Fuentes
2021-02-15  2:34     ` Dmitry Gutov
2021-02-15  2:47       ` Lars Ingebrigtsen
2021-02-14 23:51 ` Stefan Monnier
2021-02-15  2:56   ` Lars Ingebrigtsen

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).