원문 캡처 · debuff.jp
원문 캡처 · debuff.jp

Chromium의 긴 애니메이션 프레임(Long Animation Frames, LoAF) API는 50ms를 넘긴 프레임의 실행 시간과 관련 스크립트를 기록하지만, 게임에서 체감되는 더 짧은 끊김은 놓칠 수 있다. 웹 게임용 프레임 프로파일러 myaku는 모든 프레임을 측정하고 게임 엔진의 작업 구간을 나눠 보여준다.

LoAF는 Chrome 123이 출시된 2024년 3월부터 사용할 수 있으며 Chrome, Edge, Opera, Brave에 들어 있다. W3C 명세는 아직 초안이고 Firefox와 Safari는 지원하지 않는다. 페이지가 열려 있는 동안 성능 항목을 계속 관찰해 느린 프레임의 시간, 스크립트·스타일·레이아웃에 걸린 시간과 실행된 스크립트의 위치를 알려준다.

Phaser 3 러너 게임에 의도적으로 느린 함수 두 개를 추가해 Chrome에서 8초간 측정한 결과, 70ms가 걸리는 rebuildSkyline() 프레임은 LoAF에 잡혔지만 30ms가 걸리는 sortClouds() 프레임은 잡히지 않았다. LoAF는 3개 프레임을 보고했지만 실제 끊김은 7번 발생했다. 게임에서는 30ms도 60Hz 기준 약 두 프레임에 해당하지만, LoAF의 50ms 기준에는 미치지 못한다.

또한 게임의 작업 대부분은 하나의 requestAnimationFrame 콜백 안에서 이뤄진다. LoAF만으로는 그 안에서 어느 게임 작업이 느렸는지 구분하기 어렵다. myaku는 모든 프레임을 측정하고, 화면 주사율에 따른 프레임 간격의 1.5배를 느린 프레임 기준으로 삼는다. 60Hz에서는 25ms다. Phaser에서는 update, update:<scene key>, render 구간을 따로 보여주며 PixiJS, KAPLAY, Excalibur, three.js도 지원한다.

myaku가 함수 이름까지 자동으로 찾아내는 것은 아니다. 예를 들어 Phaser 게임의 특정 장면에서 update에 70ms가 쓰였다는 점은 알 수 있지만, 그 안의 rebuildSkyline()을 식별하려면 사용자가 직접 구간을 표시해야 한다.

tsimport { myaku } from "myaku"; const profiler = myaku(); update() { profiler.span("skyline", () => this.rebuildSkyline()); profiler.span("clouds", () => this.sortClouds()); }

myaku는 스크립트 실행뿐 아니라 WebGL 텍스처 업로드와 셰이더 컴파일, 가비지 컬렉션, 숨겨지거나 가려진 창에 대한 브라우저의 처리 제한도 확인한다. 원인이 불분명하면 추측하지 않고 unknown으로 표시하며, 각 판정에는 신뢰도도 붙는다.

Firefox와 Safari에서도 프레임과 사용자가 설정한 구간, 엔진 구간, WebGL·힙 관련 근거를 측정할 수 있다. 다만 스크립트 위치 정보는 빠지므로 스크립트 관련 판정은 프레임 코드 실행 시간과 구간 정보에 의존한다. 게임을 자동으로 실행해 기록하는 myaku record는 Chrome이나 Edge가 필요하다.

화면에 프레임 그래프를 표시하려면 진입 파일 맨 위에 다음을 추가한다.

tsimport "myaku/auto";

기존 빌드를 수정하지 않고 기록하려면 다음 명령을 사용한다.

bashnpx myaku record dist/

myaku 시작 안내 · Phaser 게임이 끊기는 이유 · PixiJS 게임이 끊기는 이유