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.
|
||||
This preserves node and region identity and routes viewport-dependent changes
|
||||
through dirty-set and patch-set execution before falling back to root rerender."
|
||||
(let* ((state (ebox--buffer-render-state buffer))
|
||||
(old-viewport-width (and state
|
||||
(plist-get state :viewport-width))))
|
||||
(unless (ebox-surface-buffer-mounted-p buffer)
|
||||
(user-error "Ebox buffer has no mounted TP surface: %S" buffer))
|
||||
(ebox--cancel-buffer-runtime-prewarm buffer)
|
||||
(prog1
|
||||
(ebox-surface-update-buffer-viewport
|
||||
buffer viewport-width viewport-height)
|
||||
(ebox--schedule-buffer-runtime-prewarm buffer nil t)
|
||||
(ebox--schedule-buffer-reflow-cache-prewarm
|
||||
buffer old-viewport-width viewport-width))))
|
||||
(let ((execute
|
||||
(lambda ()
|
||||
(let* ((state (ebox--buffer-render-state buffer))
|
||||
(old-viewport-width
|
||||
(and state (plist-get state :viewport-width))))
|
||||
(unless (ebox-surface-buffer-mounted-p buffer)
|
||||
(user-error "Ebox buffer has no mounted TP surface: %S" buffer))
|
||||
(ebox--cancel-buffer-runtime-prewarm buffer)
|
||||
(prog1
|
||||
(ebox-surface-update-buffer-viewport
|
||||
buffer viewport-width viewport-height)
|
||||
(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)
|
||||
"Rerender BUFFER from stored runtime state without rebuilding identity."
|
||||
|
||||
@ -3277,6 +3277,103 @@
|
||||
(when (and buffer (buffer-live-p 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 ()
|
||||
"Measured layout pressure should only raise an active burst budget."
|
||||
(let ((gc-cons-threshold 1000)
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
(lambda (_window)
|
||||
(error "Window outer width must not be sampled")))
|
||||
((symbol-function 'window-body-height)
|
||||
(lambda (_window) 31)))
|
||||
(lambda (_window &optional _pixelwise) 31)))
|
||||
(let ((values (ebox-surface--context-values buffer nil nil)))
|
||||
(should (= 775 (plist-get values :viewport-width)))
|
||||
(should (= 31 (plist-get values :viewport-height)))))
|
||||
@ -92,7 +92,7 @@
|
||||
((symbol-function 'window-pixel-width)
|
||||
(lambda (_window) 1430))
|
||||
((symbol-function 'window-body-height)
|
||||
(lambda (_window) 62)))
|
||||
(lambda (_window &optional _pixelwise) 62)))
|
||||
(let ((values (ebox-surface--context-values buffer nil nil)))
|
||||
(should (= 1428 (plist-get values :viewport-width)))
|
||||
(should (= 62 (plist-get values :viewport-height)))))
|
||||
@ -130,7 +130,7 @@
|
||||
(should pixelwise)
|
||||
1400))
|
||||
((symbol-function 'window-body-height)
|
||||
(lambda (candidate)
|
||||
(lambda (candidate &optional _pixelwise)
|
||||
(should (eq candidate window))
|
||||
60)))
|
||||
(let ((values (ebox-surface--context-values buffer nil nil)))
|
||||
@ -163,7 +163,7 @@
|
||||
(should pixelwise)
|
||||
(if (eq window 'current-frame-window) 901 333)))
|
||||
((symbol-function 'window-body-height)
|
||||
(lambda (_window) 31)))
|
||||
(lambda (_window &optional _pixelwise) 31)))
|
||||
(let ((values (ebox-surface--context-values buffer nil nil)))
|
||||
(should (= 899 (plist-get values :viewport-width)))
|
||||
(should (= 31 (plist-get values :viewport-height)))))
|
||||
@ -188,7 +188,7 @@
|
||||
((symbol-function 'ebox-surface--window-content-width)
|
||||
(lambda (_window) 240))
|
||||
((symbol-function 'window-body-height)
|
||||
(lambda (_window) 20))
|
||||
(lambda (_window &optional _pixelwise) 20))
|
||||
((symbol-function 'ebox-rerender-buffer-with-context)
|
||||
(lambda (target width height)
|
||||
(setq calls (list target width height))))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user