From c4d5ddb9ce5cdb8c283928daf6b166e4ce5a430d Mon Sep 17 00:00:00 2001 From: Daniel Pettersson Date: Wed, 28 Feb 2024 13:03:56 +0100 Subject: [PATCH] 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 --- lisp/jsonrpc.el | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el index 14fe0447008..5037d8c5b2b 100644 --- a/lisp/jsonrpc.el +++ b/lisp/jsonrpc.el @@ -4,7 +4,7 @@ ;; Author: João Távora ;; 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 @@ jsonrpc--process-filter (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 @@ jsonrpc--process-filter ;; 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. -- 2.39.3 (Apple Git-145)