PERF-SCRIPT-PYTHON(1) perf Manual PERF-SCRIPT-PYTHON(1)

perf-script-python - پردازش داده‌های ردگیری با یک اسکریپت Python

perf script [-s [Python]:script[.py] ]

این گزینهٔ perf script برای پردازش داده‌های perf script با استفاده از مفسر داخلی Python در perf به کار می‌رود. این ابزار فایل ورودی را خوانده و پردازش می‌کند و در صورت وجود، نتایج تحلیل ردگیری (trace) پیاده‌سازی‌شده در اسکریپت Python ارائه‌شده را نمایش می‌دهد.

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

این مثال در واقع مراحلی را شرح می‌دهد که برای ایجاد اسکریپت syscall-counts استفاده شده‌اند؛ همان اسکریپتی که هنگام فهرست کردن اسکریپت‌های موجود perf script از طریق perf script -l مشاهده می‌کنید. بدین ترتیب، این اسکریپت همچنین نحوهٔ ادغام اسکریپت شما را در فهرست اسکریپت‌های همه‌منظورهٔ perf script که با آن دستور فهرست می‌شوند، نشان می‌دهد.

اسکریپت syscall-counts اسکریپتی ساده است، اما تمام ایده‌های پایه‌ای لازم برای ایجاد یک اسکریپت کاربردی را نشان می‌دهد. در اینجا نمونه‌ای از خروجی آن آمده است (نام‌های syscall هنوز پشتیبانی نمی‌شوند و به‌صورت شماره نمایش خواهند یافت):

.ft C
syscall events:
event                                          count
----------------------------------------  -----------
sys_write                                     455067
sys_getdents                                    4072
sys_close                                       3037
sys_swapoff                                     1769
sys_read                                         923
sys_sched_setparam                               826
sys_open                                         331
sys_newfstat                                     326
sys_mmap                                         217
sys_munmap                                       216
sys_futex                                        141
sys_select                                       102
sys_poll                                          84
sys_setitimer                                     12
sys_writev                                         8
15                                                 8
sys_lseek                                          7
sys_rt_sigprocmask                                 6
sys_wait4                                          3
sys_ioctl                                          3
sys_set_robust_list                                1
sys_exit                                           1
56                                                 1
sys_access                                         1
.ft

در اصل، وظیفهٔ ما نگه‌داشتن یک شمارش به ازای هر syscall است که با هر بار رخ دادن یک فراخوانی سیستمی در سیستم به‌روزرسانی شود. اسکریپت ما این کار را انجام خواهد داد، اما ابتدا باید داده‌هایی را ضبط کنیم که توسط آن اسکریپت پردازش می‌شوند. از نظر نظری، چند روش برای انجام این کار پیش رو داریم:

•می‌توانیم تمام رویدادهای زیر دایرکتوری tracing/events/syscalls را فعال کنیم، اما این مقدار بیش از ۶۰۰ فراخوانی سیستمی (syscall) است که بسیار فراتر از تعداد مجاز توسط perf می‌باشد. با این حال، اگر بعداً بخواهیم با تکیه بر راهنمایی‌های به‌دست‌آمده از اسکریپت‌های همه‌منظوره جزئیات بیشتری دربارهٔ syscallهای مورد نظر بررسی و استخراج کنیم، این رویدادهای مجزای syscall مفید خواهند بود.
•می‌توانیم syscallهای sys_enter و/یا sys_exit موجود در tracing/events/raw_syscalls را فعال کنیم. این‌ها برای همهٔ فراخوانی‌های سیستمی اجرا می‌شوند؛ از فیلد id می‌توان برای تمایز میان شماره‌های جداگانهٔ syscall استفاده کرد.

برای این اسکریپت، تنها نیاز داریم بدانیم که یک syscall آغاز (enter) شده است؛ چگونگی خروج آن اهمیتی ندارد، بنابراین از perf record فقط برای ضبط رویدادهای sys_enter استفاده خواهیم کرد:

.ft C
# perf record -a -e raw_syscalls:sys_enter
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ]
.ft

این گزینه‌ها در اصل مشخص می‌کنند که داده‌ها برای تمام رویدادهای syscall در سراسر سیستم (system-wide) جمع‌آوری شوند و خروجی‌های به ازای هر پردازنده (per-cpu) در یک جریان واحد ادغام (multiplex) گردند. آن جریان واحد در فایلی به نام perf.data در دایرکتوری جاری ذخیره خواهد شد.

پس از در اختیار داشتن فایل perf.data حاوی داده‌هایمان، می‌توانیم از گزینهٔ -g در perf script برای تولید یک اسکریپت Python استفاده کنیم که شامل یک گردانندهٔ بازخوانی (callback handler) برای هر نوع رویداد موجود در جریان ردگیری perf.data خواهد بود (برای جزئیات بیشتر، بخش STARTER SCRIPTS را ببینید).

.ft C
# perf script -g python
generated Python script: perf-script.py
The output file created also in the current directory is named
perf-script.py.  Here's the file in its entirety:
# perf script event handlers, generated by perf script -g python
# Licensed under the terms of the GNU GPL License version 2
# The common_* event handler fields are the most useful fields common to
# all events.  They don't necessarily correspond to the 'common_*' fields
# in the format files.  Those fields not available as handler params can
# be retrieved using Python functions of the form common_*(context).
# See the perf-script-python Documentation for the list of available functions.
import os
import sys
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
        '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
from perf_trace_context import *
from Core import *
def trace_begin():
        print "in trace_begin"
def trace_end():
        print "in trace_end"
def raw_syscalls__sys_enter(event_name, context, common_cpu,
        common_secs, common_nsecs, common_pid, common_comm,
        id, args):
                print_header(event_name, common_cpu, common_secs, common_nsecs,
                        common_pid, common_comm)
                print "id=%d, args=%s\n" % \
                (id, args),
def trace_unhandled(event_name, context, event_fields_dict):
                print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])
def print_header(event_name, cpu, secs, nsecs, pid, comm):
        print "%-20s %5u %05u.%09u %8u %-20s " % \
        (event_name, cpu, secs, nsecs, pid, comm),
.ft
در بالا یک بلوک توضیح (کامنت) قرار دارد که در پی آن چند عبارت import و یک الحاق مسیر (path append) آمده است که هر اسکریپتِ perf script باید شامل آن‌ها باشد.

به دنبال آن دو تابع تولیدشده، trace_begin() و trace_end() قرار دارند که به ترتیب در ابتدا و انتهای اسکریپت فراخوانی می‌شوند (برای جزئیات بیشتر، بخش SCRIPT_LAYOUT در زیر را ببینید).

به دنبال آن‌ها توابع event handler قرار دارند که به ازای هر رویداد در خروجی perf record یکی از آن‌ها تولید می‌شود. توابع اداره‌کننده (handler) به شکل subsystem__event_name هستند و شامل پارامترهای نام‌گذاری‌شده می‌باشند، یکی برای هر فیلد در رویداد؛ در این مورد، تنها یک رویداد وجود دارد، raw_syscalls__sys_enter(). (برای اطلاعات بیشتر درباره اداره‌کننده‌های رویداد، بخش EVENT HANDLERS در زیر را ببینید).

دو تابع نهایی نیز، همانند توابع آغاز و پایان، برای هر اسکریپت تولید می‌شوند. اولی، trace_unhandled()، هر بار فراخوانی می‌شود که اسکریپت رویدادی را در فایل perf.data پیدا کند که با هیچ اداره‌کننده رویدادی در اسکریپت مطابقت ندارد. این می‌تواند به این معنی باشد که مرحله ضبط، انواع رویدادهایی را ضبط کرده است که واقعاً مورد نظر نبوده‌اند، یا اینکه اسکریپت بر روی یک فایل ردگیری (trace) اجرا شده است که با اسکریپت مطابقت ندارد.

اسکریپت تولیدشده با گزینه -g صرفاً به ازای هر رویداد یافت‌شده در جریان ردگیری یک خط چاپ می‌کند؛ یعنی اساساً رویداد و مقادیر پارامترهای آن را در stdout می‌ریزد. تابع print_header() صرفاً یک تابع کمکی است که برای همین منظور استفاده می‌شود. بیایید نام اسکریپت را تغییر داده و آن را اجرا کنیم تا خروجی پیش‌فرض را ببینیم:

.ft C
# mv perf-script.py syscall-counts.py
# perf script -s syscall-counts.py
raw_syscalls__sys_enter     1 00840.847582083     7506 perf                  id=1, args=
raw_syscalls__sys_enter     1 00840.847595764     7506 perf                  id=1, args=
raw_syscalls__sys_enter     1 00840.847620860     7506 perf                  id=1, args=
raw_syscalls__sys_enter     1 00840.847710478     6533 npviewer.bin          id=78, args=
raw_syscalls__sys_enter     1 00840.847719204     6533 npviewer.bin          id=142, args=
raw_syscalls__sys_enter     1 00840.847755445     6533 npviewer.bin          id=3, args=
raw_syscalls__sys_enter     1 00840.847775601     6533 npviewer.bin          id=3, args=
raw_syscalls__sys_enter     1 00840.847781820     6533 npviewer.bin          id=3, args=
.
.
.
.ft

البته برای این اسکریپت، ما علاقه‌ای به چاپ هر رویداد ردگیری نداریم، بلکه ترجیح می‌دهیم آن را به شیوه‌ای مفید تجمیع کنیم. بنابراین تمام موارد مربوط به چاپ و همچنین توابع trace_begin() و trace_unhandled() را که استفاده نخواهیم کرد، حذف می‌کنیم. این کار ما را با این اسکلت کمینه‌گرا باقی می‌گذارد:

.ft C
import os
import sys
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
        '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
from perf_trace_context import *
from Core import *
def trace_end():
        print "in trace_end"
def raw_syscalls__sys_enter(event_name, context, common_cpu,
        common_secs, common_nsecs, common_pid, common_comm,
        id, args):
.ft

در تابع trace_end()، ما صرفاً نتایج را چاپ می‌کنیم، اما ابتدا باید نتایجی برای چاپ تولید کنیم. برای انجام این کار باید اداره‌کننده sys_enter() ما شمارش لازم را تا زمانی که همه رویدادها شمرده شوند، انجام دهد. یک جدول درهم‌سازی (hash table) که با syscall id نمایه‌گذاری شده باشد، روش مناسبی برای ذخیره این اطلاعات است؛ هر بار که اداره‌کننده sys_enter() فراخوانی می‌شود، ما صرفاً شمارنده مرتبط با آن مدخل درهم‌سازی را که با آن syscall id نمایه‌گذاری شده است، یکی افزایش می‌دهیم:

.ft C
  syscalls = autodict()
  try:
    syscalls[id] += 1
  except TypeError:
    syscalls[id] = 1
.ft

شیء autodict مربوط به syscalls نوع خاصی از دیکشنری‌های پایتون (پیاده‌سازی‌شده در Core.py) است که درهم‌سازی‌های autovivifying زبان Perl را در پایتون پیاده‌سازی می‌کند؛ یعنی با درهم‌سازی‌های خودزنده‌ساز (autovivifying)، می‌توانید مقادیر درهم‌سازی تودرتو را بدون نیاز به زحمتِ ایجاد سطوح میانی در صورت عدم وجودشان مقداردهی کنید؛ به عنوان مثال syscalls[comm][pid][id] = 1 سطوح میانی درهم‌سازی را ایجاد کرده و در نهایت مقدار 1 را به مدخل درهم‌سازی برای id اختصاص می‌دهد (از آنجا که مقدار اختصاص‌یافته خود یک شیء درهم‌سازی نیست، مقدار اولیه در استثنای TypeError مقداردهی می‌شود. البته، شاید روش بهتری برای این کار در پایتون وجود داشته باشد، اما این چیزی است که در حال حاضر کار می‌کند).

با قرار دادن آن کد در اداره‌کننده raw_syscalls__sys_enter()، عملاً به یک دیکشنری تک‌سطحی دست می‌یابیم که کلید آن syscall id است و مقادیر آن شامل شمارش‌هایی است که تجمیع کرده‌ایم.

تابع print_syscall_totals() روی مدخل‌های دیکشنری پیمایش کرده و برای هر مدخل، خطی شامل نام فراخوان سیستمی (syscall) را نمایش می‌دهد (کلیدهای دیکشنری شامل syscall id هستند که به تابع کمکی Util به نام syscall_name() ارسال می‌شوند؛ این تابع شماره‌های خام فراخوان‌های سیستمی را به رشته‌های نام فراخوان سیستمی متناظر ترجمه می‌کند). خروجی پس از پردازش تمام رویدادها در ردگیری، با فراخوانی تابع print_syscall_totals() از اداره‌کننده trace_end() که در پایان پردازش اسکریپت فراخوانده می‌شود، به نمایش درمی‌آید.

اسکریپت نهایی که خروجی نشان‌داده‌شده در بالا را تولید می‌کند، به طور کامل در زیر نشان داده شده است (تابع کمکی syscall_name() هنوز در دسترس نیست، فعلاً فقط می‌توانید با idها کار کنید):

.ft C
import os
import sys
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
        '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
from perf_trace_context import *
from Core import *
from Util import *
syscalls = autodict()
def trace_end():
        print_syscall_totals()
def raw_syscalls__sys_enter(event_name, context, common_cpu,
        common_secs, common_nsecs, common_pid, common_comm,
        id, args):
        try:
                syscalls[id] += 1
        except TypeError:
                syscalls[id] = 1
def print_syscall_totals():
    if for_comm is not None:
            print "\nsyscall events for %s:\n\n" % (for_comm),
    else:
            print "\nsyscall events:\n\n",
    print "%-40s  %10s\n" % ("event", "count"),
    print "%-40s  %10s\n" % ("----------------------------------------", \
                                 "-----------"),
    for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
                                  reverse = True):
            print "%-40s  %10d\n" % (syscall_name(id), val),
.ft

اسکریپت را می‌توان دقیقاً مانند قبل اجرا کرد:

# perf script -s syscall-counts.py

بنابراین این‌ها مراحل اساسی در نوشتن و اجرای یک اسکریپت هستند. این فرایند را می‌توان به هر نقطه ردگیری (tracepoint) یا مجموعه‌ای از نقاط ردگیری که به آن‌ها علاقه‌مندید تعمیم داد - اساساً با بررسی فهرست رویدادهای موجود که توسط perf list نشان داده می‌شوند یا جستجو در /sys/kernel/tracing/events/ برای اطلاعات تفصیلی رویداد و فیلدها، نقطه(های) ردگیری مورد نظر خود را بیابید، داده‌های ردگیری متناظر را با استفاده از perf record با ارسال فهرست رویدادهای مورد نظر ضبط کنید، با استفاده از perf script -g python یک اسکلت اولیه برای اسکریپت ایجاد کرده و کد را متناسب با نیازهای خاص خود برای تجمیع و نمایش تغییر دهید.

پس از انجام این کار، ممکن است یک اسکریپت چندمنظوره داشته باشید که بخواهید آن را نگه داشته و برای استفاده‌های آینده در دسترس بگذارید. با نوشتن چند اسکریپت شل بسیار ساده و قرار دادن آن‌ها در محل مناسب، می‌توانید اسکریپت خود را در کنار سایر اسکریپت‌های فهرست‌شده توسط دستور perf script -l قرار دهید؛ برای مثال:

.ft C
# perf script -l
List of available trace scripts:
  wakeup-latency                       system-wide min/max/avg wakeup latency
  rw-by-file <comm>                    r/w activity for a program, by file
  rw-by-pid                            system-wide r/w activity
.ft

یک مزیت جانبی خوب انجام این کار این است که دستور احتمالاً طولانی perf record را که برای ضبط رویدادهای اسکریپت لازم است نیز ثبت و حفظ می‌کنید..sp برای اینکه اسکریپت به‌صورت یک اسکریپت built-in ظاهر شود، دو اسکریپت ساده می‌نویسید؛ یکی برای ضبط و دیگری برای reporting.

اسکریپت record یک شل‌اسکریپت با همان نام پایهٔ اسکریپت شما است، اما عبارت -record به انتهای آن افزوده شده است. این شل‌اسکریپت باید در دایرکتوری perf/scripts/python/bin در درخت منبع هسته قرار گیرد. در آن اسکریپت، خط فرمان perf record مورد نیاز برای اسکریپت خود را می‌نویسید:

.ft C
# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record
#!/bin/bash
perf record -a -e raw_syscalls:sys_enter
.ft

اسکریپت report نیز یک شل‌اسکریپت با همان نام پایهٔ اسکریپت شما است، اما عبارت -report به انتهای آن الحاق شده است. این اسکریپت نیز باید در دایرکتوری perf/scripts/python/bin قرار گیرد. در آن اسکریپت، خط فرمان perf script -s مورد نیاز برای اجرای اسکریپت خود را می‌نویسید:

.ft C
# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report
#!/bin/bash
# description: system-wide syscall counts
perf script -s ~/libexec/perf-core/scripts/python/syscall-counts.py
.ft

توجه داشته باشید که مکان اسکریپت Python مشخص‌شده در شل‌اسکریپت در دایرکتوری libexec/perf-core/scripts/python قرار دارد - این همان مکانی است که اسکریپت هنگام نصب perf توسط make install در آن کپی می‌شود. برای اینکه فرایند نصب اسکریپت شما را در آنجا نصب کند، اسکریپت شما باید در دایرکتوری perf/scripts/python در درخت منبع هسته قرار داشته باشد:

.ft C
# ls -al kernel-source/tools/perf/scripts/python
total 32
drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py
drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util
-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
.ft

پس از انجام این کار (فراموش نکنید که مجدداً make install را اجرا کنید، در غیر این صورت اسکریپت شما در زمان اجرا نمایش داده نخواهد شد)، دستور perf script -l باید مدخل جدیدی را برای اسکریپت شما نشان دهد:

.ft C
# perf script -l
List of available trace scripts:
  wakeup-latency                       system-wide min/max/avg wakeup latency
  rw-by-file <comm>                    r/w activity for a program, by file
  rw-by-pid                            system-wide r/w activity
  syscall-counts                       system-wide syscall counts
.ft

اکنون می‌توانید مرحلهٔ ضبط را از طریق perf script record انجام دهید:

# perf script record syscall-counts

و خروجی را با استفاده از perf script report نمایش دهید:

# perf script report syscall-counts

شما می‌توانید با ایجاد یک اسکریپت اسکلتی با استفاده از perf script -g python در همان دایرکتوری که فایل ردگیری perf.data موجود قرار دارد، نوشتن اسکریپت برای مجموعه مشخصی از داده‌های ردگیری (trace) را به سرعت آغاز کنید. این کار یک اسکریپت آغازین تولید می‌کند که حاوی یک گرداننده (handler) برای هر یک از انواع رویدادها در فایل ردگیری است؛ این اسکریپت به سادگی تمام فیلدهای موجود برای هر رویداد در فایل ردگیری را چاپ می‌کند.

همچنین می‌توانید به اسکریپت‌های موجود در مسیر ~/libexec/perf-core/scripts/python نگاهی بیندازید تا مثال‌های نمونه‌ای را ببینید که نحوه انجام کارهای پایه‌ای مانند تجمیع داده‌های رویداد، چاپ نتایج و غیره را نشان می‌دهند. علاوه بر این، اسکریپت check-perf-script.py گرچه از نظر نتایج آنچنان جذاب نیست، اما تلاش می‌کند تا تمام قابلیت‌های اصلی اسکریپت‌نویسی را به کار بگیرد.

هنگامی که perf script با استفاده از یک اسکریپت ردگیری اجرا می‌شود، برای هر رویداد در ردگیری، یک handler function (تابع گرداننده) تعریف‌شده توسط کاربر فراخوانی می‌شود. اگر هیچ تابع گرداننده‌ای برای یک نوع رویداد معین تعریف نشده باشد، آن رویداد نادیده گرفته می‌شود (یا به یک تابع trace_unhandled ارسال می‌شود، پایین‌تر را ببینید) و رویداد بعدی پردازش می‌شود.

بیشتر مقادیر فیلدهای رویداد به عنوان آرگومان به تابع گرداننده ارسال می‌شوند؛ برخی از فیلدهایی که کمتر متداول هستند ارسال نمی‌شوند - آن موارد به عنوان بازفراخوانی‌ها به درون فایل اجرایی perf در دسترس هستند (پایین‌تر را ببینید).

به عنوان مثال، می‌توان از دستور perf record زیر برای ضبط تمام رویدادهای sched_wakeup در سیستم استفاده کرد:

# perf record -a -e sched:sched_wakeup

ردگیری‌هایی که قرار است با استفاده از یک اسکریپت پردازش شوند باید با گزینه بالا ضبط شوند: -a برای فعال‌سازی گردآوری سراسری در سطح سیستم.

فایل قالب (format) مربوط به رویداد sched_wakeup فیلدهای زیر را تعریف می‌کند (مسیر /sys/kernel/tracing/events/sched/sched_wakeup/format را ببینید):

.ft C
 format:
        field:unsigned short common_type;
        field:unsigned char common_flags;
        field:unsigned char common_preempt_count;
        field:int common_pid;
        field:char comm[TASK_COMM_LEN];
        field:pid_t pid;
        field:int prio;
        field:int success;
        field:int target_cpu;
.ft

تابع گرداننده برای این رویداد به این صورت تعریف می‌شود:

.ft C
def sched__sched_wakeup(event_name, context, common_cpu, common_secs,
       common_nsecs, common_pid, common_comm,
       comm, pid, prio, success, target_cpu):
       pass
.ft

تابع گرداننده قالب subsystem__event_name را به خود می‌گیرد.

آرگومان‌های common_* در فهرست آرگومان‌های تابع گرداننده، مجموعه‌ای از آرگومان‌ها هستند که به تمامی گرداننده‌های رویداد ارسال می‌شوند؛ برخی از این فیلدها با فیلدهای common_* در فایل قالب مطابقت دارند، اما برخی دیگر به‌صورت ترکیبی (synthesized) تولید شده‌اند، و برخی از فیلدهای common_* نیز به اندازه کافی عمومی نیستند که به عنوان آرگومان به هر رویداد ارسال شوند، اما به صورت توابع کتابخانه‌ای در دسترس هستند.

در اینجا توضیح مختصری درباره هر یک از آرگومان‌های ثابت رویداد آورده شده است:

event_name                 نام رویداد به صورت متنی
context                    یک 'cookie' غیرشفاف مورد استفاده در بازفراخوانی‌ها به perf
common_cpu                 پردازنده‌ای (cpu) که رویداد روی آن رخ داده است
common_secs                بخش ثانیه‌های برچسب زمانی رویداد
common_nsecs               بخش نانوثانیه‌های برچسب زمانی رویداد
common_pid                 شناسه pid تسک جاری
common_comm                نام فرآیند جاری

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

موارد فوق، اصول اولیه‌ای را ارائه می‌دهند که برای دسترسی مستقیم به تک‌تک فیلدهای هر رویداد در یک ردگیری نیاز است، که ۹۰٪ از آنچه را که برای نوشتن یک اسکریپت ردگیری مفید نیاز دارید پوشش می‌دهد. بخش‌های زیر سایر موارد را پوشش می‌دهند..SH "ساختار اسکریپت (SCRIPT LAYOUT)"

هر اسکریپت پایتونِ perf script باید با تنظیم مسیر جستجوی ماژول‌های پایتون و 'import’ کردن چند ماژول پشتیبان آغاز شود (توضیحات ماژول‌ها را در زیر ببینید):

.ft C
 import os
 import sys
 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
              '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
 from perf_trace_context import *
 from Core import *
.ft

باقی اسکریپت می‌تواند شامل توابع گرداننده (handler) و توابع پشتیبان به هر ترتیبی باشد.

جدا از توابع گردانندهٔ رویداد که در بالا بررسی شد، هر اسکریپت می‌تواند مجموعه‌ای از توابع اختیاری را پیاده‌سازی کند:

تابع trace_begin، در صورت تعریف شدن، پیش از پردازش هرگونه رویدادی فراخوانی می‌شود و به اسکریپت‌ها این فرصت را می‌دهد تا وظایف راه‌اندازی و مقداردهی اولیه را انجام دهند:

.ft C
def trace_begin():
    pass
.ft

تابع trace_end، در صورت تعریف شدن، پس از پردازش همهٔ رویدادها فراخوانی می‌شود و به اسکریپت‌ها این فرصت را می‌دهد تا وظایف پایان اسکریپت، مانند نمایش نتایج را انجام دهند:

.ft C
def trace_end():
    pass
.ft

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

.ft C
def trace_unhandled(event_name, context, event_fields_dict):
    pass
.ft

تابع process_event، در صورت تعریف شدن، برای هر رویداد غیر tracepoint فراخوانی می‌شود

.ft C
def process_event(param_dict):
    pass
.ft

تابع context_switch، در صورت تعریف شدن، برای هر تعویض زمینه (context switch) فراخوانی می‌شود

.ft C
def context_switch(ts, cpu, pid, tid, np_pid, np_tid, machine_pid, out, out_preempt, *x):
    pass
.ft

تابع auxtrace_error، در صورت تعریف شدن، برای هر خطای ردیابی ناحیهٔ AUX فراخوانی می‌شود

.ft C
def auxtrace_error(typ, code, cpu, pid, tid, ip, ts, msg, cpumode, *x):
    pass
.ft

بخش‌های باقی‌مانده، توضیحاتی دربارهٔ هر یک از ماژول‌های پایتون داخلیِ موجود در perf script و توابع مرتبط با آن‌ها ارائه می‌دهند..SH "ماژول‌ها و توابع موجود (AVAILABLE MODULES AND FUNCTIONS)"

بخش‌های زیر توابع و متغیرهای موجود از طریق ماژول‌های پایتون مختلف perf script را شرح می‌دهند. برای استفاده از توابع و متغیرهای یک ماژول مشخص، خط متناظر from XXXX import را به اسکریپت perf script خود اضافه کنید.

این توابع برخی قابلیت‌های اساسی را برای اسکریپت‌های کاربر فراهم می‌کنند.

توابع flag_str و symbol_str رشته‌های خوانا برای انسان را برای فیلدهای پرچم و فیلدهای نمادین ارائه می‌دهند. این‌ها متناظر با رشته‌ها و مقادیر تجزیه‌شده از فیلدهای print fmt در فایل‌های فرمت رویداد هستند:

flag_str(event_name, field_name, field_value) - نمایش رشته‌ای متناظر با field_value را برای فیلد پرچم field_name از رویداد event_name بازمی‌گرداند
symbol_str(event_name, field_name, field_value) - نمایش رشته‌ای متناظر با field_value را برای فیلد نمادین field_name از رویداد event_name بازمی‌گرداند

تابع autodict نوع خاصی از دیکشنری پایتون را بازمی‌گرداند که درهم‌سازی‌های autovivifying (خودکارسازنده) پرل را در پایتون پیاده‌سازی می‌کند؛ بدین معنا که با درهم‌سازی‌های خودکارسازنده، می‌توانید مقادیر درهم‌سازی تودرتو را بدون نیاز به زحمت ایجاد سطوح میانی در صورت عدم وجود، مقداردهی کنید.

autodict() - یک نمونه دیکشنری خودکارسازنده (autovivifying) بازمی‌گرداند

برخی از فیلدهای common در فایل فرمت رویداد آن‌چنان هم عمومی نیستند، اما با این وجود باید برای اسکریپت‌های کاربر قابل دسترس باشند.

ماژول perf_trace_context مجموعه‌ای از توابع را تعریف می‌کند که می‌توانند برای دسترسی به این داده‌ها در زمینه (context) رویداد جاری استفاده شوند. هر یک از این توابع انتظار یک متغیر context را دارند، که همان متغیر context ارسالی به تمام گرداننده‌های رویداد tracepoint به‌عنوان آرگومان دوم است. برای رویدادهای غیر tracepoint، متغیر context همچنین به‌صورت perf_trace_context.perf_script_context نیز موجود است.

common_pc(context) - مقدار common_preempt count را برای رویداد جاری بازمی‌گرداند
common_flags(context) - مقدار common_flags را برای رویداد جاری بازمی‌گرداند
common_lock_depth(context) - مقدار common_lock_depth را برای رویداد جاری بازمی‌گرداند
perf_sample_insn(context) - دستور کد ماشین را بازمی‌گرداند
perf_set_itrace_options(context, itrace_options) - گزینه‌های --itrace را در صورت تنظیم نشدن تعیین می‌کند
perf_sample_srcline(context) - مقادیر source_file_name, line_number را بازمی‌گرداند
perf_sample_srccode(context) - مقادیر source_file_name, line_number, source_line را بازمی‌گرداند
perf_config_get(config_name) - مقدار آیتم پیکربندی نام‌برده، یا None را در صورت عدم تنظیم بازمی‌گرداند

توابع کمکی و کاربردی گوناگون برای استفاده با perf script:

nsecs(secs, nsecs) - کل نانوثانیه‌ها را با دریافت جفت secs/nsecs بازمی‌گرداند
nsecs_secs(nsecs) - بخش کامل ثانیه‌ها را با دریافت nsecs بازمی‌گرداند
nsecs_nsecs(nsecs) - باقی‌مانده نانوثانیه‌ها را با دریافت nsecs بازمی‌گرداند
nsecs_str(nsecs) - رشته قابل چاپ را به صورت secs.nsecs بازمی‌گرداند
avg(total, n) - میانگین را بر اساس یک مجموع و تعداد کل مقادیر بازمی‌گرداند

فیلدهایی که در حال حاضر پشتیبانی می‌شوند:

ev_name, comm, id, stream_id, pid, tid, cpu, ip, time, period, phys_addr, addr, symbol, symoff, dso, time_enabled, time_running, values, callchain, brstack, brstacksym, datasrc, datasrc_decode, iregs, uregs, weight, transaction, raw_buf, attr, cpumode.

فیلدهایی که ممکن است وجود داشته باشند:

flags - پرچم‌های نمونه
flags_disp - نمایش پرچم‌های نمونه
insn_cnt - تعداد دستورالعمل‌ها برای تعیین تعداد دستورالعمل در هر چرخه (IPC)
cyc_cnt - تعداد چرخه‌ها برای تعیین IPC
addr_correlates_sym - فیلد addr می‌تواند با یک نماد مرتبط باشد
addr_dso - مشخصه dso مربوط به addr
addr_symbol - نماد مربوط به addr
addr_symoff - آفست نماد مربوط به addr

برخی فیلدها دارای زیرآیتم هستند:

brstack: from, to, from_dsoname, to_dsoname, mispred, predicted, in_tx, abort, cycles.

brstacksym: آیتم‌ها: from, to, pred, in_tx, abort (رشته تبدیل‌شده)

به عنوان مثال، می‌توانیم از این کد برای چاپ "from"، "to" و "cycles" مربوط به brstack استفاده کنیم.

if brstack in dict: for entry in dict[brstack]: print "from %s, to %s, cycles %s" % (entry["from"], entry["to"], entry["cycles"]).SH "همچنین ببینید (SEE ALSO)"

perf-script(1)

09/04/2026 perf