원문 캡처 · mathspp.com
원문 캡처 · mathspp.com

Python 3.15에 샘플링 프로파일러 Tachyon이 추가됐다. 스크립트를 실행하며 분석하거나 이미 실행 중인 프로세스에 연결해 성능 병목을 찾을 수 있다.

Tachyon은 표준 라이브러리의 profiling.sampling 모듈을 가리키는 이름이다. 샘플링 프로파일링은 프로그램의 호출 스택을 주기적으로 포착해 각 코드가 실행 시간에서 차지하는 비중을 추정하는 방식이다. 예를 들어 10초 동안 수집한 100만 개 샘플 가운데 2만 5,000개에서 foobar 함수가 나타났다면, Tachyon은 이 함수가 전체 시간의 2.5%인 250밀리초를 사용했다고 추정한다. 프로파일링 시간이 길고 샘플 간격이 짧을수록 결과가 더 정확해진다.

CLI는 run, attach, dump, replay 네 가지 명령을 제공한다. uv를 사용하는 경우 uv run -m profiling.sampling ... 형식으로 실행할 수도 있다.

% python -m profiling.sampling --help
usage: python -m profiling.sampling [-h] {run,attach,dump,replay} ...

Sample a process's stack frames and generate profiling data.

Examples: ...

Use python -m profiling.sampling <command> --help for command-specific help.

positional arguments:
 {run,attach,dump,replay}
 Command to run
 run Run and profile a script or module
 attach Attach to and profile a running process
 dump Dump a running process's current stack
 replay Replay a binary profile and convert to another format

options:
 -h, --help show this help message and exit

run은 스크립트나 모듈을 실행하면서 처음부터 끝까지 프로파일링한다. 실행이 끝나면 터미널에 결과를 출력한다.

% python -m profiling.sampling run myscript.py

--heatmap 옵션을 주면 분석 결과를 HTML 파일로 만든다. 생성된 폴더의 index.html을 열면 분석한 소스 파일을 살펴보고, 시간이 많이 걸린 것으로 추정되는 줄을 확인할 수 있다.

% python -m profiling.sampling run --heatmap myscript.py
...
Heatmap output written to heatmap_30282/
 - Index: heatmap_30282/index.html
 - 1 source file analyzed

--flamegraph는 불꽃 그래프를 HTML 파일로 저장한다. 그래프에서 막대 길이는 해당 코드 줄에 소요된 시간에 비례한다.

% python -m profiling.sampling run --flamegraph myscript.py
...
Flamegraph data: 1 root function, 71388 total samples, 51 unique strings
Flamegraph saved to: flamegraph_30335.html

이미 실행 중인 프로그램의 현재 호출 스택만 확인하려면 프로세스 ID를 지정해 dump를 실행한다. 이 명령은 한 번의 스냅샷을 만든다.

% python -m profiling.sampling dump 12345

프로세스에 연결해 프로파일링하려면 attach를 사용한다. 기본적으로 대상 프로세스가 종료될 때까지 분석하며, --duration SECONDS로 시간을 제한하거나 --live로 실시간 결과를 볼 수 있다. run에서 지원하는 여러 출력 형식도 사용할 수 있다. 원문은 샘플링 방식이라 실행 중인 프로세스를 사실상 오버헤드 없이 분석할 수 있어 운영 시스템에 적합하다고 설명한다.

% python -m profiling.sampling attach 12345

프로파일링 데이터를 바이너리 파일로 저장한 뒤 replay로 다른 형식으로 변환할 수도 있다. 이렇게 하면 코드를 한 번만 프로파일링하고 여러 방식으로 분석할 수 있다.

% python -m profiling.sampling run --binary -o profile.bin myscript.py

별도 옵션 없이 replay를 실행하면 기본 형식인 pstats를 표준 출력으로 내보낸다.

% python -m profiling.sampling replay profile.bin
# Prints the pstats format to stdout.

다음 명령은 바이너리 데이터를 불꽃 그래프로 변환해 my_flamegraph라는 파일로 저장한다.

% python -m profiling.sampling replay --flamegraph -o my_flamegraph profile.bin

Tachyon은 짧은 실행 시간이나 마이크로벤치마크를 측정하는 데 적합하지 않다. 짧은 프로그램은 추적 프로파일링을 사용하거나 반복 실행해야 하며, 마이크로벤치마크에는 timeit을 쓰는 편이 낫다. 두 구현 사이의 1~2% 정도의 작은 성능 차이를 가려내지 못할 수 있고, 함수 호출 횟수를 정확히 세지도 못한다. 이런 정밀 측정에는 추적 프로파일링을 사용해야 한다.

자세한 내용은 PEP 799와 Python 표준 라이브러리의 profiling.sampling 문서를 참고할 수 있다.