Three fixes: 1. Patch 0000 now compiles standalone: replaced forward declaration of ns_ax_face_is_selected (defined in VoiceOver patches) with self-contained ns_zoom_face_is_selected in the Zoom patch. 2. ns_accessibility_enabled defaults to nil: eliminates ALL VoiceOver overhead (text cache rebuild, AX notifications, Mach IPC to AX server) when VoiceOver is not in use. Zero per-redisplay cost. Enable with (setq ns-accessibility-enabled t). 3. UAZoomEnabled() cached for 1s + ns_zoom_track_completion rate- limited to 2Hz: eliminates 150-600µs/frame of IPC overhead.
107 lines
4.1 KiB
Diff
107 lines
4.1 KiB
Diff
From 36b206ece4323fb4a81b92d056291b4835ffd907 Mon Sep 17 00:00:00 2001
|
|
From: Daneel <daneel@sukany.cz>
|
|
Date: Sun, 1 Mar 2026 05:50:40 +0100
|
|
Subject: [PATCH 11/11] perf: cache UAZoomEnabled() result and rate-limit
|
|
completion tracking
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
UAZoomEnabled() is a synchronous Mach IPC roundtrip to the macOS
|
|
Accessibility server (~50-200 µs per call). Called from
|
|
ns_draw_window_cursor, ns_update_end and ns_zoom_track_completion
|
|
on every redisplay cycle, the total cost reaches ~150-600 µs/frame.
|
|
At 60 fps this adds 9-36 ms/s of IPC overhead that blocks the main
|
|
thread and amplifies Emacs's inherent per-frame redisplay cost.
|
|
|
|
* src/nsterm.m (ns_zoom_cached_enabled, ns_zoom_cache_time): New
|
|
static variables for caching the UAZoomEnabled() result.
|
|
(ns_zoom_enabled_p): New function. Cache UAZoomEnabled() for one
|
|
second using CFAbsoluteTimeGetCurrent() (a near-free VDSO read).
|
|
Zoom state changes only on explicit user action in System Settings.
|
|
(ns_zoom_track_completion): Rate-limit to 2 Hz. Completion state
|
|
changes at human interaction speed; 500 ms polling is imperceptible.
|
|
---
|
|
src/nsterm.m | 40 +++++++++++++++++++++++++++++++++++++---
|
|
1 file changed, 37 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/src/nsterm.m b/src/nsterm.m
|
|
index 1da6f41..27607c0 100644
|
|
--- a/src/nsterm.m
|
|
+++ b/src/nsterm.m
|
|
@@ -1087,6 +1087,29 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
|
|
#if defined (MAC_OS_X_VERSION_MIN_REQUIRED) \
|
|
&& MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
|
|
|
|
+/* Cached wrapper around ns_zoom_enabled_p ().
|
|
+ ns_zoom_enabled_p () performs a synchronous Mach IPC roundtrip to the
|
|
+ macOS Accessibility server (~50-200 µs per call). With call sites
|
|
+ in ns_draw_window_cursor, ns_update_end, and ns_zoom_track_completion,
|
|
+ the overhead accumulates to ~150-600 µs per redisplay cycle. Zoom
|
|
+ state changes only on explicit user action in System Settings, so a
|
|
+ 1-second TTL is safe and indistinguishable from querying every frame.
|
|
+ Uses CFAbsoluteTimeGetCurrent() (~5 ns, a VDSO read) for timing. */
|
|
+static BOOL ns_zoom_cached_enabled;
|
|
+static CFAbsoluteTime ns_zoom_cache_time;
|
|
+
|
|
+static BOOL
|
|
+ns_zoom_enabled_p (void)
|
|
+{
|
|
+ CFAbsoluteTime now = CFAbsoluteTimeGetCurrent ();
|
|
+ if (now - ns_zoom_cache_time > 1.0)
|
|
+ {
|
|
+ ns_zoom_cached_enabled = UAZoomEnabled ();
|
|
+ ns_zoom_cache_time = now;
|
|
+ }
|
|
+ return ns_zoom_cached_enabled;
|
|
+}
|
|
+
|
|
/* Identify faces that mark a selected completion candidate.
|
|
Matches vertico-current, corfu-current, icomplete-selected-match,
|
|
ivy-current-match, etc. by checking the face symbol name.
|
|
@@ -1235,11 +1258,22 @@ If a completion candidate is selected (overlay or child frame),
|
|
static void
|
|
ns_zoom_track_completion (struct frame *f, EmacsView *view)
|
|
{
|
|
- if (!UAZoomEnabled ())
|
|
+ if (!ns_zoom_enabled_p ())
|
|
return;
|
|
if (!WINDOWP (f->selected_window))
|
|
return;
|
|
|
|
+ /* Rate-limit completion scan to 2 Hz. Completion state changes at
|
|
+ human interaction speed; checking every 500 ms eliminates
|
|
+ per-redisplay FOR_EACH_FRAME overhead with no perceptible lag. */
|
|
+ {
|
|
+ static CFAbsoluteTime last_check;
|
|
+ CFAbsoluteTime now = CFAbsoluteTimeGetCurrent ();
|
|
+ if (now - last_check < 0.5)
|
|
+ return;
|
|
+ last_check = now;
|
|
+ }
|
|
+
|
|
specpdl_ref count = SPECPDL_INDEX ();
|
|
record_unwind_current_buffer ();
|
|
|
|
@@ -1343,7 +1377,7 @@ so the visual offset is (ov_line + 1) * line_h from
|
|
(zoomCursorUpdated is NO). */
|
|
#if defined (MAC_OS_X_VERSION_MIN_REQUIRED) \
|
|
&& MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
|
|
- if (view && !view->zoomCursorUpdated && UAZoomEnabled ()
|
|
+ if (view && !view->zoomCursorUpdated && ns_zoom_enabled_p ()
|
|
&& !NSIsEmptyRect (view->lastCursorRect))
|
|
{
|
|
NSRect r = view->lastCursorRect;
|
|
@@ -3520,7 +3554,7 @@ EmacsView pixels (AppKit, flipped, top-left origin)
|
|
|
|
#if defined (MAC_OS_X_VERSION_MIN_REQUIRED) \
|
|
&& MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
|
|
- if (UAZoomEnabled ())
|
|
+ if (ns_zoom_enabled_p ())
|
|
{
|
|
NSRect windowRect = [view convertRect:r toView:nil];
|
|
NSRect screenRect
|
|
--
|
|
2.43.0
|
|
|