개발자 / 오픈소스

파이썬 코드 프로파일링을 위한 6가지 유용한 라이브러리

Serdar Yegulalp | InfoWorld 2021.08.02
모든 프로그래밍 언어에는 두 가지 속도가 있다. 개발 속도, 그리고 실행 속도다. 파이썬(Python)은 전통적으로 빠른 실행보다는 빠른 개발에 중점을 두는 언어다. 파이썬 코드는 대부분의 경우 충분히 빠르지만 가끔 그렇지 않을 때도 있다. 그럴 때는 속도가 떨어지는 위치와 이유를 파악해 조치를 취해야 한다.
 
ⓒ Getty Images Bank

소프트웨어 개발은 물론 엔지니어링 전반적으로 통용되는 격언으로 “추정하지 말고 측정하라”는 말이 있다. 소프트웨어에서 무엇이 잘못됐는지 추정하곤 하지만 결코 좋은 방법은 아니다. 애플리케이션 속도를 높이기 위해 가장 먼저 사용해야 하는 도구는 실제 프로그램 성능에 대한 통계다.

파이썬에는 애플리케이션을 프로파일링하고 속도가 느린 부분을 파악하는 데 사용할 수 있는 패키지가 풍부하다. 표준 라이브러리에 포함된 간단한 도구부터 실행 중인 애플리케이션에서 통계를 얻기 위한 복잡 정교한 프레임워크에 이르기까지 다양한 도구가 있다. 이번 기사에서는 가장 중요한 5가지 도구에 대해 살펴본다. 모두 크로스 플랫폼(cross-platform)이며 파이파이(PyPI) 또는 파이썬 표준 라이브러리에서 즉시 사용할 수 있다. 


타임(Time), 타임잇(Timeit)

실행 속도가 몇 초 또는 몇 분 정도인 두 코드 스니펫 간의 시간을 프로파일링하는 것이 전부라면 스톱워치만 있어도 충분하다.

파이썬 표준 라이브러리에는 스톱워치 기능을 하는 두 가지 함수가 제공된다. 타임 모듈perf_counter 함수는 운영체제의 고분해능 타이머를 호출해 임의의 타임스탬프를 구한다. time.perf_counter를 작업 전후에 한 번씩 호출해 둘 사이의 차이를 구할 수 있다. 야단스럽지 않게, 낮은 오버헤드로 코드 시간을 측정하는 방법이다.

타임잇 모듈은 파이썬 코드에 대한 실제 벤치마킹과 비슷한 작업을 수행한다. timeit.timeit 함수는 코드 스니펫을 여러 번 실행하고(기본값은 100만 번), 소요된 총 시간을 측정한다. 타이트한 루프에서 단일 작업 또는 함수 호출의 성능을 알아보는 용도로 적합하다. 예를 들어 많은 횟수 반복 실행되는 어떤 작업에서 리스트 내포 또는 일반적인 리스트 구조 중 어느 것이 더 빠른지 확인하려는 경우 사용한다.

타임의 단점은 스톱워치 이상의 기능은 없다는 것, 타임잇의 단점은 주 사용례가 코드의 각 라인 또는 블록에 대한 마이크로벤치마크(microbenchmarks)라는 점이다. 두 모듈은 개별 코드를 다룰 때만 유용하고, 수천 라인의 코드 중에서 프로그램이 가장 많은 시간을 소비하는 지점을 찾는 등 전체 프로그램 분석 용도로는 부족하다.


c프로파일(cProfile)

파이썬 표준 라이브러리에는 전체 프로그램 분석 프로파일러인 c프로파일도 제공된다. c프로파일은 프로그램의 모든 함수 호출을 추적하고 가장 자주 호출되는 함수와 이러한 호출에 소요된 평균 시간을 목록화한다.

c프로파일에는 세 가지 큰 강점이 있다. 첫째, 표준 라이브러리에 포함되므로 기본 파이썬 설치에서도 사용할 수 있다. 둘째, 호출 동작에 대한 다양한 통계를 프로파일링한다. 예를 들어 함수 호출의 자체 명령에 소비된 시간과 함수에 의해 호출된 다른 모든 호출에 소비된 시간을 분리할 수 있다. 따라서 함수 자체가 느린지, 이 함수가 호출하는 다른 함수가 느린지를 확인할 수 있다.

셋째는 가장 큰 강점으로, c프로파일을 자유롭게 제한할 수 있다는 것이다. 전체 프로그램 실행을 샘플링하거나, 선택한 함수가 실행될 때만 프로파일링을 켜서 해당 함수가 수행하는 작업과 호출하는 대상에 초점을 맞출 수 있다. 이 방법은 대상의 범위를 어느정도 좁힌 후에 가장 효과적이지만 전체 프로파일 트레이스의 노이즈 속을 헤집는 수고를 덜 수 있다. 

이 특성에 c프로파일의 단점도 있다. c프로파일은 기본적으로 많은 양의 통계를 생성한다. 이 커다란 건초더미에서 정확한 바늘을 찾기는 매우 어려울 수 있다. 또 다른 단점은 c프로파일의 실행 모델이다. 모든 함수 호출을 포착하므로 상당한 오버헤드가 발생하고, 따라서 라이브 데이터를 사용하는 프로덕션 앱을 프로파일링하는 용도로는 적합하지 않다. 개발 중의 프로파일링이라면 문제되지 않을 것이다.


팔란티어(Palanteer)

파이썬 프로파일링 영역에 비교적 새롭게 추가된 도구인 팔란티어는 파이썬과 C++ 프로그램을 프로파일링하는 데 사용할 수 있다. 따라서 직접 만든 C++ 라이브러리를 래핑하는 파이썬 애플리케이션을 작성하면서 앱의 두 구성요소에 대한 매우 세부적인 시야가 필요할 때 매우 유용하다. 무엇보다 좋은 점은 데스크톱에서 실행되는 GUI 앱에 결과가 표시되고 프로그램 실행에 따라 라이브로 업데이트된다는 점이다.

파이썬 애플리케이션을 계측하려면 c프로파일 사용 방법과 마찬가지로 팔란티어를 통해 해당 앱을 실행하기만 하면 된다. 함수 호출, 예외, 가비지 수집, OS 수준 메모리 할당 모두 추적된다. 앱의 성능 문제가 메모리 사용 또는 객체 할당과 관련된 경우 특히 마지막 두 가지가 유용하다.

최소한 지금 시점에서 팔란티어의 한 가지 큰 단점은 소스에서 빌드해야 한다는 점이다. 설치 가능한 파이썬 휠 형태의 사전 컴파일된 바이너리가 아직 제공되지 않으므로 C++ 컴파일러를 꺼내야 하고, C파이썬의 소스 사본도 필요하다.


파이인스트루먼트(Pyinstrument)

파이인스트루먼트는 c프로파일과 마찬가지로 프로그램을 추적하고 대부분의 시간을 점유하는 코드에 대한 보고서를 생성한다. 그러나 파이인스트루먼트는 c프로파일과 비교할 때 두 가지 큰 장점이 있다.

첫째, 파이인스트루먼트는 함수 호출의 모든 인스턴스를 잡아내려고 시도하지 않는다. 프로그램의 호출 스택을 밀리초 단위로 샘플링하므로 과도하지 않으면서도 프로그램 런타임의 대부분을 소비하는 것이 무엇인지 감지할 만큼의 민감도는 갖췄다.

둘째, 파이인스트루먼트 보고서가 훨씬 더 간결하다. 프로그램에서 가장 많은 시간을 점유하는 함수를 보여주므로 가장 큰 요인의 분석에 집중할 수 있다. 또한 군더더기 없이 신속하게 결과를 찾을 수 있게 해준다.

파이인스트루먼트에는 c프로파일의 편의 기능 역시 많다. 프로파일러를 애플리케이션의 객체로 사용해서 전체 애플리케이션이 아닌 선택한 함수의 동작을 기록할 수 있고 출력은 HTML을 포함한 많은 방법으로 표현이 가능하다. 원할 경우 호출의 전체 타임라인도 볼 수 있다.

주의해야 할 점도 두 가지 있다. 첫째, 사이썬(Cython)으로 만든 프로그램과 같이 C 컴파일된 확장을 사용하는 일부 프로그램은 명령줄을 통해 파이인스트루먼트와 함께 호출할 경우 제대로 작동하지 않을 수 있다. 그러나 파이인스트루먼트가 프로그램 자체에서 사용되는 경우에는 정상 작동한다. 예를 들어 파이인스트루먼 프로파일러 호출로 main() 함수를 래핑하는 방법이 있다.

두 번째 주의 사항은 파이인스트루먼트는 여러 스레드에서 실행되는 코드는 처리하지 않는다는 점이다. 이 경우에는 다음에서 설명할 파이-스파이(Py-spy)가 더 나은 선택이다.


파이-스파이(Py-spy)

파이-스파이는 파이인스트루먼트(Pyinstrument)와 마찬가지로 모든 호출을 기록하는 것이 아닌 일정 간격으로 프로그램 호출 스택의 상태를 샘플링하는 방식으로 작동한다. 파이-스파이는 파이인스트루먼트와 달리 코어 구성요소가 러스트(Rust)로 작성됐으며(파이인스트루먼트는 C 확장을 사용함), 프로파일링되는 프로그램과 함께 프로세스 외부에서 실행되므로 프로덕션에서 실행 중인 코드에서 안전하게 사용할 수 있다.

이 아키텍처 덕분에 파이-스파이는 다른 많은 프로파일러는 할 수 없는 일, 멀티스레드 또는 서브프로세스 파이썬 애플리케이션 프로파일링이 가능하다. 파이-스파이는 C 확장도 프로파일링할 수 있지만 쓸모가 있으려면 확장을 심볼로 컴파일해야 한다. 또한 사이썬으로 컴파일된 확장의 경우 생성된 C 파일이 있어야 적절한 추적 정보가 수집된다.

파이-스파이로 앱을 검사하는 기본적인 방법은 두 가지다. 파이-스파이의 record 명령을 사용해 앱을 실행하면 실행이 완료된 후 플레임 그래프가 생성된다. 또는 파이-스파이의 top 명령을 사용해 앱을 실행할 수 있으며 이 경우 파이썬 앱의 내부 동작이 라이브로 업데이트되는 인터랙티브한 화면이 표시된다. 유닉스의 top 유틸리티와 같은 방식이다. 명령줄에서 개별 스레드 스택을 덤프할 수도 있다.

파이-스파이의 한 가지 큰 단점은 주로 외부에서 전체 프로그램 또는 일부 구성요소를 프로파일링하도록 만들어졌다는 점이다. 특정 함수만 데코레이션하고 샘플링할 수는 없다.


야피(Yappi)

야피는 'Yet Another Python Profiler'의 약어로, 다른 프로파일러의 가장 좋은 여러 기능과 함께 다른 도구에는 없는 고유한 기능도 제공한다. 파이참(PyCharm)은 기본 프로파일러로 야피를 설치하므로 파이참 IDE 사용자는 바로 야피를 사용할 수 있다.

야피를 사용하려면 프로파일링 메커니즘을 호출, 시작, 중지하고 보고서를 생성하는 명령으로 코드를 데코레이션한다. 야피에서는 소요된 시간 측정에 '벽 시간(wall time)' 또는 'CPU 시간'을 선택할 수 있다. 벽 시간은 단순한 스톱워치다. CPU 시간은 시스템 네이티브 API를 통한 시계로, I/O 또는 스레드 대기를 위한 일시 정지 시간은 뺀, 코드 실행에 실제로 CPU가 관여한 시간이다. CPU 시간은 수치 코드 실행과 같은 특정 작업이 실제로 소비한 시간을 가장 정확히 알 수 있는 지표다.

야피가 스레드에서 통계를 불러오는 방식 측면에서 한 가지 좋은 점은 스레드 코드를 데코레이션할 필요가 없다는 것이다. 야피가 제공하는 yappi.get_thread_stats() 함수는 기록하는 스레드 활동에서 통계를 불러오므로 개별적으로 파싱할 수 있다. 통계는 c프로파일과 비슷하게 세분화해 필터링, 정렬할 수 있다.

마지막으로, 야피는 그린렛(Greenlets)과 코루틴(Coroutines)도 프로파일링할 수 있다. 다른 프로파일러에서는 쉽게 할 수 없거나 아예 할 수 없는 기능이다. 파이썬에서 비동기 메타포의 사용이 증가하고 있음을 감안하면 동시 코드를 프로파일링하는 기능은 강력한 도구가 된다. editor@itworld.co.kr 

회사명 : 한국IDG | 제호: ITWorld | 주소 : 서울시 중구 세종대로 23, 4층 우)04512
| 등록번호 : 서울 아00743 등록발행일자 : 2009년 01월 19일

발행인 : 박형미 | 편집인 : 박재곤 | 청소년보호책임자 : 한정규
| 사업자 등록번호 : 214-87-22467 Tel : 02-558-6950

Copyright © 2024 International Data Group. All rights reserved.