1P by GN⁺ 30일전 | ★ favorite | 댓글 1개
  • 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에서 제공하는 다른 메모리 할당기인 jemallocmimalloc 테스트
  • 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로 변환하는 기사인 줄 알았음