perf: verify continuous Flex viewport delivery
This commit is contained in:
parent
256868a7ee
commit
5d1e38856f
5
Makefile
5
Makefile
@ -3,7 +3,7 @@ ECSS_DIR ?= ../ecss
|
|||||||
TP_DIR ?= ../tp
|
TP_DIR ?= ../tp
|
||||||
LOAD_PATH = -L . -L ../ebox -L $(ECSS_DIR) -L $(TP_DIR)
|
LOAD_PATH = -L . -L ../ebox -L $(ECSS_DIR) -L $(TP_DIR)
|
||||||
|
|
||||||
.PHONY: all compile test check checkdoc load clean
|
.PHONY: all compile test check checkdoc load performance-evaluator clean
|
||||||
|
|
||||||
all: check
|
all: check
|
||||||
|
|
||||||
@ -21,6 +21,9 @@ load: compile
|
|||||||
$(EMACS) -Q --batch $(LOAD_PATH) --eval '(require (quote ebox-playground))' \
|
$(EMACS) -Q --batch $(LOAD_PATH) --eval '(require (quote ebox-playground))' \
|
||||||
--eval '(princ "ebox-playground load OK\n")'
|
--eval '(princ "ebox-playground load OK\n")'
|
||||||
|
|
||||||
|
performance-evaluator:
|
||||||
|
EMACS="$(EMACS)" ./scripts/flex-resize-evaluator.sh
|
||||||
|
|
||||||
checkdoc:
|
checkdoc:
|
||||||
$(EMACS) -Q --batch --eval '(progn (require (quote checkdoc)) (dolist (file (directory-files "." t)) (when (string-suffix-p ".el" file) (checkdoc-file file))))'
|
$(EMACS) -Q --batch --eval '(progn (require (quote checkdoc)) (dolist (file (directory-files "." t)) (when (string-suffix-p ".el" file) (checkdoc-file file))))'
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ ECSS 0.1.0 and TP 1.0.0 are independent packages and may be installed in either
|
|||||||
|
|
||||||
Standalone gallery entry points default to a definite 720 px canvas so nested examples have stable space in batch renders and one-window demos. Split-window `.ebox` previews instead bind `(viewport)` to the preview window's display-safe width, so viewport-based separators and sections fit the right-hand pane. `etaf-playground` remains the separate higher-level Component and Runtime showcase.
|
Standalone gallery entry points default to a definite 720 px canvas so nested examples have stable space in batch renders and one-window demos. Split-window `.ebox` previews instead bind `(viewport)` to the preview window's display-safe width, so viewport-based separators and sections fit the right-hand pane. `etaf-playground` remains the separate higher-level Component and Runtime showcase.
|
||||||
|
|
||||||
Standalone and batch fixture renders use the same compact 720 px default viewport unless the caller dynamically binds `ebox-viewport-width`; viewport-based references therefore stay inside the example canvas. When `C-c C-c` renders an `.ebox` source buffer, the command keeps the source on the left, opens the preview on the right, and binds `(viewport)` to Ebox's shared display-safe window width. Continuous window changes are coalesced by Ebox's single viewport controller; the Playground owns no second resize hook or timer.
|
Standalone and batch fixture renders use the same compact 720 px default viewport unless the caller dynamically binds `ebox-viewport-width`; viewport-based references therefore stay inside the example canvas. When `C-c C-c` renders an `.ebox` source buffer, the command keeps the source on the left, opens the preview on the right, and binds `(viewport)` to Ebox's shared display-safe window width. Ebox's single serialized viewport controller publishes every window change immediately through its retained path; the Playground owns no second resize hook or timer.
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(require 'ebox-playground)
|
(require 'ebox-playground)
|
||||||
|
|||||||
@ -6,7 +6,7 @@ ECSS 0.1.0 与 TP 1.0.0 是互相独立的包,安装顺序任意;两者都
|
|||||||
|
|
||||||
独立画廊入口默认使用明确的 720 px 画布,因此 batch 渲染和单窗口演示里的嵌套示例有稳定空间。分屏 `.ebox` 预览则会把 `(viewport)` 绑定为右侧预览窗口的显示安全宽度,所以依赖 viewport 的分隔条和区块会适配右侧窗格。高层 Component/Runtime 展示仍由独立的 `etaf-playground` 提供。
|
独立画廊入口默认使用明确的 720 px 画布,因此 batch 渲染和单窗口演示里的嵌套示例有稳定空间。分屏 `.ebox` 预览则会把 `(viewport)` 绑定为右侧预览窗口的显示安全宽度,所以依赖 viewport 的分隔条和区块会适配右侧窗格。高层 Component/Runtime 展示仍由独立的 `etaf-playground` 提供。
|
||||||
|
|
||||||
独立和 batch fixture 渲染默认也使用紧凑的 720 px 视口;如果调用方动态绑定了 `ebox-viewport-width`,则保留调用方的值。因此依赖 viewport 的参考例子也会保持在示例画布内。通过 `C-c C-c` 渲染 `.ebox` 源文件时,命令会把源文件保留在左侧、在右侧打开预览,并将 `(viewport)` 绑定为 Ebox 统一计算的显示安全宽度;连续 window-size 变化由 Ebox 唯一的 viewport controller 合并,Playground 不再拥有第二套 resize hook 或 timer。
|
独立和 batch fixture 渲染默认也使用紧凑的 720 px 视口;如果调用方动态绑定了 `ebox-viewport-width`,则保留调用方的值。因此依赖 viewport 的参考例子也会保持在示例画布内。通过 `C-c C-c` 渲染 `.ebox` 源文件时,命令会把源文件保留在左侧、在右侧打开预览,并将 `(viewport)` 绑定为 Ebox 统一计算的显示安全宽度;Ebox 唯一且串行的 viewport controller 会立即通过 retained 路径发布每次 window-size 变化,Playground 不再拥有第二套 resize hook 或 timer。
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(require 'ebox-playground)
|
(require 'ebox-playground)
|
||||||
|
|||||||
@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
;; This evaluator exercises the public playground path used by an interactive
|
;; This evaluator exercises the public playground path used by an interactive
|
||||||
;; `.ebox' preview: source buffer on the left, rendered buffer on the right,
|
;; `.ebox' preview: source buffer on the left, rendered buffer on the right,
|
||||||
;; and a real window resize that reaches `window-size-change-functions'.
|
;; and a sustained window-resize burst that reaches
|
||||||
|
;; `window-size-change-functions'.
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
@ -23,6 +24,16 @@
|
|||||||
:type 'number
|
:type 'number
|
||||||
:group 'ebox-playground)
|
:group 'ebox-playground)
|
||||||
|
|
||||||
|
(defcustom ebox-playground-flex-resize-evaluator-max-update-seconds 0.05
|
||||||
|
"Maximum allowed time for one published viewport update."
|
||||||
|
:type 'number
|
||||||
|
:group 'ebox-playground)
|
||||||
|
|
||||||
|
(defcustom ebox-playground-flex-resize-evaluator-max-gap-seconds 0.08
|
||||||
|
"Maximum allowed completion gap during the resize burst."
|
||||||
|
:type 'number
|
||||||
|
:group 'ebox-playground)
|
||||||
|
|
||||||
(defvar ebox-playground-flex-resize-evaluator--output-lines nil
|
(defvar ebox-playground-flex-resize-evaluator--output-lines nil
|
||||||
"Report lines collected during one evaluator run.")
|
"Report lines collected during one evaluator run.")
|
||||||
|
|
||||||
@ -87,14 +98,14 @@ than charging initial frame settling to resize."
|
|||||||
(defun ebox-playground-flex-resize-evaluator-run ()
|
(defun ebox-playground-flex-resize-evaluator-run ()
|
||||||
"Run the real GUI flex preview resize evaluator.
|
"Run the real GUI flex preview resize evaluator.
|
||||||
|
|
||||||
The function returns non-nil only when one splitter resize schedules exactly
|
The function returns non-nil only when a sustained splitter resize burst uses
|
||||||
one Ebox viewport update, publishes valid output, and stays under the timing
|
Ebox's immediate serialized viewport hook, publishes every intermediate and
|
||||||
threshold. It leaves the normal idle-prewarm configuration untouched; the
|
final result through the retained path, and stays under the timing threshold.
|
||||||
daemon evaluator does not enable background prewarm, keeping the measured
|
It leaves the normal idle prewarm configuration untouched; the daemon evaluator
|
||||||
action free of concurrent cache-warming CPU work."
|
does not enable background prewarm, keeping the measured action free of
|
||||||
|
concurrent cache warming CPU work."
|
||||||
(let ((ebox-render-gc-cons-threshold nil)
|
(let ((ebox-render-gc-cons-threshold nil)
|
||||||
(ebox-render-gc-cons-percentage nil)
|
(ebox-render-gc-cons-percentage nil)
|
||||||
(ebox-viewport-resize-delay 0.05)
|
|
||||||
(source nil)
|
(source nil)
|
||||||
(preview nil)
|
(preview nil)
|
||||||
(preview-window nil)
|
(preview-window nil)
|
||||||
@ -102,6 +113,10 @@ action free of concurrent cache-warming CPU work."
|
|||||||
(resize-count 0)
|
(resize-count 0)
|
||||||
(resize-elapsed 0.0)
|
(resize-elapsed 0.0)
|
||||||
(resize-finished nil)
|
(resize-finished nil)
|
||||||
|
(action-start nil)
|
||||||
|
(last-event-elapsed nil)
|
||||||
|
(resize-publications nil)
|
||||||
|
(resize-durations nil)
|
||||||
(completed-without-error nil)
|
(completed-without-error nil)
|
||||||
(ebox-playground-flex-resize-evaluator--output-lines nil)
|
(ebox-playground-flex-resize-evaluator--output-lines nil)
|
||||||
(checks nil))
|
(checks nil))
|
||||||
@ -130,22 +145,40 @@ action free of concurrent cache-warming CPU work."
|
|||||||
(let ((start (float-time)))
|
(let ((start (float-time)))
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(apply original arguments)
|
(apply original arguments)
|
||||||
(setq resize-elapsed
|
(let ((duration (- (float-time) start)))
|
||||||
(+ resize-elapsed (- (float-time) start)))
|
(setq resize-elapsed (+ resize-elapsed duration))
|
||||||
|
(push duration resize-durations))
|
||||||
|
(when action-start
|
||||||
|
(push (- (float-time) action-start)
|
||||||
|
resize-publications))
|
||||||
(setq resize-finished t)))))
|
(setq resize-finished t)))))
|
||||||
(advice-add 'ebox-rerender-buffer-with-context
|
(advice-add 'ebox-rerender-buffer-with-context
|
||||||
:around resize-advice)
|
:around resize-advice)
|
||||||
(let* ((start (float-time))
|
(let* ((start (float-time))
|
||||||
(old-width
|
(old-width
|
||||||
(ebox-playground--window-viewport-width preview-window))
|
(ebox-playground--window-viewport-width preview-window)))
|
||||||
(delta -10)
|
(setq action-start start)
|
||||||
(deadline (+ start 15.0)))
|
(dolist (delta '(-4 2 -4 2 -4 2))
|
||||||
(window-resize preview-window delta t)
|
(setq last-event-elapsed (- (float-time) start))
|
||||||
(while (and (not resize-finished)
|
(window-resize preview-window delta t)
|
||||||
(< (float-time) deadline))
|
|
||||||
(redisplay t)
|
(redisplay t)
|
||||||
(sleep-for 0.01))
|
(sleep-for 0.02))
|
||||||
(let* ((elapsed (- (float-time) start))
|
(let* ((elapsed (- (float-time) start))
|
||||||
|
(publication-times
|
||||||
|
(sort (copy-sequence resize-publications) #'<))
|
||||||
|
(publication-gaps
|
||||||
|
(cl-loop for tail on publication-times
|
||||||
|
while (cdr tail)
|
||||||
|
collect (- (cadr tail) (car tail))))
|
||||||
|
(first-publication (car publication-times))
|
||||||
|
(last-publication (car (last publication-times)))
|
||||||
|
(max-publication
|
||||||
|
(if resize-durations (apply #'max resize-durations) 0.0))
|
||||||
|
(max-gap
|
||||||
|
(if publication-gaps (apply #'max publication-gaps) 0.0))
|
||||||
|
(final-latency
|
||||||
|
(and last-publication
|
||||||
|
(- last-publication last-event-elapsed)))
|
||||||
(viewport-width
|
(viewport-width
|
||||||
(ebox-playground--window-viewport-width preview-window))
|
(ebox-playground--window-viewport-width preview-window))
|
||||||
(report (ebox-buffer-update-report preview))
|
(report (ebox-buffer-update-report preview))
|
||||||
@ -203,10 +236,39 @@ action free of concurrent cache-warming CPU work."
|
|||||||
(window-live-p preview-window))
|
(window-live-p preview-window))
|
||||||
(format "source=%S preview=%S" source preview))
|
(format "source=%S preview=%S" source preview))
|
||||||
(ebox-playground-flex-resize-evaluator--check
|
(ebox-playground-flex-resize-evaluator--check
|
||||||
"one resize update"
|
"intermediate resize updates"
|
||||||
(= resize-count 1)
|
(and (>= resize-count 4)
|
||||||
(format "ebox-rerender-buffer-with-context=%d"
|
first-publication
|
||||||
resize-count))
|
(<= first-publication
|
||||||
|
ebox-playground-flex-resize-evaluator-max-update-seconds)
|
||||||
|
(< first-publication last-event-elapsed))
|
||||||
|
(format "updates=%d first=%.6fs last-event=%.6fs"
|
||||||
|
resize-count
|
||||||
|
(or first-publication 0.0)
|
||||||
|
last-event-elapsed))
|
||||||
|
(ebox-playground-flex-resize-evaluator--check
|
||||||
|
"per-update resize budget"
|
||||||
|
(<= max-publication
|
||||||
|
ebox-playground-flex-resize-evaluator-max-update-seconds)
|
||||||
|
(format "max=%.6fs threshold=%.6fs"
|
||||||
|
max-publication
|
||||||
|
ebox-playground-flex-resize-evaluator-max-update-seconds))
|
||||||
|
(ebox-playground-flex-resize-evaluator--check
|
||||||
|
"continuous resize cadence"
|
||||||
|
(<= max-gap
|
||||||
|
ebox-playground-flex-resize-evaluator-max-gap-seconds)
|
||||||
|
(format "max-gap=%.6fs threshold=%.6fs"
|
||||||
|
max-gap
|
||||||
|
ebox-playground-flex-resize-evaluator-max-gap-seconds))
|
||||||
|
(ebox-playground-flex-resize-evaluator--check
|
||||||
|
"final resize latency"
|
||||||
|
(and final-latency
|
||||||
|
(>= final-latency 0)
|
||||||
|
(<= final-latency
|
||||||
|
ebox-playground-flex-resize-evaluator-max-update-seconds))
|
||||||
|
(format "final=%.6fs threshold=%.6fs"
|
||||||
|
(or final-latency -1.0)
|
||||||
|
ebox-playground-flex-resize-evaluator-max-update-seconds))
|
||||||
(ebox-playground-flex-resize-evaluator--check
|
(ebox-playground-flex-resize-evaluator--check
|
||||||
"resize completed"
|
"resize completed"
|
||||||
resize-finished
|
resize-finished
|
||||||
@ -249,8 +311,10 @@ action free of concurrent cache-warming CPU work."
|
|||||||
elapsed
|
elapsed
|
||||||
ebox-playground-flex-resize-evaluator-max-seconds))))
|
ebox-playground-flex-resize-evaluator-max-seconds))))
|
||||||
(push (format
|
(push (format
|
||||||
"RESIZE old-viewport-px=%S new-viewport-px=%S total=%.6fs rerender=%.6fs strategy=%S projection=%S axes=%S reconciled=%S native-flex=%S tp-ops=%S cache-hits=%S cache-misses=%S"
|
"RESIZE old-viewport-px=%S new-viewport-px=%S total=%.6fs rerender=%.6fs first=%.6fs max-update=%.6fs max-gap=%.6fs final=%.6fs strategy=%S projection=%S axes=%S reconciled=%S native-flex=%S tp-ops=%S cache-hits=%S cache-misses=%S"
|
||||||
old-width viewport-width elapsed resize-elapsed
|
old-width viewport-width elapsed resize-elapsed
|
||||||
|
(or first-publication 0.0) max-publication max-gap
|
||||||
|
(or final-latency -1.0)
|
||||||
(plist-get report :strategy) projection-kind
|
(plist-get report :strategy) projection-kind
|
||||||
(plist-get report :viewport-axes)
|
(plist-get report :viewport-axes)
|
||||||
(plist-get report :reconciled-objects)
|
(plist-get report :reconciled-objects)
|
||||||
|
|||||||
@ -15,7 +15,7 @@ trap cleanup EXIT INT TERM
|
|||||||
# that directly affect this render path. Loading the complete user init would
|
# that directly affect this render path. Loading the complete user init would
|
||||||
# add unrelated packages, timers, and UI state to the performance gate.
|
# add unrelated packages, timers, and UI state to the performance gate.
|
||||||
"$emacs" -Q --daemon="$server" \
|
"$emacs" -Q --daemon="$server" \
|
||||||
-L "$root" -L "$root/../ebox" -L "$root/../new-architecture/ecss" \
|
-L "$root" -L "$root/../ebox" -L "$root/../ecss" \
|
||||||
-L "$root/../tp" \
|
-L "$root/../tp" \
|
||||||
--eval '(setq load-prefer-newer t
|
--eval '(setq load-prefer-newer t
|
||||||
gc-cons-threshold most-positive-fixnum
|
gc-cons-threshold most-positive-fixnum
|
||||||
|
|||||||
@ -305,8 +305,7 @@
|
|||||||
(ert-deftest ebox-playground-preview-resizes-through-ebox-viewport-update ()
|
(ert-deftest ebox-playground-preview-resizes-through-ebox-viewport-update ()
|
||||||
"A preview resize should publish an incremental Ebox viewport update."
|
"A preview resize should publish an incremental Ebox viewport update."
|
||||||
(let ((preview "*Ebox Preview: /tmp/ebox-playground-viewport-resize.ebox*")
|
(let ((preview "*Ebox Preview: /tmp/ebox-playground-viewport-resize.ebox*")
|
||||||
(window-width 987)
|
(window-width 987))
|
||||||
(ebox-viewport-resize-delay 0))
|
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(cl-letf (((symbol-function 'window-body-width)
|
(cl-letf (((symbol-function 'window-body-width)
|
||||||
(lambda (&optional _window _pixelwise) window-width))
|
(lambda (&optional _window _pixelwise) window-width))
|
||||||
@ -323,16 +322,7 @@
|
|||||||
(should (memq #'ebox--window-size-change
|
(should (memq #'ebox--window-size-change
|
||||||
window-size-change-functions))
|
window-size-change-functions))
|
||||||
(let ((noninteractive nil))
|
(let ((noninteractive nil))
|
||||||
(ebox--window-size-change (window-frame window)))
|
(ebox--window-size-change (window-frame window)))))
|
||||||
;; Batch Emacs does not service idle timers from `sit-for'.
|
|
||||||
(let ((pending
|
|
||||||
(gethash (current-buffer)
|
|
||||||
ebox--viewport-resize-pending-table)))
|
|
||||||
(should pending)
|
|
||||||
(when (timerp (aref pending 4))
|
|
||||||
(cancel-timer (aref pending 4)))
|
|
||||||
(ebox--viewport-resize-apply
|
|
||||||
(current-buffer) (aref pending 0)))))
|
|
||||||
(with-current-buffer preview
|
(with-current-buffer preview
|
||||||
(should (= (ebox-playground-test--max-line-width
|
(should (= (ebox-playground-test--max-line-width
|
||||||
(buffer-string))
|
(buffer-string))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user