Anda dapat mengubah format file untuk menghasilkan profil speedscope atau data mentah dengan parameter --format
. Lihat py-spy record --help
untuk informasi tentang opsi lain termasuk mengubah laju pengambilan sampel, memfilter untuk hanya menyertakan thread yang menyimpan GIL, membuat profil ekstensi C asli, menampilkan id thread, membuat profil subproses, dan banyak lagi.
Top menunjukkan tampilan langsung fungsi apa yang paling banyak memakan waktu dalam program python Anda, mirip dengan perintah top Unix. Menjalankan py-spy dengan:
py-spy top --pid 12345
# OR
py-spy top -- python myprogram.py
akan memunculkan tampilan tingkat tinggi yang diperbarui secara langsung dari program python Anda:
py-spy juga dapat menampilkan tumpukan panggilan saat ini untuk setiap thread python dengan perintah dump
:
py-spy dump --pid 12345
Ini akan membuang tumpukan panggilan untuk setiap thread, dan beberapa info proses dasar lainnya ke konsol:
Ini berguna jika Anda hanya memerlukan satu tumpukan panggilan untuk mengetahui di mana program python Anda digantung. Perintah ini juga memiliki kemampuan untuk mencetak variabel lokal yang terkait dengan setiap frame tumpukan dengan menyetel flag --locals
.
Proyek ini bertujuan untuk memungkinkan Anda membuat profil dan men-debug program Python apa pun yang sedang berjalan, meskipun program tersebut melayani lalu lintas produksi.
Meskipun ada banyak proyek pembuatan profil python lainnya, hampir semuanya memerlukan modifikasi program yang diprofilkan dalam beberapa cara. Biasanya, kode pembuatan profil dijalankan di dalam proses python target, yang akan memperlambat dan mengubah cara program beroperasi. Artinya, secara umum tidak aman menggunakan profiler ini untuk men-debug masalah di layanan produksi karena biasanya akan berdampak nyata pada performa.
py-spy bekerja dengan membaca langsung memori program python menggunakan panggilan sistem process_vm_readv di Linux, panggilan vm_read di OSX, atau panggilan ReadProcessMemory di Windows.
Mencari tahu tumpukan panggilan program Python dilakukan dengan melihat variabel global PyInterpreterState untuk menjalankan semua thread Python di penerjemah, dan kemudian mengulangi setiap PyFrameObject di setiap thread untuk mendapatkan tumpukan panggilan. Karena Python ABI berubah antar versi, kami menggunakan bindgen karat untuk menghasilkan struktur karat yang berbeda untuk setiap kelas interpreter Python yang kami pedulikan dan menggunakan struct yang dihasilkan ini untuk mengetahui tata letak memori dalam program Python.
Mendapatkan alamat memori Interpreter Python bisa menjadi sedikit rumit karena Pengacakan Tata Letak Ruang Alamat. Jika interpreter python target dikirimkan dengan simbol, maka cukup mudah untuk mengetahui alamat memori interpreter dengan melakukan dereferensi variabel interp_head
atau _PyRuntime
tergantung pada versi Python. Namun, banyak versi Python dikirimkan dengan biner yang dilucuti atau dikirimkan tanpa file simbol PDB yang sesuai di Windows. Dalam kasus ini, kami memindai bagian BSS untuk mencari alamat yang sepertinya mengarah ke PyInterpreterState yang valid dan memeriksa apakah tata letak alamat tersebut sesuai dengan yang kami harapkan.
Ya! py-spy mendukung pembuatan profil ekstensi python asli yang ditulis dalam bahasa seperti C/C++ atau Cython, di x86_64 Linux dan Windows. Anda dapat mengaktifkan mode ini dengan meneruskan --native
pada baris perintah. Untuk hasil terbaik, Anda harus mengkompilasi ekstensi Python Anda dengan simbol. Yang juga perlu diperhatikan untuk program Cython adalah py-spy memerlukan file C atau C++ yang dihasilkan untuk mengembalikan nomor baris dari file .pyx asli. Baca posting blog untuk informasi lebih lanjut.
Dengan meneruskan flag --subprocesses
ke rekaman atau tampilan atas, py-spy juga akan menyertakan keluaran dari proses python apa pun yang merupakan proses turunan dari program target. Ini berguna untuk membuat profil aplikasi yang menggunakan kumpulan pekerja multiprosesor atau gunicorn. py-spy akan memantau proses baru yang sedang dibuat, dan secara otomatis melampirkannya dan memasukkan sampel dari proses tersebut ke dalam output. Tampilan rekaman akan menyertakan PID dan cmdline setiap program di tumpukan panggilan, dengan subproses muncul sebagai anak dari proses induknya.
py-spy bekerja dengan membaca memori dari proses python yang berbeda, dan ini mungkin tidak diperbolehkan karena alasan keamanan tergantung pada OS dan pengaturan sistem Anda. Dalam banyak kasus, menjalankan sebagai pengguna root (dengan sudo atau sejenisnya) dapat mengatasi batasan keamanan ini. OSX selalu mengharuskan dijalankan sebagai root, tetapi di Linux itu tergantung pada bagaimana Anda meluncurkan py-spy dan pengaturan keamanan sistem.
Di Linux, konfigurasi defaultnya memerlukan izin root saat melampirkan ke proses yang bukan anak. Untuk py-spy ini berarti Anda dapat membuat profil tanpa akses root dengan meminta py-spy untuk membuat proses ( py-spy record -- python myprogram.py
) tetapi melampirkan ke proses yang ada dengan menentukan PID biasanya memerlukan root ( sudo py-spy record --pid 123456
). Anda dapat menghapus batasan ini di Linux dengan mengatur variabel sysctl ptrace_scope.
py-spy mencoba untuk hanya menyertakan jejak tumpukan dari thread yang menjalankan kode secara aktif, dan mengecualikan thread yang sedang tidur atau menganggur. Jika memungkinkan, py-spy mencoba mendapatkan informasi aktivitas thread ini dari OS: dengan membaca /proc/PID/stat
di Linux, dengan menggunakan panggilan mach thread_basic_info di OSX, dan dengan melihat apakah SysCall saat ini diketahui menganggur di Windows.
Ada beberapa keterbatasan dalam pendekatan ini yang mungkin menyebabkan thread yang menganggur masih ditandai sebagai aktif. Pertama, kita harus mendapatkan informasi aktivitas thread ini sebelum menjeda program, karena mendapatkan ini dari program yang dijeda akan menyebabkannya selalu kembali bahwa ini menganggur. Artinya ada potensi kondisi race, dimana kita mendapatkan aktivitas thread dan kemudian thread berada dalam keadaan berbeda saat kita mendapatkan pelacakan tumpukan. Meminta OS untuk aktivitas thread juga belum diterapkan untuk prosesor FreeBSD dan i686/ARM di Linux. Di Windows, panggilan yang diblokir di IO juga belum akan ditandai sebagai idle, misalnya saat membaca input dari stdin. Terakhir, pada beberapa panggilan Linux, lampiran ptrace yang kita gunakan dapat menyebabkan thread yang menganggur aktif sesaat, menyebabkan kesalahan positif saat membaca dari procfs. Karena alasan ini, kami juga memiliki fallback heuristik yang menandai panggilan tertentu yang diketahui dengan python sebagai tidak aktif.
Anda dapat menonaktifkan fungsi ini dengan menyetel tanda --idle
, yang akan menyertakan bingkai yang dianggap tidak aktif oleh py-spy.
Kita mendapatkan aktivitas GIL dengan melihat nilai threadid yang ditunjuk oleh simbol _PyThreadState_Current
untuk Python 3.6 dan yang lebih lama dan dengan mencari tahu persamaannya dari struct _PyRuntime
di Python 3.7 dan yang lebih baru. Simbol-simbol ini mungkin tidak disertakan dalam distribusi python Anda, yang akan menyebabkan kegagalan penyelesaian thread mana yang menyimpan GIL. Penggunaan GIL saat ini juga ditampilkan di tampilan top
sebagai %GIL.
Meneruskan flag --gil
hanya akan menyertakan jejak thread yang memegang Global Interpreter Lock. Dalam beberapa kasus, ini mungkin merupakan gambaran yang lebih akurat tentang bagaimana program python Anda menghabiskan waktunya, meskipun Anda harus menyadari bahwa ini akan kehilangan aktivitas di ekstensi yang melepaskan GIL saat masih aktif.
OSX memiliki fitur yang disebut Perlindungan Integritas Sistem yang mencegah bahkan pengguna root membaca memori dari biner mana pun yang terletak di /usr/bin. Sayangnya, ini termasuk juru bahasa python yang dikirimkan bersama OSX.
Ada beberapa cara berbeda untuk mengatasi hal ini:
Menjalankan py-spy di dalam wadah buruh pelabuhan juga biasanya akan memunculkan kesalahan izin ditolak bahkan ketika dijalankan sebagai root.
Kesalahan ini disebabkan oleh buruh pelabuhan yang membatasi panggilan sistem process_vm_readv yang kita gunakan. Hal ini dapat diatasi dengan menyetel --cap-add SYS_PTRACE
saat memulai kontainer buruh pelabuhan.
Alternatifnya, Anda dapat mengedit file yaml penulisan buruh pelabuhan
your_service:
cap_add:
- SYS_PTRACE
Perhatikan bahwa Anda harus memulai ulang kontainer buruh pelabuhan agar pengaturan ini dapat diterapkan.
Anda juga dapat menggunakan py-spy dari OS Host untuk membuat profil proses yang berjalan di dalam wadah buruh pelabuhan.
py-spy membutuhkan SYS_PTRACE
untuk dapat membaca memori proses. Kubernetes menghilangkan kemampuan tersebut secara default, sehingga mengakibatkan kesalahan
Permission Denied: Try running again with elevated permissions by going 'sudo env "PATH=$PATH" !!'
Cara yang disarankan untuk mengatasi hal ini adalah dengan mengedit spesifikasi dan menambahkan kemampuan tersebut. Untuk penerapan, hal ini dilakukan dengan menambahkan ini ke Deployment.spec.template.spec.containers
securityContext:
capabilities:
add:
- SYS_PTRACE
Detail lebih lanjut tentang ini di sini: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-capabilities-for-a-container Perhatikan bahwa ini akan menghapus pod yang ada dan membuatnya lagi .
Alpine python memilih keluar dari roda manylinux
: pypa/pip#3969 (komentar). Anda dapat mengganti perilaku ini untuk menggunakan pip untuk menginstal py-spy di Alpine dengan membuka:
echo 'manylinux1_compatible = True' > /usr/local/lib/python3.7/site-packages/_manylinux.py
Alternatifnya, Anda dapat mengunduh biner musl dari halaman rilis GitHub.
Dengan menyetel opsi --nonblocking
, py-spy tidak akan menjeda python target yang Anda gunakan untuk membuat profil. Meskipun dampak kinerja pengambilan sampel dari proses dengan py-spy biasanya sangat rendah, menyetel opsi ini akan sepenuhnya menghindari gangguan pada program python yang sedang berjalan.
Dengan rangkaian opsi ini, py-spy akan membaca status penerjemah dari proses python saat sedang berjalan. Karena panggilan yang kita gunakan untuk membaca memori bukanlah panggilan atomik, dan kita harus mengeluarkan beberapa panggilan untuk mendapatkan pelacakan tumpukan, ini berarti terkadang kita mendapatkan kesalahan saat pengambilan sampel. Hal ini dapat muncul sebagai peningkatan tingkat kesalahan saat pengambilan sampel, atau sebagai sebagian bingkai tumpukan yang disertakan dalam output.
Belum =).
Jika ada fitur yang ingin Anda lihat di py-spy, acungkan jempol pada masalah yang sesuai atau buat fitur baru yang menjelaskan fungsi apa yang hilang.
py-spy mengikuti spesifikasi CLICOLOR, sehingga pengaturan CLICOLOR_FORCE=1
di lingkungan Anda akan memiliki keluaran cetak berwarna py-spy bahkan ketika disalurkan ke pager.
py-spy sangat terinspirasi oleh karya luar biasa Julia Evans di rbspy. Secara khusus, kode untuk menghasilkan file flamegraph dan speedscope diambil langsung dari rbspy, dan proyek ini menggunakan peti memori-proses-baca dan peta proc yang dipisahkan dari rbspy.
py-spy dirilis di bawah Lisensi MIT, lihat file LISENSI untuk teks lengkap.