kitty/benchmark.py
Kovid Goyal 896fc0c36a
Improve benchmark script
It now benchmarks the I/O thread as well for results much closer to what
you get when running in real kitty
2026-08-12 15:37:22 +05:30

85 lines
2.5 KiB
Python
Executable file

#!./kitty/launcher/kitty +launch
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import fcntl
import os
import select
import signal
import struct
import sys
import termios
import time
from pty import CHILD, fork
from kitty.constants import kitten_exe
from kitty.fast_data_types import ChildMonitor, Screen, safe_pipe
from kitty.utils import read_screen_size
BENCHMARK_WINDOW_ID = 1
def run_parsing_benchmark(cell_width: int = 10, cell_height: int = 20, scrollback: int = 20000) -> None:
isatty = sys.stdout.isatty()
if isatty:
sz = read_screen_size()
columns, rows = sz.cols, sz.rows
else:
columns, rows = 80, 25
child_pid, master_fd = fork()
is_child = child_pid == CHILD
argv = [kitten_exe(), '__benchmark__', '--with-scrollback']
if is_child:
while read_screen_size().width != columns * cell_width:
time.sleep(0.01)
signal.pthread_sigmask(signal.SIG_SETMASK, ())
os.execvp(argv[0], argv)
x_pixels = columns * cell_width
y_pixels = rows * cell_height
s = struct.pack('HHHH', rows, columns, x_pixels, y_pixels)
fcntl.ioctl(master_fd, termios.TIOCSWINSZ, s)
child_died = False
def on_child_death(window_id: int, died: bool, exit_status: int) -> None:
nonlocal child_died
child_died = True
child_monitor = ChildMonitor(on_child_death, None)
# r_pipe: benchmark polls this; w_pipe: io_thread writes here on data ready
r_pipe, w_pipe = safe_pipe(False)
child_monitor.set_wakeup_fd(w_pipe)
screen = Screen(None, rows, columns, scrollback, cell_width, cell_height, BENCHMARK_WINDOW_ID)
child_monitor.add_child(BENCHMARK_WINDOW_ID, child_pid, master_fd, screen)
child_monitor.start()
try:
while not child_died:
rd, _, _ = select.select([r_pipe], [], [], 1.0)
if rd:
# drain all accumulated wakeup bytes
try:
os.read(r_pipe, 256)
except OSError:
pass
child_monitor.parse_input_once()
finally:
child_monitor.shutdown_monitor() # io_loop closes master_fd via cleanup_child
os.close(r_pipe)
os.close(w_pipe)
if isatty:
lines: list[str] = []
screen.linebuf.as_ansi(lines.append)
sys.stdout.write(''.join(lines))
else:
sys.stdout.write(str(screen.linebuf))
def main() -> None:
run_parsing_benchmark()
if __name__ == '__main__':
main()