Python

profiling — Python 프로파일러

Added in version 3.15.

소스 코드: Lib/profiling/


프로파일링 소개

프로파일(profile) 은 프로그램의 다양한 부분이 얼마나 자주, 그리고 얼마나 오랫동안 실행되는지 설명하는 통계 집합입니다. 이러한 통계는 성능 병목 지점을 파악하고 최적화 노력을 안내하는 데 도움이 됩니다. 파이썬은 이 정보를 수집하기 위해 통계적 샘플링과 결정론적 추적이라는 근본적으로 다른 두 가지 접근 방식을 제공합니다.

profiling 패키지는 파이썬의 내장 프로파일링 도구들을 단일 네임스페이스로 구성합니다. 이 패키지는 서로 다른 프로파일링 방법론을 구현하는 두 개의 서브 모듈을 포함합니다.

profiling.sampling

콜 스택을 주기적으로 샘플링하는 통계적 프로파일러입니다. 스크립트를 직접 실행하거나 PID를 통해 실행 중인 프로세스에 연결할 수 있습니다. 여러 출력 형식(flame graphs, heatmaps, Firefox Profiler), GIL 분석, GC 추적 및 다양한 프로파일링 모드(wall-clock, CPU, GIL)를 거의 없는 오버헤드로 제공합니다.

profiling.tracing

모든 함수 호출, 반환 및 예외 이벤트를 추적하는 결정론적 프로파일러입니다. 정확한 호출 횟수와 정밀한 타이밍 정보를 제공하며, 매우 빠르게 실행되는 함수를 포함한 모든 호출을 캡처합니다.

참고

프로파일러 모듈은 벤치마킹 목적이 아니라 주어진 프로그램에 대한 실행 프로파일을 제공하기 위해 설계되었습니다. 벤치마킹을 위해서는 비교적 정확한 시간 측정을 제공하는 timeit 모듈을 사용하십시오. 이러한 구분은 특히 파이썬 코드를 C 코드와 비교할 때 중요합니다. 결정론적 프로파일러는 파이썬 코드에는 오버헤드를 발생시키지만 C 수준 함수에는 발생시키지 않으므로, 결과가 왜곡될 수 있습니다.

프로파일러 선택

대부분의 성능 분석에는 통계적 프로파일러(profiling.sampling)를 사용하십시오. 오버헤드가 거의 없으며 개발 및 운영 환경 모두에서 작동하며, flame graphs, heatmaps, GIL 분석 등 풍부한 시각화 옵션을 제공합니다.

정확한 호출 횟수 가 필요하고 어떠한 함수 호출도 놓쳐서는 안 되는 경우에 결정론적 프로파일러(profiling.tracing)를 사용하십시오. 이 방식은 모든 함수 호출과 반환을 계측하므로 샘플링 간격 사이에 완료되는 매우 빠른 함수까지 모두 캡처합니다. 대신 더 높은 오버헤드가 발생합니다.

다음 표는 주요 차이점을 요약한 것입니다.

기능

통계적 샘플링 (profiling.sampling)

결정론적 (profiling.tracing)

오버헤드

거의 없음

보통

정확도

통계적 추정치

정확한 호출 횟수

출력 형식

pstats, flame graph, heatmap, gecko, collapsed

pstats

프로파일링 모드

Wall-clock, CPU, GIL

Wall-clock

특수 프레임

GC, native (C 확장)

해당 없음

PID 연결

아니요

통계적 샘플링을 사용하는 경우

대부분의 성능 분석 작업에는 통계적 프로파일러(profiling.sampling)를 권장합니다. 사용 방법은 profiling.tracing 과 동일합니다:

python -m profiling.sampling run script.py

샘플링 프로파일러의 주요 장점 중 하나는 다양한 출력 형식입니다. 기존의 pstats 테이블 외에도 호출 계층을 시각화하는 대화형 flame graph, 코드 내에서 시간이 소모되는 지점을 정확히 보여주는 라인 단위 소스 heatmap, 타임라인 기반 분석을 위한 Firefox Profiler 결과 등을 생성할 수 있습니다.

또한 이 프로파일러는 결정론적 프로파일링으로는 파악할 수 없는 파이썬 인터프리터의 동작에 대한 통찰을 제공합니다. 멀티스레드 코드에서 GIL 경합을 확인하려면 --mode gil``을, I/O 대기 시간을 제외한 실제 CPU 시간을 측정하려면 ``--mode cpu``를 사용하거나, ``<GC> 프레임을 조사하여 가비지 컬렉션 오버헤드를 파악할 수 있습니다. --native 옵션은 C 확장에서 소모된 시간을 보여주어 파이썬 자체의 오버헤드와 라이브러리 성능을 구분하는 데 도움을 줍니다.

멀티스레드 애플리케이션의 경우, -a 옵션을 사용하면 모든 스레드를 동시에 샘플링하여 작업이 어떻게 분산되는지 보여줍니다. 또한 운영 환경 디버깅을 위해 attach 명령을 사용하면 재시작이나 코드 수정 없이 PID를 통해 실행 중인 파이썬 프로세스에 연결할 수 있습니다.

결정론적 추적을 사용하는 경우

결정론적 프로파일러(profiling.tracing)는 모든 함수 호출과 반환을 계측합니다. 이 방식은 샘플링보다 오버헤드가 높지만 프로그램 실행에 대한 전체적인 커버리지를 보장합니다.

결정론적 추적을 선택하는 주요 이유는 정확한 호출 횟수가 필요할 때입니다. 통계적 프로파일링은 샘플링을 기반으로 빈도를 추정하므로, 샘플링 간격 사이에 완료되는 짧은 수명의 함수를 과소 계산할 수 있습니다. 최적화를 통해 함수 호출 횟수가 실제로 줄어들었는지 확인해야 하거나, 전체 호출 그래프를 추적하여 호출자-피호출자 관계를 파악하고자 할 때는 결정론적 추적이 적합한 선택입니다.

결정론적 추적은 마이크로초 단위로 실행되는 함수를 캡처하는 데도 탁월합니다. 이러한 함수들은 통계적 샘플에서 충분히 자주 나타나지 않을 수 있지만, 결정론적 추적은 실행 기간에 관계없이 모든 호출을 기록합니다.

빠른 시작

이 섹션에서는 프로파일링을 시작하는 데 필요한 최소한의 단계를 제공합니다. 전체 문서는 각 프로파일러 전용 페이지를 참조하십시오.

통계적 프로파일링

스크립트를 프로파일링하려면 run 명령과 함께 profiling.sampling 모듈을 사용하십시오:

python -m profiling.sampling run script.py
python -m profiling.sampling run -m mypackage.module

이 명령어는 스크립트를 프로파일러 아래에서 실행하고 시간이 어디에 소비되었는지 요약본을 출력합니다. 대화형 flame graph를 보려면:

python -m profiling.sampling run --flamegraph script.py

이미 실행 중인 프로세스를 프로파일링하려면 프로세스 ID와 함께 attach 명령을 사용하십시오:

python -m profiling.sampling attach 1234

사용자 정의 설정을 위해 샘플링 간격(마이크로초)과 지속 시간(초)을 지정하십시오:

python -m profiling.sampling run -i 50 -d 30 script.py

결정론적 프로파일링

커맨드라인에서 스크립트를 프로파일링하려면:

python -m profiling.tracing script.py

프로그램적으로 코드 조각을 프로파일링하려면:

import profiling.tracing
profiling.tracing.run('my_function()')

이 명령은 주어진 코드를 프로파일러 아래에서 실행하고 정확한 함수 호출 횟수와 타이밍을 보여주는 요약본을 출력합니다.

프로파일 결과 해석

두 프로파일러 모두 함수 수준의 통계를 수집하지만, 서로 다른 형식으로 표시합니다. 샘플링 프로파일러는 다양한 시각화(flame graphs, heatmaps, Firefox Profiler, pstats 테이블)를 제공하는 반면, 결정론적 프로파일러는 pstats 호환 출력을 생성합니다. 형식에 관계없이 기본 개념은 동일합니다.

주요 프로파일링 개념:

직접 시간(Direct time) (self time 또는 tottime이라고도 함)

호출한 함수에서 소모된 시간을 제외하고 해당 함수 자체의 코드를 실행하는 데 걸린 시간입니다. 직접 시간이 높다는 것은 해당 함수에 비용이 많이 드는 작업이 포함되어 있음을 나타냅니다.

누적 시간(Cumulative time) (total time 또는 cumtime이라고도 함)

해당 함수와 그 함수가 호출한 모든 함수에서 소모된 시간입니다. 이는 전체 호출 하위 트리를 포함하여 함수를 호출하는 데 드는 총 비용을 측정합니다.

호출 수(Call count) (ncalls 또는 samples라고도 함)

(결정론적 프로파일링에서) 함수가 호출된 횟수 또는 (통계적 프로파일링에서) 샘플링된 횟수입니다. 결정론적 프로파일링에서 이 값은 정확합니다. 통계적 프로파일링에서 이 값은 스택 샘플에서 해당 함수가 나타난 횟수를 의미합니다.

기본 호출(Primitive calls)

재귀에 의해 유발되지 않은 호출입니다. 함수가 재귀될 때 총 호출 수는 재귀적 호출을 포함하지만, 기본 호출은 초기 진입만 카운트합니다. total/primitive 형식으로 표시되며(예를 들어, 3/1 은 총 3번의 호출 중 1번이 초기 진입임을 의미함).

호출자/피호출자 관계(Caller/Callee relationships)

어떤 함수가 주어진 함수를 호출했는지(호출자)와 그 함수가 어떤 함수를 호출했는지(피호출자)입니다. Flame graph는 이를 중첩된 사각형으로 시각화하며, pstats는 print_callers()print_callees() 메서드를 통해 표시할 수 있습니다.

레거시 호환성

하위 호환성을 위해 cProfile 모듈은 profiling.tracing 의 별칭으로 유지됩니다. import cProfile 을 사용하는 기존 코드는 향후 모든 파이썬 버전에서 수정 없이 작동합니다.

버전 3.15부터 폐지됨: 순수 파이썬인 profile 모듈은 더 이상 권장되지 않으며(deprecated), Python 3.17에서 제거될 예정입니다. 대신 profiling.tracing (또는 별칭인 cProfile)을 사용하십시오. 마이그레이션 가이드는 profile 을 참조하십시오.

더 보기

profiling.sampling

flame graphs, heatmaps, GIL 분석 기능이 포함된 통계적 샘플링 프로파일러입니다. 대부분의 사용자에게 권장됩니다.

profiling.tracing

정확한 호출 횟수를 위한 결정론적 추적 프로파일러입니다.

pstats

프로파일 데이터의 통계 분석 및 포맷팅.

timeit

작은 코드 조각의 실행 시간을 측정하는 모듈입니다.

서브 모듈

분실물 보관소