django cProfile 프로파일 방법

전언

개발/운영하는 서비스가 느려질 때 혹인 기능변경이 있을 경우 서비스 동작의 상세 내용을 분석 할 때가 있습니다. 느려진 이유를 찾아 개선하거나 기능변경(추가)로 인해 어떤 영향을 끼치는지 분석을 할 수도 있습니다. python은 여러 프로파일링 툴이 있지만 저는 cProfile을 활용 하는 방법에 대해 공유드리고자 합니다.

cProfile

cProfile은 C extension으로 개발되어 low-overhead 특징있는 프로파일링 라이브러리 & 툴 입니다.

추가 특징으로는 python level function에는 overhead가 있지만 C level function은 overhead가 없다는 점 입니다. 이 로 인해 결과가 python level 코드가 좀 더 느리게 나올 수 있습니다.

call stack에 대한 function단위로 프로파일링 정보를 제공합니다.

214 function calls (207 primitive calls) in 0.002 seconds

Ordered by: cumulative time

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.002    0.002 {built-in method builtins.exec}
     1    0.000    0.000    0.001    0.001 <string>:1(<module>)
     1    0.000    0.000    0.001    0.001 __init__.py:250(compile)
     1    0.000    0.000    0.001    0.001 __init__.py:289(_compile)
     1    0.000    0.000    0.000    0.000 _compiler.py:759(compile)
     1    0.000    0.000    0.000    0.000 _parser.py:937(parse)
     1    0.000    0.000    0.000    0.000 _compiler.py:598(_code)
     1    0.000    0.000    0.000    0.000 _parser.py:435(_parse_sub)

CLI 사용법

$ python -m cProfile [-o output_file] [-s sort_order] (-m module | myscript.py)

예시:

$ python -m cProfile -o out.prof manage.py runserver 0.0.0.0:8000
$ python -m cProfile -o out.prof test_script.py <args1> <args2>

script over django

서버로 테스트가 가능하지만, 반복이 가능하고 시작과 종료가 동일한 재현 가능한 스크립트로 분석이 필요 할 경우가 있습니다.

django의 기능(ORM, etc.)을 활용하는 파이썬 스크립트를 프로파일링 하는 방법입니다.

django-extension의 RunScript 기능을 활용할 것입니다.

django extension RunScript는 django를 사용하는 python script를 간편하게 개발 실행을 도와주는 툴입니다.

memo_care_backend/
├── manage.py
├── ...
└── scripts/
    └── profile_script.py

위 처럼 기본 디렉토리는 <root_project>/scripts 입니다. 이 위치에 파이썬 코드를 위치 시 아래처럼 실행이 가능합니다.

# memo_care_backend/scripts/test_script.py

from django.conf import settings

def run(*args):
        # django extension이 run함수를 entry point로 잡습니다.
        print(f"[*] DATABASES settings: {settings.DATABASES}, args1: {args[0]}")
$ python -m cProfile -o out.prof manage.py runscript test_script --script-args foo

[*] Current Secret ID: [******-secret-env]
[*] Current ENV file: [.env.isaacpark]
[*] AWS ENV: dev | IAM: isaac@*****.com

[*] DATABASES settings: {'default': {'NAME': '*********', 'USER': 'user', 'PASSWORD': '*******', 'HOST': 'localhost', 'PORT': 3307, 'ENGINE': 'django.db.backends.mysql', 'CHARSET': 'utf8mb4', 'OPTIONS': {'read_default_file': '/Users/isaacpark/git/backend/******/my.cnf'}, 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'TIME_ZONE': None, 'TEST': {'CHARSET': None, 'COLLATION': None, 'MIGRATE': True, 'MIRROR': None, 'NAME': None}}}, args1: foo

다른 위치에 파일을 스크립트로 사용 시 —-chdir 를 사용합니다.

$ python -m cProfile -o out.prof manage.py runscript --chdir <other_dir> <script_name>

덤프파일 분석 툴

cProfile 덤프파일을 분석목적 사각화 툴은 많이 있습니다. 저는 제가 사용해보고 결정하게 된 snakeviz를 소개드리려고 합니다.

Official site: https://jiffyclub.github.io/snakeviz/

$ python -m pip install snakeviz
$ snakeviz program.prof

실행 시 자동 브라우저로 redirection이 됩니다.

Untitled

Snakeviz 화면:

가장 아래 function 검색할 수 있습니다.

왼쪽에는 stack depth나 UI stype, gutoff 기능이 있습니다.

depth는 UI로 stack depth를 표시할 수치입니다.

cutoff는 parent function의 cumtime을 적게 사용 시 UI서 보이지 않게 하는 기능입니다.

Untitled