Skip to content

Performance Benchmarks

Woojin Kim edited this page Jun 20, 2026 · 1 revision

퍼포먼스 벤치마크 보고서

pytmux 는 성능을 추측이 아니라 측정으로 관리한다. 매 푸시마다 GitHub Actions 가 macOS·Linux·Windows 세 OS에서 헤드리스 벤치마크를 돌려 결과를 저장소에 미러링하고, 이 페이지는 그 최신 수치(2026-06-20 기준)와 2주간의 추세를 정리한다.

측정값 출처: docs/benchmark/{darwin-arm64,linux-x86_64,windows-amd64}/. 생성기: scripts/bench.py · 워크플로: .github/workflows/benchmark.yml.


1. 측정 방법

벤치마크는 전부 헤드리스다. 실제 터미널·셸·ssh 가 없어도, 합성 입력을 코어에 직접 먹여(드라이브) 순수 코드 경로의 비용만 잰다. 덕분에 OS·CI 환경 차이를 빼면 수치 변동이 곧 우리 코드 변경의 효과가 된다.

  • CI 매트릭스: GitHub Actions 의 ubuntu / macos / windows 러너가 push 마다 동일 시나리오를 측정한다. 결과는 OS별 JSON·Markdown 으로 저장소에 커밋된다.
  • 반복 수: 워크로드당 reps=200 (콜드 import 는 별도 프로세스 n=5), 탭 12개·활성 패널 6개, flood 8 MB.
  • 신호 판단: CI 러너는 공유 클라우드 VM 이라 max·p99 꼬리에 노이즈가 섞인다. 추세는 일별 중앙값(median) 을 1차 신호로, 단발값은 보조로 읽는다.

측정 3축은 ① 시작 시간 ② 다중 탭/패널 반응성 ③ 출력 폭증(처리량·프레임 지연)이다. 아래 표의 시간 단위는 모두 ms 이며, 부드러운 입력의 기준선은 60fps = 16.7 ms, 30fps = 33.3 ms 슬라이스 예산이다.


2. 지표 카테고리

카테고리 무엇을 재나 좋은 방향
시작 시간 콜드 import(별도 프로세스), 프레임워크 init(Server+세션+첫 layout, 셸 제외) 낮을수록
탭/패널 반응성 layout 메시지 빌드·직렬화, 전 패널 render+직렬화, 탭 전환 낮을수록
출력 폭증 feed 처리량(MB/s), 슬라이스 지연(p50/p99/max), 프레임당 render MB/s 높을수록·ms 낮을수록
메모리/프로세스 비용 탭/패널당 프로세스 생성 비용(특히 Windows의 PTY 호스트) 낮을수록

메모리는 CI 벤치마크 JSON 에 별도 수치 표가 없고, 프로세스 모델 차원에서 정성적으로 다룬다(§5). pytmux 는 단일 서버(데몬)–다중 클라이언트 구조라 탭이 늘어도 코어 메모리는 완만하게 증가하지만, Windows 는 탭 하나당 PTY 호스트 프로세스가 따로 뜨는 게 지배적 비용이다.


3. 현재 대표 수치 (2026-06-20)

환경: Linux CPython 3.12.13 / 6.17.0-azure · macOS CPython 3.12.10 / Darwin 24.6.0 · Windows CPython 3.12.10 / Windows 2025Server. 공통 의존성 textual 8.2.7, wcwidth 0.8.1.

3.1 시작 시간

항목 macOS Linux Windows
cold import p50 60.8 ms 56.8 ms 82.9 ms
cold import p99 82.5 ms 71.4 ms 101.7 ms
framework init p50 2.29 ms 3.49 ms 3.95 ms

콜드 import 가 시작 비용의 대부분이며, 이는 사실상 Python 인터프리터 기동 + 모듈 import 비용이다. pytmux 자체의 init 로직(플러그인 load 포함)은 수 ms 로 무시할 수준이다.

3.2 다중 탭/패널 반응성 (탭 12 · 활성 패널 6 · 200×50)

작업 (매 프레임/이벤트) macOS Linux Windows
layout 빌드+직렬화 p50 0.027 ms 0.034 ms 0.033 ms
전 패널 render+직렬화 p50 0.052 ms 0.069 ms 0.066 ms
탭 전환(select+layout) p50 0.007 ms 0.009 ms 0.009 ms

세 OS 모두 정상 상태 재렌더가 60fps 예산 대비 2~3 자릿수의 여유를 갖는다. 탭을 12개 띄우고 활성 윈도우에 6패널을 배치해도 한 프레임의 코어 비용이 0.1 ms 미만이다.

다중 탭 레이아웃

3.3 출력 폭증 — 처리량 & 프레임 지연 (8 MB feed)

워크로드 OS feed MB/s slice p50 slice p99 render ms/frame
claude_busy 200×50 (alt 풀리페인트) macOS 0.82 8.08 26.7 4.27
Linux 0.64 12.36 20.4 5.53
Windows 0.68 11.50 20.4 5.34
plain_cat 200×50 (main 스크롤) macOS 0.85 7.94 22.9 3.06
Linux 0.57 13.06 27.7 4.61
Windows 0.62 12.07 34.1 4.47
claude_busy 80×24 (원격 흔한 크기) macOS 0.84 7.10 20.5 0.70
Linux 0.59 12.21 19.9 1.03
Windows 0.63 11.57 20.4 0.99

풀리페인트 프레임 비용(render ms/frame)은 전 OS에서 60fps 예산 안이다. 처리량은 워크로드가 합성 입력에 묶여 있어 변동이 작으며, macOS(Apple Silicon)가 처리량·프레임 양쪽에서 가장 빠르다.

실제 Claude 패널 출력


4. OS 간 비교 — 무엇이 차이를 만드나

지표 (현재 median) macOS Linux Windows 해석
cold import p50 ~61 ms ~57 ms ~83 ms Windows 가 인터프리터 기동·import 부담 최대
전 패널 render p50 0.052 0.069 0.066 셋 다 사실상 무료
claude_busy200 frame 4.27 5.53 5.34 macOS 최속(Apple Silicon)
claude_busy200 feed 0.82 MB/s 0.64 MB/s 0.68 MB/s macOS 처리량 우위
plain_cat slice p99 22.9 27.7 34.1 ⚠ Windows 꼬리가 30fps 경계 근접

차이를 만드는 요인:

  • CPU/메모리 대역폭 — macOS arm64 가 feed 처리량과 프레임 비용 양쪽에서 앞선다. CPU 바운드인 VT 파싱·셀 직렬화 경로가 그대로 칩 성능을 반영한다.
  • 인터프리터 기동 + import — 콜드 import 절대값은 Windows 가 가장 크다. 프로세스 생성 비용 자체가 Windows 에서 비싸기 때문이며, pytmux 코드 탓이 아니다.
  • PTY 호스트 모델 — Windows 는 탭/패널 하나를 새로 열 때 CreatePseudoConsole 이 PTY 호스트 프로세스를 즉시 spawn 한다. 멀티바이트 무손상 스트리밍을 위해 번들 콘솔 호스트를 쓰는데, 이 선택이 시스템 기본 대비 ~40 ms 를 더 쓰지만 출력 정확성을 보장하는 의도된 비용이다. 자세한 배경은 Why-pytmux-on-Windows 참고.

전 지표에서 모든 OS가 60fps/30fps 예산 안의 정상 작동 영역에 있다. 유일하게 예산에 근접하는 건 plain_cat 슬라이스 p99 꼬리뿐이며, 이는 §6의 추적 항목과 같은 지표다.


5. 메모리 / 프로세스 비용

CI 벤치마크는 RSS 수치를 표로 수집하지 않지만, 프로세스 모델 차원의 비용은 명확하다.

  • 단일 서버–다중 클라이언트: 모든 세션·탭은 하나의 데몬(단일 asyncio 루프) 안에 산다. 탭이 늘어도 새 인터프리터가 뜨지 않으므로 코어 메모리 증가는 완만하다.
  • 셸 프로세스: 패널마다 셸 프로세스 1개. 이는 어떤 멀티플렉서든 본질적 비용이다.
  • Windows 추가 비용: 패널 하나당 PTY 호스트 프로세스가 추가로 1개 더 뜬다 (즉 탭당 프로세스 2개). 새 탭/패널 생성이 ~250–350 ms 걸리는 주원인이며, 이는 Windows 프로세스 생성 비용 + 콘솔 호스트 spawn 의 합이다.

macOS/Linux 는 PTY 가 커널 객체라 추가 호스트 프로세스가 없다. 플랫폼별 동작 차이 전반은 Platform-Differences 에 정리돼 있다.


6. 성능 추세 · 회귀 추적 (2026-06-05 → 06-20)

2주간 OS당 약 400 run(총 ~1,200 run)을 누적해 본 큰 그림:

6.1 단일 최대 성과 — 정상 상태 재렌더 ~99% 제거

초기 베이스라인을 한 번 찍은 직후, 렌더 경로 최적화가 착륙해 render_all p50 이 세 OS에서 동시에 ~99% 하강했다. 핵심은 라이브 뷰에서 변경된(dirty) 행만 재직렬화하고 나머지는 행 캐시를 재사용하는 것이다. 정상 상태 재렌더가 사실상 공짜가 됐다.

OS 최적화 전 최적화 후 변화
Linux 8.66 ms 0.07 ms −99.2%
macOS 4.54 ms 0.05 ms −99.0%
Windows 7.56 ms 0.07 ms −99.2%

같은 스프린트가 풀리페인트 프레임 비용도 약 절반으로(예: Linux 10.3→5.7 ms), 콜드 import 도 한 단(약 −30%) 끌어내렸다. 이후 2주간 무회귀로 평탄 유지됐다 — 코드가 빠르게 늘어나는 기간에도 핵심 성능 지표를 지킨 셈이다.

6.2 CI 가 잡아낸 회귀 — plain_cat 슬라이스 p99 (Linux/Windows)

plain_cat 200×50(메인 스크롤)의 슬라이스 p99 가 06-18 부터 Linux/Windows 에서만 상승했다(Linux ~+13%, Windows ~+21%). 같은 기간 macOS 는 오히려 하강해, 전형적인 OS 비대칭 회귀 신호다.

  • 시점이 클라이언트 경로의 기능 작업과 겹친다.
  • 절대 크기는 수 ms 로 작고 합성 flood 의 꼬리 지표지만, macOS 엔 없고 두 OS 에만 나타나는 비대칭이라 추적 대상으로 남겼다.

이것이 벤치마크 매트릭스의 가치다. 단일 머신에선 보이지 않았을 OS 비대칭 회귀를, 세 OS를 매 푸시마다 측정하기 때문에 작은 단계에서 포착한다.

6.3 노이즈 vs 추세

framework_init 의 first/last 단발값은 ±15~36% 흔들리지만 일별 중앙값으로 보면 추세가 아니라 CI 러너 노이즈다(간헐 스파이크 max 가 큼). 단발 비교를 신뢰하지 않고 중앙값 추세를 1차 신호로 삼는 이유다.


7. 요약

  1. 성능 개선의 거의 전부는 렌더 dirty-행 캐시 한 번의 스프린트에서 나왔고, 이후 2주는 무회귀로 평탄하다.
  2. 현재 모든 OS가 60fps/30fps 예산 안의 정상 작동 영역에 있다.
  3. macOS(Apple Silicon)가 처리량·프레임에서 최속, Windows 가 시작 비용·꼬리 지연에서 가장 무겁다 — 대부분 OS의 프로세스/콘솔 모델에서 비롯되며 코드 회귀가 아니다.
  4. 유일한 추적 항목은 Linux/Windows 의 plain_cat 슬라이스 p99 미세 상승이며, CI 매트릭스가 OS 비대칭으로 포착했다.

관련 문서

Clone this wiki locally