perf: defer GC across interactive viewport rerenders
This commit is contained in:
parent
c591a9fcf4
commit
b25328198c
31
ebox.el
31
ebox.el
@ -4626,18 +4626,25 @@ When VIEWPORT-HEIGHT is non-nil, height values using `(viewport-height)' are
|
|||||||
resolved against that line count.
|
resolved against that line count.
|
||||||
This preserves node and region identity and routes viewport-dependent changes
|
This preserves node and region identity and routes viewport-dependent changes
|
||||||
through dirty-set and patch-set execution before falling back to root rerender."
|
through dirty-set and patch-set execution before falling back to root rerender."
|
||||||
(let* ((state (ebox--buffer-render-state buffer))
|
(let ((execute
|
||||||
(old-viewport-width (and state
|
(lambda ()
|
||||||
(plist-get state :viewport-width))))
|
(let* ((state (ebox--buffer-render-state buffer))
|
||||||
(unless (ebox-surface-buffer-mounted-p buffer)
|
(old-viewport-width
|
||||||
(user-error "Ebox buffer has no mounted TP surface: %S" buffer))
|
(and state (plist-get state :viewport-width))))
|
||||||
(ebox--cancel-buffer-runtime-prewarm buffer)
|
(unless (ebox-surface-buffer-mounted-p buffer)
|
||||||
(prog1
|
(user-error "Ebox buffer has no mounted TP surface: %S" buffer))
|
||||||
(ebox-surface-update-buffer-viewport
|
(ebox--cancel-buffer-runtime-prewarm buffer)
|
||||||
buffer viewport-width viewport-height)
|
(prog1
|
||||||
(ebox--schedule-buffer-runtime-prewarm buffer nil t)
|
(ebox-surface-update-buffer-viewport
|
||||||
(ebox--schedule-buffer-reflow-cache-prewarm
|
buffer viewport-width viewport-height)
|
||||||
buffer old-viewport-width viewport-width))))
|
(ebox--schedule-buffer-runtime-prewarm buffer nil t)
|
||||||
|
(ebox--schedule-buffer-reflow-cache-prewarm
|
||||||
|
buffer old-viewport-width viewport-width))))))
|
||||||
|
(if noninteractive
|
||||||
|
(ebox--with-render-gc
|
||||||
|
(funcall execute))
|
||||||
|
(ebox--with-deferred-render-gc
|
||||||
|
(funcall execute)))))
|
||||||
|
|
||||||
(defun ebox--rerender-buffer-preserving-runtime (buffer)
|
(defun ebox--rerender-buffer-preserving-runtime (buffer)
|
||||||
"Rerender BUFFER from stored runtime state without rebuilding identity."
|
"Rerender BUFFER from stored runtime state without rebuilding identity."
|
||||||
|
|||||||
@ -3277,6 +3277,103 @@
|
|||||||
(when (and buffer (buffer-live-p buffer))
|
(when (and buffer (buffer-live-p buffer))
|
||||||
(kill-buffer buffer)))))
|
(kill-buffer buffer)))))
|
||||||
|
|
||||||
|
(ert-deftest ebox-interactive-viewport-rerender-owns-deferred-render-gc ()
|
||||||
|
"Keep GC outside an interactive viewport transaction until it settles."
|
||||||
|
(ebox-test--reset-runtime-state)
|
||||||
|
(let ((ebox-runtime-idle-prewarm nil)
|
||||||
|
(ebox-runtime-idle-reflow-cache-prewarm nil)
|
||||||
|
(buffer nil))
|
||||||
|
(unwind-protect
|
||||||
|
(progn
|
||||||
|
(setq buffer
|
||||||
|
(ebox-render-to-buffer
|
||||||
|
(generate-new-buffer-name " *ebox-test*")
|
||||||
|
(ebox-create :width '(viewport) :content "resize")))
|
||||||
|
(let ((noninteractive nil)
|
||||||
|
(gc-cons-threshold 1000)
|
||||||
|
(gc-cons-percentage 0.1)
|
||||||
|
(ebox-deferred-render-gc-cons-threshold 4000)
|
||||||
|
(ebox-render-gc-cons-percentage 0.8)
|
||||||
|
(ebox--deferred-render-gc-state nil)
|
||||||
|
(ebox--deferred-render-gc-timer nil)
|
||||||
|
(ebox--deferred-render-gc-depth 0)
|
||||||
|
(original-update
|
||||||
|
(symbol-function 'ebox-surface-update-buffer-viewport))
|
||||||
|
observed-threshold
|
||||||
|
observed-depth
|
||||||
|
scheduled
|
||||||
|
(gc-count 0))
|
||||||
|
(cl-letf (((symbol-function 'ebox-surface-update-buffer-viewport)
|
||||||
|
(lambda (&rest arguments)
|
||||||
|
(setq observed-threshold gc-cons-threshold
|
||||||
|
observed-depth ebox--deferred-render-gc-depth)
|
||||||
|
(apply original-update arguments)))
|
||||||
|
((symbol-function 'run-at-time)
|
||||||
|
(lambda (delay _repeat function &rest arguments)
|
||||||
|
(setq scheduled (list delay function arguments))
|
||||||
|
'ebox-test-viewport-gc-timer))
|
||||||
|
((symbol-function 'timerp)
|
||||||
|
(lambda (value)
|
||||||
|
(eq value 'ebox-test-viewport-gc-timer)))
|
||||||
|
((symbol-function 'cancel-timer) #'ignore)
|
||||||
|
((symbol-function 'garbage-collect)
|
||||||
|
(lambda () (cl-incf gc-count))))
|
||||||
|
(ebox-rerender-buffer-with-context buffer 320)
|
||||||
|
(should (= observed-threshold 4000))
|
||||||
|
(should (= observed-depth 1))
|
||||||
|
(should (= (plist-get (ebox--buffer-render-state buffer)
|
||||||
|
:viewport-width)
|
||||||
|
320))
|
||||||
|
(should (= ebox--deferred-render-gc-depth 0))
|
||||||
|
(should ebox--deferred-render-gc-state)
|
||||||
|
(should (eq ebox--deferred-render-gc-timer
|
||||||
|
'ebox-test-viewport-gc-timer))
|
||||||
|
(should (= (car scheduled) 0.2))
|
||||||
|
(apply (nth 1 scheduled) (nth 2 scheduled))
|
||||||
|
(should (= gc-cons-threshold 1000))
|
||||||
|
(should (= gc-cons-percentage 0.1))
|
||||||
|
(should (= gc-count 1)))))
|
||||||
|
(ebox-test--reset-runtime-state)
|
||||||
|
(when (and buffer (buffer-live-p buffer))
|
||||||
|
(kill-buffer buffer)))))
|
||||||
|
|
||||||
|
(ert-deftest ebox-batch-viewport-rerender-uses-render-gc-boundary ()
|
||||||
|
"Raise GC only during a batch viewport transaction and restore on return."
|
||||||
|
(ebox-test--reset-runtime-state)
|
||||||
|
(let ((ebox-runtime-idle-prewarm nil)
|
||||||
|
(ebox-runtime-idle-reflow-cache-prewarm nil)
|
||||||
|
(buffer nil))
|
||||||
|
(unwind-protect
|
||||||
|
(progn
|
||||||
|
(setq buffer
|
||||||
|
(ebox-render-to-buffer
|
||||||
|
(generate-new-buffer-name " *ebox-test*")
|
||||||
|
(ebox-create :width '(viewport) :content "resize")))
|
||||||
|
(let ((noninteractive t)
|
||||||
|
(gc-cons-threshold 1000)
|
||||||
|
(gc-cons-percentage 0.1)
|
||||||
|
(ebox-render-gc-cons-threshold 4000)
|
||||||
|
(ebox-render-gc-cons-percentage 0.8)
|
||||||
|
(original-update
|
||||||
|
(symbol-function 'ebox-surface-update-buffer-viewport))
|
||||||
|
observed-threshold
|
||||||
|
observed-percentage)
|
||||||
|
(cl-letf (((symbol-function 'ebox-surface-update-buffer-viewport)
|
||||||
|
(lambda (&rest arguments)
|
||||||
|
(setq observed-threshold gc-cons-threshold
|
||||||
|
observed-percentage gc-cons-percentage)
|
||||||
|
(apply original-update arguments))))
|
||||||
|
(ebox-rerender-buffer-with-context buffer 320))
|
||||||
|
(should (= observed-threshold 4000))
|
||||||
|
(should (= observed-percentage 0.8))
|
||||||
|
(should (= gc-cons-threshold 1000))
|
||||||
|
(should (= gc-cons-percentage 0.1))
|
||||||
|
(should-not ebox--deferred-render-gc-state)
|
||||||
|
(should-not ebox--deferred-render-gc-timer)))
|
||||||
|
(ebox-test--reset-runtime-state)
|
||||||
|
(when (and buffer (buffer-live-p buffer))
|
||||||
|
(kill-buffer buffer)))))
|
||||||
|
|
||||||
(ert-deftest ebox-deferred-render-gc-can-raise-an-active-burst-budget ()
|
(ert-deftest ebox-deferred-render-gc-can-raise-an-active-burst-budget ()
|
||||||
"Measured layout pressure should only raise an active burst budget."
|
"Measured layout pressure should only raise an active burst budget."
|
||||||
(let ((gc-cons-threshold 1000)
|
(let ((gc-cons-threshold 1000)
|
||||||
|
|||||||
@ -59,7 +59,7 @@
|
|||||||
(lambda (_window)
|
(lambda (_window)
|
||||||
(error "Window outer width must not be sampled")))
|
(error "Window outer width must not be sampled")))
|
||||||
((symbol-function 'window-body-height)
|
((symbol-function 'window-body-height)
|
||||||
(lambda (_window) 31)))
|
(lambda (_window &optional _pixelwise) 31)))
|
||||||
(let ((values (ebox-surface--context-values buffer nil nil)))
|
(let ((values (ebox-surface--context-values buffer nil nil)))
|
||||||
(should (= 775 (plist-get values :viewport-width)))
|
(should (= 775 (plist-get values :viewport-width)))
|
||||||
(should (= 31 (plist-get values :viewport-height)))))
|
(should (= 31 (plist-get values :viewport-height)))))
|
||||||
@ -92,7 +92,7 @@
|
|||||||
((symbol-function 'window-pixel-width)
|
((symbol-function 'window-pixel-width)
|
||||||
(lambda (_window) 1430))
|
(lambda (_window) 1430))
|
||||||
((symbol-function 'window-body-height)
|
((symbol-function 'window-body-height)
|
||||||
(lambda (_window) 62)))
|
(lambda (_window &optional _pixelwise) 62)))
|
||||||
(let ((values (ebox-surface--context-values buffer nil nil)))
|
(let ((values (ebox-surface--context-values buffer nil nil)))
|
||||||
(should (= 1428 (plist-get values :viewport-width)))
|
(should (= 1428 (plist-get values :viewport-width)))
|
||||||
(should (= 62 (plist-get values :viewport-height)))))
|
(should (= 62 (plist-get values :viewport-height)))))
|
||||||
@ -130,7 +130,7 @@
|
|||||||
(should pixelwise)
|
(should pixelwise)
|
||||||
1400))
|
1400))
|
||||||
((symbol-function 'window-body-height)
|
((symbol-function 'window-body-height)
|
||||||
(lambda (candidate)
|
(lambda (candidate &optional _pixelwise)
|
||||||
(should (eq candidate window))
|
(should (eq candidate window))
|
||||||
60)))
|
60)))
|
||||||
(let ((values (ebox-surface--context-values buffer nil nil)))
|
(let ((values (ebox-surface--context-values buffer nil nil)))
|
||||||
@ -163,7 +163,7 @@
|
|||||||
(should pixelwise)
|
(should pixelwise)
|
||||||
(if (eq window 'current-frame-window) 901 333)))
|
(if (eq window 'current-frame-window) 901 333)))
|
||||||
((symbol-function 'window-body-height)
|
((symbol-function 'window-body-height)
|
||||||
(lambda (_window) 31)))
|
(lambda (_window &optional _pixelwise) 31)))
|
||||||
(let ((values (ebox-surface--context-values buffer nil nil)))
|
(let ((values (ebox-surface--context-values buffer nil nil)))
|
||||||
(should (= 899 (plist-get values :viewport-width)))
|
(should (= 899 (plist-get values :viewport-width)))
|
||||||
(should (= 31 (plist-get values :viewport-height)))))
|
(should (= 31 (plist-get values :viewport-height)))))
|
||||||
@ -188,7 +188,7 @@
|
|||||||
((symbol-function 'ebox-surface--window-content-width)
|
((symbol-function 'ebox-surface--window-content-width)
|
||||||
(lambda (_window) 240))
|
(lambda (_window) 240))
|
||||||
((symbol-function 'window-body-height)
|
((symbol-function 'window-body-height)
|
||||||
(lambda (_window) 20))
|
(lambda (_window &optional _pixelwise) 20))
|
||||||
((symbol-function 'ebox-rerender-buffer-with-context)
|
((symbol-function 'ebox-rerender-buffer-with-context)
|
||||||
(lambda (target width height)
|
(lambda (target width height)
|
||||||
(setq calls (list target width height))))
|
(setq calls (list target width height))))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user