통합 터미널 성능 개선
2017년 10월 3일 Daniel Imms, @Tyriar
Visual Studio Code 1.17 버전 출시에 맞춰 통합 터미널의 렌더링 엔진이 성능을 염두에 두고 완전히 재작성되었습니다. 이번 버전에서는 DOM 기반 렌더링 시스템에서 벗어나 HTML canvas 요소를 사용하게 됩니다.
DOM 렌더링
놀랍게도, 정적 문서를 표시하도록 설계된 시스템에서도 인터랙티브 터미널 렌더링이 가능했습니다. 하지만 시간이 지남에 따라 몇 가지 문제를 해결하기 위해 DOM이 제공하는 특정 기능을 재정의해야 함을 알게 되었습니다.
선택: 터미널 사용 사례를 다루기 위해 DOM의 선택 시스템과 많은 작업을 해야 했습니다. DOM에 보이는 것만 렌더링했기 때문에, 선택 기능을 재구현하지 않고는 여러 페이지의 내용을 선택할 수 없었습니다. 스크롤링도 선택을 해제시키는 원인이 되었습니다. 이러한 문제를 해결하기 위해 사용자 정의 선택 로직이 추가되었습니다.
문자 정렬 불일치: 많은 고정 폭 글꼴이 일부 유니코드 문자에 대해 엄격하게 고정 폭이 아니기 때문에, 아래 이미지의 오른쪽에서 볼 수 있는 것과 같은 상황이 발생할 수 있습니다.

이에 대한 해결책은 모든 유니코드 문자를 고정 너비 span으로 감싸는 것이었지만, 이렇게 하면 프레임 렌더링에 걸리는 시간이 증가합니다.
과도한 가비지 컬렉션: 터미널을 렌더링하는 데 필요한 요소의 수가 많아 가비지 컬렉터가 메모리를 자주 정리해야 했으며, 종종 눈에 띄는 양만큼 렌더링 시간을 지연시켰습니다. 이 문제를 해결하기 위해 객체 풀이 도입되어 DOM 요소를 재활용할 수 있도록 했습니다.
성능: 아무리 노력해도 레이아웃 엔진에 의해 부과되는 성능의 하드 캡을 벗어날 수 없습니다.
레이아웃 엔진 우회
경우에 따라 요소 구성 및 레이아웃을 수행하는 데 프레임(16.6ms)보다 더 오래 걸릴 수 있으며, 이는 터미널에서 부드러운 초당 60프레임(FPS)을 유지하려면 허용할 수 없습니다. 이에 대한 해결책은 새로운 canvas 기반 렌더링 엔진이었습니다.
<canvas> HTML 요소는 JavaScript API를 사용하여 그래픽 및 텍스트를 그릴 수 있도록 합니다.
렌더 계층
터미널의 다른 부분을 렌더링하는 것을 단순화하기 위해 "렌더 계층"이라고 하는 여러 개의 canvas 요소가 사용됩니다.
현재 계층은 다음과 같은 순서입니다.
- 텍스트: 배경색 및 전경 텍스트, 이 계층은 불투명합니다.
- 선택: 마우스를 사용한 선택.
- 링크: 링크 위에 마우스를 올렸을 때의 밑줄.
- 커서: 터미널의 커서.
이러한 부분을 각자의 작은 구성 요소로 분리함으로써 드로잉 방식이 크게 단순화되었습니다.
변경된 것만 그리기
새로운 렌더러의 중요한 부분은 *변경된* 것만 그린다는 것입니다. 이를 위해 셀의 그려진 상태에 대한 최소한의 정보를 포함하는 슬림한 내부 모델이 유지됩니다. 그런 다음 이 상태를 사용하여 더 비용이 많이 드는 그리기 작업을 수행하기 전에 셀을 변경해야 하는지 여부를 빠르게 확인할 수 있습니다. **텍스트** 계층의 경우, 이 모델에는 문자, 텍스트 스타일, 전경색 및 배경색에 대한 참조가 포함됩니다.
이전 렌더링 엔진에서는 아무것도 변경되지 않았더라도 전체 줄이 DOM에서 제거되고, 재구성되고, 다시 추가되었습니다.

위 이미지의 녹색 사각형은 다시 그려지는 영역을 나타냅니다.
텍스처 아틀라스
렌더링 시간을 더욱 단축하기 위해 텍스처 아틀라스가 사용됩니다. 백그라운드에는 기본 배경색으로 가장 일반적인 스타일의 모든 ASCII 문자를 포함하는 ImageBitmap이 있습니다.
이러한 스타일의 텍스트를 그릴 때, 일반적인 CanvasRenderingContext2D.fillText 호출 대신 텍스처 아틀라스가 사용됩니다. ImageBitmap은 GPU에 함께 배치되므로 그리기 속도가 상당히 향상됩니다.

강제 프레임 건너뛰기
DOM에서의 렌더링 속도 때문에 파서가 충분한 CPU 시간을 확보하도록 추가 프레임을 건너뛰는 것이 필요했습니다. 이렇게 하면 명령이 이전보다 빠르게 실행되었지만, 터미널을 통해 스트리밍되는 많은 데이터는 프레임 속도를 10 FPS 미만으로 떨어뜨릴 수 있었습니다.
새로운 렌더러 덕분에 이 제한이 제거되었으며 이제 터미널에서 최대 60 FPS를 즐길 수 있습니다.

결과
벤치마크에 따르면 통합 터미널은 이제 상황에 따라 **이전보다 약 5~45배 더 빠르게** 렌더링됩니다. 증가된 응답성과 프레임 속도를 눈치채지 못하더라도, 더 빠른 렌더링은 배터리 사용량 감소를 의미합니다! 성능 개선을 즐기시기 바랍니다. 몇 일 안에 VS Code 1.17에 적용될 예정이며, 지금 바로 Insider 빌드에서 테스트할 수 있습니다.
더 자세한 내용을 보려면 기능을 추가한 원본 xterm.js pull request로 이동할 수도 있습니다.
행복한 코딩 되세요!
Daniel Imms, VS Code 팀원 @Tyriar