profiling.tracing --- پروفایل‌گیر قطعی

اضافه شده در نسخه‌ی 3.15.

کد منبع: Lib/profiling/tracing/


ماژول profiling.tracing امکان پروفایل‌گیری قطعی از برنامه‌های پایتون را فراهم می‌کند. این ماژول هر فراخوانی تابع، بازگشت تابع و رویداد استثنا را مانیتور کرده و زمان‌بندی دقیق هر کدام را ثبت می‌کند. این رویکرد تعداد دقیق فراخوانی‌ها و دید کامل نسبت به اجرای برنامه را فراهم می‌کند که آن را برای سناریوهای توسعه و تست ایده‌آل می‌سازد.

نکته

این ماژول همچنین به عنوان cProfile برای سازگاری عقبگرد در دسترس است. نام cProfile در تمام نسخه‌های آینده‌ی پایتون به کار خود ادامه خواهد داد. از هر سبک ایمپورتی که با پایگاه کُد شما سازگار است استفاده کنید:

# Preferred (new style)
import profiling.tracing
profiling.tracing.run('my_function()')

# Also works (backward compatible)
import cProfile
cProfile.run('my_function()')

پروفایل‌گیری قطعی چیست؟

پروفایل‌گیری قطعی هر فراخوانی تابع، بازگشت تابع و رویداد استثنا را در طول اجرای برنامه ثبت می‌کند. پروفایل‌گیر فاصله‌های زمانی دقیق بین این رویدادها را اندازه‌گیری می‌کند و آمارهای دقیقی درباره‌ی نحوه‌ی رفتار برنامه ارائه می‌دهد.

برخلاف پروفایل‌گیری آماری که پشته‌ی فراخوانی را به طور دوره‌ای نمونه‌برداری می‌کند تا تخمین بزند زمان صرف کجا می‌شود، پروفایل‌گیری قطعی هر رویداد را ثبت می‌کند. این یعنی به‌جای تخمین‌های آماری، تعداد فراخوانی‌های دقیقی دریافت می‌کنید. هزینه‌ی مبادله این است که ابزارگذاری روی هر رویدادی سرباری ایجاد می‌کند که می‌تواند اجرای برنام را کند کند.

ماهیت تفسیرشده‌ی پایتون، پروفایل‌گیری قطعی را کاربردی می‌سازد. مفسر از پیش رویدادها را برای فراخوانی‌ها و بازگشت‌های تابع ارسال می‌کند، بنابراین پروفایل‌گیر می‌تواند بدون نیاز به تغییر کد، به این مکانیسم متصل شود. سربار این کار معمولاً نسبت به هزینه‌ی ذاتی تفسیر معتدل است و پروفایل‌گیری قطعی را برای بیشتر چرخه‌های کاری توسعه مناسب می‌سازد.

پروفایل‌گیری قطعی به پاسخ دادن به سوالاتی مانند موارد زیر کمک می‌کند:

  • این تابع چند بار فراخوانی شده است؟

  • گراف فراخوانی کامل برنامه‌ی من چیست؟

  • کدام تابع‌ها توسط یک تابع خاص فراخوانی می‌شوند؟

  • آیا فراخوانی‌های تابع غیرمنتظره‌ای در حال رخ دادن است؟

آمارهای تعداد فراخوانی می‌توانند اشکالات (تعداد تعجب‌آور) و فرصت‌های گسترش درون‌خطی (تعداد فراخوانی بالا) را شناسایی کنند. آمارهای زمان داخلی، «حلقه‌های داغ» را آشکار می‌کنند که مستحق بهینه‌سازی هستند. آمارهای زمان تجمعی به شناسایی ناکارآمدی‌های الگوریتمی کمک می‌کنند. نحوه‌ی مدیریت زمان‌های تجمعی در این پروفایل‌گیر امکان مقایسه‌ی مستقیم پیاده‌سازی‌های بازگشتی و تکراری را فراهم می‌کند.

رابط خط فرمان

ماژول profiling.tracing را می‌توان به عنوان یک اسکریپت برای پروفایل‌گیری یک اسکریپت یا ماژول دیگر فراخوانی کرد:

python -m profiling.tracing [-o output_file] [-s sort_order] (-m module | script.py)

این کار اسکریپت یا ماژول مشخص‌شده را تحت پروفایل‌گیر اجرا می‌کند و نتایج را در خروجی استاندارد چاپ می‌کند (یا آن‌ها را در یک پرونده ذخیره می‌کند).

-o <output_file>

نتایج پروفایل‌گیری را به‌جای خروجی استاندارد در یک پرونده بنویسید. پرونده‌ی خروجی را می‌توان توسط ماژول pstats برای تحلیل‌های بعدی خواند.

-s <sort_order>

خروجی را بر اساس کلید مشخص‌شده مرتب کنید. این گزینه هر یک از کلیدهای مرتب‌سازی شناخته‌شده توسط pstats.Stats.sort_stats() مانند cumulative، time، calls یا name را می‌پذیرد. این گزینه فقط زمانی اعمال می‌شود که -o مشخص نشده باشد.

-m <module>

یک ماژول را به‌جای یک اسکریپت پروفایل‌گیری کنید. ماژول با استفاده از مکانیسم ایمپورت استاندارد پیدا می‌شود.

اضافه شده در نسخه‌ی 3.7: گزینه‌ی -m برای cProfile.

اضافه شده در نسخه‌ی 3.8: گزینه‌ی -m برای profile.

نمونه‌های استفاده‌ی برنامه‌نویسی

برای کنترل بیشتر روی پروفایل‌گیری، از توابع و کلاس‌های ماژول به‌طور مستقیم استفاده کنید.

پروفایل‌گیری پایه‌ای

ساده‌ترین رویکرد استفاده از تابع run() است:

import profiling.tracing
profiling.tracing.run('my_function()')

این کار رشته‌ی کد داده‌شده را پروفایل کرده و خلاصه‌ای را به خروجی استاندارد چاپ می‌کند. برای ذخیره‌ی نتایج جهت تحلیل‌های بعدی:

profiling.tracing.run('my_function()', 'output.prof')

استفاده از کلاس Profile

کلاس Profile کنترل دقیق‌تری را فراهم می‌کند:

import profiling.tracing
import pstats
from io import StringIO

pr = profiling.tracing.Profile()
pr.enable()
# ... code to profile ...
pr.disable()

# Print results
s = StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats(pstats.SortKey.CUMULATIVE)
ps.print_stats()
print(s.getvalue())

کلاس Profile همچنین به عنوان یک مدیر زمینه کار می‌کند:

import profiling.tracing

with profiling.tracing.Profile() as pr:
    # ... code to profile ...

pr.print_stats()

ارجاع به ماژول

profiling.tracing.run(command, filename=None, sort=-1)

اجرای یک دستور را پروفایل کرده و نتایج را چاپ یا ذخیره کنید.

این تابع رشته‌ی command را با استفاده از exec() در فضای نام ماژول __main__ اجرا می‌کند:

exec(command, __main__.__dict__, __main__.__dict__)

اگر filename فراهم نشده باشد، این تابع یک نمونه از pstats.Stats ایجاد کرده و خلاصه‌ای را به خروجی استاندارد چاپ می‌کند. اگر filename فراهم شده باشد، داده‌های خام پروفایل برای تحلیل بعدی با pstats در آن پرونده ذخیره می‌شوند.

آرگومان sort ترتیب مرتب‌سازی خروجی چاپ‌شده را مشخص می‌کند و هر مقداری را که توسط pstats.Stats.sort_stats() شناخته شود، می‌پذیرد.

profiling.tracing.runctx(command, globals, locals, filename=None, sort=-1)

اجرای پروفایل یک دستور با فضاهای نام صریح.

مانند run() است، اما دستور را با نگاشت‌های globals و locals مشخص‌شده به‌جای استفاده از فضای نام ماژول __main__ اجرا می‌کند:

exec(command, globals, locals)
class profiling.tracing.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)

یک شیء پروفایل‌گیر که آمارهای اجرای برنامه را جمع‌آوری می‌کند.

آرگومان اختیاری timer یک تابع زمان‌سنج سفارشی را مشخص می‌کند. اگر ارائه نشود، پروفایل‌گیر از یک زمان‌سنج پیش‌فرض مناسب با سکو استفاده می‌کند. هنگام ارائه دادن یک زمان‌سنج سفارشی، این تابع باید یک عدد واحد که نشان‌دهنده‌ی زمان فعلی است برگرداند. اگر زمان‌سنج اعداد صحیح برمی‌گرداند، از timeunit برای مشخص کردن مدت‌زمان یک واحد زمانی استفاده کنید (برای مثال، 0.001 برای میلی‌ثانیه‌ها).

آرگومان subcalls کنترل می‌کند که آیا پروفایل‌گیر روابط فراخوانی بین تابع‌ها را ردگیری می‌کند یا خیر. آرگومان builtins کنترل می‌کند که آیا تابع‌های توکار پروفایل می‌شوند یا خیر.

تغییر یافته در نسخه‌ی 3.8: پشتیبانی از مدیر زمینه اضافه شد.

enable()

شروع جمع‌آوری داده‌های پروفایل‌گیری.

disable()

توقف جمع‌آوری داده‌های پروفایل‌گیری.

create_stats()

جمع‌آوری داده‌ها را متوقف کرده و نتایج را به‌طور داخلی به عنوان پروفایل فعلی ثبت کنید.

print_stats(sort=-1)

یک شیء از pstats.Stats از پروفایل فعلی ایجاد کنید و نتایج را در خروجی استاندارد چاپ کنید.

آرگومان sort ترتیب مرتب‌سازی را مشخص می‌کند. این آرگومان یک کلید واحد یا یک چندتایی از کلیدها را برای مرتب‌سازی چندسطحی می‌پذیرد و از مقادیر مشابھی با pstats.Stats.sort_stats() استفاده می‌کند.

اضافه شده در نسخه‌ی 3.13: پشتیبانی از یک چندتایی از کلیدهای مرتب‌سازی.

dump_stats(filename)

داده‌های پروفایل فعلی را در filename بنویسید. این پرونده می‌تواند توسط pstats.Stats برای تحلیل بعدی خوانده شود.

run(cmd)

رشته‌ی دستور را از طریق exec() پروفایل کنید.

runctx(cmd, globals, locals)

رشته‌ی دستور را از طریق exec() با فضاهای نام مشخص‌شده پروفایل کنید.

runcall(func, /, *args, **kwargs)

یک فراخوانی تابع را پروفایل کنید. هر چه که func برمی‌گرداند را برمی‌گرداند:

result = pr.runcall(my_function, arg1, arg2, keyword=value)

نکته

پروفایل‌گیری مستلزم این است که کد پروفایل‌شده به‌طور عادی برگردد. اگر مفسر در طول پروفایل‌گیری خاتمه یابد (برای مثال، از طریق sys.exit())، هیچ نتیجه‌ای در دسترس نخواهد بود.

استفاده از یک زمان‌سنج سفارشی

کلاس Profile یک تابع زمان‌سنج سفارشی را می‌پذیرد و به شما اجازه می‌دهد جنبه‌های مختلف اجرا مانند زمان ساعت دیواری یا زمان پردازنده را اندازه‌گیری کنید. تابع زمان‌سنج را به سازنده ارسال کنید:

pr = profiling.tracing.Profile(my_timer_function)

تابع زمان‌سنج باید یک عدد واحد که نشان‌دهنده‌ی زمان فعلی است برگرداند. اگر این تابع اعداد صحیح برمی‌گرداند، همچنین timeunit را برای نشان دادن مدت‌زمان یک واحد مشخص کنید:

# Timer returns time in milliseconds
pr = profiling.tracing.Profile(my_ms_timer, 0.001)

برای بهترین عملکرد، تابع تایمر باید تا حد امکان سریع باشد. پروفایل‌گیر آن را مکرراً فراخوانی می‌کند، بنابراین سربار تایمر مستقیماً روی سربار پروفایل‌گیری تأثیر می‌گذارد.

ماژول time چندین تابع مناسب برای استفاده به عنوان تایمرهای سفارشی فراهم می‌کند:

محدودیت‌ها

پروفایل‌گیری قطعی دارای محدودیت‌های ذاتی مربوط به دقت زمان‌بندی است.

تایمر زیرین معمولاً وضوحی در حدود یک میلی‌ثانیه دارد. اندازه‌گیری‌ها نمی‌توانند دقیق‌تر از این وضوح باشند. با انجام اندازه‌گیری‌های کافی، خطاهای زمان‌بندی معمولاً خنثی می‌شوند، اما اندازه‌گیری‌های منفرد ممکن است دقیق نباشند.

همچنین بین زمان وقوع یک رویداد و زمان ثبت برچسب زمانی توسط پروفایل‌گیر، تاخیر وجود دارد. به همین صورت، پس از خواندن برچسب زمانی و پیش از ازسرگیری کدهای کاربر نیز تاخیر وجود دارد. توابعی که مکرراً فراخوانی می‌شوند این تاخیر را انباشته می‌کنند، که می‌تواند باعث شود کندتر از آنچه واقعاً هستند به نظر برسند. این خطا معمولاً کمتر از یک تیک ساعت در هر فراخوانی است اما می‌تواند برای توابعی که بارها فراخوانی می‌شوند قابل توجه باشد.

ماژول profiling.tracing (و نام مستعار cProfile آن) به عنوان یک افزونه‌ی C با سربار کم پیاده‌سازی شده است، بنابراین این مسائل مربوط به زمان‌بندی در مقایسه با ماژول منسوخ profile که کاملاً به زبان پایتون است، کمتر به چشم می‌آیند.

همچنین ببینید

profiling

نمای کلی از ابزارهای پروفایل‌گیری پایتون و راهنمایی درباره‌ی انتخاب یک پروفایل‌گیر.

profiling.sampling

پروفایل‌گیر نمونه‌برداری آماری برای استفاده در محیط تولید.

pstats

تجزیه‌وتحلیل آمار و قالب‌بندی برای داده‌های پروفایل.

profile

پروفایل‌گیر کاملاً پایتونی منسوخ (شامل مستندات کالیبراسیون).