'\" t .\" Title: perf-script-python .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 09/04/2026 .\" Manual: perf Manual .\" Source: perf .\" Language: Persian .\" .TH "PERF\-SCRIPT\-PYTHON" "1" "09/04/2026" "perf" "perf Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "نام (NAME)" perf-script-python \- پردازش داده‌های ردگیری با یک اسکریپت Python .SH "خلاصه دستور (SYNOPSIS)" .sp .nf \fIperf script\fR [\-s [Python]:script[\&.py] ] .fi .SH "توضیحات (DESCRIPTION)" .sp این گزینهٔ \fIperf script\fR برای پردازش داده‌های \fIperf script\fR با استفاده از مفسر داخلی Python در perf به کار می‌رود\&. این ابزار فایل ورودی را خوانده و پردازش می‌کند و در صورت وجود، نتایج تحلیل ردگیری (trace) پیاده‌سازی‌شده در اسکریپت Python ارائه‌شده را نمایش می‌دهد\&. .SH "یک مثال سریع (A QUICK EXAMPLE)" .sp این بخش، فرایند ایجاد یک اسکریپت کاربردی Python از ابتدا تا انتها را نشان می‌دهد که اطلاعات مفید را از یک جریان خام \fIperf script\fR گردآوری و استخراج می‌کند\&. اگر بررسی یک مثال برای شما کافی است، می‌توانید از خواندن ادامهٔ این سند صرف‌نظر کنید؛ باقی این سند جزئیات بیشتری دربارهٔ هر مرحله ارائه می‌دهد و توابع کتابخانه‌ای موجود برای اسکریپت‌نویسان را فهرست می‌کند\&. .sp این مثال در واقع مراحلی را شرح می‌دهد که برای ایجاد اسکریپت \fIsyscall\-counts\fR استفاده شده‌اند؛ همان اسکریپتی که هنگام فهرست کردن اسکریپت‌های موجود \fIperf script\fR از طریق \fIperf script \-l\fR مشاهده می‌کنید\&. بدین ترتیب، این اسکریپت همچنین نحوهٔ ادغام اسکریپت شما را در فهرست اسکریپت‌های همه‌منظورهٔ \fIperf script\fR که با آن دستور فهرست می‌شوند، نشان می‌دهد\&. .sp اسکریپت syscall\-counts اسکریپتی ساده است، اما تمام ایده‌های پایه‌ای لازم برای ایجاد یک اسکریپت کاربردی را نشان می‌دهد\&. در اینجا نمونه‌ای از خروجی آن آمده است (نام‌های syscall هنوز پشتیبانی نمی‌شوند و به‌صورت شماره نمایش خواهند یافت): .sp .if n \{\ .RS 4 .\} .nf \&.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 .fi .if n \{\ .RE .\} .sp در اصل، وظیفهٔ ما نگه‌داشتن یک شمارش به ازای هر syscall است که با هر بار رخ دادن یک فراخوانی سیستمی در سیستم به‌روزرسانی شود\&. اسکریپت ما این کار را انجام خواهد داد، اما ابتدا باید داده‌هایی را ضبط کنیم که توسط آن اسکریپت پردازش می‌شوند\&. از نظر نظری، چند روش برای انجام این کار پیش رو داریم: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} می‌توانیم تمام رویدادهای زیر دایرکتوری tracing/events/syscalls را فعال کنیم، اما این مقدار بیش از ۶۰۰ فراخوانی سیستمی (syscall) است که بسیار فراتر از تعداد مجاز توسط perf می‌باشد\&. با این حال، اگر بعداً بخواهیم با تکیه بر راهنمایی‌های به‌دست‌آمده از اسکریپت‌های همه‌منظوره جزئیات بیشتری دربارهٔ syscallهای مورد نظر بررسی و استخراج کنیم، این رویدادهای مجزای syscall مفید خواهند بود\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} می‌توانیم syscallهای sys_enter و/یا sys_exit موجود در tracing/events/raw_syscalls را فعال کنیم\&. این‌ها برای همهٔ فراخوانی‌های سیستمی اجرا می‌شوند؛ از فیلد \fIid\fR می‌توان برای تمایز میان شماره‌های جداگانهٔ syscall استفاده کرد\&. .RE .sp برای این اسکریپت، تنها نیاز داریم بدانیم که یک syscall آغاز (enter) شده است؛ چگونگی خروج آن اهمیتی ندارد، بنابراین از \fIperf record\fR فقط برای ضبط رویدادهای sys_enter استفاده خواهیم کرد: .sp .if n \{\ .RS 4 .\} .nf \&.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 .fi .if n \{\ .RE .\} .sp این گزینه‌ها در اصل مشخص می‌کنند که داده‌ها برای تمام رویدادهای syscall در سراسر سیستم (system\-wide) جمع‌آوری شوند و خروجی‌های به ازای هر پردازنده (per\-cpu) در یک جریان واحد ادغام (multiplex) گردند\&. آن جریان واحد در فایلی به نام perf\&.data در دایرکتوری جاری ذخیره خواهد شد\&. .sp پس از در اختیار داشتن فایل perf\&.data حاوی داده‌هایمان، می‌توانیم از گزینهٔ \-g در \fIperf script\fR برای تولید یک اسکریپت Python استفاده کنیم که شامل یک گردانندهٔ بازخوانی (callback handler) برای هر نوع رویداد موجود در جریان ردگیری perf\&.data خواهد بود (برای جزئیات بیشتر، بخش STARTER SCRIPTS را ببینید)\&. .sp .if n \{\ .RS 4 .\} .nf \&.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\*(Aqs 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\*(Aqt necessarily correspond to the \*(Aqcommon_*\*(Aq 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[\*(AqPERF_EXEC_PATH\*(Aq] + \e \*(Aq/scripts/python/Perf\-Trace\-Util/lib/Perf/Trace\*(Aq) 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\en" % \e (id, args), def trace_unhandled(event_name, context, event_fields_dict): print \*(Aq \*(Aq\&.join([\*(Aq%s=%s\*(Aq%(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 " % \e (event_name, cpu, secs, nsecs, pid, comm), \&.ft .fi .if n \{\ .RE .\}.sp در بالا یک بلوک توضیح (کامنت) قرار دارد که در پی آن چند عبارت import و یک الحاق مسیر (path append) آمده است که هر اسکریپتِ perf script باید شامل آن‌ها باشد\&. .sp به دنبال آن دو تابع تولیدشده، trace_begin() و trace_end() قرار دارند که به ترتیب در ابتدا و انتهای اسکریپت فراخوانی می‌شوند (برای جزئیات بیشتر، بخش SCRIPT_LAYOUT در زیر را ببینید)\&. .sp به دنبال آن‌ها توابع \fIevent handler\fR قرار دارند که به ازای هر رویداد در خروجی \fIperf record\fR یکی از آن‌ها تولید می‌شود\&. توابع اداره‌کننده (handler) به شکل subsystem__event_name هستند و شامل پارامترهای نام‌گذاری‌شده می‌باشند، یکی برای هر فیلد در رویداد؛ در این مورد، تنها یک رویداد وجود دارد، raw_syscalls__sys_enter()\&. (برای اطلاعات بیشتر درباره اداره‌کننده‌های رویداد، بخش EVENT HANDLERS در زیر را ببینید)\&. .sp دو تابع نهایی نیز، همانند توابع آغاز و پایان، برای هر اسکریپت تولید می‌شوند\&. اولی، trace_unhandled()، هر بار فراخوانی می‌شود که اسکریپت رویدادی را در فایل perf\&.data پیدا کند که با هیچ اداره‌کننده رویدادی در اسکریپت مطابقت ندارد\&. این می‌تواند به این معنی باشد که مرحله ضبط، انواع رویدادهایی را ضبط کرده است که واقعاً مورد نظر نبوده‌اند، یا اینکه اسکریپت بر روی یک فایل ردگیری (trace) اجرا شده است که با اسکریپت مطابقت ندارد\&. .sp اسکریپت تولیدشده با گزینه \-g صرفاً به ازای هر رویداد یافت‌شده در جریان ردگیری یک خط چاپ می‌کند؛ یعنی اساساً رویداد و مقادیر پارامترهای آن را در stdout می‌ریزد\&. تابع print_header() صرفاً یک تابع کمکی است که برای همین منظور استفاده می‌شود\&. بیایید نام اسکریپت را تغییر داده و آن را اجرا کنیم تا خروجی پیش‌فرض را ببینیم: .sp .if n \{\ .RS 4 .\} .nf \&.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 .fi .if n \{\ .RE .\} .sp البته برای این اسکریپت، ما علاقه‌ای به چاپ هر رویداد ردگیری نداریم، بلکه ترجیح می‌دهیم آن را به شیوه‌ای مفید تجمیع کنیم\&. بنابراین تمام موارد مربوط به چاپ و همچنین توابع trace_begin() و trace_unhandled() را که استفاده نخواهیم کرد، حذف می‌کنیم\&. این کار ما را با این اسکلت کمینه‌گرا باقی می‌گذارد: .sp .if n \{\ .RS 4 .\} .nf \&.ft C import os import sys sys\&.path\&.append(os\&.environ[\*(AqPERF_EXEC_PATH\*(Aq] + \e \*(Aq/scripts/python/Perf\-Trace\-Util/lib/Perf/Trace\*(Aq) 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 .fi .if n \{\ .RE .\} .sp در تابع trace_end()، ما صرفاً نتایج را چاپ می‌کنیم، اما ابتدا باید نتایجی برای چاپ تولید کنیم\&. برای انجام این کار باید اداره‌کننده sys_enter() ما شمارش لازم را تا زمانی که همه رویدادها شمرده شوند، انجام دهد\&. یک جدول درهم‌سازی (hash table) که با syscall id نمایه‌گذاری شده باشد، روش مناسبی برای ذخیره این اطلاعات است؛ هر بار که اداره‌کننده sys_enter() فراخوانی می‌شود، ما صرفاً شمارنده مرتبط با آن مدخل درهم‌سازی را که با آن syscall id نمایه‌گذاری شده است، یکی افزایش می‌دهیم: .sp .if n \{\ .RS 4 .\} .nf \&.ft C syscalls = autodict() try: syscalls[id] += 1 except TypeError: syscalls[id] = 1 \&.ft .fi .if n \{\ .RE .\} .sp شیء \fIautodict\fR مربوط به syscalls نوع خاصی از دیکشنری‌های پایتون (پیاده‌سازی‌شده در Core\&.py) است که درهم‌سازی‌های \fIautovivifying\fR زبان Perl را در پایتون پیاده‌سازی می‌کند؛ یعنی با درهم‌سازی‌های خودزنده‌ساز (autovivifying)، می‌توانید مقادیر درهم‌سازی تودرتو را بدون نیاز به زحمتِ ایجاد سطوح میانی در صورت عدم وجودشان مقداردهی کنید؛ به عنوان مثال syscalls[comm][pid][id] = 1 سطوح میانی درهم‌سازی را ایجاد کرده و در نهایت مقدار 1 را به مدخل درهم‌سازی برای \fIid\fR اختصاص می‌دهد (از آنجا که مقدار اختصاص‌یافته خود یک شیء درهم‌سازی نیست، مقدار اولیه در استثنای TypeError مقداردهی می‌شود\&. البته، شاید روش بهتری برای این کار در پایتون وجود داشته باشد، اما این چیزی است که در حال حاضر کار می‌کند)\&. .sp با قرار دادن آن کد در اداره‌کننده raw_syscalls__sys_enter()، عملاً به یک دیکشنری تک‌سطحی دست می‌یابیم که کلید آن syscall id است و مقادیر آن شامل شمارش‌هایی است که تجمیع کرده‌ایم\&. .sp تابع print_syscall_totals() روی مدخل‌های دیکشنری پیمایش کرده و برای هر مدخل، خطی شامل نام فراخوان سیستمی (syscall) را نمایش می‌دهد (کلیدهای دیکشنری شامل syscall id هستند که به تابع کمکی Util به نام syscall_name() ارسال می‌شوند؛ این تابع شماره‌های خام فراخوان‌های سیستمی را به رشته‌های نام فراخوان سیستمی متناظر ترجمه می‌کند)\&. خروجی پس از پردازش تمام رویدادها در ردگیری، با فراخوانی تابع print_syscall_totals() از اداره‌کننده trace_end() که در پایان پردازش اسکریپت فراخوانده می‌شود، به نمایش درمی‌آید\&. .sp اسکریپت نهایی که خروجی نشان‌داده‌شده در بالا را تولید می‌کند، به طور کامل در زیر نشان داده شده است (تابع کمکی syscall_name() هنوز در دسترس نیست، فعلاً فقط می‌توانید با idها کار کنید): .sp .if n \{\ .RS 4 .\} .nf \&.ft C import os import sys sys\&.path\&.append(os\&.environ[\*(AqPERF_EXEC_PATH\*(Aq] + \e \*(Aq/scripts/python/Perf\-Trace\-Util/lib/Perf/Trace\*(Aq) 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 "\ensyscall events for %s:\en\en" % (for_comm), else: print "\ensyscall events:\en\en", print "%\-40s %10s\en" % ("event", "count"), print "%\-40s %10s\en" % ("\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-", \e "\-\-\-\-\-\-\-\-\-\-\-"), for id, val in sorted(syscalls\&.iteritems(), key = lambda(k, v): (v, k), \e reverse = True): print "%\-40s %10d\en" % (syscall_name(id), val), \&.ft .fi .if n \{\ .RE .\} .sp اسکریپت را می‌توان دقیقاً مانند قبل اجرا کرد: .sp .if n \{\ .RS 4 .\} .nf # perf script \-s syscall\-counts\&.py .fi .if n \{\ .RE .\} .sp بنابراین این‌ها مراحل اساسی در نوشتن و اجرای یک اسکریپت هستند\&. این فرایند را می‌توان به هر نقطه ردگیری (tracepoint) یا مجموعه‌ای از نقاط ردگیری که به آن‌ها علاقه‌مندید تعمیم داد \- اساساً با بررسی فهرست رویدادهای موجود که توسط \fIperf list\fR نشان داده می‌شوند یا جستجو در /sys/kernel/tracing/events/ برای اطلاعات تفصیلی رویداد و فیلدها، نقطه(های) ردگیری مورد نظر خود را بیابید، داده‌های ردگیری متناظر را با استفاده از \fIperf record\fR با ارسال فهرست رویدادهای مورد نظر ضبط کنید، با استفاده از \fIperf script \-g python\fR یک اسکلت اولیه برای اسکریپت ایجاد کرده و کد را متناسب با نیازهای خاص خود برای تجمیع و نمایش تغییر دهید\&. .sp پس از انجام این کار، ممکن است یک اسکریپت چندمنظوره داشته باشید که بخواهید آن را نگه داشته و برای استفاده‌های آینده در دسترس بگذارید\&. با نوشتن چند اسکریپت شل بسیار ساده و قرار دادن آن‌ها در محل مناسب، می‌توانید اسکریپت خود را در کنار سایر اسکریپت‌های فهرست‌شده توسط دستور \fIperf script \-l\fR قرار دهید؛ برای مثال: .sp .if n \{\ .RS 4 .\} .nf \&.ft C # perf script \-l List of available trace scripts: wakeup\-latency system\-wide min/max/avg wakeup latency rw\-by\-file r/w activity for a program, by file rw\-by\-pid system\-wide r/w activity \&.ft .fi .if n \{\ .RE .\} .sp یک مزیت جانبی خوب انجام این کار این است که دستور احتمالاً طولانی \fIperf record\fR را که برای ضبط رویدادهای اسکریپت لازم است نیز ثبت و حفظ می‌کنید\&..sp برای اینکه اسکریپت به‌صورت یک اسکریپت \fIbuilt\-in\fR ظاهر شود، دو اسکریپت ساده می‌نویسید؛ یکی برای ضبط و دیگری برای \fIreporting\fR\&. .sp اسکریپت \fIrecord\fR یک شل‌اسکریپت با همان نام پایهٔ اسکریپت شما است، اما عبارت \-record به انتهای آن افزوده شده است\&. این شل‌اسکریپت باید در دایرکتوری perf/scripts/python/bin در درخت منبع هسته قرار گیرد\&. در آن اسکریپت، خط فرمان \fIperf record\fR مورد نیاز برای اسکریپت خود را می‌نویسید: .sp .if n \{\ .RS 4 .\} .nf \&.ft C # cat kernel\-source/tools/perf/scripts/python/bin/syscall\-counts\-record #!/bin/bash perf record \-a \-e raw_syscalls:sys_enter \&.ft .fi .if n \{\ .RE .\} .sp اسکریپت \fIreport\fR نیز یک شل‌اسکریپت با همان نام پایهٔ اسکریپت شما است، اما عبارت \-report به انتهای آن الحاق شده است\&. این اسکریپت نیز باید در دایرکتوری perf/scripts/python/bin قرار گیرد\&. در آن اسکریپت، خط فرمان \fIperf script \-s\fR مورد نیاز برای اجرای اسکریپت خود را می‌نویسید: .sp .if n \{\ .RS 4 .\} .nf \&.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 .fi .if n \{\ .RE .\} .sp توجه داشته باشید که مکان اسکریپت Python مشخص‌شده در شل‌اسکریپت در دایرکتوری libexec/perf\-core/scripts/python قرار دارد \- این همان مکانی است که اسکریپت هنگام نصب perf توسط \fImake install\fR در آن کپی می‌شود\&. برای اینکه فرایند نصب اسکریپت شما را در آنجا نصب کند، اسکریپت شما باید در دایرکتوری perf/scripts/python در درخت منبع هسته قرار داشته باشد: .sp .if n \{\ .RS 4 .\} .nf \&.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 .fi .if n \{\ .RE .\} .sp پس از انجام این کار (فراموش نکنید که مجدداً \fImake install\fR را اجرا کنید، در غیر این صورت اسکریپت شما در زمان اجرا نمایش داده نخواهد شد)، دستور \fIperf script \-l\fR باید مدخل جدیدی را برای اسکریپت شما نشان دهد: .sp .if n \{\ .RS 4 .\} .nf \&.ft C # perf script \-l List of available trace scripts: wakeup\-latency system\-wide min/max/avg wakeup latency rw\-by\-file r/w activity for a program, by file rw\-by\-pid system\-wide r/w activity syscall\-counts system\-wide syscall counts \&.ft .fi .if n \{\ .RE .\} .sp اکنون می‌توانید مرحلهٔ ضبط را از طریق \fIperf script record\fR انجام دهید: .sp .if n \{\ .RS 4 .\} .nf # perf script record syscall\-counts .fi .if n \{\ .RE .\} .sp و خروجی را با استفاده از \fIperf script report\fR نمایش دهید: .sp .if n \{\ .RS 4 .\} .nf # perf script report syscall\-counts .fi .if n \{\ .RE .\}.SH "اسکریپت‌های آغازین (STARTER SCRIPTS)" .sp شما می‌توانید با ایجاد یک اسکریپت اسکلتی با استفاده از \fIperf script \-g python\fR در همان دایرکتوری که فایل ردگیری perf\&.data موجود قرار دارد، نوشتن اسکریپت برای مجموعه مشخصی از داده‌های ردگیری (trace) را به سرعت آغاز کنید\&. این کار یک اسکریپت آغازین تولید می‌کند که حاوی یک گرداننده (handler) برای هر یک از انواع رویدادها در فایل ردگیری است؛ این اسکریپت به سادگی تمام فیلدهای موجود برای هر رویداد در فایل ردگیری را چاپ می‌کند\&. .sp همچنین می‌توانید به اسکریپت‌های موجود در مسیر ~/libexec/perf\-core/scripts/python نگاهی بیندازید تا مثال‌های نمونه‌ای را ببینید که نحوه انجام کارهای پایه‌ای مانند تجمیع داده‌های رویداد، چاپ نتایج و غیره را نشان می‌دهند\&. علاوه بر این، اسکریپت check\-perf\-script\&.py گرچه از نظر نتایج آنچنان جذاب نیست، اما تلاش می‌کند تا تمام قابلیت‌های اصلی اسکریپت‌نویسی را به کار بگیرد\&. .SH "گرداننده‌های رویداد (EVENT HANDLERS)" .sp هنگامی که perf script با استفاده از یک اسکریپت ردگیری اجرا می‌شود، برای هر رویداد در ردگیری، یک \fIhandler function\fR (تابع گرداننده) تعریف‌شده توسط کاربر فراخوانی می‌شود\&. اگر هیچ تابع گرداننده‌ای برای یک نوع رویداد معین تعریف نشده باشد، آن رویداد نادیده گرفته می‌شود (یا به یک تابع \fItrace_unhandled\fR ارسال می‌شود، پایین‌تر را ببینید) و رویداد بعدی پردازش می‌شود\&. .sp بیشتر مقادیر فیلدهای رویداد به عنوان آرگومان به تابع گرداننده ارسال می‌شوند؛ برخی از فیلدهایی که کمتر متداول هستند ارسال نمی‌شوند \- آن موارد به عنوان بازفراخوانی‌ها به درون فایل اجرایی perf در دسترس هستند (پایین‌تر را ببینید)\&. .sp به عنوان مثال، می‌توان از دستور perf record زیر برای ضبط تمام رویدادهای sched_wakeup در سیستم استفاده کرد: .sp .if n \{\ .RS 4 .\} .nf # perf record \-a \-e sched:sched_wakeup .fi .if n \{\ .RE .\} .sp ردگیری‌هایی که قرار است با استفاده از یک اسکریپت پردازش شوند باید با گزینه بالا ضبط شوند: \-a برای فعال‌سازی گردآوری سراسری در سطح سیستم\&. .sp فایل قالب (format) مربوط به رویداد sched_wakeup فیلدهای زیر را تعریف می‌کند (مسیر /sys/kernel/tracing/events/sched/sched_wakeup/format را ببینید): .sp .if n \{\ .RS 4 .\} .nf \&.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 .fi .if n \{\ .RE .\} .sp تابع گرداننده برای این رویداد به این صورت تعریف می‌شود: .sp .if n \{\ .RS 4 .\} .nf \&.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 .fi .if n \{\ .RE .\} .sp تابع گرداننده قالب subsystem__event_name را به خود می‌گیرد\&. .sp آرگومان‌های common_* در فهرست آرگومان‌های تابع گرداننده، مجموعه‌ای از آرگومان‌ها هستند که به تمامی گرداننده‌های رویداد ارسال می‌شوند؛ برخی از این فیلدها با فیلدهای common_* در فایل قالب مطابقت دارند، اما برخی دیگر به‌صورت ترکیبی (synthesized) تولید شده‌اند، و برخی از فیلدهای common_* نیز به اندازه کافی عمومی نیستند که به عنوان آرگومان به هر رویداد ارسال شوند، اما به صورت توابع کتابخانه‌ای در دسترس هستند\&. .sp در اینجا توضیح مختصری درباره هر یک از آرگومان‌های ثابت رویداد آورده شده است: .sp .if n \{\ .RS 4 .\} .nf event_name نام رویداد به صورت متنی context یک \*(Aqcookie\*(Aq غیرشفاف مورد استفاده در بازفراخوانی‌ها به perf common_cpu پردازنده‌ای (cpu) که رویداد روی آن رخ داده است common_secs بخش ثانیه‌های برچسب زمانی رویداد common_nsecs بخش نانوثانیه‌های برچسب زمانی رویداد common_pid شناسه pid تسک جاری common_comm نام فرآیند جاری .fi .if n \{\ .RE .\} .sp تمام فیلدهای باقی‌مانده در فایل قالب رویداد، همان‌طور که در مثال بالا دیده می‌شود، دارای معادل‌هایی با همان نام به عنوان آرگومان‌های تابع گرداننده هستند\&. .sp موارد فوق، اصول اولیه‌ای را ارائه می‌دهند که برای دسترسی مستقیم به تک‌تک فیلدهای هر رویداد در یک ردگیری نیاز است، که ۹۰٪ از آنچه را که برای نوشتن یک اسکریپت ردگیری مفید نیاز دارید پوشش می‌دهد\&. بخش‌های زیر سایر موارد را پوشش می‌دهند\&..SH "ساختار اسکریپت (SCRIPT LAYOUT)" .sp هر اسکریپت پایتونِ perf script باید با تنظیم مسیر جستجوی ماژول‌های پایتون و \*(Aqimport\(cq کردن چند ماژول پشتیبان آغاز شود (توضیحات ماژول‌ها را در زیر ببینید): .sp .if n \{\ .RS 4 .\} .nf \&.ft C import os import sys sys\&.path\&.append(os\&.environ[\*(AqPERF_EXEC_PATH\*(Aq] + \e \*(Aq/scripts/python/Perf\-Trace\-Util/lib/Perf/Trace\*(Aq) from perf_trace_context import * from Core import * \&.ft .fi .if n \{\ .RE .\} .sp باقی اسکریپت می‌تواند شامل توابع گرداننده (handler) و توابع پشتیبان به هر ترتیبی باشد\&. .sp جدا از توابع گردانندهٔ رویداد که در بالا بررسی شد، هر اسکریپت می‌تواند مجموعه‌ای از توابع اختیاری را پیاده‌سازی کند: .sp تابع \fBtrace_begin\fR، در صورت تعریف شدن، پیش از پردازش هرگونه رویدادی فراخوانی می‌شود و به اسکریپت‌ها این فرصت را می‌دهد تا وظایف راه‌اندازی و مقداردهی اولیه را انجام دهند: .sp .if n \{\ .RS 4 .\} .nf \&.ft C def trace_begin(): pass \&.ft .fi .if n \{\ .RE .\} .sp تابع \fBtrace_end\fR، در صورت تعریف شدن، پس از پردازش همهٔ رویدادها فراخوانی می‌شود و به اسکریپت‌ها این فرصت را می‌دهد تا وظایف پایان اسکریپت، مانند نمایش نتایج را انجام دهند: .sp .if n \{\ .RS 4 .\} .nf \&.ft C def trace_end(): pass \&.ft .fi .if n \{\ .RE .\} .sp تابع \fBtrace_unhandled\fR، در صورت تعریف شدن، برای هر رویدادی که گرداننده‌ای به‌طور صریح برای آن تعریف نشده باشد فراخوانی می‌شود\&. مجموعهٔ استانداردی از آرگومان‌های مشترک به آن ارسال می‌شود: .sp .if n \{\ .RS 4 .\} .nf \&.ft C def trace_unhandled(event_name, context, event_fields_dict): pass \&.ft .fi .if n \{\ .RE .\} .sp تابع \fBprocess_event\fR، در صورت تعریف شدن، برای هر رویداد غیر tracepoint فراخوانی می‌شود .sp .if n \{\ .RS 4 .\} .nf \&.ft C def process_event(param_dict): pass \&.ft .fi .if n \{\ .RE .\} .sp تابع \fBcontext_switch\fR، در صورت تعریف شدن، برای هر تعویض زمینه (context switch) فراخوانی می‌شود .sp .if n \{\ .RS 4 .\} .nf \&.ft C def context_switch(ts, cpu, pid, tid, np_pid, np_tid, machine_pid, out, out_preempt, *x): pass \&.ft .fi .if n \{\ .RE .\} .sp تابع \fBauxtrace_error\fR، در صورت تعریف شدن، برای هر خطای ردیابی ناحیهٔ AUX فراخوانی می‌شود .sp .if n \{\ .RS 4 .\} .nf \&.ft C def auxtrace_error(typ, code, cpu, pid, tid, ip, ts, msg, cpumode, *x): pass \&.ft .fi .if n \{\ .RE .\} .sp بخش‌های باقی‌مانده، توضیحاتی دربارهٔ هر یک از ماژول‌های پایتون داخلیِ موجود در perf script و توابع مرتبط با آن‌ها ارائه می‌دهند\&..SH "ماژول‌ها و توابع موجود (AVAILABLE MODULES AND FUNCTIONS)" .sp بخش‌های زیر توابع و متغیرهای موجود از طریق ماژول‌های پایتون مختلف perf script را شرح می‌دهند\&. برای استفاده از توابع و متغیرهای یک ماژول مشخص، خط متناظر \fIfrom XXXX import\fR را به اسکریپت perf script خود اضافه کنید\&. .SS "ماژول Core\&.py" .sp این توابع برخی قابلیت‌های اساسی را برای اسکریپت‌های کاربر فراهم می‌کنند\&. .sp توابع \fBflag_str\fR و \fBsymbol_str\fR رشته‌های خوانا برای انسان را برای فیلدهای پرچم و فیلدهای نمادین ارائه می‌دهند\&. این‌ها متناظر با رشته‌ها و مقادیر تجزیه‌شده از فیلدهای \fIprint fmt\fR در فایل‌های فرمت رویداد هستند: .sp .if n \{\ .RS 4 .\} .nf 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 بازمی‌گرداند .fi .if n \{\ .RE .\} .sp تابع \fBautodict\fR نوع خاصی از دیکشنری پایتون را بازمی‌گرداند که درهم‌سازی‌های \fIautovivifying\fR (خودکارسازنده) پرل را در پایتون پیاده‌سازی می‌کند؛ بدین معنا که با درهم‌سازی‌های خودکارسازنده، می‌توانید مقادیر درهم‌سازی تودرتو را بدون نیاز به زحمت ایجاد سطوح میانی در صورت عدم وجود، مقداردهی کنید\&. .sp .if n \{\ .RS 4 .\} .nf autodict() \- یک نمونه دیکشنری خودکارسازنده (autovivifying) بازمی‌گرداند .fi .if n \{\ .RE .\} .SS "ماژول perf_trace_context" .sp برخی از فیلدهای \fIcommon\fR در فایل فرمت رویداد آن‌چنان هم عمومی نیستند، اما با این وجود باید برای اسکریپت‌های کاربر قابل دسترس باشند\&. .sp ماژول perf_trace_context مجموعه‌ای از توابع را تعریف می‌کند که می‌توانند برای دسترسی به این داده‌ها در زمینه (context) رویداد جاری استفاده شوند\&. هر یک از این توابع انتظار یک متغیر context را دارند، که همان متغیر context ارسالی به تمام گرداننده‌های رویداد tracepoint به‌عنوان آرگومان دوم است\&. برای رویدادهای غیر tracepoint، متغیر context همچنین به‌صورت perf_trace_context\&.perf_script_context نیز موجود است\&. .sp .if n \{\ .RS 4 .\} .nf 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 را در صورت عدم تنظیم بازمی‌گرداند .fi .if n \{\ .RE .\} .SS "ماژول Util\&.py" .sp توابع کمکی و کاربردی گوناگون برای استفاده با perf script: .sp .if n \{\ .RS 4 .\} .nf nsecs(secs, nsecs) \- کل نانوثانیه‌ها را با دریافت جفت secs/nsecs بازمی‌گرداند nsecs_secs(nsecs) \- بخش کامل ثانیه‌ها را با دریافت nsecs بازمی‌گرداند nsecs_nsecs(nsecs) \- باقی‌مانده نانوثانیه‌ها را با دریافت nsecs بازمی‌گرداند nsecs_str(nsecs) \- رشته قابل چاپ را به صورت secs\&.nsecs بازمی‌گرداند avg(total, n) \- میانگین را بر اساس یک مجموع و تعداد کل مقادیر بازمی‌گرداند .fi .if n \{\ .RE .\} .SH "فیلدهای پشتیبانی‌شده (SUPPORTED FIELDS)" .sp فیلدهایی که در حال حاضر پشتیبانی می‌شوند: .sp 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\&. .sp فیلدهایی که ممکن است وجود داشته باشند: .sp .if n \{\ .RS 4 .\} .nf flags \- پرچم‌های نمونه flags_disp \- نمایش پرچم‌های نمونه insn_cnt \- تعداد دستورالعمل‌ها برای تعیین تعداد دستورالعمل در هر چرخه (IPC) cyc_cnt \- تعداد چرخه‌ها برای تعیین IPC addr_correlates_sym \- فیلد addr می‌تواند با یک نماد مرتبط باشد addr_dso \- مشخصه dso مربوط به addr addr_symbol \- نماد مربوط به addr addr_symoff \- آفست نماد مربوط به addr .fi .if n \{\ .RE .\} .sp برخی فیلدها دارای زیرآیتم هستند: .sp brstack: from, to, from_dsoname, to_dsoname, mispred, predicted, in_tx, abort, cycles\&. .sp brstacksym: آیتم‌ها: from, to, pred, in_tx, abort (رشته تبدیل‌شده) .sp به عنوان مثال، می‌توانیم از این کد برای چاپ "from"، "to" و "cycles" مربوط به brstack استفاده کنیم\&. .sp if \fIbrstack\fR in dict: for entry in dict[\fIbrstack\fR]: print "from %s, to %s, cycles %s" % (entry["from"], entry["to"], entry["cycles"]).SH "همچنین ببینید (SEE ALSO)" .sp \fBperf-script\fR(1)