고급 Python

본 토픽은 현재 준비중입니다. 공동공부에 참여하시면 완성 되었을 때 알려드립니다.

벤치마크

Unix time 명령을 통한 벤치마크

 Unix, Linux OS에서 time 명령은 특정 명령이 실행되는 데 걸리는 시간을 측정한다. 간단한 명령 및 파일 단위의 전체 실행 시간을 측정하고자 할 때 유용하다.

 time 명령은 다음 세 가지 수치를 표시한다.

  • real: 프로세스의 실행 시작부터 끝까지 사용된 시간
  • user: 계산하는 동안 모든 CPU에서 사용한 누적 시간
  • sys: 메모리 할당, 파일 입출력 등 시스템 연관 작업 동안 모든 CPU가 사용한 누적 시간

 여러 프로세서가 병렬로 작업하는 경우 user + sys 값이 real보다 큰 경우가 있을 수 있다.

time 명령의 여러 옵션 및 측정 지표를 보려면 man time을 참조한다.

함수 단위 벤치마크

 Python 소스코드에서 함수 단위의 벤치마크를 하기 위해서는 pytest Python 패키지가 필요하다. 아래 명령을 실행하면 해당 파일의 특정 함수가 실행되면서 소요되는 시간을 측정할 수 있다.

pytest <PYTHON-FILE>.py::<FUNCTION-NAME>

 좀 더 세부적인 벤치마크를 위해서는 pytest-benchmark Python 패키지가 추가로 필요하다. 벤치마크 대상 함수의 인자에 `benchmark` 이름의 매개변수를 추가하고 

함수 단위 프로파일링

 코드의 성능을 측저하기 위해서는 어느 부분에서 시간이 많이 소요되는 지 측정할 필요가 있다. Python에서는 Profile, cProfile 모듈을 제공하여 자체적인 프로파일링을 수행할 수 있다. 측정 자체에 대한 오버헤드가 있기 때문에 보통 C로 작성된 cProfile 모듈을 사용한다. cProfile 모듈은 터미널, Python 코드, IPython으로 실행될 수 있으며, Python 코드로 구현한 예제는 다음과 같다.

import cProfile
pr = cProfile.Profile()
pr.enable()    
test_function()
pr.disable()
pr.print_stats()

 또는, 터미널에서 python 명령과 함께 실행할 수 있다. -s 옵션을 통해 어떤 측정 항목을 기준으로 정렬을 할 것인지를 지정하고, -o 옵션으로 출력 결과를 파일로 저장할 수 있다.

python -m cProfile test.py
python -m cProfile -s tottime -o prof.out test.py

라인 단위 프로파일링

 소스코드의 라인 별 소요 시간을 측정하기 위해서는 line_profiler Python 패키지를 설치해야 한다. 그 뒤 프로파일링을 하려는 함수의 선언부 위에 @profile 데코레이터를 선언한 후 kernprof 명령을 실행한다.

@profile
def test():
    a = 0
    return 0
kernprof -l -v test.py
python -m line_profiler test.py.lprof > result.txt

 -l 옵션은 함수 단위가 아닌 라인 단위로 프로파일링 하는 옵션이다. 기본적으로 결과를 소스파일명.lprof 형식으로 저장하지만, 추가로 -v 옵션을 통해 출력 결과를 터미널에 표시한다. 그 위 lprof 포맷을 텍스트 형식으로 변환하면, 소스코드의 라인 별 소요시간을 분석할 수 있다.

Total time: 21.6261 s
File: src/datasets.py
Function: __init__ at line 21

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    21                                               @profile
    22                                               def __init__(self, dataset_name, root_dir='datasets'):
    23         1          3.0      3.0      0.0          self.root_dir = root_dir
    24                                                   
    25                                                   # Dataset download
    26         2       2754.0   1377.0      0.0          for url in tqdm(AnomalyDataset.DOWNLOAD_LINKS[dataset_name], desc='Download dataset archives', dynamic_ncols=True):
    27         1     286709.0 286709.0      1.3              if not isfile(join('tmp', dataset_name, basename(url))) or getsize(join('tmp', dataset_name, basename(url))) != getattr(req.urlopen(url), 'length'):
    28                                                           self.download(url, join('tmp', dataset_name))
    29                                                       else:
    30         1       3165.0   3165.0      0.0                  tqdm.write(f'{basename(url)} is downloaded already.')
    31         1         58.0     58.0      0.0          tqdm.write('Dataset download completed.')

psutil

 

댓글

댓글 본문
버전 관리
Hyunseok Lim
현재 버전
선택 버전
graphittie 자세히 보기