기타 Hacker News · 1일 전

"인간이 컴파일러 이길 수 있나?" 직접 어셈블리 뜯어본 개발자

핵심 요약
  • 개발자가 현대 컴파일러가 생성한 인터프리터 어셈블리 코드를 역공학해 성능 비효율성을 분석했습니다.
  • 메모리에서 불필요하게 스택 인덱스를 읽는 문제와 예측 불가능한 단일 간접 분기 루프가 병목으로 지목되었습니다.
  • 프로파일링 결과 디스패치 루프의 테이블 로드 명령어가 전체 실행 시간의 3분의 1 이상을 차지하는 것으로 확인되었습니다.
요약 "현대에는 인간이 어셈블리어를 직접 짜서 컴파일러를 이기는 것은 바보짓"이라는 통념이 지배적이지만, 개발자들 사이에는 인터프리터 분야만큼은 컴파일러가 최적의 코드를 만들지 못해 직접 어셈블리로 짜면 더 빠르다는 소문이 오랜 기간 전설처럼 내려왔습니다. 이에 한 개발자가 256개 명령어 기반의 스택 아키텍처 가상 머신인 Uxn CPU 인터프리터를 구현하며 컴파일러를 뛰어넘을 수 있는지 직접 분석에 착수했습니다. 작성된 인터프리터는 램에서 바이트 단위로 명령어를 읽어와 실행하는 단순한 루프 형태였으며, 모든 연산 구현이 단일 함수 내로 인라인화되도록 구성해 이미 기존 참조 구현체보다 10~20% 더 빠른 성능을 보이고 있었습니다. 하지만 생성된 어셈블리 코드를 디버거로 역공학해 분석하자 명백한 비효율성들이 포착되었습니다. 첫째, 스택 인덱스나 RAM 베이스 주소 같은 핵심 값들이 레지스터에 상주하지 않고 메모리에 남아 있어 매번 불필요한 메모리 로드(load) 연산이 발생했습니다. 둘째, 명령어 분기 루프가 256개 오프셋으로 구성된 점프 테이블을 읽어 단일 간접 분기(indirect branch)를 수행하는 구조로 되어 있어 분기 예측이 사실상 불가능했습니다. 실제로 프로파일링 결과 가장 많은 시간이 소모되는 핫스팟이 바로 이 디스패치 루프 내의 테이블 로드 연산이었습니다.
Sponsored · 광고