1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python3.12から、PythonスクリプトでPerfが取れるようになったそうなので試してみました。12

元記事についてコメントを頂き、ミスが分かったため改版しました。どうもありがとうございました。(2024/7/14)

  • Pyenvの導入について (y-vectorfieldさん)
  • Pythonのビルドフラグと環境変数の設定 (dameyodamedameさん)

事前準備

(1) PythonがLinux perfに対応しているかを確認します。sysconfigPY_HAVE_PERF_TRAMPOLINEが設定されていれば良いようです。1

$ python -m sysconfig | grep HAVE_PERF_TRAMPOLINE
  PY_HAVE_PERF_TRAMPOLINE = "1"

(2) CPythonのビルドオプションに-fno-omit-frame-pointer, -mno-omit-leaf-frame-pointerがあったかを確認します。これは、perfが解析に利用するフレームポインタを保持するためのビルドオプション(gcc)のようです。

$ python -m sysconfig | grep 'no-omit-frame-pointer'
	CFLAGS = "-fno-strict-overflow -DNDEBUG -g -O3 -Wall -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"

(3) ユーザー権限でカーネル解析ができるようにシステムのkptr_restrictperf_event_paranoidのレベルを変更しておきます。

$ echo 0 | sudo tee  /proc/sys/kernel/kptr_restrict > /dev/null
$ echo 0 | sudo tee  /proc/sys/kernel/perf_event_paranoid > /dev/null

筆者の環境ではPythonが上記(1), (2)に対応していませんでした。
対応手順をpyenvで行うことにしました。3

pythonのインストール・確認
$ export PYTHON_CFLAGS='-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer'
$ pyenv install 3.12.4
$ pyenv local 3.12.4
$ python --version
Python 3.12.4
$ python -m sysconfig | grep HAVE_PERF_TRAMPOLINE
PY_HAVE_PERF_TRAMPOLINE = "1"
$ python -m sysconfig | grep 'no-omit-frame-pointer'
CFLAGS = "-fno-strict-overflow -DNDEBUG -g -O3 -Wall -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"

perfの取得

サンプルコード1でコールグラフを取得してみました。

example.py
def foo(n):
    result = 0
    for _ in range(n):
        result += 1
    return result

def bar(n):
    foo(n)

def baz(n):
    bar(n)

if __name__ == "__main__":
    baz(10000000)

元記事のコメントで頂いたとおり、perf recordではPYTHONPERFSUPPORT=1を環境変数で指定する必要がありました。3
この環境変数は実行時にこの機能をアクティベートするための条件になっているようです。45

perf record
$ PYTHONPERFSUPPORT=1 perf record -F 9999 -g -o perf.data python example.py
[ perf record: Woken up 4 times to write data ]
[ perf record: Captured and wrote 0.944 MB perf.data (4448 samples) ]
perf report
$ perf report --stdio -g -n 
:
# Children      Self       Samples  Command   Shared Object         Symbol                                                                        
# ........  ........  ............  ........  ....................  ..............................................................................
#
    92.93%     0.00%             0  python    libc.so.6             [.] __libc_start_call_main
            |
            ---__libc_start_call_main
               Py_BytesMain
               |          
               |--91.32%--Py_RunMain
               |          |          
               |           --90.96%--pymain_run_python.constprop.0
               |                     |          
               |                      --90.94%--_PyRun_AnyFileObject
               |                                _PyRun_SimpleFileObject
               |                                |          
               |                                 --90.91%--run_mod
               |                                           |          
               |                                            --90.89%--run_eval_code_obj
               |                                                      PyEval_EvalCode
               |                                                      py::<module>:.../example.py
               |                                                      _PyEval_EvalFrameDefault
               |                                                      |          
               |                                                       --90.87%--PyObject_Vectorcall
               |                                                                 py::baz:.../example.py
               |                                                                 _PyEval_EvalFrameDefault
               |                                                                 PyObject_Vectorcall
               |                                                                 py::bar:.../example.py
               |                                                                 _PyEval_EvalFrameDefault
               |                                                                 PyObject_Vectorcall
               |                                                                 py::foo:.../example.py
               |                                                                 |          
               |                                                                 |--81.36%--_PyEval_EvalFrameDefault

:

コールグラフが取得できているようでした。(関数のトレース情報を含む/tmp/perf-<PID>.mapも残っていました)


環境

CPU: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
OS: Ubuntu-22.04
Kernel: 6.5.0-41-generic
Pyenv: 2.4.7
Python: 3.12.4

  1. https://docs.python.org/3/howto/perf_profiling.html#python-support-for-the-linux-perf-profiler 2 3

  2. https://github.com/python/cpython/issues/96143

  3. https://realpython.com/python312-perf-profiler/#install-python-312-using-pyenv 2

  4. https://github.com/python/cpython/blob/v3.12.4/Python/initconfig.c#L152

  5. https://github.com/python/cpython/blob/v3.12.4/Python/perf_trampoline.c#L427

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?