aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/perf-perspective.el128
1 files changed, 128 insertions, 0 deletions
diff --git a/test/perf-perspective.el b/test/perf-perspective.el
new file mode 100644
index 0000000..aa43352
--- /dev/null
+++ b/test/perf-perspective.el
@@ -0,0 +1,128 @@
+;;; perf-perspective.el --- Performance harness for Perspective -*- lexical-binding: t; -*-
+
+;; Licensed under the same terms as Emacs and under the MIT license.
+
+;; URL: http://github.com/nex3/perspective-el
+;; Created: 2026-03-30
+
+;;; Commentary:
+
+;; This file provides an opt-in batch harness for comparing Perspective buffer
+;; killing behavior across revisions. It is intentionally not part of the
+;; default ERT suite.
+;;
+;; Run from the repository root with:
+;;
+;; make perf
+;;
+;; Or directly:
+;;
+;; emacs -Q --batch -L . -l test/perf-perspective.el --eval "(persp-perf-run)"
+;;
+;; Customize the run with:
+;;
+;; (let ((persp-perf-num-perspectives 16)
+;; (persp-perf-buffers-per-perspective 24)
+;; (persp-perf-temp-buffers-per-perspective 8)
+;; (persp-perf-iterations 15))
+;; (persp-perf-run))
+
+;;; Code:
+
+(require 'benchmark)
+(require 'cl-lib)
+(require 'perspective)
+
+(defvar persp-perf-num-perspectives 12
+ "How many non-main perspectives to create for the performance harness.")
+
+(defvar persp-perf-buffers-per-perspective 20
+ "How many ordinary buffers to create in each perspective.")
+
+(defvar persp-perf-temp-buffers-per-perspective 6
+ "How many temporary buffers to create in each perspective.")
+
+(defvar persp-perf-iterations 10
+ "How many times to run each benchmark scenario.")
+
+(defun persp-perf--cleanup-buffers ()
+ "Kill all live buffers except the startup scratch buffer."
+ (let ((scratch (get-buffer "*scratch*")))
+ (dolist (buffer (buffer-list))
+ (when (and (buffer-live-p buffer)
+ (not (eq buffer scratch)))
+ (kill-buffer buffer)))))
+
+(defmacro persp-perf--with-environment (&rest body)
+ "Run BODY in a fresh Perspective environment and clean up afterward."
+ (declare (indent 0))
+ `(let ((persp-suppress-no-prefix-key-warning t)
+ (persp-feature-flag-prevent-killing-last-buffer-in-perspective t))
+ (persp-perf--cleanup-buffers)
+ (persp-mode 1)
+ (unwind-protect
+ (progn ,@body)
+ (persp-mode -1)
+ (persp-perf--cleanup-buffers))))
+
+(defun persp-perf--populate-perspectives ()
+ "Populate multiple perspectives with ordinary and temporary buffers."
+ (cl-loop for idx from 1 to persp-perf-num-perspectives do
+ (let ((persp-name (format "P%d" idx)))
+ (persp-switch persp-name)
+ (cl-loop for buf-idx from 1 to persp-perf-buffers-per-perspective do
+ (switch-to-buffer (format "*%s-buf-%02d*" persp-name buf-idx)))
+ (cl-loop for tmp-idx from 1 to persp-perf-temp-buffers-per-perspective do
+ (switch-to-buffer (format " %s-temp-%02d" persp-name tmp-idx)))))
+ (persp-switch "main"))
+
+(defun persp-perf--scenario-unrelated-kill ()
+ "Kill a buffer from the current perspective while other perspectives are unrelated."
+ (persp-perf--with-environment
+ (persp-perf--populate-perspectives)
+ (let ((target (switch-to-buffer "*perf-target*")))
+ (switch-to-buffer "*perf-helper*")
+ (switch-to-buffer target)
+ (kill-buffer target))))
+
+(defun persp-perf--scenario-shared-keeper ()
+ "Kill a shared buffer that must remain alive in another perspective."
+ (persp-perf--with-environment
+ (let ((ido-ignore-buffers '("^\\*scratch\\*")))
+ (persp-perf--populate-perspectives)
+ (let ((target (switch-to-buffer "*perf-target*")))
+ (persp-switch "P1")
+ (switch-to-buffer target)
+ (persp-switch "main")
+ (switch-to-buffer "*perf-helper*")
+ (switch-to-buffer target)
+ (kill-buffer target)))))
+
+(defun persp-perf--benchmark (name function)
+ "Run benchmark NAME by calling FUNCTION `persp-perf-iterations' times."
+ (let ((result (benchmark-run persp-perf-iterations (funcall function))))
+ (message "%s" name)
+ (message " iterations: %d" persp-perf-iterations)
+ (message " elapsed: %.6fs" (nth 0 result))
+ (message " gc-count: %d" (nth 1 result))
+ (message " gc-elapsed: %.6fs" (nth 2 result))
+ (message "")))
+
+(defun persp-perf-run ()
+ "Run the Perspective performance harness in batch mode."
+ (interactive)
+ (message "Perspective performance harness")
+ (message " perspectives: %d" persp-perf-num-perspectives)
+ (message " regular buffers / perspective: %d" persp-perf-buffers-per-perspective)
+ (message " temp buffers / perspective: %d" persp-perf-temp-buffers-per-perspective)
+ (message "")
+ (persp-perf--benchmark
+ "Scenario 1: kill buffer with unrelated other perspectives"
+ #'persp-perf--scenario-unrelated-kill)
+ (persp-perf--benchmark
+ "Scenario 2: kill shared buffer that another perspective must keep"
+ #'persp-perf--scenario-shared-keeper))
+
+(provide 'perf-perspective)
+
+;;; perf-perspective.el ends here