Jsonrpc: improve performance of process filter function

`run-at-time' keeps `timer-list' list sorted by inserting each
timer based on the timer value.  This means that
`timer--time-less-p' needs is executed ~N*N/2 times for each N
pending messages.  This means that jsonrpc becomes unusable
for connections that generate a lot messages at the same time.

* lisp/jsonrpc.el (Version): Bump to 1.0.25.
(jsonrpc--process-filter): Improve performance by activating
timers in a different order.  (Bug#69241)
This commit is contained in:
Daniel Pettersson 2024-02-28 13:03:56 +01:00 committed by Eli Zaretskii
parent d5773276fb
commit 7c552b22e6

View file

@ -4,7 +4,7 @@
;; Author: João Távora <joaotavora@gmail.com>
;; Keywords: processes, languages, extensions
;; Version: 1.0.24
;; Version: 1.0.25
;; Package-Requires: ((emacs "25.2"))
;; This is a GNU ELPA :core package. Avoid functionality that is not
@ -760,10 +760,11 @@ With optional CLEANUP, kill any associated buffers."
(setq message
(plist-put message :jsonrpc-json
(buffer-string)))
(process-put proc 'jsonrpc-mqueue
(nconc (process-get proc
'jsonrpc-mqueue)
(list message)))))
;; Put new messages at the front of the queue,
;; this is correct as the order is reversed
;; before putting the timers on `timer-list'.
(push message
(process-get proc 'jsonrpc-mqueue))))
(goto-char message-end)
(let ((inhibit-read-only t))
(delete-region (point-min) (point)))
@ -782,11 +783,20 @@ With optional CLEANUP, kill any associated buffers."
;; non-locally (typically the reply to a request), so do
;; this all this processing in top-level loops timer.
(cl-loop
;; `timer-activate' orders timers by time, which is an
;; very expensive operation when jsonrpc-mqueue is large,
;; therefore the time object is reused for each timer
;; created.
with time = (current-time)
for msg = (pop (process-get proc 'jsonrpc-mqueue)) while msg
do (run-at-time 0 nil
(lambda (m) (with-temp-buffer
(jsonrpc-connection-receive conn m)))
msg)))))))
do (let ((timer (timer-create)))
(timer-set-time timer time)
(timer-set-function timer
(lambda (conn msg)
(with-temp-buffer
(jsonrpc-connection-receive conn msg)))
(list conn msg))
(timer-activate timer))))))))
(defun jsonrpc--remove (conn id &optional deferred-spec)
"Cancel CONN's continuations for ID, including its timer, if it exists.