GN⁺: 러스트 std fs가 파이썬보다 느린가? 아니, 하드웨어 문제임
(xuanwo.io)OpenDAL 파이썬 바인딩이 파이썬보다 느린가?
- OpenDAL은 다양한 저장소 서비스에서 데이터를 효율적으로 검색할 수 있게 해주는 데이터 액세스 레이어임.
- OpenDAL의 파이썬 바인딩이 파이썬 자체보다 느리다는 보고가 있음.
- 파이썬 내부 캐시, 파일 읽기 가속화, PyO3 추가 오버헤드 등이 원인일 수 있음을 가설로 제시함.
OpenDAL Fs 서비스가 파이썬보다 느린가?
- Rust, OpenDAL, Python, PyO3 등 여러 요소가 관련된 문제임.
- Rust로 구현된 OpenDAL fs 서비스도 파이썬보다 느림을 발견함.
Rust std fs가 파이썬보다 느린가?
- OpenDAL이 std::fs를 통해 fs 서비스를 구현함.
- Rust의
std::fs
를 사용한 구현도 파이썬보다 느림을 확인함.
Rust std fs가 파이썬보다 느린가? 정말!?
- Rust std fs가 파이썬보다 느리다는 결과에 의문을 제기함.
-
strace
를 사용하여 시스템 호출 분석을 배움. -
strace
결과 분석을 통해 둘 다mmap
을 사용하고 있음에도 파이썬이 더 빠른 이유를 찾지 못함.
왜 여기서 mmap
을 사용하는가?
-
mmap
은 파일을 메모리에 매핑하는 것 외에도 대규모 메모리 영역 할당에 사용됨. -
malloc
을 사용하여 메모리를 요청할 때glibc
가mmap
을 사용하여 메모리를 할당함.
파이썬은 Rust와 동일한 메모리 할당자를 가지고 있는가?
- 파이썬은
pymalloc
이라는 작은 할당에 최적화된 메모리 할당자를 사용함. -
pymalloc
은 작은 객체에 최적화되어 있으며, 큰 할당에는PyMem_RawMalloc()
와PyMem_RawRealloc()
을 사용함.
Rust가 기본 메모리 할당자로 파이썬보다 느린가?
-
mmap
이 문제를 일으키는 것으로 의심됨. -
jemalloc
으로 전환한 Rust 프로그램이 파이썬보다 빠르게 동작함을 발견함.
Rust가 내 컴퓨터에서만 파이썬보다 느린가!
- Rust가 파이썬보다 느리게 동작하는 것은 특정 컴퓨터에서만 발생함.
- CPU와 메모리에 대한 상세 정보 제공함.
- CPU 취약점 완화 기능, Transparent Hugepage, CPU 코어 친화도 등을 조정해도 결과에 변화 없음.
- eBPF 프로그램을 사용하여 Rust가 시스템 호출 수준에서도 파이썬보다 느림을 확인함.
C가 파이썬보다 느린가?
- C로 구현한 버전도 파이썬보다 느림을 발견함.
C가 파이썬보다 느린가? 지정된 오프셋 없이!
- 메모리 영역 오프셋에 차이가 있음을 발견하고, 오프셋을 조정하여 C 프로그램의 속도를 향상시킴.
- AMD Ryzen CPU에서 특정 오프셋 없이는 성능 저하가 발생함을 확인함.
AMD Ryzen 9 5900X가 지정된 오프셋 없이 느린가!
- CPU 관련 문제임을 확인하고, 커널 개발자가 논의에 참여함.
-
perf
를 사용한 프로파일링을 통해 오프셋 없이는 성능 저하가 발생함을 다시 확인함.
GN⁺의 의견: 이 글에서 가장 중요한 점은 Rust와 C가 특정 하드웨어 환경에서 파이썬보다 느리게 동작할 수 있다는 것이며, 이는 메모리 할당과 CPU의 특정 동작 방식에 기인할 수 있다는 점입니다. 이 글은 소프트웨어 성능에 영향을 미치는 다양한 요소들을 탐구하는 과정을 통해, 하드웨어와 소프트웨어의 상호작용이 얼마나 복잡할 수 있는지를 보여줍니다. 이러한 탐구는 소프트웨어 엔지니어링의 세계에서 발생할 수 있는 예상치 못한 문제들을 해결하는 데 있어 중요한 교훈을 제공합니다.
Hacker News 의견
-
혼란스러운 전제에 대한 의견
한 사용자는 Python 표준 라이브러리의 함수들이 순수 Python으로 작성되었다고 생각하는 것에 대해 혼란스러워함. Python의 파일 읽기 메소드와 OpenDAL 모두 네이티브 코드를 래핑한 Python 래퍼라는 점에서 성능 차이가 흥미롭지만, "Python보다 느리다"고 표현하는 것은 이상하다고 느낌. Python 표준 라이브러리의 함수 구현이 네이티브 코드로 되어 있고, 각각 최적화되어 있다고 기대함. 기사의 결론이 네이티브 코드의 작동 방식과 관련이 있다는 것에 놀라지 않았으며, 특정 답변에는 놀랐지만 혼란스러운 시작에도 불구하고 매우 흥미로운 기사였음을 인정함.
-
CPU 기능 플래그에 대한 토론
두 개의 전용 CPU 기능 플래그가 있어서 REP STOS/MOV 명령어가 memset/memcpy를 위한 짧은 명령어 시퀀스로서 빠르고 사용 가능함을 나타냄. 새로운 CPU 세대마다 최적화된 루틴을 수작업으로 만드는 것은 수십 년간 지속된 고통임. 이제는 CPU 제조업체의 타이밍 테스트 스위트의 일부가 되어야 하지 않을까 하는 의문을 제기함.
-
관련 glibc 버그 링크
Zen 4와 관련된 glibc 버그에 대한 링크를 제공함.
-
기사에 대한 긍정적인 반응
한 사용자는 기사를 읽고 std::fs의 잘못된 사용에 대해 비웃을 준비를 했지만, 기사가 토끼굴과 미스터리의 연속이라며 잘 쓰여졌고 매우 흥미롭다고 평가함.
-
기사에 대한 높은 평가
다른 사용자는 이 기사가 이번 주에 읽은 것 중 가장 흥미로운 기사라고 평가하며, 글이 훌륭하게 작성되었다고 칭찬함.
-
문제 해결을 위한 제안
명백한 해결책으로, "copy_user_generic" 커널 메소드를 변경하여 CPU가 문제가 있는 것으로 감지되고 메모리 정렬이 느림 버그를 유발하는 경우 다른 메모리 복사 구현을 사용하도록 패치를 보내는 것을 제안함.
-
Rust의 기본 할당자에 대한 정보
Rust의 기본 할당자가 2018년까지 jemalloc이었다는 정보와 관련 링크를 제공함.
-
성능 향상을 위한 Rust 개발자의 고려 사항
Rust 개발자들이 jemallocator로 전환하여 성능을 향상시키는 것을 고려해야 하는지, 이것이 모든 사람이 성능을 무료로 얻을 수 있는 방법인지, C 코드베이스도 이로부터 이득을 볼 수 있는지, 현재 테이블 위에 남겨진 성능인지에 대한 궁금증을 표현함.
-
AMD와 Intel의 CPU 차이에 대한 설명
AMD의 문자열 저장 방식이 Intel과 다르며, CPU의 L2 크기를 넘어서기 전까지는 사용하지 않는 것이 좋다고 설명함. 그 지점을 넘어서면 문자열 저장을 사용하는 것이 이득이며 "DRAM 속도"로 실행되어야 하지만, 높은 시작 비용이 있기 때문에 해당 임계값에 도달할 때까지는 256비트 벡터 로드/스토어를 사용해야 함을 언급함.
-
기사를 적절한 사람들에게 전달한 사실
한 사용자가 이 기사를 적절한 사람들에게 전달했다고 밝힘.