experiment(vegas): vegas_scroll.switch_interval_ms shortens the GIL switch interval during a run

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-24 14:13:29 -04:00
co-authored by Claude Opus 5.5
parent 8163104581
commit 55a2760892
3 changed files with 72 additions and 0 deletions
+10
View File
@@ -82,6 +82,14 @@ class VegasModeConfig:
# drawn off the render thread. See docs/OFFSCREEN_RENDERING.md.
offscreen_prefetch: bool = True
# How long another thread may hold the GIL before the render thread's
# request forces it to yield, in ms, while Vegas runs. CPython's default is
# 5ms. Plugin rendering on the prefetch thread and plugin updates hold the
# GIL in Pillow and Python code, and a frame waiting its turn for 5ms at a
# time misses its refresh. 0 leaves the interpreter default alone.
# Experimental: measured with scripts/frame_soak.py before it gets a default.
switch_interval_ms: float = 0.0
# Keep one continuous strip, extending it with the next group of plugins as
# the scroll approaches the end, instead of composing a fresh strip and
# swapping it in. A swap stops the motion, substitutes every pixel at once
@@ -212,6 +220,7 @@ class VegasModeConfig:
sub_pixel_blend=bool(vegas_config.get('sub_pixel_blend', False)),
continuous_scroll=vegas_config.get('continuous_scroll', True),
offscreen_prefetch=bool(vegas_config.get('offscreen_prefetch', True)),
switch_interval_ms=float(vegas_config.get('switch_interval_ms', 0.0) or 0.0),
extend_threshold_screens=float(
vegas_config.get('extend_threshold_screens', 2.0)),
auto_trim=vegas_config.get('auto_trim', True),
@@ -254,6 +263,7 @@ class VegasModeConfig:
'sub_pixel_blend': self.sub_pixel_blend,
'continuous_scroll': self.continuous_scroll,
'offscreen_prefetch': self.offscreen_prefetch,
'switch_interval_ms': self.switch_interval_ms,
'extend_threshold_screens': self.extend_threshold_screens,
'auto_trim': self.auto_trim,
'trim_threshold': self.trim_threshold,
+21
View File
@@ -13,6 +13,7 @@ Supports three display modes per plugin:
import logging
import math
import sys
import time
import threading
from typing import Optional, Dict, Any, List, Callable, TYPE_CHECKING
@@ -280,6 +281,7 @@ class VegasModeCoordinator:
# due immediately so the first sample confirms the marquee is up.
self._fps_last_health_log = 0.0
self._fps_was_degraded = False
self._apply_switch_interval()
# Line up the next group immediately, so the first extension is already
# warm rather than stalling the scroll to fetch it.
@@ -302,6 +304,8 @@ class VegasModeCoordinator:
self.stats['total_runtime_seconds'] += time.time() - self._start_time
self._start_time = None
self._restore_switch_interval()
# Cleanup components
self.render_pipeline.reset()
self.stream_manager.reset()
@@ -309,6 +313,23 @@ class VegasModeCoordinator:
logger.info("Vegas mode stopped")
def _apply_switch_interval(self) -> None:
"""Shorten the GIL switch interval for the run; see VegasModeConfig."""
ms = self.vegas_config.switch_interval_ms
if not ms or ms <= 0:
return
if getattr(self, '_saved_switch_interval', None) is None:
self._saved_switch_interval = sys.getswitchinterval()
sys.setswitchinterval(ms / 1000.0)
logger.info("Vegas: GIL switch interval %.1fms (was %.1fms)",
ms, self._saved_switch_interval * 1000.0)
def _restore_switch_interval(self) -> None:
saved = getattr(self, '_saved_switch_interval', None)
if saved is not None:
sys.setswitchinterval(saved)
self._saved_switch_interval = None
def pause(self) -> None:
"""Pause Vegas mode (for live priority interruption)."""
with self._state_lock: