profile — 순수 파이썬 프로파일러¶
소스 코드: Lib/profile.py
버전 3.15부터 사용 지원 중단(deprecated), 버전 3.17에서 제거 예정.
profile 모듈은 더 이상 사용되지 않으며(deprecated) Python 3.17에서 삭제될 예정입니다. 대신 profiling.tracing 을 사용하십시오.
profile 모듈은 결정론적 프로파일러의 순수 파이썬 구현을 제공합니다. 이 구현은 프로파일러 내부 구조를 이해하거나 하위 클래스화를 통해 프로파일러 동작을 확장하는 데 유용하지만, C 기반의 profiling.tracing 모듈과 비교했을 때 상당한 오버헤드가 발생합니다.
대부분의 프로파일링 작업에는 다음을 사용하십시오:
오버헤드 없는 운영 환경 디버깅 시에는
profiling.sampling을 사용하십시오.개발 및 테스트를 위해서는
profiling.tracing을 사용하십시오.
마이그레이션¶
profile 에서 profiling.tracing 으로 마이그레이션하는 것은 간단합니다. API가 호환됩니다:
_# 기존 (더 이상 권장되지 않음)
import profile
profile.run('my_function()')
# 신규 (권장됨)
import profiling.tracing
profiling.tracing.run('my_function()')_
대부분의 코드에서 import profile``을 ``import profiling.tracing``으로 바꾸고(전체 코드에서 ``profile 대신 profiling.tracing 사용), 간단하게 마이그레이션할 수 있습니다.
참고
cProfile 모듈은 profiling.tracing 의 하위 호환성이 있는 별칭으로 계속 유지됩니다. import cProfile 을 사용하는 기존 코드는 수정 없이 작동합니다.
profile 및 profiling.tracing 모듈 참조¶
profile 와 profiling.tracing 모듈 모두 다음 함수를 제공합니다:
- profile.run(command, filename=None, sort=-1)¶
이 함수는
exec()함수에 전달할 수 있는 단일 인자와 선택적 파일 이름을 취합니다. 모든 경우에 이 루틴은 다음을 실행합니다:exec(command, __main__.__dict__, __main__.__dict__)
그리고 실행으로부터 프로파일링 통계를 수집합니다. 파일 이름이 없으면, 이 함수는 자동으로
Stats인스턴스를 만들고 간단한 프로파일링 보고서를 인쇄합니다. 정렬 값이 지정되면, 이Stats인스턴스로 전달되어 결과 정렬 방법을 제어합니다.
- profile.runctx(command, globals, locals, filename=None, sort=-1)¶
이 함수는
run()과 유사하며, command 문자열에 대한 전역(globals)과 지역(locals) 매핑 제공하기 위한 인자가 추가되었습니다. 이 루틴은 다음을 실행합니다:exec(command, globals, locals)
그리고 위의
run()함수에서와같이 프로파일링 통계를 수집합니다.
- class profile.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)¶
이 클래스는 일반적으로
profiling.tracing.run()함수가 제공하는 것보다 더 정밀한 프로파일링 제어가 필요한 경우에만 사용됩니다.timer 인자를 통해 코드를 실행하는 데 걸리는 시간을 측정하기 위한 사용자 정의 타이머를 제공할 수 있습니다. 현재 시각을 나타내는 단일 숫자를 반환하는 함수여야 합니다. 숫자가 정수이면, timeunit는 각 시간 단위의 지속 시간을 지정하는 승수를 지정합니다. 예를 들어, 타이머가 밀리초 단위로 측정된 시간을 반환하면 시간 단위는
.001입니다.Profile클래스를 직접 사용하면 프로파일 데이터를 파일에 쓰지 않고도 프로파일 결과를 포맷할 수 있습니다:_import profiling.tracing import pstats import io from pstats import SortKey pr = profiling.tracing.Profile() pr.enable() # ... 작업 수행 ... pr.disable() s = io.StringIO() sortby = SortKey.CUMULATIVE ps = pstats.Stats(pr, stream=s).sort_stats(sortby) ps.print_stats() print(s.getvalue())_
Profile클래스는 컨텍스트 관리자로도 사용할 수 있습니다(profiling.tracing에서만 지원되며, 더 이상 권장되지 않는profile모듈에서는 지원되지 않습니다. 상세 내용은 컨텍스트 관리자 형 를 참조하십시오):_import profiling.tracing with profiling.tracing.Profile() as pr: # ... 작업 수행 ... pr.print_stats()_
버전 3.8에서 변경: 컨텍스트 관리자 지원이 추가되었습니다.
- enable()¶
프로파일링 데이터 수집을 시작합니다.
profiling.tracing에서만 제공됩니다.
- disable()¶
프로파일링 데이터 수집을 중단합니다.
profiling.tracing에서만 제공됩니다.
- create_stats()¶
프로파일링 데이터 수집을 중지하고 결과를 내부적으로 현재 프로파일로 기록합니다.
- print_stats(sort=-1)¶
현재 프로파일을 기반으로
Stats객체를 만들고 결과를 stdout에 인쇄합니다.sort 매개변수는 표시되는 통계의 정렬 순서를 지정합니다.
pstats.Stats.sort_stats()와 같이 단일 키 또는 멀티 레벨 정렬을 위한 키 튜플을 허용합니다.Added in version 3.13:
print_stats()가 이제 키의 튜플을 허용합니다.
- dump_stats(filename)¶
현재 프로파일의 결과를 filename에 씁니다.
- runcall(func, /, *args, **kwargs)¶
func(*args, **kwargs)를 프로파일 합니다
프로파일링은 호출된 명령/함수가 실제로 반환하는 경우에만 작동함에 유의하십시오. 인터프리터가 종료되면 (예를 들어 호출된 명령/함수 실행 중 sys.exit() 호출을 통해) 아무런 프로파일링 결과도 인쇄되지 않습니다.
profiling.tracing 와의 차이점¶
profile 모듈은 다음과 같은 몇 가지 면에서 profiling.tracing 과 다릅니다:
높은 오버헤드. 순수 파이썬 구현은 C 구현보다 훨씬 느리므로, 실행 시간이 긴 프로그램이나 성능에 민감한 코드를 프로파일링하는 데 적합하지 않습니다.
보정 지원. profile 모듈은 프로파일링 오버헤드를 보정하기 위한 캘리브레이션을 지원합니다. profiling.tracing 은 C 구현의 오버헤드가 미미하므로 이 기능이 필요하지 않습니다.
Custom timers. Both modules support custom timers, but profile
accepts timer functions that return tuples (like os.times()), while
profiling.tracing requires a function returning a single number.
서브클래싱. 순수 파이썬 구현은 사용자 정의 프로파일링 동작을 위해 서브클래스화하고 확장하기에 더 용이합니다.
결정론적 프로파일링이란 무엇입니까?¶
결정론적 프로파일링 은 모든 함수 호출, 함수 반환 및 예외 이벤트가 모니터링되며, 이러한 이벤트 사이의 간격(사용자 코드가 실행되는 시간)에 대해 정확한 시간이 측정됨을 반영합니다. 이와 대조적으로, profiling.sampling 모듈에서 제공하는 통계적 프로파일링 은 유효 명령어 포인터를 주기적으로 샘플링하여 시간이 소비되는 위치를 추심합니다. 후자의 기법은 전통적으로 (코드를 계측할 필요가 없기 때문에) 오버헤드가 적지만, 시간이 어디에서 소모되는지에 대한 상대적인 지표만 제공합니다.
파이썬에서는, 실행 중에 인터프리터가 활성화되어있어서, 결정론적 프로파일링을 수행하기 위해 인스트루먼트 된 코드(instrumented code)가 필요하지 않습니다. 파이썬은 각 이벤트에 대해 자동으로 훅(hook)(선택적 콜백)을 제공합니다. 또한, 파이썬의 인터프리터 적인 성격은 실행에 이미 많은 오버헤드를 추가하는 경향이 있어서, 결정론적 프로파일링은 일반적인 응용 프로그램에서 작은 처리 오버헤드만 추가하는 경향이 있습니다. 결과적으로 결정론적 프로파일링은 그다지 비싸지 않으면서도, 파이썬 프로그램의 실행에 대한 광범위한 실행 시간 통계를 제공합니다.
호출 수 통계를 사용하여 코드의 버그(놀랄만한 횟수)를 식별하고, 가능한 인라인 확장 지점(높은 호출 횟수)을 식별할 수 있습니다. 내부 시간 통계를 사용하여 신중하게 최적화해야 하는 “핫 루프(hot loops)”를 식별할 수 있습니다. 누적 시간 통계를 사용하여 알고리즘 선택에서의 고수준 에러를 식별할 수 있습니다. 이 프로파일러에서의 누적 시간의 특이한 처리는 알고리즘의 재귀 구현에 대한 통계를 반복 구현과 직접 비교할 수 있도록 함에 유의하십시오.
한계¶
타이밍 정보의 정확성과 관련하여 한 가지 제약이 있습니다. 정확성과 관련해서는 결정론적 프로파일러에 근본적인 문제가 있습니다. 가장 명백한 제약은 하부 “시계”가 (일반적으로) 약 .001 초의 속도로만 눈금이 변하는 것입니다. 따라서 하부 시계보다 더 정확한 측정은 없습니다. 충분한 측정을 수행하면, “에러”가 평균이 되어 사라지는 경향이 있습니다. 불행히도, 이 첫 번째 에러를 제거하면 두 번째 에러 원인이 발생합니다.
두 번째 문제는 이벤트가 디스패치 된 시점부터 프로파일러가 시간을 얻기 위해 호출하는 것이 실제로 시계의 상태를 얻기까지 “시간이 걸린다”는 것입니다. 마찬가지로, 프로파일러 이벤트 핸들러를 빠져나갈 때 시계값이 획득된 (그런 다음 저장됩니다) 시간부터, 사용자의 코드가 다시 실행될 때까지 어떤 지연이 발생합니다. 결과적으로, 여러 번 호출되거나, 많은 함수를 호출하는 함수는 일반적으로 이 에러를 누적합니다. 이러한 방식으로 누적되는 에러는 일반적으로 시계 정확도(1 눈금 미만)보다 작지만, 누적될 수 있어서 매우 중요해집니다.
이 문제는 오버헤드가 낮은 profiling.tracing 보다 더 이상 사용되지 않는 profile 모듈에서 더 중요합니다. 이러한 이유로, profile 은 특정 플랫폼에 맞게 자신을 보정(calibration)하는 수단을 제공하여 이 오류를 확률적으로(평균적으로) 제거할 수 있게 합니다. 프로파일러가 보정되면 정확도(최소 자승 의미에서)가 향상되지만, 때때로 음수가 생성될 수도 있습니다(호출 횟수가 매우 낮고 확률이 좋지 않을 때 등). 프로파일링 결과에 음수가 나타나더라도 당황하지 마십시오. 이는 프로파일러를 보정했을 때만 나타나야 하며, 이 경우 결과는 보정 전보다 실제로 더 정확합니다.
보정¶
profile 모듈의 프로파일러는 시간 함수 호출 및 결과 처리에 따르는 오버헤드를 보상하기 위해 각 이벤트 처리 시간에서 상수를 뺍니다. 기본적으로 이 상수는 0입니다. 특정 플랫폼에 대해 더 나은 상수를 얻으려면 다음 절차를 사용할 수 있습니다(한계 참조).
import profile
pr = profile.Profile()
for i in range(5):
print(pr.calibrate(10000))
이 메서드는 인자가 제공한 횟수의 파이썬 호출을, 직접하고 프로파일러하에서 다시 하면서, 두 두 시간을 측정합니다. 그런 다음 프로파일러 이벤트 당 숨겨진 오버헤드를 계산하여 부동 소수점으로 반환합니다. 예를 들어, 맥 OS를 실행하는 1.8Ghz 인텔 코어 i5에서, 그리고 파이썬의 time.process_time()을 타이머로 사용할 때, 매직 넘버는 약 4.04e-6입니다.
이 반복의 목적은 상당히 일관된 결과를 얻는 것입니다. 컴퓨터가 매우 빠르거나, 타이머 함수의 해상도가 좋지 않으면, 일관된 결과를 얻기 위해 100000이나 심지어 1000000을 전달해야 할 수 있습니다.
일관된 대답을 얻었을 때, 세 가지 방법으로 사용할 수 있습니다:
import profile
# 1. 이후에 만들어지는 모든 Profile 인스턴스에 계산된 바이어스를 적용합니다.
profile.Profile.bias = your_computed_bias
# 2. 특정 Profile 인스턴스에 계산된 바이어스를 적용합니다.
pr = profile.Profile()
pr.bias = your_computed_bias
# 3. 인스턴스 생성자에 계산된 바이어스를 지정합니다.
pr = profile.Profile(bias=your_computed_bias)
선택해야 한다면, 더 작은 상수를 선택하는 것이 좋습니다, 그러면 결과가 프로파일 통계에서 결과가 “덜 자주” 음수로 표시됩니다.
사용자 정의 타이머 사용하기¶
현재 시각을 결정하는 방법을 변경하려면 (예를 들어, 벽시계 시간이나 소요된 프로세스 시간을 사용하도록 만들려면), Profile 클래스 생성자에게 원하는 타이밍 함수를 전달합니다:
pr = profile.Profile(your_time_func)
그 결과로 생성된 프로파일러는 your_time_func 을 호출합니다. profile.Profile 또는 profiling.tracing.Profile 중 어느 것을 사용하는지에 따라 your_time_func 의 반환 값이 다르게 해석됩니다.
profile.Profileyour_time_func는 단일 숫자를 반환하거나, 또는 (os.times()가 반환하는 것과 같이) 합계가 현재 시각인 숫자 리스트를 반환해야 합니다. 함수가 단일 시간 숫자를 반환하거나, 반환된 숫자의 리스트 길이가 2이면, 특히 빠른 버전의 디스패치 루틴을 얻게 됩니다.여러분이 선택한 타이머 함수에 대해 프로파일러 클래스를 보정해야 합니다 (보정을 참조하십시오). 대부분의 기계에서, 단일 정숫값을 반환하는 타이머는 프로파일링 중 낮은 오버헤드 측면에서 최상의 결과를 제공합니다. (
os.times()는 부동 소수점 값의 튜플을 반환하므로 꽤 나쁩니다). 더 좋은 타이머를 가장 깨끗한 방식으로 대체하려면, 클래스를 파생하고 적절한 보정 상수와 함께 타이머 호출을 가장 잘 처리하는 대체 디스패치 메서드를 배선하십시오.profiling.tracing.Profileyour_time_func는 단일 숫자를 반환해야 합니다. 정수를 반환하면, 시간 단위의 실제 지속 시간을 지정하는 두 번째 인자로 클래스 생성자를 호출할 수도 있습니다. 예를 들어,your_integer_time_func가 밀리초 단위로 측정된 시간을 반환하면, 다음과 같이Profile인스턴스를 구성합니다:pr = profiling.tracing.Profile(your_integer_time_func, 0.001)
profiling.tracing.Profile클래스는 보정이 불가능하므로, 사용자 정의 타이머 함수는 주의해서 사용해야 하며 최대한 빠르게 작동해야 합니다. 사용자 정의 타이머로 최상의 결과를 얻으려면 내부_lsprof모듈의 C 소스에 하드 코딩해야 할 수도 있습니다.
파이썬 3.3은 time에 프로세스나 벽시계 시간을 정확하게 측정하는 데 사용할 수 있는 몇 가지 새로운 함수를 추가합니다. 예를 들어, time.perf_counter()를 참조하십시오.
더 보기
profilingPython 프로파일링 도구 개요.
profiling.tracing이 모듈을 대체할 것을 권장하는 모듈.
pstats프로파일 데이터에 대한 통계 분석 및 포맷팅.