Ubuntu 패키지를 다시 빌드하여 90% 더 빠르게 만들기
(gist.github.com/jwbee)- Ubuntu에서 제공하는
jq
의 소스 코드 패키지를 직접 빌드하면 성능이 최대 90% 개선될 수 있음 - 컴파일러, 최적화 플래그, 메모리 할당기를 개선함으로써 성능을 극대화함
설정
-
jq
는 JSON 형식의 GeoJSON 파일 처리에 사용됨- 500MB 크기의 Alameda County Assessor's parcel map에서 특정 값 이상인 모든 parcel의 도시명을 출력하는 쿼리 실행
- Ryzen 9 9950X 시스템에서 캐시된 파일 기준으로 약 5초 소요 되어 이를 향상시켜보기로 함
1단계: 패키지 재빌드
- Launchpad에서
jq
소스 코드 다운로드 후, 아무 플래그 없이 재빌드 - 결과: 2~4% 성능 향상
-
벤치마크 결과
- 빌드된 jq: 평균 4.517초
- Ubuntu 기본 패키지: 평균 4.641초
- 성능 개선: 1.03배 빨라짐
2단계: Clang 및 고급 최적화 플래그 사용
- Clang-18로 컴파일하고 최적화 레벨 및 LTO 사용
- 사용한 주요 플래그:
-
-O3
→ 최적화 레벨 향상 -
-flto
→ Link-Time Optimization 적용 -
-DNDEBUG
→ 디버그 코드 제외
-
-
벤치마크 결과
- 빌드된 jq: 평균 3.853초
- Ubuntu 기본 패키지: 평균 4.631초
- 성능 개선: 1.20배 빨라짐
3단계: TCMalloc 추가
- GNU libc의 기본 malloc 대신 TCMalloc 사용
-
-L/usr/lib/x86_64-linux-gnu -ltcmalloc_minimal
추가 후 빌드 -
벤치마크 결과
- 빌드된 jq: 평균 3.253초
- Ubuntu 기본 패키지: 평균 4.611초
- 성능 개선: 1.42배 빨라짐
4단계: TCMalloc 동적 프리로드 적용
- Ubuntu 기본 패키지에서 동적 프리로드로 TCMalloc 사용
-
벤치마크 결과
- 기본 jq: 평균 4.601초
- TCMalloc 적용 jq: 평균 4.082초
- 성능 개선: 1.13배 빨라짐
5단계: 다른 할당기 동적 프리로드 테스트
- Ubuntu에서 제공하는 다른 메모리 할당기인 jemalloc과 mimalloc 테스트
- mimalloc이 가장 우수한 성능 제공
-
벤치마크 결과
- 기본 jq: 평균 4.123초
- TCMalloc 적용 jq: 평균 4.130초
- Jemalloc 적용 jq: 평균 3.510초
- Mimalloc 적용 jq: 평균 3.154초 → 성능 1.31배 향상
6단계: mimalloc로 직접 빌드
- mimalloc을 동적 프리로드가 아닌 정적으로 링크
- 성능 극대화
-
벤치마크 결과
- 빌드된 jq: 평균 2.428초
- Ubuntu 기본 패키지: 평균 4.606초
- 성능 개선: 1.90배 빨라짐
🚀 최종 결과
- Ubuntu 패키지보다 직접 빌드된 jq가 90% 더 빠름
- 2.2GB JSON 파일 13,000개 처리 성능:
- 빌드된 jq: 0.755초
- 기본 jq: 1.424초
- 성능 개선: 약 2배
Hacker News 의견
-
"Ubuntu 패키지를 재구성하고 메모리 할당기를 변경하여 90% 더 빠르게 만들기"라는 제목은 클릭베이트 같음
- 단 하나의 패키지에 대한 이야기이며, 일부 성능 향상은 재컴파일로 실현되지 않았음
- jemalloc을 미리 로드하여 malloc 구현을 교체한 경험이 있으며, 메모리 사용량을 안정화하는 데 긍정적인 결과를 얻었음
- 이는 메모리 누수 문제를 해결했으며, 애플리케이션 자체의 문제가 아닌 메모리 단편화 문제였을 가능성이 높음
-
엔지니어링은 타협의 예술임
- 기사에서는 메모리 할당기를 전문화하여 대부분의 성능 향상을 얻었다고 설명함
- 멀티스레드 프로젝트에서는 할당기 선택이 중요하며, 한 프로젝트에서의 속도 향상이 다른 프로젝트에서는 충돌을 일으킬 수 있음
- 재할당 전략도 고려해야 하며, 장기적인 안정성과 단기적인 속도 사이의 선택이 필요함
- 비디오 편집기 개발 중 다양한 할당기를 실험했으며, glibc 할당기가 장기적인 안정성을 제공함을 발견했음
-
Gentoo Linux는 사용자의 특정 용도에 맞게 최적화할 수 있도록 설계된 운영체제임
- 초기 설정 후 사용이 간단하며, Gentoo Linux 채널에서 많은 친구를 사귀었던 기억이 있음
- 초기 ChromeOS는 기본적으로 커스텀 Gentoo Linux 설치였음
-
jq와 같은 패키지를 수동으로 설치하면 보안 업데이트에서 제외될 수 있음
- 예를 들어, onigurama의 보안 업데이트가 있었으며, 이러한 상황이 다시 발생하면 취약해질 수 있음
- CVE-2017-9224 등 여러 보안 취약점이 수정된 사례가 있음
-
비공식적인 malloc을 사용하면 이상한 버그가 발생할 수 있음
- 개발자들이 사용하는 플래그를 넘어서면 문제가 발생할 가능성이 높음
-
간단한 변경으로 큰 속도 향상을 얻을 수 있다는 것을 읽고 jq의 개발자에게 알리고 싶음
- 기사는 이 옵션을 고려하지 않은 것 같으며, 댓글에서도 언급되지 않음
-
패키지를 소스에서 컴파일하거나 공식 바이너리를 다운로드하는 것이 유익할 수 있음
- 수동 설치 및 소스 컴파일 패키지의 업데이트 확인이 어려웠으나, 이를 해결하기 위한 도구를 개발했음
-
Rust의 "cargo install" 기능은 특정 플랫폼의 최적화를 가능하게 하여 유용함
- jaq와 yq는 jq를 사용할 때 성능 향상을 위해 자주 사용하는 옵션임
-
메모리 할당기를 변경한 후 Ubuntu 패키지를 재구성하여 90% 더 빠르게 만들 수 있음
- Debian과 RedHat에서도 작동할 가능성이 있음
- 처음에는 Ubuntu를 Linux From Scratch로 변환하는 기사인 줄 알았음