고급 Python

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

벤치마크

Unix time 명령을 통한 벤치마크

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

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

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

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

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

함수 단위 벤치마크

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

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

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

함수 단위 프로파일링

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

1
2
3
4
5
6
import cProfile
pr = cProfile.Profile()
pr.enable()
test_function()
pr.disable()
pr.print_stats()

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

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

라인 단위 프로파일링

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 자세히 보기