렉서(Lexer) 2배 빨라졌지만, I/O가 발목을 잡았다!
ARM64 어셈블리 렉서(Lexer)를 개발하여 Dart 코드 처리 속도를 2배 향상시켰지만, I/O 병목 현상에 직면함
104,000개의 파일을 처리하는 과정에서 300,000개 이상의 시스템 콜(System Calls)로 인한 오버헤드 발생
tar.gz 아카이브(Archive)를 활용하여 I/O 속도를 42배 향상시키고, 전체 처리 시간을 2.27배 단축함
SQLite 데이터베이스(Database), Haiku OS의 packagefs 등 다양한 I/O 최적화 기법에 대한 논의가 진행됨
I/O 병목 현상과 시스템 콜(System Call) 오버헤드
게시물에서는 렉서(Lexer) 성능 향상에도 불구하고 I/O 작업이 병목으로 작용하는 문제를 지적한다. 특히, 104,000개의 파일을 처리하는 과정에서 발생하는 300,000개 이상의 시스템 콜(System Calls)이 주요 원인으로 분석된다. 각 시스템 콜은 컨텍스트 스위칭(Context Switching), 커널(Kernel) 작업, 권한 검사 등을 포함하며, 이는 상당한 오버헤드를 발생시킨다. 파일 시스템 메타데이터(Filesystem Metadata) 조회 및 디렉토리 탐색 또한 I/O 시간을 증가시키는 요인으로 작용한다.
tar.gz 아카이브(Archive)를 활용한 I/O 최적화
게시자는 I/O 병목 현상을 해결하기 위해 tar.gz 아카이브(Archive)를 활용하는 방법을 제시한다. 104,000개의 개별 파일을 1,351개의 tar.gz 아카이브로 묶어 처리함으로써 I/O 시간을 42.85배 단축했다. 이는 시스템 콜 횟수를 300,000+에서 4,000으로 줄인 결과이다. 또한, 순차적인 파일 접근은 캐시 효율성을 높여 페이지 캐시(Page Cache)를 유지하는 데 기여한다. 하지만, 압축 해제(Decompression) 과정이 새로운 병목 지점으로 부상했다.
압축 및 압축 해제(Decompression) 성능 개선 방안
게시물에서는 압축 해제(Decompression) 성능 개선을 위한 다양한 방법을 제시한다. zstd와 같은 더 빠른 압축 알고리즘을 사용하거나, 압축 해제 속도를 높이기 위해 압축 속도를 'fastest'로 설정하는 방법이 언급된다. 또한, dart:io를 활용하여 gzip 압축 해제를 수행하는 방법도 제안된다. 블록 기반 압축(Block-Based Compression)을 통해 무작위 접근을 지원하는 방법도 고려해볼 만하다. 이러한 방법들은 압축 해제 병목 현상을 완화하고 전체적인 성능을 향상시킬 수 있다.
SQLite 및 Haiku OS의 packagefs
댓글에서는 SQLite 데이터베이스(Database)를 활용하여 시스템 콜(System Call) 오버헤드를 줄이는 방안이 제시된다. SQLite는 파일 내용을 데이터베이스에 저장하여 무작위 접근을 가능하게 한다. 또한, Haiku OS의 packagefs는 패키지를 단일 압축 파일로 관리하여 I/O 오버헤드를 근본적으로 제거한다. 이러한 접근 방식은 파일 시스템 대신 데이터베이스 또는 가상 파일 시스템을 활용하여 I/O 성능을 최적화하는 방법의 예시이다.
렉서(Lexer) 생성 및 최적화 기법
게시물에서는 렉서(Lexer) 생성 및 최적화에 대한 다양한 기법이 언급된다. RE2C와 같은 도구를 사용하여 직접 코딩된 렉서를 생성하면 테이블 기반 렉서보다 성능을 향상시킬 수 있다. 또한, 프로파일 기반 최적화(Profile-Guided Optimization)를 통해 렉서의 핫 패스(Hot Path)를 최적화할 수 있다. 렉서의 아키텍처(Architecture)와 기능 집합 간의 성능 차이를 분석하는 것도 중요하다.