PERF-INTEL-PT(1) perf Manual PERF-INTEL-PT(1)

perf-intel-pt - پشتیبانی از Intel Processor Trace در ابزارهای perf

perf record -e intel_pt//

قابلیت ردگیری پردازنده اینتل یا همان Intel Processor Trace (Intel PT) یک ویژگی الحاقی برای معماری اینتل است که اطلاعات اجرای نرم‌افزار مانند جریان کنترل، حالت‌های اجرا و زمان‌بندی‌ها را جمع‌آوری کرده و آن‌ها را در بسته‌های دودویی بسیار فشرده قالب‌بندی می‌کند. جزئیات فنی در راهنماهای توسعه‌دهنده نرم‌افزار معماری‌های Intel 64 و IA-32، فصل ۳۶ Intel Processor Trace مستند شده است.

قابلیت Intel PT نخستین بار در پردازنده‌های Intel Core M و نسل پنجم پردازنده‌های Intel Core که مبتنی بر ریزمعماری با نام رمز Broadwell بودند، پشتیبانی شد.

داده‌های ردگیری توسط perf record جمع‌آوری شده و درون فایل perf.data ذخیره می‌شوند. برای گزینه‌های مربوط به perf record به ادامه مراجعه کنید.

داده‌های ردگیری باید رمزگشایی (decode) شوند که این کار شامل پیمایش کد شیء و تطبیق دادن بسته‌های داده‌های ردگیری با آن است. به عنوان مثال، یک بسته TNT تنها مشخص می‌کند که یک انشعاب شرطی طی شده یا طی نشده است؛ بنابراین برای استفاده از آن بسته، رمزگشا باید دقیقاً بداند که کدام دستورالعمل در حال اجرا بوده است.

رمزگشایی به‌صورت بی‌درنگ انجام می‌شود. رمزگشا نمونه‌ها را در همان قالبی خارج می‌کند که خروجی نمونه‌های رویدادهای سخت‌افزاری perf دارند؛ به عنوان مثال طوری که گویی رویدادهای "instructions" یا "branches" ثبت شده‌اند. در حال حاضر ۳ ابزار از این قابلیت پشتیبانی می‌کنند: perf script، perf report و perf inject. برای اطلاعات بیشتر در خصوص استفاده از این ابزارها به ادامه متن مراجعه کنید.

ویژگی متمایزکننده اصلی Intel PT این است که رمزگشا می‌تواند جریان دقیق اجرای نرم‌افزار را تعیین کند. از Intel PT می‌توان برای درک این که نرم‌افزار چرا و چگونه به یک نقطه مشخص رسیده یا رفتاری خاص نشان داده است استفاده کرد. نیازی به کامپایل مجدد نرم‌افزار نیست، بنابراین Intel PT با ساخت‌های دیباگ یا نهایی کار می‌کند؛ با این حال فایل‌های ایمیج اجراشده مورد نیاز هستند - که استفاده از آن را در محیط‌های کامپایل‌شده با JIT یا با کدهای خوداصلاح‌شونده به یک چالش تبدیل می‌کند. همچنین نمادها باید ارائه شوند تا آدرس‌ها معنادار باشند.

یکی از محدودیت‌های Intel PT این است که حجم عظیمی از داده‌های ردگیری را تولید می‌کند (صدها مگابایت در ثانیه به ازای هر هسته) که رمزگشایی آن زمان زیادی می‌برد؛ به عنوان مثال دو یا سه مرتبه بزرگی بیشتر از زمانی که برای جمع‌آوری آن صرف شده است. محدودیت دیگر، اثر ردگیری بر کارایی و عملکرد است؛ چیزی که بسته به مورد استفاده و معماری متفاوت خواهد بود.

شروع کار در مقیاس کوچک مهم است؛ زیرا به سادگی ممکن است داده‌هایی بسیار فراتر از توان پردازش جمع‌آوری شود.

ساده‌ترین کار با Intel PT، پروفایل‌گیری برنامه‌های کوچک در فضای کاربری است. داده‌ها با perf record جمع‌آوری می‌شوند؛ به عنوان مثال برای ردگیری ls فقط در فضای کاربری:

perf record -e intel_pt//u ls

و با perf report پروفایل‌گیری می‌شود؛ مانند:

perf report

ردگیری فضای هسته نیز مشکلی را ایجاد می‌کند، یعنی کدهای خوداصلاح‌شونده هسته. یک ایمیج نسبتاً خوب از هسته در /proc/kcore موجود است، اما برای دریافت یک ایمیج دقیق، باید یک رونوشت از /proc/kcore تحت شرایط مشابه جمع‌آوری داده‌ها ایجاد شود. چنانچه گزینه --kcore استفاده شود، perf record می‌تواند یک کپی از /proc/kcore تهیه کند، اما دسترسی به /proc/kcore محدود است؛ برای نمونه:

sudo perf record -o pt_ls --kcore -e intel_pt// -- ls

که دایرکتوری جدیدی به نام pt_ls ایجاد کرده و فایل perf.data (که به سادگی data نامیده شده) و رونوشت‌هایی از /proc/kcore، /proc/kallsyms و /proc/modules را در آن قرار می‌دهد. ابزارهای دیگر این ساختار دایرکتوری را متوجه می‌شوند، بنابراین استفاده از perf report به صورت زیر می‌شود:

sudo perf report -i pt_ls

از آنجا که نمونه‌ها پس از رویداد ترکیب (synthesize) می‌شوند، دوره تناوب نمونه‌برداری را می‌توان برای گزارش‌گیری انتخاب کرد؛ به عنوان مثال نمونه‌برداری در هر میکروثانیه:

sudo perf report pt_ls --itrace=i1usge

برای اطلاعات بیشتر درباره گزینه --itrace بخش‌های زیر را ببینید.

توجه داشته باشید که هر چه دوره تناوب کوچک‌تر باشد، نمونه‌های بیشتری تولید می‌شوند و زمان پردازش آن‌ها طولانی‌تر خواهد بود.

همچنین در نظر داشته باشید که با کوچک‌تر شدن دوره تناوب نمونه‌برداری، درشت‌دانگی اطلاعات زمان‌بندی Intel PT شروع به تحریف ارزش آماری نمونه‌برداری خواهد کرد.

برای نمایش جریان کنترل نرم‌افزار، نمونه‌های "branches" تولید می‌شوند. به‌طور پیش‌فرض، برای هر یک از انشعاب‌ها یک نمونه انشعاب ترکیب می‌شود. برای به دست آوردن دیدی کلی از داده‌های موجود، می‌توانید از ابزار perf script با تمام گزینه‌های نمونه‌برداری itrace استفاده کنید، که همه نمونه‌ها را فهرست خواهد کرد:

perf record -e intel_pt//u ls
perf script --itrace=iybxwpe

یک فیلد جالب که به‌طور پیش‌فرض چاپ نمی‌شود flags است که می‌تواند به صورت زیر نمایش داده شود:

perf script --itrace=iybxwpe -F+flags

پرچم‌ها عبارتند از "bcrosyiABExghDt" که به ترتیب نشان‌دهنده branch (انشعاب)، call (فراخوانی)، return (بازگشت)، conditional (شرطی)، system (سیستم)، asynchronous (ناهمگام)، interrupt (وقفه)، transaction abort (لغو تراکنش)، trace begin (شروع ردگیری)، trace end (پایان ردگیری)، in transaction (درون تراکنش)، VM-entry (ورود به VM)، VM-exit (خروج از VM)، interrupt disabled (وقفه غیرفعال) و interrupt disable toggle (تغییر وضعیت غیرفعال‌سازی وقفه) هستند.

دستور perf script همچنین از روش‌های سطح بالاتری برای استخراج رد دستورالعمل‌ها پشتیبانی می‌کند:

perf script --insn-trace=disasm

یا برای استفاده از دیس‌اسمبلر xed، که نیازمند نصب ابزار xed است (بخش XED در ادامه را ببینید):

perf script --insn-trace --xed

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

perf script --call-trace

یا

perf script --call-ret-trace

و سپس یک بازه زمانی مورد نظر را برگزینید. سپس بازه زمانی می‌تواند با جزئیات بیشتر بررسی شود با

perf script --time starttime,stoptime --insn-trace=disasm

هنگام بررسی ردگیری، پالایش بر اساس پردازنده‌های مشخص با استفاده از گزینه -C نیز سودمند است:

perf script --time starttime,stoptime --insn-trace=disasm -C 1

تخلیه تمام دستورالعمل‌ها در بازه زمانی روی CPU 1.

فیلد جالب دیگری که به‌طور پیش‌فرض چاپ نمی‌شود ipc است که می‌تواند به صورت زیر نمایش داده شود:

perf script --itrace=be -F+ipc

بسته به نحوه ضبط، دو روش برای محاسبه دستورالعمل بر چرخه (IPC) وجود دارد.

اگر عبارت پیکربندی cyc (بخش عبارت‌های پیکربندی را در ادامه ببینید) استفاده شده باشد، آنگاه IPC و رویدادهای چرخه با استفاده از شمارش چرخه برگرفته از بسته‌های CYC محاسبه می‌شوند، در غیر این صورت بسته‌های MTC استفاده می‌شوند - به عبارت پیکربندی mtc مراجعه کنید. با این حال هنگامی که MTC به کار رود، مقادیر دقت کمتری دارند چرا که زمان‌بندی دقت کمتری دارد.

از آنجا که Intel PT شمارش چرخه را در هر انشعاب یا دستورالعمل به‌روزرسانی نمی‌کند، مقادیر غالباً صفر خواهند بود. هنگامی که مقادیری موجود باشد، آن‌ها تعداد دستورالعمل‌ها و تعداد چرخه‌ها از زمان آخرین به‌روزرسانی خواهند بود، و بنابراین میانگین شمارش چرخه IPC را از آخرین IPC برای آن نوع رویداد نشان می‌دهند. توجه داشته باشید که IPC برای رویدادهای "branches" جدا از IPC برای رویدادهای "instructions" محاسبه می‌شود.

حتی با استفاده از عبارت پیکربندی cyc، تولید اطلاعات IPC به ازای هر تغییر برچسب زمان امکان‌پذیر است، اما به بهای کاهش دقت. این حالت با تعیین گزینه A در itrace انتخاب می‌شود. به دلیل دانه‌بندی برچسب‌های زمان، تعداد واقعی چرخه‌ها افزایش می‌یابد حتی اگر چرخه‌های گزارش‌شده تغییر نکنند. تعداد دستورالعمل‌ها مشخص است، اما اگر IPC گزارش شود، ممکن است چرخه‌ها بیش از حد کم گزارش شده و بنابراین IPC بسیار بالا باشد. توجه داشته باشید که با افزایش دوره نمونه‌برداری، این عدم دقت کاهش می‌یابد؛ یعنی اگر تعداد چرخه‌ها به میزان کمی پایین باشد، در صورتی که تعداد چرخه‌ها بزرگ باشد این موضوع کم‌اهمیت‌تر خواهد بود. همچنین ممکن است استفاده از گزینه A همراه با dlfilter-show-cycles.so برای ارائه اطلاعات چرخه با دانه‌بندی دقیق‌تر سودمند باشد.

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

نکته دیگر اینکه در مورد رویدادهای "branches"، انشعاب‌های طی‌نشده در حال حاضر نمونه‌برداری نمی‌شوند، بنابراین مقادیر IPC برای آن‌ها ظاهر نمی‌شود؛ به عنوان مثال یک بسته CYC با یک بسته TNT که با یک انشعاب طی‌نشده آغاز می‌شود. برای مشاهده تمام مقادیر ممکن IPC، می‌توان از رویدادهای "instructions" استفاده کرد؛ مانند --itrace=i0ns

در حالی که امکان ایجاد اسکریپت‌ها برای تحلیل داده‌ها وجود دارد، یک رویکرد جایگزین برای برون‌ریزی داده‌ها به پایگاه داده sqlite یا postgresql در دسترس است. برای جزئیات بیشتر به اسکریپت export-to-sqlite.py یا export-to-postgresql.py و برای نمونه‌ای از به‌کارگیری پایگاه داده به اسکریپت exported-sql-viewer.py مراجعه کنید.

همچنین اسکریپت intel-pt-events.py وجود دارد که نمونه‌ای از نحوه استخراج داده‌های خام برای رویدادهای توان و PTWRITE را ارائه می‌دهد. این اسکریپت همچنین انشعاب‌ها را نمایش می‌دهد و از ۲ حالت اضافی که با گزینه انتخاب می‌شوند پشتیبانی می‌کند:

•--insn-trace - ردگیری دستورالعمل‌ها
•--src-trace - ردگیری کد مبدأ

اسکریپت intel-pt-events.py نیز دارای گزینه‌هایی است:

•--all-switch-events - نمایش همهٔ رویدادهای تعویض (switch)، نه فقط آخرین رویداد متوالی.
•--interleave [<n>] - درهم‌آمیزی خروجی نمونه‌ها برای برچسب زمانی یکسان، به‌طوری‌که بیش از n نمونه برای یک CPU پشت سر هم نمایش داده نشود. n به طور پیش‌فرض ۴ است. توجه داشته باشید که این موضوع تنها بر ترتیب خروجی و فقط زمانی که برچسب زمانی یکسان باشد تأثیر می‌گذارد.

همان‌طور که در بالا ذکر شد، ضبط حجم بسیار زیادی از داده‌ها به سادگی رخ می‌دهد. یک راه برای محدود کردن داده‌های ضبط‌شده، استفاده از حالت snapshot است که در ادامه توضیح داده شده است. در ادامه به new snapshot option و Intel PT modes of operation مراجعه کنید.

مشکل دیگری که با آن مواجه خواهید شد، خطاهای رمزگشا (decoder) است. این خطاها می‌توانند ناشی از عدم امکان دسترسی به تصویر اجرایی (executed image)، کدهای خود‌اصلاح‌شونده یا JIT شده، یا عدم توانایی در تطبیق اطلاعات جانبی (مانند تعویض متن‌ها و mmapها) باشند که باعث می‌شود رمزگشا نداند چه کدی اجرا شده است.

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

درایور کرنل Intel PT یک PMU جدید برای Intel PT ایجاد می‌کند. رویدادهای PMU با ارائه نام PMU و به دنبال آن "config" که با اسلش جدا شده‌اند انتخاب می‌شوند. بهبودی حاصل شده است تا مقدار پیش‌فرض "config" مجاز باشد، برای مثال گزینهٔ

-e intel_pt//

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

-e intel_pt/tsc,noretcomp=0/

است که با

-e intel_pt/tsc=1,noretcomp=0/

یکسان است. توجه داشته باشید عبارات config دیگری نیز وجود دارند - بخش عبارات config را در ادامه ببینید.

عبارات config در مسیر /sys/devices/intel_pt/format فهرست شده‌اند. آن‌ها فیلدهای بیتی در عضو config از struct perf_event_attr هستند که توسط فراخوان سیستمی perf_event_open به کرنل ارسال می‌شود. آن‌ها با فیلدهای بیتی در IA32_RTIT_CTL MSR مطابقت دارند. در اینجا فهرستی از آن‌ها و تعاریفشان آمده است:

$ grep -H . /sys/bus/event_source/devices/intel_pt/format/*
/sys/bus/event_source/devices/intel_pt/format/cyc:config:1
/sys/bus/event_source/devices/intel_pt/format/cyc_thresh:config:19-22
/sys/bus/event_source/devices/intel_pt/format/mtc:config:9
/sys/bus/event_source/devices/intel_pt/format/mtc_period:config:14-17
/sys/bus/event_source/devices/intel_pt/format/noretcomp:config:11
/sys/bus/event_source/devices/intel_pt/format/psb_period:config:24-27
/sys/bus/event_source/devices/intel_pt/format/tsc:config:10

توجه داشته باشید که پیکربندی پیش‌فرض باید برای هر عبارت بازنویسی شود، یعنی:

-e intel_pt/noretcomp=0/

معادل است با:

-e intel_pt/tsc=1,noretcomp=0/

بنابراین، برای غیرفعال کردن بسته‌های TSC استفاده کنید از:

-e intel_pt/tsc=0/

همچنین مشخص کردن مقدار config به صورت صریح امکان‌پذیر است:

-e intel_pt/config=0x400/

توجه داشته باشید که همانند تمامی رویدادها، این رویداد با تغییردهنده‌های رویداد پسوند می‌گیرد:

u       userspace
k       kernel
h       hypervisor
G       guest
H       host
p       precise ip

تغییردهنده‌های h، G و H برای مجازی‌سازی هستند که توسط Intel PT استفاده نمی‌شوند. همچنین p به Intel PT مربوط نیست. بنابراین فقط گزینه‌های u و k برای Intel PT معنادار هستند.

در صورتی که از گزینهٔ -vv استفاده شود، perf_event_attr نمایش داده می‌شود؛ به عنوان مثال:

------------------------------------------------------------
perf_event_attr:
type                             6
size                             112
config                           0x400
{ sample_period, sample_freq }   1
sample_type                      IP|TID|TIME|CPU|IDENTIFIER
read_format                      ID
disabled                         1
inherit                          1
exclude_kernel                   1
exclude_hv                       1
enable_on_exec                   1
sample_id_all                    1
------------------------------------------------------------
sys_perf_event_open: pid 31104  cpu 0  group_fd -1  flags 0x8
sys_perf_event_open: pid 31104  cpu 1  group_fd -1  flags 0x8
sys_perf_event_open: pid 31104  cpu 2  group_fd -1  flags 0x8
sys_perf_event_open: pid 31104  cpu 3  group_fd -1  flags 0x8
------------------------------------------------------------

«عبارات پیکربندی» (Config terms) پارامترهایی هستند که با گزینهٔ رویداد -e intel_pt// مشخص می‌شوند، برای مثال:

-e intel_pt/cyc/

که حالت دقیق بر حسب چرخه (cycle accurate) را انتخاب می‌کند. هر عبارت پیکربندی می‌تواند مقداری داشته باشد که مقدار پیش‌فرض آن 1 است، بنابراین مورد بالا با عبارت زیر یکسان است:

-e intel_pt/cyc=1/

برخی عبارات به‌طور پیش‌فرض فعال هستند، بنابراین برای خاموش کردن آن‌ها باید مقدارشان برابر با 0 قرار گیرد. برای مثال، جهت غیرفعال کردن ردگیری انشعاب (branch tracing):

-e intel_pt/branch=0/

چندین عبارت پیکربندی با کاما از یکدیگر جدا می‌شوند، برای مثال:

-e intel_pt/cyc,mtc_period=9/

همچنین عبارات پیکربندی مشترکی نیز وجود دارند؛ مستندات perf-record(1) را ببینید.

عبارات پیکربندی Intel PT در زیر شرح داده شده‌اند.

tsc

همیشه پشتیبانی می‌شود. بسته‌های برچسب زمانی TSC را برای ارائهٔ اطلاعات زمان‌بندی تولید می‌کند. در برخی موارد امکان رمزگشایی بدون اطلاعات زمان‌بندی وجود دارد، برای مثال در یک بافت به‌ازای‌رشته (per-thread context) که با نگاشت‌های حافظهٔ اجرایی هم‌پوشانی ندارد.

پیکربندی پیش‌فرض tsc را انتخاب می‌کند (یعنی tsc=1).

noretcomp

همیشه پشتیبانی می‌شود. «فشرده‌سازی بازگشت» (return compression) را غیرفعال می‌کند تا هنگام بازگشت یک تابع، یک بستهٔ TIP تولید شود. این کار موجب تولید بسته‌های بیشتری می‌شود اما ممکن است رمزگشایی را قابل‌اطمینان‌تر سازد.

پیکربندی پیش‌فرض noretcomp را انتخاب نمی‌کند (یعنی noretcomp=0).

psb_period

امکان تعیین بسامد بسته‌های PSB را فراهم می‌سازد.

بستهٔ PSB یک بستهٔ همگام‌سازی است که نقطهٔ آغازی را برای رمزگشایی یا بازیابی از خطاها فراهم می‌کند.

پشتیبانی از psb_period توسط مسیر زیر مشخص می‌شود:

/sys/bus/event_source/devices/intel_pt/caps/psb_cyc

که در صورت پشتیبانی از این ویژگی حاوی «1» و در غیر این صورت «0» است.

مقادیر معتبر توسط مسیر زیر مشخص می‌شوند:

/sys/bus/event_source/devices/intel_pt/caps/psb_periods

که حاوی مقداری هگزادسیمال است و بیت‌های آن نشان‌دهندهٔ مقادیر معتبر هستند؛ برای مثال، تنظیم بودن بیت 2 به این معناست که مقدار 2 معتبر است.

مقدار psb_period به تعداد تقریبی بایت‌های ردگیری (trace) بین بسته‌های PSB به این صورت تبدیل می‌شود:

2 ^ (value + 11)

برای مثال، مقدار 3 به معنای 16KiB بایت بین PSBها است.

اگر مقداری نامعتبر وارد شود، پیام خطا فهرستی از مقادیر معتبر را ارائه خواهد داد؛ برای مثال:

$ perf record -e intel_pt/psb_period=15/u uname
Invalid psb_period for intel_pt. Valid values are: 0-5

اگر بسته‌های MTC انتخاب شده باشند، پیکربندی پیش‌فرض مقدار 3 (یعنی psb_period=3) یا نزدیک‌ترین مقدار کمترِ پشتیبانی‌شده را انتخاب می‌کند (0 همیشه پشتیبانی می‌شود). در غیر این صورت مقدار پیش‌فرض 0 است.

اگر انتظار می‌رود رمزگشایی قابل‌اطمینان باشد و بافر بزرگ است، می‌توان از دورهٔ PSB بزرگی استفاده کرد.

از آنجا که یک بستهٔ TSC همراه با PSB تولید می‌شود، دورهٔ PSB می‌تواند در غیاب MTC یا CYC، بر میزان تفکیک‌پذیری اطلاعات زمان‌بندی نیز تأثیر بگذارد.

mtc

بسته‌های زمان‌بندی MTC را تولید می‌کند.

بسته‌های MTC اطلاعات برچسب زمانی با تفکیک‌پذیری دقیق‌تری نسبت به بسته‌های TSC ارائه می‌دهند. بسته‌های MTC زمان را با استفاده از ساعت کریستالی سخت‌افزار (CTC) ثبت می‌کنند که ارتباط آن با بسته‌های TSC با استفاده از یک بستهٔ TMA برقرار می‌شود.

پشتیبانی از این ویژگی توسط مسیر زیر مشخص می‌شود:

/sys/bus/event_source/devices/intel_pt/caps/mtc

که در صورت پشتیبانی از این ویژگی حاوی «1» و در غیر این صورت «0» است.

بسامد بسته‌های MTC را نیز می‌توان مشخص کرد - بخش mtc_period در زیر را ببینید.

mtc_period

مشخص می‌کند که بسته‌های MTC با چه بسامدی تولید شوند - برای چگونگی تعیین پشتیبانی از بسته‌های MTC، بخش mtc در بالا را ببینید.

مقادیر معتبر توسط مسیر زیر مشخص می‌شوند:

/sys/bus/event_source/devices/intel_pt/caps/mtc_periods

که حاوی مقداری هگزادسیمال است و بیت‌های آن نشان‌دهندهٔ مقادیر معتبر هستند؛ برای مثال، تنظیم بودن بیت 2 یعنی مقدار 2 معتبر است.

مقدار mtc_period به بسامد MTC به این صورت تبدیل می‌شود:

CTC-frequency / (2 ^ value)

برای مثال، مقدار 3 به معنای یک‌هشتمِ CTC-frequency است.

که در آن CTC ساعت کریستالی سخت‌افزاری است و بسامد آن می‌تواند از طریق مقادیر ارائه‌شده در cpuid leaf 0x15 به TSC مرتبط شود.

اگر مقداری نامعتبر وارد شود، پیام خطا فهرستی از مقادیر معتبر را ارائه می‌دهد؛ برای مثال:

$ perf record -e intel_pt/mtc_period=15/u uname
Invalid mtc_period for intel_pt. Valid values are: 0,3,6,9

مقدار پیش‌فرض 3 یا نزدیک‌ترین مقدار کمترِ پشتیبانی‌شده است (0 همیشه پشتیبانی می‌شود). cyc

بسته‌های زمان‌بندی CYC را تولید می‌کند.

بسته‌های CYC اطلاعات مهرزمانی (timestamp) حتی دقیق‌تری را نسبت به بسته‌های MTC و TSC فراهم می‌آورند. یک بستهٔ CYC شامل تعداد چرخه‌های CPU از زمان آخرین بستهٔ CYC است. برخلاف بسته‌های MTC و TSC، بسته‌های CYC تنها زمانی فرستاده می‌شوند که بستهٔ دیگری نیز ارسال شود.

پشتیبانی از این ویژگی توسط مسیر زیر مشخص می‌شود:

/sys/bus/event_source/devices/intel_pt/caps/psb_cyc

که در صورت پشتیبانی از این ویژگی حاوی «1» و در غیر این صورت حاوی «0» است.

تعداد بسته‌های CYC تولیدشده را می‌توان با تعیین یک آستانه کاهش داد - بخش cyc_thresh را در زیر ببینید.

cyc_thresh

بسامد تولید بسته‌های CYC را مشخص می‌کند - برای نحوهٔ تشخیص پشتیبانی از بسته‌های CYC، بخش cyc در بالا را ببینید.

مقادیر معتبر cyc_thresh توسط مسیر زیر ارائه می‌شوند:

/sys/bus/event_source/devices/intel_pt/caps/cycle_thresholds

که شامل یک مقدار هگزادسیمال است و بیت‌های آن نمایانگر مقادیر معتبر هستند؛ برای مثال، تنظیم بودن بیت ۲ نشان می‌دهد مقدار ۲ معتبر است.

مقدار cyc_thresh نشان‌دهندهٔ حداقل تعداد چرخه‌های CPU است که پیش از امکان ارسال یک بستهٔ CYC باید سپری شده باشند. تعداد چرخه‌های CPU عبارت است از:

2 ^ (value - 1)

برای مثال، مقدار ۴ یعنی پیش از ارسال یک بستهٔ CYC باید ۸ چرخهٔ CPU سپری شود. توجه داشته باشید که بستهٔ CYC همچنان فقط زمانی فرستاده می‌شود که بستهٔ دیگری ارسال شده باشد، نه لزوماً در هر مثلاً ۸ چرخهٔ CPU.

اگر مقدار نامعتبری وارد شود، پیام خطا فهرستی از مقادیر معتبر را ارائه خواهد داد؛ مانند:

$ perf record -e intel_pt/cyc,cyc_thresh=15/u uname
Invalid cyc_thresh for intel_pt. Valid values are: 0-12

بسته‌های CYC به‌طور پیش‌فرض درخواست نمی‌شوند.

pt

حالت عبور مستقیم (pass-through) را مشخص می‌کند که عبارت پیکربندی branch را فعال می‌سازد.

پیکربندی پیش‌فرض در صورت در دسترس بودن، pt را انتخاب می‌کند، بنابراین کاربر هرگز نیازی به تعیین این عبارت نخواهد داشت.

branch

ردیابی انشعاب‌ها را فعال می‌کند. ردیابی انشعاب به‌طور پیش‌فرض فعال است، بنابراین برای غیرفعال کردن آن از branch=0 استفاده کنید.

پیکربندی پیش‌فرض در صورت موجود بودن، branch را انتخاب می‌کند.

ptw

بسته‌های PTWRITE را فعال می‌کند که در زمان اجرای دستورالعمل ptwrite تولید می‌شوند.

پشتیبانی از این ویژگی توسط مسیر زیر مشخص می‌شود:

/sys/bus/event_source/devices/intel_pt/caps/ptwrite

که در صورت پشتیبانی از این ویژگی حاوی «1» و در غیر این صورت حاوی «0» است.

به‌عنوان جایگزین، به بخش «Emulated PTWRITE» در ادامه مراجعه کنید.

fup_on_ptw

ارسال یک بستهٔ FUP به دنبال بستهٔ PTWRITE را فعال می‌کند. بستهٔ FUP نشانی دستورالعمل ptwrite را فراهم می‌سازد. در نبود fup_on_ptw، چنانچه ردیابی انشعاب فعال باشد دیکودر از نشانی انشعاب قبلی استفاده می‌کند، در غیر این صورت نشانی صفر خواهد بود. توجه داشته باشید که fup_on_ptw حتی در زمان غیرفعال بودن ردیابی انشعاب نیز کار خواهد کرد.

pwr_evt

رویدادهای توان (power events) را فعال می‌کند. این رویدادها اطلاعاتی دربارهٔ تغییرات وضعیت C-state پردازنده ارائه می‌دهند.

پشتیبانی از این ویژگی توسط مسیر زیر مشخص می‌شود:

/sys/bus/event_source/devices/intel_pt/caps/power_event_trace

که در صورت پشتیبانی از این ویژگی حاوی «1» و در غیر این صورت حاوی «0» است.

event

ردیابی رویدادها (Event Trace) را فعال می‌کند. این رویدادها اطلاعاتی را دربارهٔ رویدادهای ناهمگام ارائه می‌دهند.

پشتیبانی از این ویژگی توسط مسیر زیر مشخص می‌شود:

/sys/bus/event_source/devices/intel_pt/caps/event_trace

که در صورت پشتیبانی از این ویژگی حاوی «1» و در غیر این صورت حاوی «0» است.

notnt

بسته‌های TNT را غیرفعال می‌کند. بدون بسته‌های TNT، پیمایش کد اجرایی جهت بازسازی جریان کنترل (control flow) امکان‌پذیر نیست؛ با این حال بسته‌های FUP، TIP، TIP.PGE و TIP.PGD همچنان جریان کنترل ناهمگام و عبارات return (در صورتی که فشرده‌سازی بازگشت غیرفعال باشد - بخش noretcomp را ببینید) را نشان می‌دهند. مزیت حذف بسته‌های TNT، کاهش حجم ردیابی و سربار ردیابی متناظر با آن است.

پشتیبانی از این ویژگی توسط مسیر زیر مشخص می‌شود:

/sys/bus/event_source/devices/intel_pt/caps/tnt_disable

که در صورت پشتیبانی از این ویژگی حاوی «1» و در غیر این صورت حاوی «0» است.

aux-action=start-paused

ردیابی را در حالت متوقف‌شده (paused) آغاز می‌کند؛ به بخش Pause or Resume Tracing مراجعه کنید.

برخی از قابلیت‌های Intel PT با سایر رویدادها کار می‌کنند؛ قابلیت‌هایی نظیر نمونه‌برداری ناحیه AUX و PEBS-via-PT. در این موارد، سایر رویدادها می‌توانند اصطلاحات پیکربندی زیر را داشته باشند:

aux-sample-size

برای تنظیم اندازه نمونه ناحیه AUX استفاده می‌شود؛ به بخش AUX area sampling option مراجعه کنید

aux-output

برای انتخاب PEBS-via-PT استفاده می‌شود؛ به بخش PEBS via Intel PT مراجعه کنید

aux-action

برای مکث یا ازسرگیری ردگیری استفاده می‌شود؛ به بخش Pause or Resume Tracing مراجعه کنید

برای انتخاب «نمونه‌برداری» (sampling) در Intel PT، می‌توان از گزینه نمونه‌برداری ناحیه AUX استفاده کرد:

--aux-sample

به صورت اختیاری می‌توان اندازه نمونه را بر حسب بایت به دنبال آن آورد؛ به عنوان مثال:

--aux-sample=8192

علاوه بر این، رویداد Intel PT برای نمونه‌برداری باید تعریف شود؛ به عنوان مثال:

-e intel_pt//u

نمونه‌ها روی رویدادهای دیگر حاوی داده‌های Intel PT ایجاد خواهند شد؛ برای مثال دستور زیر نمونه‌های Intel PT را روی رویداد branch-misses ایجاد می‌کند، توجه داشته باشید که رویدادها باید با استفاده از {} گروه‌بندی شوند:

perf record --aux-sample -e '{intel_pt//u,branch-misses:u}'

یک جایگزین برای --aux-sample افزودن اصطلاح پیکربندی aux-sample-size به رویدادها است. در این حالت، گروه‌بندی به صورت ضمنی اعمال می‌شود؛ به عنوان مثال:

perf record -e intel_pt//u -e branch-misses/aux-sample-size=8192/u

مشابه این است:

perf record -e '{intel_pt//u,branch-misses/aux-sample-size=8192/u}'

اما همچنین امکان استفاده از یک فیلتر آدرس را فراهم می‌کند؛ به عنوان مثال:

perf record -e intel_pt//u --filter 'filter * @/bin/ls' -e branch-misses/aux-sample-size=8192/u -- ls

انتخاب اندازه نمونه‌ای که به اندازه کافی بزرگ باشد تا حداقل یک بسته PSB را در بر گیرد اهمیت دارد. در غیر این صورت هشداری نمایش داده خواهد شد:

Intel PT sample size (%zu) may be too small for PSB period (%zu)

محاسبه مورد استفاده برای آن بدین صورت است: اگر sample_size ⟨ psb_period + 256 باشد هشدار نمایش داده می‌شود. هنگامی که نمونه‌برداری استفاده می‌شود، مقدار پیش‌فرض psb_period برابر با 0 (2KiB) است.

اندازه پیش‌فرض نمونه 4KiB است.

اندازه نمونه در aux_sample_size در struct perf_event_attr ارسال می‌شود. اندازه نمونه با حداکثر اندازه رویداد که 64KiB است محدود می‌شود. بدون پیوست بودن نمونه ردگیری، دانستن اینکه رویداد چقدر ممکن است بزرگ باشد دشوار است، اما ابزار اعتبارسنجی می‌کند که اندازه نمونه بزرگ‌تر از 60KiB نباشد..SS "گزینه جدید snapshot"

تفاوت میان full trace و snapshot از دیدگاه هسته (kernel) در این است که در full trace داده‌های ردیابی که کاربر هنوز آن‌ها را جمع‌آوری نکرده است (و این موضوع را با پیش بردن aux_tail مشخص ساخته) بازنویسی نمی‌شوند، در حالی که در حالت snapshot اجازه می‌دهیم ردیابی اجرا شده و داده‌های قدیمی‌تر در بافر بازنویسی شوند تا هر زمان اتفاق جالبی رخ داد، بتوانیم آن را متوقف کرده و یک تصویر لحظه‌ای (snapshot) از آنچه در حول‌وحوش آن لحظه خاص در جریان بوده است برداریم.

برای انتخاب حالت snapshot، گزینه جدیدی اضافه شده است:

-S

به‌صورت اختیاری می‌توان اندازه snapshot را در ادامه آن ذکر کرد، به عنوان مثال:

-S0x100000

اندازه پیش‌فرض snapshot، همان اندازه auxtrace mmap است. اگر هیچ‌یک از اندازه auxtrace mmap یا اندازه snapshot تعیین نشده باشد، مقدار پیش‌فرض برای کاربران دارای دسترسی ممتاز (یا در صورتی که /proc/sys/kernel/perf_event_paranoid < 0 باشد) برابر با 4MiB و برای کاربران عادی (فاقد دسترسی ممتاز) برابر با 128KiB است. چنانچه کاربری فاقد دسترسی ممتاز صفحات mmap را مشخص نکند، صفحات mmap مطابق آنچه در بخش گزینه جدید auxtrace mmap size در زیر توضیح داده شده است، کاهش خواهند یافت.

اندازه snapshot در صورت استفاده از گزینه -vv نمایش داده می‌شود، برای نمونه:

Intel PT snapshot size: %zu

اندازه بافر Intel PT با افزودن مقداری به گزینه -m مشخص می‌شود، به عنوان مثال:

-m,16

اندازه بافری برابر با ۱۶ صفحه، یعنی 64KiB را انتخاب می‌کند.

توجه داشته باشید که کارکرد موجود -m بدون تغییر باقی مانده است. اندازه auxtrace mmap با افزودن اختیاری یک ویرگول و مقدار آن تعیین می‌شود.

اندازه پیش‌فرض auxtrace mmap برای Intel PT برای کاربران دارای دسترسی ممتاز (یا در صورتی که /proc/sys/kernel/perf_event_paranoid < 0 باشد) برابر با 4MiB/page_size، و برای کاربران عادی برابر با 128KiB است. اگر کاربر عادی صفحات mmap را مشخص نکند، صفحات mmap از مقدار پیش‌فرض 512KiB/page_size به 256KiB/page_size کاهش می‌یابد؛ در غیر این صورت احتمالاً کاربر با خطا مواجه خواهد شد زیرا از سقف mlock خود (حداکثر حافظه قفل‌شده مطابق آنچه در /proc/self/limits نشان داده شده است) فراتر می‌رود. توجه داشته باشید که perf مقدار 512KiB نخست (در واقع /proc/sys/kernel/perf_event_mlock_kb منهای ۱ صفحه) به ازای هر cpu را جزو سقف mlock به حساب نمی‌آورد؛ بنابراین یک کاربر عادی مجاز به استفاده از 512KiB به ازای هر cpu به اضافه سقف mlock خود است (که پیش‌فرض آن 64KiB است اما در تعداد cpuها ضرب نمی‌شود).

در حالت full-trace، توان‌های ۲ برای اندازه بافر مجاز هستند و حداقل اندازه ۲ صفحه است. در حالت snapshot یا حالت نمونه‌برداری (sampling mode)، وضعیت مشابه است اما حداقل اندازه ۱ صفحه می‌باشد.

اندازه mmap و اندازه auxtrace mmap در صورت استفاده از گزینه -vv نمایش داده می‌شوند، به عنوان مثال:

mmap length 528384
auxtrace mmap length 4198400

ابزار Intel PT می‌تواند در ۳ حالت استفاده شود: حالت full-trace، حالت sample و حالت snapshot.

حالت full-trace به‌طور پیوسته ردیابی را انجام می‌دهد، برای نمونه:

perf record -e intel_pt//u uname

حالت sample یک نمونه Intel PT را به سایر رویدادها متصل می‌کند، به عنوان مثال:

perf record --aux-sample -e intel_pt//u -e branch-misses:u

حالت snapshot داده‌های دردسترس را هنگامی که یک سیگنال ارسال می‌شود یا فرمان کنترلی “snapshot” صادر می‌گردد، ضبط می‌کند؛ برای نمونه با استفاده از یک سیگنال:

perf record -v -e intel_pt//u -S ./loopy 1000000000 &
[1] 11435
kill -USR2 11435
Recording AUX area tracing snapshot

توجه داشته باشید که سیگنال ارسال‌شده SIGUSR2 است. همچنین توجه داشته باشید که عبارت “Recording AUX area tracing snapshot” به دلیل استفاده از گزینه -v نمایش داده شده است.

مزیت استفاده از فرمان کنترلی “snapshot” این است که دسترسی از طریق یک FIFO کنترل می‌شود، برای نمونه:

$ mkfifo perf.control
$ mkfifo perf.ack
$ cat perf.ack &
[1] 15235
$ sudo ~/bin/perf record --control fifo:perf.control,perf.ack -S -e intel_pt//u -- sleep 60 &
[2] 15243
$ ps -e | grep perf
15244 pts/1    00:00:00 perf
$ kill -USR2 15244
bash: kill: (15244) - Operation not permitted
$ echo snapshot > perf.control
ack

این ۳ حالت عملکردی Intel PT را نمی‌توان به طور هم‌زمان استفاده کرد..SS "مدیریت بافر (Buffer handling)"

ممکن است محدودیت‌هایی برای بافر وجود داشته باشد (به‌عنوان مثال یک مدخل ToPa منفرد) که به این معنی است که اندازه‌های واقعی بافر به توان‌هایی از ۲ تا ۴ مبی‌بایت (MAX_PAGE_ORDER) محدود می‌شود. به منظور فراهم کردن اندازه‌های دیگر، و به‌ویژه اندازه‌ای دلخواه و بزرگ، چندین بافر به‌صورت منطقی به یکدیگر متصل (پیوسته) می‌شوند. با این حال، برای جابه‌جایی میان بافرها باید از یک وقفه (interrupt) استفاده شود. این امر دو مشکل بالقوه در پی دارد: الف) ممکن است به وقفه به‌موقع رسیدگی نشود، به طوری که بافر فعلی پر شده و بخشی از داده‌های ردگیری (trace) از دست برود. ب) وقفه‌ها ممکن است سیستم را کُند کرده و بر نتایج کارایی تأثیر بگذارند.

اگر داده‌های ردگیری از دست بروند، درایور پرچم truncated را در رویداد PERF_RECORD_AUX تنظیم می‌کند که ابزارها آن را به‌عنوان یک خطا گزارش می‌دهند.

در حالت ردگیری کامل (full-trace mode)، درایور پیش از آنکه اجازه دهد بافر (منطقی) به ابتدا بازگردد (wrap-around)، منتظر می‌ماند تا داده‌ها به بیرون کپی شوند. اگر داده‌ها به اندازه کافی سریع به بیرون کپی نشوند، مجدداً truncated در رویداد PERF_RECORD_AUX تنظیم می‌شود. اگر درایور مجبور به انتظار شود، رویداد intel_pt غیرفعال می‌گردد. از آنجا که دانستن زمان وقوع این اتفاق دشوار است، ابزارهای perf همیشه پس از کپی کردن داده‌ها به بیرون، رویداد intel_pt را مجدداً فعال می‌کنند.

به‌طور پیش‌فرض «perf record» جریان رویداد را پس‌پردازش می‌کند تا تمام شناسه‌های ساخت (build ids) فایل‌های اجرایی را برای تمامی آدرس‌های نمونه‌برداری‌شده بیابد. برای این منظور، Intel PT عمداً رمزگشایی نمی‌شود (زیرا زمان بسیار زیادی طول می‌کشد). در عوض، شناسه‌های ساخت برای تمام فایل‌های اجراییِ مشاهده‌شده (به دلیل رویدادهای mmap، comm یا task) در فایل perf.data گنجانده می‌شوند.

برای مشاهده شناسه‌های ساخت گنجانده‌شده در فایل perf.data از این دستور استفاده کنید:

perf buildid-list

اگر فایل perf.data شامل داده‌های Intel PT باشد، این دستور معادل است با:

perf buildid-list --with-hits

به منظور ایجاد یک تصویر لحظه‌ای (snapshot)، رویداد intel_pt با استفاده از یک فراخوانی IOCTL، یعنی PERF_EVENT_IOC_DISABLE غیرفعال می‌شود. با این حال، انجام این کار می‌تواند جمع‌آوری اطلاعات جانبی (side-band) را نیز غیرفعال کند. برای جلوگیری از این موضوع، یک رویداد نرم‌افزاری ساختگی (dummy) معرفی شده است که اجازه می‌دهد ضبط رویدادهای ردگیری (مانند mmapها) در حالی که intel_pt غیرفعال است ادامه یابد. این امر برای اطمینان از کامل بودن اطلاعات جانبی جهت امکان‌پذیر ساختن رمزگشایی تصاویر لحظه‌ای بعدی بسیار مهم است.

آزمونی برای این منظور ایجاد شده است. برای یافتن این آزمون:

perf test list
...
23: Test using a dummy software event to keep tracking

برای اجرای آزمون:

perf test 23
23: Test using a dummy software event to keep tracking     : Ok

دستور perf record اساساً در یکی از سه حالت زیر عمل می‌کند: به ازای هر رشته (per thread)، به ازای هر پردازنده (per cpu)، یا فقط بار کاری (workload only).

حالت «به ازای هر رشته» با -t یا با --per-thread (همراه با -p یا -u یا فقط یک بار کاری) انتخاب می‌شود. حالت «به ازای هر پردازنده» با -C یا -a انتخاب می‌شود. حالت «فقط بار کاری» با عدم استفاده از سایر گزینه‌ها و مشخص کردن دستوری برای اجرا (یعنی همان بار کاری) انتخاب می‌شود.

در حالت به ازای هر رشته (per-thread)، فهرست دقیقی از رشته‌ها ردگیری می‌شود. هیچ وراثتی وجود ندارد. هر رشته بافر رویداد مختص به خود را دارد.

در حالت به ازای هر پردازنده (per-cpu)، تمام فرایندها (یا فرایندهای مربوط به cgroup انتخاب‌شده یعنی گزینه -G، یا فرایندهای انتخاب‌شده با -p یا -u) ردگیری می‌شوند. هر پردازنده بافر مخصوص به خود را دارد. وراثت مجاز است.

در حالت فقط بار کاری (workload-only)، بار کاری ردگیری می‌شود اما با بافرهای به ازای هر پردازنده. وراثت مجاز است. توجه داشته باشید که اکنون می‌توانید با استفاده از گزینه --per-thread، یک بار کاری را در حالت به ازای هر رشته ردگیری کنید.

مگر در حالتی که /proc/sys/kernel/perf_event_paranoid بر روی -1 تنظیم شده باشد، محدودیت‌های حافظه بر کاربران غیرممتاز اعمال می‌شود. همان‌طور که در بالا توضیح داده شد، این موضوع بر اندازه‌های بافری که آنها می‌توانند در اختیار داشته باشند تأثیر می‌گذارد.

هسته نسخه v4.2 پشتیبانی از یک رویداد فراداده تعویض زمینه (context switch) به نام PERF_RECORD_SWITCH را معرفی کرد که به کاربران غیرممتاز امکان می‌دهد ببینند چه زمانی فرایندهایشان از زمان‌بندی خارج یا به آن وارد می‌شوند، اما نه اینکه توسط چه کسی؛ این مورد برای PERF_RECORD_SWITCH_CPU_WIDE باقی مانده که تنها در زمینه کل سیستم (system wide) در دسترس است و به نوبه خود به CAP_PERFMON یا CAP_SYS_ADMIN نیاز دارد.

برای اطلاعات بیشتر، لطفاً کامیت 45ac1403f564 با عنوان ("perf: Add PERF_RECORD_SWITCH to indicate context switches") را که این رویدادهای فراداده را معرفی کرده است مشاهده کنید.

هنگام کار با هسته‌های قبل از نسخه ۴.۲ (kernels < v4.2)، نکات زیر باید مد نظر قرار گیرند، زیرا از نقاط ردگیری sched:sched_switch برای دریافت چنین اطلاعاتی استفاده خواهد شد:

مگر در حالتی که /proc/sys/kernel/perf_event_paranoid بر روی -1 تنظیم شده باشد، کاربران غیرممتاز مجاز به استفاده از نقاط ردگیری نیستند؛ این بدان معناست که اطلاعات جانبی (side-band) کافی برای رمزگشایی Intel PT در حالت به ازای هر پردازنده (per-cpu) و همچنین بالقوه در حالت فقط بار کاری (اگر بار کاری فرایندهای جدیدی بسازد) وجود نخواهد داشت.

همچنین توجه داشته باشید که برای استفاده از نقاط ردگیری، دسترسی خواندن به debugfs الزامی است. بنابراین اگر debugfs سوار نشده باشد یا کاربر دسترسی خواندن نداشته باشد، باز هم رمزگشایی Intel PT در حالت به ازای هر پردازنده امکان‌پذیر نخواهد بود.

نقطه ردگیری sched_switch برای فراهم آوردن داده‌های جانبی جهت رمزگشایی Intel PT در هسته‌هایی به کار می‌رود که رویداد فراداده PERF_RECORD_SWITCH در آنها در دسترس نیست.

رویدادهای sched_switch به‌طور خودکار افزوده می‌شوند؛ به عنوان مثال رویداد دومی که در زیر نشان داده شده است:

$ perf record -vv -e intel_pt//u uname
------------------------------------------------------------
perf_event_attr:
type                             6
size                             112
config                           0x400
{ sample_period, sample_freq }   1
sample_type                      IP|TID|TIME|CPU|IDENTIFIER
read_format                      ID
disabled                         1
inherit                          1
exclude_kernel                   1
exclude_hv                       1
enable_on_exec                   1
sample_id_all                    1
------------------------------------------------------------
sys_perf_event_open: pid 31104  cpu 0  group_fd -1  flags 0x8
sys_perf_event_open: pid 31104  cpu 1  group_fd -1  flags 0x8
sys_perf_event_open: pid 31104  cpu 2  group_fd -1  flags 0x8
sys_perf_event_open: pid 31104  cpu 3  group_fd -1  flags 0x8
------------------------------------------------------------
perf_event_attr:
type                             2
size                             112
config                           0x108
{ sample_period, sample_freq }   1
sample_type                      IP|TID|TIME|CPU|PERIOD|RAW|IDENTIFIER
read_format                      ID
inherit                          1
sample_id_all                    1
exclude_guest                    1
------------------------------------------------------------
sys_perf_event_open: pid -1  cpu 0  group_fd -1  flags 0x8
sys_perf_event_open: pid -1  cpu 1  group_fd -1  flags 0x8
sys_perf_event_open: pid -1  cpu 2  group_fd -1  flags 0x8
sys_perf_event_open: pid -1  cpu 3  group_fd -1  flags 0x8
------------------------------------------------------------
perf_event_attr:
type                             1
size                             112
config                           0x9
{ sample_period, sample_freq }   1
sample_type                      IP|TID|TIME|IDENTIFIER
read_format                      ID
disabled                         1
inherit                          1
exclude_kernel                   1
exclude_hv                       1
mmap                             1
comm                             1
enable_on_exec                   1
task                             1
sample_id_all                    1
mmap2                            1
comm_exec                        1
------------------------------------------------------------
sys_perf_event_open: pid 31104  cpu 0  group_fd -1  flags 0x8
sys_perf_event_open: pid 31104  cpu 1  group_fd -1  flags 0x8
sys_perf_event_open: pid 31104  cpu 2  group_fd -1  flags 0x8
sys_perf_event_open: pid 31104  cpu 3  group_fd -1  flags 0x8
mmap size 528384B
AUX area mmap length 4194304
perf event ring buffer mmapped per cpu
Synthesizing auxtrace information
Linux
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.042 MB perf.data ]

توجه داشته باشید که رویداد sched_switch تنها در صورتی اضافه می‌شود که کاربر مجاز به استفاده از آن باشد و صرفاً در حالت per-cpu افزوده می‌گردد.

همچنین توجه داشته باشید که رویداد sched_switch تنها در صورتی افزوده می‌شود که بسته‌های TSC درخواست شده باشند. دلیل این امر آن است که در صورت نبود اطلاعات زمان‌بندی، رویدادهای sched_switch را نمی‌توان با ردگیری Intel PT مطابقت داد..SH "PERF SCRIPT"

به‌طور پیش‌فرض، perf script داده‌های ردگیری (trace) موجود در فایل perf.data را رمزگشایی خواهد کرد. این مورد را می‌توان با گزینه جدید --itrace بیشتر کنترل کرد.

تعیین نکردن این گزینه معادل با مورد زیر است:

--itrace

که آن هم به نوبه خود همانند مورد زیر است:

--itrace=cepwxy

حروف به شرح زیر هستند:

i       تولید رویدادهای "instructions"
y       تولید رویدادهای "cycles"
b       تولید رویدادهای "branches"
x       تولید رویدادهای "transactions"
w       تولید رویدادهای "ptwrite"
p       تولید رویدادهای "power" (شامل رویدادهای PSB)
c       تولید رویدادهای branches (فقط فراخوانی‌ها یا calls)
r       تولید رویدادهای branches (فقط بازگشت‌ها یا returns)
o       تولید رویدادهای PEBS-via-PT
I       تولید رویدادهای ردگیری رویداد (Event Trace)
e       تولید رویدادهای خطای ردگیری (tracing error)
d       ایجاد یک لاگ اشکال‌زدایی (debug log)
g       تولید زنجیره فراخوانی (call chain) (استفاده همراه با i یا x)
G       تولید زنجیره فراخوانی روی رکوردهای رویداد موجود
l       تولید ورودی‌های آخرین شاخه (last branch entries) (استفاده همراه با i یا x)
L       تولید ورودی‌های آخرین شاخه روی رکوردهای رویداد موجود
s       نادیده گرفتن تعداد مشخصی از رویدادهای اولیه
q       رمزگشایی سریع‌تر (با جزئیات کمتر)
A       محاسبه تقریبی IPC
Z       ترجیح به نادیده گرفتن برچسب‌های زمانی (رمزگشایی اصطلاحاً "timeless")

رویدادهای "Instructions" شبیه رویدادهایی هستند که توسط "perf record -e instructions"; ثبت شده‌اند.

رویدادهای "Cycles" شبیه رویدادهایی هستند که توسط "perf record -e cycles"; (یعنی حالت پیش‌فرض) ثبت شده‌اند. توجه داشته باشید که حتی با فعال بودن بسته‌های CYC و عدم نمونه‌برداری، این رویدادها کاملاً دقیق نیستند؛ چرا که بسته‌های CYC برای تک‌تک دستورالعمل‌ها ارسال نمی‌شوند، بلکه فقط زمانی ارسال می‌شوند که رویداد دیگری (مانند یک شاخه غیرمستقیم، یا یک بسته TNT که نشان‌دهنده چندین انشعاب است) رخ دهد و باعث صدور یک بسته شود. بنابراین، این روش برای انتساب چرخه‌ها به توابع (و احتمالاً بلوک‌های پایه) مؤثرتر از انتساب به دستورالعمل‌های فردی است، هرچند برای توابع نیز بی‌نقص نیست (اگرچه با فعال بودن گزینه noretcomp وضعیت بهتر می‌شود).

رویدادهای "Branches" شبیه مواردی هستند که توسط "perf record -e branches"; ثبت شده‌اند. می‌توان "c" و "r" را با هم ترکیب کرد تا فراخوانی‌ها و بازگشت‌ها به‌دست آیند.

رویدادهای "Transactions" متناظر با شروع یا پایان تراکنش‌ها هستند. از فیلد flags در perf script می‌توان برای تعیین این‌که آیا رویداد مربوط به شروع تراکنش، ثبت (commit) یا لغو (abort) است استفاده کرد.

توجه داشته باشید که رویدادهای "instructions" ،"cycles" ،"branches" و "transactions" به بسته‌های جریان کد (code flow packets) وابسته هستند که می‌توان آن‌ها را با استفاده از عبارت پیکربندی "branch=0" غیرفعال کرد. به بخش عبارت‌های پیکربندی در بالا مراجعه کنید.

رویدادهای "ptwrite" بار داده (payload) دستورالعمل ptwrite و استفاده یا عدم استفاده از "fup_on_ptw" را ثبت می‌کنند. رویدادهای "ptwrite" به بسته‌های PTWRITE وابسته هستند که تنها در صورت استفاده از عبارت پیکربندی "ptw" ثبت می‌شوند. به بخش عبارت‌های پیکربندی در بالا مراجعه کنید. فیلد "synth" در perf script اطلاعات "ptwrite" را به این صورت نمایش می‌دهد: "ip: 0 payload: 0x123456789abcdef0" که در آن اگر از "fup_on_ptw" استفاده شده باشد، مقدار "ip" برابر ۱ است.

رویدادهای "Power" متناظر با بسته‌های رویداد انرژی و بسته‌های CBR (نسبت هسته به گذرگاه یا core-to-bus ratio) هستند. در حالی که بسته‌های CBR در صورت فعال بودن ردگیری همواره ثبت می‌شوند، بسته‌های رویداد انرژی تنها در صورتی ثبت می‌شوند که از عبارت پیکربندی "pwr_evt" استفاده شده باشد. به بخش عبارت‌های پیکربندی در بالا مراجعه کنید. رویدادهای انرژی اطلاعات مربوط به تغییرات C-state را ثبت می‌کنند، در حالی که CBR نشان‌دهنده فرکانس CPU است. فیلدهای "event,synth" در perf script اطلاعات را به این صورت نمایش می‌دهند:

cbr:  cbr: 22 freq: 2189 MHz (200%)
mwait:  hints: 0x60 extensions: 0x1
pwre:  hw: 0 cstate: 2 sub-cstate: 0
exstop:  ip: 1
pwrx:  deepest cstate: 2 last cstate: 2 wake reason: 0x4

که در آن:

"cbr" شامل فرکانس و درصد نسبت به حداکثر مقدار non-turbo است
"mwait" راهنماها (hints) و پسوندهای mwait را نشان می‌دهد
"pwre" گذارهای C-state (به C-state عمیق‌تر از C0) و آغاز شدن
آن توسط سخت‌افزار را نشان می‌دهد
"exstop" توقف اجرا و دقیق بودن IP ثبت‌شده را نشان می‌دهد،
"pwrx" بازگشت به C0 را نشان می‌دهد

برای جزئیات بیشتر به کتاب‌های راهنمای توسعه‌دهنده نرم‌افزار معماری‌های Intel 64 و IA-32 مراجعه کنید.

رویدادهای PSB نشان می‌دهند که یک PSB+ در چه زمانی رخ داده و همچنین آفست بایتی آن در ردگیری چقدر بوده است. انتشار یک PSB+ می‌تواند باعث تأخیر ناچیزی در پردازنده شود. هنگام تحلیل زمان‌بندی کد با Intel PT، دانستن این‌که آیا یک حباب زمانی (timing bubble) ناشی از Intel PT بوده است یا خیر، مفید است.

رویدادهای خطا نشان می‌دهند که رمزگشا در چه نقطه‌ای ردگیری را گم کرده است. رویدادهای خطا بسیار مهم هستند؛ کاربران باید بدانند تصویری که مشاهده می‌کنند کامل است یا خیر. پس از گزینه "e" می‌توان پرچم‌هایی قرار داد که مشخص می‌کنند چه خطاهایی گزارش شوند یا نشوند. قبل از هر پرچم باید + یا - قرار گیرد. پرچم‌های پشتیبانی‌شده توسط Intel PT عبارتند از:

-o      نادیده‌گرفتن خطاهای سرریز (overflow)
-l      نادیده‌گرفتن خطاهای داده‌های ردگیری از دست رفته (data lost)

به عنوان مثال، برای گزارش خطاها به جز خطاهای سرریز یا از دست رفتن داده‌ها:

--itrace=e-o-l

گزینه "d" باعث ایجاد فایلی به نام "intel_pt.log" شامل تمامی بسته‌ها و دستورالعمل‌های رمزگشایی‌شده می‌شود. توجه داشته باشید که این گزینه سرعت رمزگشا را کاهش می‌دهد و فایل حاصل ممکن است بسیار بزرگ باشد. پس از گزینه "d" می‌توان پرچم‌هایی قرار داد که مشخص می‌کنند چه پیام‌های اشکال‌زدایی ثبت شوند یا نشوند. قبل از هر پرچم باید + یا - قرار گیرد. پرچم‌های پشتیبانی‌شده توسط Intel PT عبارتند از:

-a      نادیده‌گرفتن ثبت رویدادهای perf
+a      ثبت تمامی رویدادهای perf
+e      خروجی دادن تنها در صورت بروز خطاهای رمزگشایی (اندازه قابل تنظیم است)
+o      ارسال خروجی به stdout به‌جای "intel_pt.log"

به‌طور پیش‌فرض، رویدادهای ثبت‌شده perf بر اساس محدوده‌های زمانی مشخص‌شده فیلتر می‌شوند، اما پرچم +a این رفتار را لغو می‌کند. پرچم +e می‌تواند برای تحلیل خطاها سودمند باشد. اندازه لاگ در این حالت به‌طور پیش‌فرض ۱۶۳۸۴ بایت است، اما می‌تواند با perf-config(1) تغییر کند، مانند perf config itrace.debug-log-buffer-size=30000

علاوه بر این، دوره تناوب رویداد "instructions" را می‌توان مشخص کرد. برای مثال:

--itrace=i10us

دوره تناوب را روی 10us تنظیم می‌کند؛ یعنی به ازای هر ۱۰ میکروثانیه از ردگیری، یک نمونه دستورالعمل تولید می‌شود. گزینه‌های جایگزین برای "us" عبارتند از "ms" (میلی‌ثانیه)، "ns" (نانوثانیه)، "t" (تیک‌های TSC) یا "i" (دستورالعمل‌ها).

واحدهای "ms" ،"us" و "ns" به تیک‌های TSC تبدیل می‌شوند.

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

برای Intel PT، دوره تناوب پیش‌فرض 100us است.

تنظیم آن بر روی دوره‌ای با مقدار صفر به معنای «تا حد امکان مکرر» است.

در مورد Intel PT، این حالت معادل دوره‌ای برابر با ۱ و با واحد instructions است (یعنی --itrace=i1i).

همچنین اندازه زنجیره فراخوانی (call chain) (پیش‌فرض ۱۶، حداکثر ۱۰۲۴) را می‌توان برای رویدادهای instructions یا transactions مشخص کرد. برای مثال:

--itrace=ig32
--itrace=xg32

همچنین تعداد ورودی‌های آخرین شاخه (پیش‌فرض ۶۴، حداکثر ۱۰۲۴) را می‌توان برای رویدادهای instructions یا transactions مشخص کرد. برای مثال:

--itrace=il10
--itrace=xl10

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

گزینه‌های G و L به‌طور خاص برای حالت نمونه (sample mode) طراحی شده‌اند، و عملکردی بسیار شبیه به g و l دارند اما زنجیره فراخوانی و پشته شاخه (branch stack) را به جای رویدادهای تولیدشده، به سایر رویدادهای انتخاب‌شده اضافه می‌کنند. برای مثال، جهت ثبت رویدادهای branch-misses برای ls و سپس افزودن یک زنجیره فراخوانی مشتق‌شده از ردگیری Intel PT:

perf record --aux-sample -e '{intel_pt//u,branch-misses:u}' -- ls
perf report --itrace=Ge

اگرچه در عمل G یک مقدار پیش‌فرض برای perf report است، بنابراین این دستور معادل مورد زیر خواهد بود:

perf report

یک نکته مهم در مورد گزینه‌های G و L این است که با "Large PEBS" به خوبی کار نمی‌کنند. قابلیت Large PEBS به این معنی است که رکوردهای PEBS توسط سخت‌افزار جمع‌آوری شده و به صورت یکجا در بافر رویداد نوشته می‌شوند. این کار وقفه‌ها را کاهش می‌دهد، اما می‌تواند برچسب‌های زمانی با تاخیر زیادی ایجاد کند. از آنجا که ردگیری Intel PT بر اساس برچسب‌های زمانی همگام‌سازی می‌شود، رویدادهای PEBS با ردگیری مطابقت نخواهند داشت. در حال حاضر، Large PEBS فقط در شرایط خاصی استفاده می‌شود: - سخت‌افزار از آن پشتیبانی کند - PEBS استفاده شود - دوره تناوب رویداد به جای فرکانس مشخص شده باشد - نوع نمونه به پرچم‌های زیر محدود شده باشد: PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_ADDR | PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_TRANSACTION | PERF_SAMPLE_PHYS_ADDR | PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_PERIOD (و گاهی اوقات) | PERF_SAMPLE_TIME. از آنجا که حالت نمونه‌برداری Intel PT از نوع نمونه متفاوتی نسبت به فهرست بالا استفاده می‌کند، Large PEBS با حالت نمونه‌برداری Intel PT استفاده نمی‌شود. برای جلوگیری از Large PEBS در سایر موارد، از تعیین دوره تناوب رویداد خودداری کنید؛ یعنی از گزینه -c در perf record، گزینه --count، یا عبارت پیکربندی period استفاده نکنید.

برای غیرفعال کردن کامل رمزگشایی ردگیری، از گزینه --no-itrace استفاده کنید.

همچنین می‌توان رویدادهای تولیدشده در ابتدا (instructions، branches، transactions) را نادیده گرفت. این ویژگی برای نادیده‌گرفتن کدهای راه‌اندازی اولیه کاربرد دارد.

--itrace=i0nss1000000

یک میلیون دستورالعمل نخست را نادیده می‌گیرد.

گزینه q نحوه رمزگشایی ردگیری را تغییر می‌دهد. در این حالت رمزگشایی بسیار سریع‌تر اما با جزئیات بسیار کمتری انجام می‌شود. به‌طور مشخص، با گزینه q، رمزگشا بسته‌های TNT را رمزگشایی نمی‌کند و در کد شیء (object code) پیمایش انجام نمی‌دهد، بلکه ip را از بسته‌های FUP و TIP دریافت می‌کند. گزینه q می‌تواند با گزینه‌های b و i استفاده شود اما دوره تناوب اعمال نخواهد شد. گزینه q با سرعت بیشتری رمزگشایی می‌کند، اما تنها زمانی مفید است که جریان کنترل مورد نظر توسط بسته‌های FUP، TIP، TIP.PGE، یا TIP.PGD نشان داده یا مشخص شده باشد (به ادامه متن مراجعه کنید). با این حال، می‌توان از گزینه q برای یافتن بازه‌های زمانی استفاده کرد که سپس با استفاده از گزینه --time به‌طور کامل رمزگشایی شوند.

مواردی که با گزینه q (تکی) رمزگشایی نخواهند شد:

•فراخوانی‌ها و jmpهای مستقیم
•انشعاب‌های شرطی
•دستورالعمل‌های غیرانشعابی

آنچه با گزینهٔ (تک) q رمزگشایی خواهد شد:

•انشعاب‌های ناهمگام مانند وقفه‌ها
•انشعاب‌های غیرمستقیم
•آدرس مقصد بازگشت تابع اگر عبارت پیکربندی noretcomp (به بخش عبارات پیکربندی مراجعه کنید) استفاده شده باشد
•شروع ردگیری (جریان کنترل)
•پایان ردگیری (جریان کنترل)، اگر خارج از بافت نباشد
•رویدادهای توان، ptwrite، شروع و لغو تراکنش
•اشاره‌گر دستورالعمل مرتبط با بسته‌های PSB

توجه داشته باشید که گزینهٔ q مشخص نمی‌کند چه رویدادهایی سنتز خواهند شد؛ برای نمونه، برای نمایش رویدادهای توان باید از گزینهٔ p نیز استفاده شود.

تکرار گزینهٔ q (یعنی q دوتایی یا qq) به رمزگشایی حتی سریع‌تر و با جزئیات حتی کمتر منجر می‌شود. رمزگشا تنها بسته‌های PSB گسترش‌یافته (PSB+) را رمزگشایی می‌کند و در صورتی که یک بستهٔ FUP درون PSB+ (یعنی بین PSB و PSBEND) وجود داشته باشد، اشاره‌گر دستورالعمل را دریافت می‌نماید. توجه داشته باشید که بسته‌های PSB بر اساس عبارت پیکربندی psb_period (به بخش عبارات پیکربندی مراجعه کنید) به‌طور منظم در رد رخ می‌دهند. اگر PSB+ در زمان ردگیری جریان کنترل رخ دهد، یک بستهٔ FUP وجود خواهد داشت.

آنچه با گزینهٔ qq رمزگشایی نخواهد شد:

•همه‌چیز به جز اشاره‌گر دستورالعمل مرتبط با بسته‌های PSB

آنچه با گزینهٔ qq رمزگشایی خواهد شد:

•اشاره‌گر دستورالعمل مرتبط با بسته‌های PSB

گزینهٔ Z معادل ضبط یک رد بدون TSC است (یعنی عبارت پیکربندی tsc=0). این گزینه می‌تواند برای جلوگیری از مشکلات برچسب زمانی هنگام رمزگشایی ردِ یک ماشین مجازی مفید باشد..SS "dlfilter-show-cycles.so"

چرخه‌ها را می‌توان با استفاده از dlfilter-show-cycles.so نمایش داد که در این صورت، گزینه itrace A می‌تواند برای ارائه اطلاعات چرخه با تفکیک‌پذیری دقیق‌تر (دانه‌بندی بالاتر) مفید باشد:

perf script --itrace=A --call-trace --dlfilter dlfilter-show-cycles.so

برای مشاهده فهرستی از dlfilterها:

perf script -v --list-dlfilters

همچنین ببینید: perf-dlfilters(1)

دستور perf script گزینه‌ای (-D) برای تخلیه (dump) رویدادها دارد، به این معنی که داده‌های باینری را نمایش می‌دهد.

هنگامی که -D استفاده می‌شود، بسته‌های Intel PT نمایش داده می‌شوند. رمزگشای بسته به بسته‌های PSB توجهی نمی‌کند و صرفاً بایت‌ها را رمزگشایی می‌کند - بنابراین بسته‌های مشاهده‌شده توسط رمزگشای واقعی ممکن است در جاهایی که داده‌ها خراب شده‌اند، یکسان نباشند. یک نمونه از آن زمانی است که وقفه تعویض بافر بسیار کُند عمل کرده و بافر کاملاً پُر شده باشد. در این حالت، ممکن است آخرین بسته در بافر ناقص (truncated) شده و با ادامه ردگیری در بافر بعدی، بلافاصله یک PSB پس از آن قرار گیرد.

برای غیرفعال کردن نمایش بسته‌های Intel PT، گزینه -D را با --no-itrace ترکیب کنید.

به‌طور پیش‌فرض، perf report داده‌های ردگیری یافت‌شده در فایل perf.data را رمزگشایی می‌کند. این رفتار را می‌توان با گزینه جدید --itrace دقیقاً مشابه perf script بیشتر کنترل کرد، با این تفاوت که پیش‌فرض آن --itrace=igxe است.

دستور perf inject نیز گزینه --itrace را می‌پذیرد که در این حالت داده‌های ردگیری حذف شده و با رویدادهای سنتزشده جایگزین می‌شوند؛ به عنوان مثال:

perf inject --itrace -i perf.data -o perf.data.new

در زیر مثالی از به‌کارگیری Intel PT با autofdo آورده شده است. این کار به autofdo (https://github.com/google/autofdo) و gcc نسخه ۵ نیاز دارد. مثال مرتب‌سازی حبابی از آموزش AutoFDO (https://gcc.gnu.org/wiki/AutoFDO/Tutorial) برگرفته شده که برای دریافت تعداد عناصر به عنوان پارامتر اصلاح شده است.

$ gcc-5 -O3 sort.c -o sort_optimized
$ ./sort_optimized 30000
Bubble sorting array of 30000 elements
2254 ms
$ cat ~/.perfconfig
[intel-pt]
        mispred-all = on
$ perf record -e intel_pt//u ./sort 3000
Bubble sorting array of 3000 elements
58 ms
[ perf record: Woken up 2 times to write data ]
[ perf record: Captured and wrote 3.939 MB perf.data ]
$ perf inject -i perf.data -o inj --itrace=i100usle --strip
$ ./create_gcov --binary=./sort --profile=inj --gcov=sort.gcov -gcov_version=1
$ gcc-5 -O3 -fauto-profile=sort.gcov sort.c -o sort_autofdo
$ ./sort_autofdo 30000
Bubble sorting array of 30000 elements
2155 ms

توجه داشته باشید که در حال حاضر استفاده از Intel PT به جای LBR مزیتی ندارد، اما اگر در آینده استفاده بیشتری از این داده‌ها صورت گیرد، ممکن است این موضوع تغییر کند.

برخی سخت‌افزارها این قابلیت را دارند که رکوردهای PEBS را به ردگیری Intel PT تغییر مسیر (redirect) دهند. ضبط داده‌ها با استفاده از عبارت پیکربندی aux-output انتخاب می‌شود؛ به عنوان مثال:

perf record -c 10000 -e '{intel_pt/branch=0/,cycles/aux-output/ppp}' uname

در ابتدا، نرم‌افزار تنها از هدایت حداکثر یک رویداد PEBS پشتیبانی می‌کرد زیرا قادر به تفکیک رویدادها از یکدیگر نبود. برای برطرف کردن این محدودیت، هسته‌ها و ابزارهای perf جدیدتر پشتیبانی از رویداد جانبی PERF_RECORD_AUX_OUTPUT_HW_ID را اضافه کرده‌اند. برای بررسی وجود این رویداد در یک ردگیری PEBS-via-PT:

perf script -D --no-itrace | grep PERF_RECORD_AUX_OUTPUT_HW_ID

برای نمایش رویدادهای PEBS از ردگیری Intel PT، از گزینه itrace o استفاده کنید؛ مانند:

perf script --itrace=oe

برای --xed به ابزار xed نیاز است. نحوه نصب آن به شرح زیر است:

$ git clone https://github.com/intelxed/mbuild.git mbuild
$ git clone https://github.com/intelxed/xed
$ cd xed
$ ./mfile.py --share
$ ./mfile.py examples
$ sudo ./mfile.py --prefix=/usr/local install
$ sudo ldconfig
$ sudo cp obj/examples/xed /usr/local/bin

آزمایش اولیه xed:

$ xed | head -3
ERROR: required argument(s) were missing
Copyright (C) 2017, Intel Corporation. All rights reserved.
XED version: [v10.0-328-g7d62c8c49b7b]
$

در حال حاضر، ردیابی هسته یا با رمزگشایی «بدون زمان» (timeless) (یعنی بدون برچسب‌های زمانی TSC) یا با «همبستگی زمانی ماشین مجازی» (VM Time Correlation) پشتیبانی می‌شود. همبستگی زمانی ماشین مجازی یک مرحله اضافی با استفاده از perf inject است و به VMX TSC Offset تغییرناپذیر و عدم وجود VMX TSC Scaling نیاز دارد.

سایر محدودیت‌ها و نکات قابل‌توجه

کنترل‌های VMX ممکن است بسته‌های مورد نیاز برای رمزگشایی را سرکوب کنند که به بروز خطاهای رمزگشایی می‌انجامد
کنترل‌های VMX ممکن است ارسال perf NMI به میزبان را مسدود کنند که بالقوه منجر به از دست رفتن داده‌های ردیابی می‌شود
کد خود-اصلاح‌گر هسته مهمان (مانند jump labels یا eBPF کامپایل‌شده با JIT) منجر به بروز خطاهای رمزگشایی خواهد شد
اطلاعات ریسه مهمان نامشخص است
VCPU مهمان نامشخص است اما ممکن است بتوان آن را از روی ریسه میزبان استنباط کرد
زنجیره‌های فراخوانی (Callchains) پشتیبانی نمی‌شوند

مثال با استفاده از رمزگشایی «بدون زمان» (timeless)

راه‌اندازی ماشین مجازی

$ sudo virsh start kubuntu20.04
Domain kubuntu20.04 started

سوار کردن سیستم‌فایل مهمان. توجه داشته باشید که sshfs به -o direct_io نیاز دارد تا خواندن فایل‌های proc فعال شود. برای خواندن /proc/kcore به دسترسی ریشه (root) نیاز است.

$ mkdir vm0
$ sshfs -o direct_io root@vm0:/ vm0

رونوشت از /proc/kallsyms، /proc/modules و /proc/kcore مهمان

$ perf buildid-cache -v --kcore vm0/proc/kcore
kcore added to build-id cache directory /home/user/.debug/[kernel.kcore]/9600f316a53a0f54278885e8d9710538ec5f6a08/2021021807494306
$ KALLSYMS=/home/user/.debug/[kernel.kcore]/9600f316a53a0f54278885e8d9710538ec5f6a08/2021021807494306/kallsyms

یافتن فرایند ماشین مجازی

$ ps -eLl | grep 'KVM\|PID'
F S   UID     PID    PPID     LWP  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
3 S 64055    1430       1    1440  1  80   0 - 1921718 -    ?        00:02:47 CPU 0/KVM
3 S 64055    1430       1    1441  1  80   0 - 1921718 -    ?        00:02:41 CPU 1/KVM
3 S 64055    1430       1    1442  1  80   0 - 1921718 -    ?        00:02:38 CPU 2/KVM
3 S 64055    1430       1    1443  2  80   0 - 1921718 -    ?        00:03:18 CPU 3/KVM

یک ضبط بدون پایان مشخص با perf record را برای ردیابی فرایند ماشین مجازی آغاز کنید، کاری را در ماشین مجازی انجام دهید و سپس ctrl-C را برای توقف فشار دهید. از TSC پشتیبانی نمی‌شود و tsc=0 باید مشخص گردد. این بدان معناست که mtc بی‌استفاده است، بنابراین mtc=0 را اضافه کنید. با این حال، IPC همچنان قابل محاسبه است، بنابراین می‌توان cyc=1 را اضافه کرد. تنها رمزگشایی هسته پشتیبانی می‌شود، بنابراین باید k مشخص شود. از آنجا که Intel PT هم میزبان و هم مهمان را ردیابی می‌کند، باید --guest و --host مشخص شوند. بدون برچسب‌های زمانی، برای تمایز میان ریسه‌ها باید --per-thread مشخص گردد.

$ sudo perf kvm --guest --host --guestkallsyms $KALLSYMS record --kcore -e intel_pt/tsc=0,mtc=0,cyc=1/k -p 1430 --per-thread
^C
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 5.829 MB ]

برای ارائه یک ردیابی دستورالعمل (instruction trace) می‌توان از perf script استفاده کرد

$ perf script --guestkallsyms $KALLSYMS --insn-trace=disasm -F+ipc | grep -C10 vmresume | head -21
      CPU 0/KVM  1440  ffffffff82133cdd __vmx_vcpu_run+0x3d ([kernel.kallsyms])                movq  0x48(%rax), %r9
      CPU 0/KVM  1440  ffffffff82133ce1 __vmx_vcpu_run+0x41 ([kernel.kallsyms])                movq  0x50(%rax), %r10
      CPU 0/KVM  1440  ffffffff82133ce5 __vmx_vcpu_run+0x45 ([kernel.kallsyms])                movq  0x58(%rax), %r11
      CPU 0/KVM  1440  ffffffff82133ce9 __vmx_vcpu_run+0x49 ([kernel.kallsyms])                movq  0x60(%rax), %r12
      CPU 0/KVM  1440  ffffffff82133ced __vmx_vcpu_run+0x4d ([kernel.kallsyms])                movq  0x68(%rax), %r13
      CPU 0/KVM  1440  ffffffff82133cf1 __vmx_vcpu_run+0x51 ([kernel.kallsyms])                movq  0x70(%rax), %r14
      CPU 0/KVM  1440  ffffffff82133cf5 __vmx_vcpu_run+0x55 ([kernel.kallsyms])                movq  0x78(%rax), %r15
      CPU 0/KVM  1440  ffffffff82133cf9 __vmx_vcpu_run+0x59 ([kernel.kallsyms])                movq  (%rax), %rax
      CPU 0/KVM  1440  ffffffff82133cfc __vmx_vcpu_run+0x5c ([kernel.kallsyms])                callq  0xffffffff82133c40
      CPU 0/KVM  1440  ffffffff82133c40 vmx_vmenter+0x0 ([kernel.kallsyms])            jz 0xffffffff82133c46
      CPU 0/KVM  1440  ffffffff82133c42 vmx_vmenter+0x2 ([kernel.kallsyms])            vmresume         IPC: 0.11 (50/445)
          :1440  1440  ffffffffbb678b06 native_write_msr+0x6 ([guest.kernel.kallsyms])                 nopl  %eax, (%rax,%rax,1)
          :1440  1440  ffffffffbb678b0b native_write_msr+0xb ([guest.kernel.kallsyms])                 retq     IPC: 0.04 (2/41)
          :1440  1440  ffffffffbb666646 lapic_next_deadline+0x26 ([guest.kernel.kallsyms])             data16 nop
          :1440  1440  ffffffffbb666648 lapic_next_deadline+0x28 ([guest.kernel.kallsyms])             xor %eax, %eax
          :1440  1440  ffffffffbb66664a lapic_next_deadline+0x2a ([guest.kernel.kallsyms])             popq  %rbp
          :1440  1440  ffffffffbb66664b lapic_next_deadline+0x2b ([guest.kernel.kallsyms])             retq     IPC: 0.16 (4/25)
          :1440  1440  ffffffffbb74607f clockevents_program_event+0x8f ([guest.kernel.kallsyms])               test %eax, %eax
          :1440  1440  ffffffffbb746081 clockevents_program_event+0x91 ([guest.kernel.kallsyms])               jz 0xffffffffbb74603c    IPC: 0.06 (2/30)
          :1440  1440  ffffffffbb74603c clockevents_program_event+0x4c ([guest.kernel.kallsyms])               popq  %rbx
          :1440  1440  ffffffffbb74603d clockevents_program_event+0x4d ([guest.kernel.kallsyms])               popq  %r12

مثال با استفاده از همبستگی زمانی ماشین مجازی (VM Time Correlation)

راه‌اندازی ماشین مجازی

$ sudo virsh start kubuntu20.04
Domain kubuntu20.04 started

سوار کردن سیستم‌فایل مهمان. توجه داشته باشید که sshfs به -o direct_io نیاز دارد تا خواندن فایل‌های proc فعال شود. برای خواندن /proc/kcore دسترسی ریشه (root) لازم است.

$ mkdir -p vm0
$ sshfs -o direct_io root@vm0:/ vm0

رونوشت از /proc/kallsyms، /proc/modules و /proc/kcore مهمان

$ perf buildid-cache -v --kcore vm0/proc/kcore
same kcore found in /home/user/.debug/[kernel.kcore]/cc9c55a98c5e4ec0aeda69302554aabed5cd6491/2021021312450777
$ KALLSYMS=/home/user/.debug/\[kernel.kcore\]/cc9c55a98c5e4ec0aeda69302554aabed5cd6491/2021021312450777/kallsyms

یافتن فرایند ماشین مجازی

$ ps -eLl | grep 'KVM\|PID'
F S   UID     PID    PPID     LWP  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
3 S 64055   16998       1   17005 13  80   0 - 1818189 -    ?        00:00:16 CPU 0/KVM
3 S 64055   16998       1   17006  4  80   0 - 1818189 -    ?        00:00:05 CPU 1/KVM
3 S 64055   16998       1   17007  3  80   0 - 1818189 -    ?        00:00:04 CPU 2/KVM
3 S 64055   16998       1   17008  4  80   0 - 1818189 -    ?        00:00:05 CPU 3/KVM

یک ضبط بدون پایان مشخص با perf record را برای ردیابی فرایند ماشین مجازی آغاز کنید، کاری را در ماشین مجازی انجام دهید و سپس برای توقف ctrl-C را بزنید. مقدار IPC قابل محاسبه است، بنابراین می‌توان cyc=1 را اضافه کرد. تنها رمزگشایی هسته پشتیبانی می‌شود، بنابراین k باید مشخص گردد. از آنجا که Intel PT هم میزبان و هم مهمان را ردیابی می‌کند، گزینه‌های --guest و --host باید تعیین شوند.

$ sudo perf kvm --guest --host --guestkallsyms $KALLSYMS record --kcore -e intel_pt/cyc=1/k -p 16998
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 9.041 MB perf.data.kvm ]

اکنون می‌توان از perf inject برای تعیین VMX TCS Offset استفاده کرد. توجه داشته باشید که بسته‌های TSC در Intel PT تنها ۷ بایتی هستند، بنابراین مقدار TSC Offset ممکن است در بایت هشتم با مقدار واقعی تفاوت داشته باشد. این موضوع هیچ تأثیری نخواهد داشت، یعنی برچسب‌های زمانی حاصل در هر صورت صحیح خواهند بود.

$ perf inject -i perf.data.kvm --vm-time-correlation=dry-run
ERROR: Unknown TSC Offset for VMCS 0x1bff6a
VMCS: 0x1bff6a  TSC Offset 0xffffe42722c64c41
ERROR: Unknown TSC Offset for VMCS 0x1cbc08
VMCS: 0x1cbc08  TSC Offset 0xffffe42722c64c41
ERROR: Unknown TSC Offset for VMCS 0x1c3ce8
VMCS: 0x1c3ce8  TSC Offset 0xffffe42722c64c41
ERROR: Unknown TSC Offset for VMCS 0x1cbce9
VMCS: 0x1cbce9  TSC Offset 0xffffe42722c64c41

هر پردازنده مجازی دارای ساختار کنترل ماشین مجازی (VMCS) متفاوتی است که در بالا همراه با TSC Offset محاسبه‌شده نشان داده شده است. برای یک TSC Offset تغییرناپذیر، همه آن‌ها برای یک ماشین مجازی یکسان باید برابر باشند.

اکنون که TSC Offset مشخص شده است، می‌توان آن را به perf inject ارائه داد

$ perf inject -i perf.data.kvm --vm-time-correlation="dry-run 0xffffe42722c64c41"

توجه داشته باشید که گزینه‌های --vm-time-correlation در perf inject عبارتند از:

[ dry-run ] [ <TSC Offset> [ : <VMCS> [ , <VMCS> ]... ]  ]...

بنابراین می‌توان مقادیر متفاوتی از TSC Offset را برای VMCSهای گوناگون مشخص کرد. گزینه «dry-run» باعث می‌شود که فایل بدون به‌روزرسانی شدن پردازش شود. توجه داشته باشید که دریافت یک فایل intel_pt.log نیز با افزودن گزینه --itrace=d امکان‌پذیر است.

هیچ خطایی رخ نداد، بنابراین آن را به صورت واقعی اجرا کنید

$ perf inject -i perf.data.kvm --vm-time-correlation=0xffffe42722c64c41 --force

می‌توان از perf script برای بررسی وجود هرگونه خطای رمزگشا استفاده کرد

$ perf script -i perf.data.kvm --guestkallsyms $KALLSYMS --itrace=e-o

هیچ خطایی وجود نداشت.

می‌توان از perf script برای ارائه ردیابی دستورالعمل‌ها به همراه برچسب‌های زمانی استفاده کرد

$ perf script -i perf.data.kvm --guestkallsyms $KALLSYMS --insn-trace=disasm -F+ipc | grep -C10 vmresume | head -21
      CPU 1/KVM 17006 [001] 11500.262865593:  ffffffff82133cdd __vmx_vcpu_run+0x3d ([kernel.kallsyms])                 movq  0x48(%rax), %r9
      CPU 1/KVM 17006 [001] 11500.262865593:  ffffffff82133ce1 __vmx_vcpu_run+0x41 ([kernel.kallsyms])                 movq  0x50(%rax), %r10
      CPU 1/KVM 17006 [001] 11500.262865593:  ffffffff82133ce5 __vmx_vcpu_run+0x45 ([kernel.kallsyms])                 movq  0x58(%rax), %r11
      CPU 1/KVM 17006 [001] 11500.262865593:  ffffffff82133ce9 __vmx_vcpu_run+0x49 ([kernel.kallsyms])                 movq  0x60(%rax), %r12
      CPU 1/KVM 17006 [001] 11500.262865593:  ffffffff82133ced __vmx_vcpu_run+0x4d ([kernel.kallsyms])                 movq  0x68(%rax), %r13
      CPU 1/KVM 17006 [001] 11500.262865593:  ffffffff82133cf1 __vmx_vcpu_run+0x51 ([kernel.kallsyms])                 movq  0x70(%rax), %r14
      CPU 1/KVM 17006 [001] 11500.262865593:  ffffffff82133cf5 __vmx_vcpu_run+0x55 ([kernel.kallsyms])                 movq  0x78(%rax), %r15
      CPU 1/KVM 17006 [001] 11500.262865593:  ffffffff82133cf9 __vmx_vcpu_run+0x59 ([kernel.kallsyms])                 movq  (%rax), %rax
      CPU 1/KVM 17006 [001] 11500.262865593:  ffffffff82133cfc __vmx_vcpu_run+0x5c ([kernel.kallsyms])                 callq  0xffffffff82133c40
      CPU 1/KVM 17006 [001] 11500.262865593:  ffffffff82133c40 vmx_vmenter+0x0 ([kernel.kallsyms])             jz 0xffffffff82133c46
      CPU 1/KVM 17006 [001] 11500.262866075:  ffffffff82133c42 vmx_vmenter+0x2 ([kernel.kallsyms])             vmresume         IPC: 0.05 (40/769)
         :17006 17006 [001] 11500.262869216:  ffffffff82200cb0 asm_sysvec_apic_timer_interrupt+0x0 ([guest.kernel.kallsyms])           clac
         :17006 17006 [001] 11500.262869216:  ffffffff82200cb3 asm_sysvec_apic_timer_interrupt+0x3 ([guest.kernel.kallsyms])           pushq  $0xffffffffffffffff
         :17006 17006 [001] 11500.262869216:  ffffffff82200cb5 asm_sysvec_apic_timer_interrupt+0x5 ([guest.kernel.kallsyms])           callq  0xffffffff82201160
         :17006 17006 [001] 11500.262869216:  ffffffff82201160 error_entry+0x0 ([guest.kernel.kallsyms])               cld
         :17006 17006 [001] 11500.262869216:  ffffffff82201161 error_entry+0x1 ([guest.kernel.kallsyms])               pushq  %rsi
         :17006 17006 [001] 11500.262869216:  ffffffff82201162 error_entry+0x2 ([guest.kernel.kallsyms])               movq  0x8(%rsp), %rsi
         :17006 17006 [001] 11500.262869216:  ffffffff82201167 error_entry+0x7 ([guest.kernel.kallsyms])               movq  %rdi, 0x8(%rsp)
         :17006 17006 [001] 11500.262869216:  ffffffff8220116c error_entry+0xc ([guest.kernel.kallsyms])               pushq  %rdx
         :17006 17006 [001] 11500.262869216:  ffffffff8220116d error_entry+0xd ([guest.kernel.kallsyms])               pushq  %rcx
         :17006 17006 [001] 11500.262869216:  ffffffff8220116e error_entry+0xe ([guest.kernel.kallsyms])               pushq  %rax

امکان استفاده از perf record برای ثبت رویدادهای باند جانبی (sideband events) در یک ماشین مجازی وجود دارد، به طوری که ردگیری Intel PT روی میزبان قابل رمزگشایی باشد. رویدادهای باند جانبی از فایل perf.data ماشین مهمان را می‌توان با استفاده از perf inject به درون فایل perf.data ماشین میزبان تزریق کرد.

در اینجا نمونه‌ای از مراحل مورد نیاز آورده شده است:

در ماشین مهمان:

بررسی کنید که گزینهٔ خط فرمان هسته no-kvmclock برای بوت استفاده شده باشد:

توجه داشته باشید، این مورد برای فعال‌سازی همبستگی زمانی بین ماشین‌های میزبان و مهمان ضروری است.

$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-5.10.0-16-amd64 root=UUID=cb49c910-e573-47e0-bce7-79e293df8e1d ro no-kvmclock

در حال حاضر پشتیبانی از BPF وجود ندارد، بنابراین در صورت امکان کامپایل JIT را غیرفعال کنید:

$ echo 0 | sudo tee /proc/sys/net/core/bpf_jit_enable
0

دستور perf record را برای جمع‌آوری رویدادهای باند جانبی آغاز کنید:

$ sudo perf record -o guest-sideband-testing-guest-perf.data --sample-identifier --buildid-all --switch-events --kcore -a -e dummy

در ماشین میزبان:

دستور perf record را برای جمع‌آوری ردگیری Intel PT آغاز کنید:

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

$ sudo perf record -o guest-sideband-testing-host-perf.data -m,64M --kcore -a -e intel_pt/cyc/

در ماشین مهمان:

یک مورد آزمایشی کوچک اجرا کنید، در این مثال فقط uname:

$ uname
Linux

در ماشین میزبان:

ردگیری Intel PT را متوقف کنید:

^C
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 76.122 MB guest-sideband-testing-host-perf.data ]

در ماشین مهمان:

ردگیری Intel PT را متوقف کنید:

^C
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.247 MB guest-sideband-testing-guest-perf.data ]

و سپس guest-sideband-testing-guest-perf.data را به میزبان کپی کنید (در اینجا نشان داده نشده است).

در ماشین میزبان:

با وجود این ۲ فایل ضبط‌شدهٔ perf.data، و پس از تغییر مالکیت آن‌ها به کاربر.

مقدار TSC Offset را شناسایی کنید:

$ perf inject -i guest-sideband-testing-host-perf.data --vm-time-correlation=dry-run
VMCS: 0x103fc6  TSC Offset 0xfffffa6ae070cb20
VMCS: 0x103ff2  TSC Offset 0xfffffa6ae070cb20
VMCS: 0x10fdaa  TSC Offset 0xfffffa6ae070cb20
VMCS: 0x24d57c  TSC Offset 0xfffffa6ae070cb20

برچسب‌های زمانی TSC مربوط به Intel PT را برای ماشین مهمان اصلاح کنید:

$ perf inject -i guest-sideband-testing-host-perf.data --vm-time-correlation=0xfffffa6ae070cb20 --force

شناسهٔ فرایند (PID) ماشین مهمان را شناسایی کنید:

$ perf script -i guest-sideband-testing-host-perf.data --no-itrace --show-task-events | grep KVM
      CPU 0/KVM     0 [000]     0.000000: PERF_RECORD_COMM: CPU 0/KVM:13376/13381
      CPU 1/KVM     0 [000]     0.000000: PERF_RECORD_COMM: CPU 1/KVM:13376/13382
      CPU 2/KVM     0 [000]     0.000000: PERF_RECORD_COMM: CPU 2/KVM:13376/13383
      CPU 3/KVM     0 [000]     0.000000: PERF_RECORD_COMM: CPU 3/KVM:13376/13384

توجه داشته باشید که گزینهٔ QEMU با عنوان -name debug-threads=on لازم است تا بتوان از نام نخ‌ها برای تعیین این‌که کدام نخ در حال اجرای کدام VCPU است (مانند بالا) استفاده کرد. به نظر می‌رسد libvirt به‌طور پیش‌فرض از این گزینه استفاده می‌کند.

یک guestmount ایجاد کنید، با فرض اینکه ماشین مهمان vm_to_test است:

$ mkdir -p ~/guestmount/13376
$ sshfs -o direct_io vm_to_test:/ ~/guestmount/13376

فایل perf.data مهمان را به فایل perf.data میزبان تزریق کنید:

توجه داشته باشید، به دلیل گزینهٔ guestmount، فایل‌های شیء و فایل‌های اشکال‌زدایی مهمان از ماشین مهمان در حافظهٔ نهان build ID کپی می‌شوند، به استثنای قابل توجه VDSO. در صورت نیاز، VDSO را می‌توان به صورت دستی و مشابه روش استفاده‌شده توسط اسکریپت perf-archive کپی کرد.

$ perf inject -i guest-sideband-testing-host-perf.data -o inj --guestmount ~/guestmount --guest-data=guest-sideband-testing-guest-perf.data,13376,0xfffffa6ae070cb20

گزیده‌ای از نتیجه را نشان دهید. در این مورد CPU و محدودهٔ زمانی طوری انتخاب شده‌اند تا برهم‌کنش میان مهمان و میزبان را هنگامی که uname شروع به اجرا روی ماشین مهمان می‌کند، نمایش دهند:

نکات:

•پردازنده نمایش‌داده‌شده، در این مورد [002]، همواره پردازنده میزبان است
•رویدادهایی که در ماشین مجازی رخ می‌دهند با VM:13376 VCPU:003 آغاز می‌شوند که شناسه فرایند (PID) ناظر 13376 و شماره VCPU را نمایش می‌دهد
•تنها فراخوانی‌ها و خطاها نمایش داده می‌شوند؛ یعنی --itrace=ce
•شاخه‌های ورودی و خروجی ماشین مجازی تفکیک شده‌اند و به صورت ۲ شاخه به/از "0 [unknown] ([unknown])" نمایش داده می‌شوند
$ perf script -i inj --itrace=ce -F+machine_pid,+vcpu,+addr,+pid,+tid,-period --ns --time 7919.408803365,7919.408804631 -C 2
      CPU 3/KVM 13376/13384 [002]  7919.408803365:      branches:  ffffffffc0f8ebe0 vmx_vcpu_enter_exit+0xc0 ([kernel.kallsyms]) => ffffffffc0f8edc0 __vmx_vcpu_run+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803365:      branches:  ffffffffc0f8edd5 __vmx_vcpu_run+0x15 ([kernel.kallsyms]) => ffffffffc0f8eca0 vmx_update_host_rsp+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803365:      branches:  ffffffffc0f8ee1b __vmx_vcpu_run+0x5b ([kernel.kallsyms]) => ffffffffc0f8ed60 vmx_vmenter+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803461:      branches:  ffffffffc0f8ed62 vmx_vmenter+0x2 ([kernel.kallsyms]) =>                0 [unknown] ([unknown])
VM:13376 VCPU:003            uname  3404/3404  [002]  7919.408803461:      branches:                 0 [unknown] ([unknown]) =>     7f851c9b5a5c init_cacheinfo+0x3ac (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
VM:13376 VCPU:003            uname  3404/3404  [002]  7919.408803567:      branches:      7f851c9b5a5a init_cacheinfo+0x3aa (/usr/lib/x86_64-linux-gnu/libc-2.31.so) =>                0 [unknown] ([unknown])
      CPU 3/KVM 13376/13384 [002]  7919.408803567:      branches:                 0 [unknown] ([unknown]) => ffffffffc0f8ed80 vmx_vmexit+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803596:      branches:  ffffffffc0f6619a vmx_vcpu_run+0x26a ([kernel.kallsyms]) => ffffffffb2255c60 x86_virt_spec_ctrl+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803801:      branches:  ffffffffc0f66445 vmx_vcpu_run+0x515 ([kernel.kallsyms]) => ffffffffb2290b30 native_write_msr+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803850:      branches:  ffffffffc0f661f8 vmx_vcpu_run+0x2c8 ([kernel.kallsyms]) => ffffffffc1092300 kvm_load_host_xsave_state+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803850:      branches:  ffffffffc1092327 kvm_load_host_xsave_state+0x27 ([kernel.kallsyms]) => ffffffffc1092220 kvm_load_host_xsave_state.part.0+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803862:      branches:  ffffffffc0f662cf vmx_vcpu_run+0x39f ([kernel.kallsyms]) => ffffffffc0f63f90 vmx_recover_nmi_blocking+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803862:      branches:  ffffffffc0f662e9 vmx_vcpu_run+0x3b9 ([kernel.kallsyms]) => ffffffffc0f619a0 __vmx_complete_interrupts+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803872:      branches:  ffffffffc109cfb2 vcpu_enter_guest+0x752 ([kernel.kallsyms]) => ffffffffc0f5f570 vmx_handle_exit_irqoff+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803881:      branches:  ffffffffc109d028 vcpu_enter_guest+0x7c8 ([kernel.kallsyms]) => ffffffffb234f900 __srcu_read_lock+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803897:      branches:  ffffffffc109d06f vcpu_enter_guest+0x80f ([kernel.kallsyms]) => ffffffffc0f72e30 vmx_handle_exit+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803897:      branches:  ffffffffc0f72e3d vmx_handle_exit+0xd ([kernel.kallsyms]) => ffffffffc0f727c0 __vmx_handle_exit+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803897:      branches:  ffffffffc0f72b15 __vmx_handle_exit+0x355 ([kernel.kallsyms]) => ffffffffc0f60ae0 vmx_flush_pml_buffer+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803903:      branches:  ffffffffc0f72994 __vmx_handle_exit+0x1d4 ([kernel.kallsyms]) => ffffffffc10b7090 kvm_emulate_cpuid+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803903:      branches:  ffffffffc10b70f1 kvm_emulate_cpuid+0x61 ([kernel.kallsyms]) => ffffffffc10b6e10 kvm_cpuid+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803941:      branches:  ffffffffc10b7125 kvm_emulate_cpuid+0x95 ([kernel.kallsyms]) => ffffffffc1093110 kvm_skip_emulated_instruction+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803941:      branches:  ffffffffc109311f kvm_skip_emulated_instruction+0xf ([kernel.kallsyms]) => ffffffffc0f5e180 vmx_get_rflags+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803951:      branches:  ffffffffc109312a kvm_skip_emulated_instruction+0x1a ([kernel.kallsyms]) => ffffffffc0f5fd30 vmx_skip_emulated_instruction+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803951:      branches:  ffffffffc0f5fd79 vmx_skip_emulated_instruction+0x49 ([kernel.kallsyms]) => ffffffffc0f5fb50 skip_emulated_instruction+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803956:      branches:  ffffffffc0f5fc68 skip_emulated_instruction+0x118 ([kernel.kallsyms]) => ffffffffc0f6a940 vmx_cache_reg+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803964:      branches:  ffffffffc0f5fc11 skip_emulated_instruction+0xc1 ([kernel.kallsyms]) => ffffffffc0f5f9e0 vmx_set_interrupt_shadow+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803980:      branches:  ffffffffc109f8b1 vcpu_run+0x71 ([kernel.kallsyms]) => ffffffffc10ad2f0 kvm_cpu_has_pending_timer+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803980:      branches:  ffffffffc10ad2fb kvm_cpu_has_pending_timer+0xb ([kernel.kallsyms]) => ffffffffc10b0490 apic_has_pending_timer+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803991:      branches:  ffffffffc109f899 vcpu_run+0x59 ([kernel.kallsyms]) => ffffffffc109c860 vcpu_enter_guest+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803993:      branches:  ffffffffc109cd4c vcpu_enter_guest+0x4ec ([kernel.kallsyms]) => ffffffffc0f69140 vmx_prepare_switch_to_guest+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803996:      branches:  ffffffffc109cd7d vcpu_enter_guest+0x51d ([kernel.kallsyms]) => ffffffffb234f930 __srcu_read_unlock+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803996:      branches:  ffffffffc109cd9c vcpu_enter_guest+0x53c ([kernel.kallsyms]) => ffffffffc0f609b0 vmx_sync_pir_to_irr+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408803996:      branches:  ffffffffc0f60a6d vmx_sync_pir_to_irr+0xbd ([kernel.kallsyms]) => ffffffffc10adc20 kvm_lapic_find_highest_irr+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804010:      branches:  ffffffffc0f60abd vmx_sync_pir_to_irr+0x10d ([kernel.kallsyms]) => ffffffffc0f60820 vmx_set_rvi+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804019:      branches:  ffffffffc109ceca vcpu_enter_guest+0x66a ([kernel.kallsyms]) => ffffffffb2249840 fpregs_assert_state_consistent+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804021:      branches:  ffffffffc109cf10 vcpu_enter_guest+0x6b0 ([kernel.kallsyms]) => ffffffffc0f65f30 vmx_vcpu_run+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804024:      branches:  ffffffffc0f6603b vmx_vcpu_run+0x10b ([kernel.kallsyms]) => ffffffffb229bed0 __get_current_cr3_fast+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804024:      branches:  ffffffffc0f66055 vmx_vcpu_run+0x125 ([kernel.kallsyms]) => ffffffffb2253050 cr4_read_shadow+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804030:      branches:  ffffffffc0f6608d vmx_vcpu_run+0x15d ([kernel.kallsyms]) => ffffffffc10921e0 kvm_load_guest_xsave_state+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804030:      branches:  ffffffffc1092207 kvm_load_guest_xsave_state+0x27 ([kernel.kallsyms]) => ffffffffc1092110 kvm_load_guest_xsave_state.part.0+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804032:      branches:  ffffffffc0f660c6 vmx_vcpu_run+0x196 ([kernel.kallsyms]) => ffffffffb22061a0 perf_guest_get_msrs+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804032:      branches:  ffffffffb22061a9 perf_guest_get_msrs+0x9 ([kernel.kallsyms]) => ffffffffb220cda0 intel_guest_get_msrs+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804039:      branches:  ffffffffc0f66109 vmx_vcpu_run+0x1d9 ([kernel.kallsyms]) => ffffffffc0f652c0 clear_atomic_switch_msr+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804040:      branches:  ffffffffc0f66119 vmx_vcpu_run+0x1e9 ([kernel.kallsyms]) => ffffffffc0f73f60 intel_pmu_lbr_is_enabled+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804042:      branches:  ffffffffc0f73f81 intel_pmu_lbr_is_enabled+0x21 ([kernel.kallsyms]) => ffffffffc10b68e0 kvm_find_cpuid_entry+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804045:      branches:  ffffffffc0f66454 vmx_vcpu_run+0x524 ([kernel.kallsyms]) => ffffffffc0f61ff0 vmx_update_hv_timer+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804057:      branches:  ffffffffc0f66142 vmx_vcpu_run+0x212 ([kernel.kallsyms]) => ffffffffc10af100 kvm_wait_lapic_expire+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804057:      branches:  ffffffffc0f66156 vmx_vcpu_run+0x226 ([kernel.kallsyms]) => ffffffffb2255c60 x86_virt_spec_ctrl+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804057:      branches:  ffffffffc0f66161 vmx_vcpu_run+0x231 ([kernel.kallsyms]) => ffffffffc0f8eb20 vmx_vcpu_enter_exit+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804057:      branches:  ffffffffc0f8eb44 vmx_vcpu_enter_exit+0x24 ([kernel.kallsyms]) => ffffffffb2353e10 rcu_note_context_switch+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804057:      branches:  ffffffffb2353e1c rcu_note_context_switch+0xc ([kernel.kallsyms]) => ffffffffb2353db0 rcu_qs+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804066:      branches:  ffffffffc0f8ebe0 vmx_vcpu_enter_exit+0xc0 ([kernel.kallsyms]) => ffffffffc0f8edc0 __vmx_vcpu_run+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804066:      branches:  ffffffffc0f8edd5 __vmx_vcpu_run+0x15 ([kernel.kallsyms]) => ffffffffc0f8eca0 vmx_update_host_rsp+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804066:      branches:  ffffffffc0f8ee1b __vmx_vcpu_run+0x5b ([kernel.kallsyms]) => ffffffffc0f8ed60 vmx_vmenter+0x0 ([kernel.kallsyms])
      CPU 3/KVM 13376/13384 [002]  7919.408804162:      branches:  ffffffffc0f8ed62 vmx_vmenter+0x2 ([kernel.kallsyms]) =>                0 [unknown] ([unknown])
VM:13376 VCPU:003            uname  3404/3404  [002]  7919.408804162:      branches:                 0 [unknown] ([unknown]) =>     7f851c9b5a5c init_cacheinfo+0x3ac (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
VM:13376 VCPU:003            uname  3404/3404  [002]  7919.408804273:      branches:      7f851cb7c0e4 _dl_init+0x74 (/usr/lib/x86_64-linux-gnu/ld-2.31.so) =>     7f851cb7bf50 call_init.part.0+0x0 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
VM:13376 VCPU:003            uname  3404/3404  [002]  7919.408804526:      branches:      55e0c00136f0 _start+0x0 (/usr/bin/uname) => ffffffff83200ac0 asm_exc_page_fault+0x0 ([kernel.kallsyms])
VM:13376 VCPU:003            uname  3404/3404  [002]  7919.408804526:      branches:  ffffffff83200ac3 asm_exc_page_fault+0x3 ([kernel.kallsyms]) => ffffffff83201290 error_entry+0x0 ([kernel.kallsyms])
VM:13376 VCPU:003            uname  3404/3404  [002]  7919.408804534:      branches:  ffffffff832012fa error_entry+0x6a ([kernel.kallsyms]) => ffffffff830b59a0 sync_regs+0x0 ([kernel.kallsyms])
VM:13376 VCPU:003            uname  3404/3404  [002]  7919.408804631:      branches:  ffffffff83200ad9 asm_exc_page_fault+0x19 ([kernel.kallsyms]) => ffffffff830b8210 exc_page_fault+0x0 ([kernel.kallsyms])
VM:13376 VCPU:003            uname  3404/3404  [002]  7919.408804631:      branches:  ffffffff830b82a4 exc_page_fault+0x94 ([kernel.kallsyms]) => ffffffff830b80e0 __kvm_handle_async_pf+0x0 ([kernel.kallsyms])
VM:13376 VCPU:003            uname  3404/3404  [002]  7919.408804631:      branches:  ffffffff830b80ed __kvm_handle_async_pf+0xd ([kernel.kallsyms]) => ffffffff830b80c0 kvm_read_and_reset_apf_flags+0x0 ([kernel.kallsyms])

یک حالت متداول در برنامه‌های آزمایشی KVM این است که برنامه آزمایشی به عنوان ناظر (hypervisor) عمل کرده، ماشین مجازی را ایجاد، اجرا و نابود می‌سازد و کد شیء (object code) مهمان را از کد شیء خود تأمین می‌کند. در این حالت، ماشین مجازی یک سیستم‌عامل را اجرا نمی‌کند، بلکه تنها توابعی را اجرا می‌کند که توسط برنامه آزمایشی ناظر در آن بارگذاری شده‌اند و به شکلی مناسب در همان آدرس‌های مجازی بارگذاری می‌شوند. برای پشتیبانی از این قابلیت، گزینه "--guest-code" به perf script و perf kvm report اضافه شده است.

در اینجا نمونه‌ای از ردیابی یک برنامه آزمایشی از KVM selftests هسته آمده است:

# perf record --kcore -e intel_pt/cyc/ -- tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.280 MB perf.data ]
# perf script --guest-code --itrace=bep --ns -F-period,+addr,+flags
[SNIP]
  tsc_msrs_test 18436 [007] 10897.962087733:      branches:   call                   ffffffffc13b2ff5 __vmx_vcpu_run+0x15 (vmlinux) => ffffffffc13b2f50 vmx_update_host_rsp+0x0 (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962087733:      branches:   return                 ffffffffc13b2f5d vmx_update_host_rsp+0xd (vmlinux) => ffffffffc13b2ffa __vmx_vcpu_run+0x1a (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962087733:      branches:   call                   ffffffffc13b303b __vmx_vcpu_run+0x5b (vmlinux) => ffffffffc13b2f80 vmx_vmenter+0x0 (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962087836:      branches:   vmentry                ffffffffc13b2f82 vmx_vmenter+0x2 (vmlinux) =>                0 [unknown] ([unknown])
  [guest/18436] 18436 [007] 10897.962087836:      branches:   vmentry                               0 [unknown] ([unknown]) =>           402c81 guest_code+0x131 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test)
  [guest/18436] 18436 [007] 10897.962087836:      branches:   call                             402c81 guest_code+0x131 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test) =>           40dba0 ucall+0x0 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test)
  [guest/18436] 18436 [007] 10897.962088248:      branches:   vmexit                           40dba0 ucall+0x0 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test) =>                0 [unknown] ([unknown])
  tsc_msrs_test 18436 [007] 10897.962088248:      branches:   vmexit                                0 [unknown] ([unknown]) => ffffffffc13b2fa0 vmx_vmexit+0x0 (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962088248:      branches:   jmp                    ffffffffc13b2fa0 vmx_vmexit+0x0 (vmlinux) => ffffffffc13b2fd2 vmx_vmexit+0x32 (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962088256:      branches:   return                 ffffffffc13b2fd2 vmx_vmexit+0x32 (vmlinux) => ffffffffc13b3040 __vmx_vcpu_run+0x60 (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962088270:      branches:   return                 ffffffffc13b30b6 __vmx_vcpu_run+0xd6 (vmlinux) => ffffffffc13b2f2e vmx_vcpu_enter_exit+0x4e (vmlinux)
[SNIP]
  tsc_msrs_test 18436 [007] 10897.962089321:      branches:   call                   ffffffffc13b2ff5 __vmx_vcpu_run+0x15 (vmlinux) => ffffffffc13b2f50 vmx_update_host_rsp+0x0 (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962089321:      branches:   return                 ffffffffc13b2f5d vmx_update_host_rsp+0xd (vmlinux) => ffffffffc13b2ffa __vmx_vcpu_run+0x1a (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962089321:      branches:   call                   ffffffffc13b303b __vmx_vcpu_run+0x5b (vmlinux) => ffffffffc13b2f80 vmx_vmenter+0x0 (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962089424:      branches:   vmentry                ffffffffc13b2f82 vmx_vmenter+0x2 (vmlinux) =>                0 [unknown] ([unknown])
  [guest/18436] 18436 [007] 10897.962089424:      branches:   vmentry                               0 [unknown] ([unknown]) =>           40dba0 ucall+0x0 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test)
  [guest/18436] 18436 [007] 10897.962089701:      branches:   jmp                              40dc1b ucall+0x7b (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test) =>           40dc39 ucall+0x99 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test)
  [guest/18436] 18436 [007] 10897.962089701:      branches:   jcc                              40dc3c ucall+0x9c (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test) =>           40dc20 ucall+0x80 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test)
  [guest/18436] 18436 [007] 10897.962089701:      branches:   jcc                              40dc3c ucall+0x9c (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test) =>           40dc20 ucall+0x80 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test)
  [guest/18436] 18436 [007] 10897.962089701:      branches:   jcc                              40dc37 ucall+0x97 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test) =>           40dc50 ucall+0xb0 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test)
  [guest/18436] 18436 [007] 10897.962089878:      branches:   vmexit                           40dc55 ucall+0xb5 (/home/user/git/work/tools/testing/selftests/kselftest_install/kvm/tsc_msrs_test) =>                0 [unknown] ([unknown])
  tsc_msrs_test 18436 [007] 10897.962089878:      branches:   vmexit                                0 [unknown] ([unknown]) => ffffffffc13b2fa0 vmx_vmexit+0x0 (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962089878:      branches:   jmp                    ffffffffc13b2fa0 vmx_vmexit+0x0 (vmlinux) => ffffffffc13b2fd2 vmx_vmexit+0x32 (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962089887:      branches:   return                 ffffffffc13b2fd2 vmx_vmexit+0x32 (vmlinux) => ffffffffc13b3040 __vmx_vcpu_run+0x60 (vmlinux)
  tsc_msrs_test 18436 [007] 10897.962089901:      branches:   return                 ffffffffc13b30b6 __vmx_vcpu_run+0xd6 (vmlinux) => ffffffffc13b2f2e vmx_vcpu_enter_exit+0x4e (vmlinux)
[SNIP]
# perf kvm --guest-code --guest --host report -i perf.data --stdio | head -20
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 12  of event 'instructions'
# Event count (approx.): 2274583
#
# Children      Self  Command        Shared Object         Symbol
# ........  ........  .............  ....................  ...........................................
#
   54.70%     0.00%  tsc_msrs_test  [kernel.vmlinux]      [k] entry_SYSCALL_64_after_hwframe
           |
           ---entry_SYSCALL_64_after_hwframe
              do_syscall_64
              |
              |--29.44%--syscall_exit_to_user_mode
              |          exit_to_user_mode_prepare
              |          task_work_run
              |          __fput

ردیابی رویداد (Event Trace) اطلاعات مربوط به رویدادهای ناهمگام را ثبت می‌کند؛ برای نمونه وقفه‌ها، نقص‌ها (faults)، خروج‌ها و ورودهای ماشین مجازی (VM exits and entries). این اطلاعات در بسته‌های CFE و EVD ذخیره می‌شوند، و همچنین پرچم وقفه (Interrupt Flag) در بسته MODE.Exec ثبت می‌گردد. بسته CFE شامل فیلد نوع (type) است که یکی از موارد زیر را مشخص می‌کند:

 1      INTR            interrupt, fault, exception, NMI
 2      IRET            interrupt return
 3      SMI             system management interrupt
 4      RSM             resume from system management mode
 5      SIPI            startup interprocessor interrupt
 6      INIT            INIT signal
 7      VMENTRY         VM-Entry
 8      VMEXIT          VM-Entry
 9      VMEXIT_INTR     VM-Exit due to interrupt
10      SHUTDOWN        Shutdown

برای جزئیات بیشتر، به راهنماهای توسعه‌دهنده نرم‌افزار معماری‌های Intel 64 و IA-32 (نسخه 076 یا بالاتر) مراجعه کنید.

قابلیت انجام Event Trace توسط فایل /sys/bus/event_source/devices/intel_pt/caps/event_trace مشخص می‌شود.

ردیابی رویداد با استفاده از عبارت پیکربندی "event" برای ثبت انتخاب می‌شود؛ برای مثال:

perf record -e intel_pt/event/u uname

رویدادهای Event trace با استفاده از گزینه --itrace I خروجی داده می‌شوند؛ برای مثال:

perf script --itrace=Ie

دستور perf script رویدادهای شامل نوع CFE، بردار (vector) و داده‌های رویداد را به این شکل نمایش می‌دهد:

evt:   hw int            (t)  cfe: INTR IP: 1 vector: 3 PFA: 0x8877665544332211

پرچم IP مشخص می‌کند که آیا رویداد به یک IP پیوند خورده است یا خیر، که این شامل هر حالتی است که در آن تولید بسته کنترل جریان فعال باشد، و همچنین زمانی که بیت IP در بسته CFE تنظیم شده باشد.

دستور perf script رویدادهای شامل تغییرات در Interrupt Flag را به این شکل نمایش می‌دهد:

iflag:   t                      IFLAG: 1->0 via branch

که در آن "via branch" نشان‌دهنده یک انشعاب (وقفه یا بازگشت از وقفه) است و "non branch" نشان‌دهنده دستورالعملی مانند CFI، STI یا POPF می‌باشد).

علاوه بر این، وضعیت کنونی پرچم وقفه با وجود یا عدم وجود پرچم "D" (وقفه غیرفعال است) در perf script نشان داده می‌شود. اگر پرچم وقفه تغییر کند، پرچم "t" نیز گنجانده می‌شود؛ یعنی:

        no flag, interrupts enabled IF=1
t       interrupts become disabled IF=1 -> IF=0
D       interrupts are disabled IF=0
Dt      interrupts become enabled  IF=0 -> IF=1

اسکریپت intel-pt-events.py نحوه دسترسی به اطلاعات Event Trace را با استفاده از یک اسکریپت Python نشان می‌دهد.

بسته‌های TNT با استفاده از عبارت پیکربندی "notnt" غیرفعال می‌شوند؛ برای مثال:

perf record -e intel_pt/notnt/u uname

در این حالت گزینه --itrace q اجباری است، زیرا پیمایش کد اجرایی جهت بازسازی جریان کنترل (control flow) امکان‌پذیر نیست.

نسخه‌های جدیدتر ابزارهای perf از روشی برای شبیه‌سازی دستورالعمل ptwrite پشتیبانی می‌کنند که در صورت عدم پشتیبانی سخت‌افزار از این دستورالعمل می‌تواند مفید باشد.

به جای استفاده از دستورالعمل ptwrite، تابعی به کار گرفته می‌شود که ردیابی‌ای (trace) تولید می‌کند که داده‌های بار مفید (payload) را درون بسته‌های TNT کدگذاری می‌نماید. در اینجا نمونه‌ای از این تابع آورده شده است:

#include <stdint.h>
void perf_emulate_ptwrite(uint64_t x)
__attribute__((externally_visible, noipa, no_instrument_function, naked));
#define PERF_EMULATE_PTWRITE_8_BITS \
                "1: shl %rax\n"     \
                "   jc 1f\n"        \
                "1: shl %rax\n"     \
                "   jc 1f\n"        \
                "1: shl %rax\n"     \
                "   jc 1f\n"        \
                "1: shl %rax\n"     \
                "   jc 1f\n"        \
                "1: shl %rax\n"     \
                "   jc 1f\n"        \
                "1: shl %rax\n"     \
                "   jc 1f\n"        \
                "1: shl %rax\n"     \
                "   jc 1f\n"        \
                "1: shl %rax\n"     \
                "   jc 1f\n"
/* Undefined instruction */
#define PERF_EMULATE_PTWRITE_UD2        ".byte 0x0f, 0x0b\n"
#define PERF_EMULATE_PTWRITE_MAGIC        PERF_EMULATE_PTWRITE_UD2 ".ascii \"perf,ptwrite  \"\n"
void perf_emulate_ptwrite(uint64_t x __attribute__ ((__unused__)))
{
         /* Assumes SysV ABI : x passed in rdi */
        __asm__ volatile (
                "jmp 1f\n"
                PERF_EMULATE_PTWRITE_MAGIC
                "1: mov %rdi, %rax\n"
                PERF_EMULATE_PTWRITE_8_BITS
                PERF_EMULATE_PTWRITE_8_BITS
                PERF_EMULATE_PTWRITE_8_BITS
                PERF_EMULATE_PTWRITE_8_BITS
                PERF_EMULATE_PTWRITE_8_BITS
                PERF_EMULATE_PTWRITE_8_BITS
                PERF_EMULATE_PTWRITE_8_BITS
                PERF_EMULATE_PTWRITE_8_BITS
                "1: ret\n"
        );
}

برای مثال، یک برنامه آزمایشی با تابع بالا:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "perf_emulate_ptwrite.h"
int main(int argc, char *argv[])
{
        uint64_t x = 0;
        if (argc > 1)
                x = strtoull(argv[1], NULL, 0);
        perf_emulate_ptwrite(x);
        return 0;
}

می‌تواند کامپایل و ردیابی شود:

$ gcc -Wall -Wextra -O3 -g -o eg_ptw eg_ptw.c
$ perf record -e intel_pt//u ./eg_ptw 0x1234567890abcdef
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.017 MB perf.data ]
$ perf script --itrace=ew
          eg_ptw 19875 [007]  8061.235912:     ptwrite:  IP: 0 payload: 0x1234567890abcdef      55701249a196 perf_emulate_ptwrite+0x16 (/home/user/eg_ptw)
$

حالت لوله (Pipe mode) برای Intel PT و احتمالاً سایر کاربران auxtrace یک مشکل است. استفاده از یک لوله به عنوان خروجی داده با Intel PT به دلیل زیر توصیه نمی‌شود.

در اصل بافرهای auxtrace مانند بافرهای رویداد معمولی perf رفتار نمی‌کنند. دلیل آن این است که head و tail توسط نرم‌افزار به‌روزرسانی می‌شوند، اما در مورد auxtrace داده‌ها توسط سخت‌افزار نوشته می‌شوند. بنابراین هم‌زمان با نوشته شدن داده‌ها، head و tail به‌روزرسانی نمی‌شوند.

در مورد Intel PT، مقادیر head و tail فقط هنگامی به‌روزرسانی می‌شوند که ردگیری توسط نرم‌افزار غیرفعال شود؛ برای مثال: - ردگیری کامل در سطح سیستم (full-trace, system wide): هنگامی که بافر از watermark عبور کند - ردگیری کامل غیرسراسری (full-trace, not system-wide): هنگامی که بافر از watermark عبور کند یا تعویض زمینه (context switch) رخ دهد - حالت تصویر لحظه‌ای (snapshot mode): همانند بالا، و همچنین زمانی که یک snapshot گرفته شود - حالت نمونه‌برداری (sample mode): همانند بالا، و همچنین زمانی که یک نمونه (sample) گرفته شود

این بدان معناست که ترتیب‌بندی دورِ پایان‌یافته (finished-round ordering) کار نمی‌کند. ممکن است بافر auxtraceای پدیدار شود که دارای داده‌هایی از گذشته در زمان باشد، احتمالاً حتی تا همان ابتدای شروع ردگیری.

برای یک فایل perf.data، این مشکل با پیمایش ردگیری و صف‌بندی پیشاپیش بافرهای auxtrace حل شده است.

برای حالت لوله، ترتیب رویدادها و برچسب‌های زمانی (timestamps) احتمالاً می‌تواند به‌هم بریزد.

در هسته‌های جدیدتر، این امکان وجود دارد که از سایر رویدادهای برگزیده برای مکث یا ازسرگیری ردگیری Intel PT استفاده شود. این ویژگی با استفاده از عبارت پیکربندی "aux-action" پیکربندی می‌شود:

عبارت "aux-action=pause" برای رویدادهایی استفاده می‌شود که قرار است ردگیری Intel PT را متوقف (مکث) کنند.

عبارت "aux-action=resume" برای رویدادهایی استفاده می‌شود که قرار است ردگیری Intel PT را از سر بگیرند.

عبارت "aux-action=start-paused" با رویداد Intel PT برای شروع در وضعیت متوقف‌شده استفاده می‌شود.

به عنوان مثال، برای ردگیری تنها فراخوان سیستمی uname (sys_newuname) هنگام اجرای ابزار خط فرمانی uname:

$ perf record --kcore -e intel_pt/aux-action=start-paused/k,syscalls:sys_enter_newuname/aux-action=resume/,syscalls:sys_exit_newuname/aux-action=pause/ uname
Linux
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.043 MB perf.data ]
$ perf script --call-trace
uname   30805 [000] 24001.058782799: name: 0x7ffc9c1865b0
uname   30805 [000] 24001.058784424:  psb offs: 0
uname   30805 [000] 24001.058784424:  cbr: 39 freq: 3904 MHz (139%)
uname   30805 [000] 24001.058784629: ([kernel.kallsyms])        debug_smp_processor_id
uname   30805 [000] 24001.058784629: ([kernel.kallsyms])        __x64_sys_newuname
uname   30805 [000] 24001.058784629: ([kernel.kallsyms])            down_read
uname   30805 [000] 24001.058784629: ([kernel.kallsyms])                __cond_resched
uname   30805 [000] 24001.058784629: ([kernel.kallsyms])                preempt_count_add
uname   30805 [000] 24001.058784629: ([kernel.kallsyms])                    in_lock_functions
uname   30805 [000] 24001.058784629: ([kernel.kallsyms])                preempt_count_sub
uname   30805 [000] 24001.058784629: ([kernel.kallsyms])            up_read
uname   30805 [000] 24001.058784629: ([kernel.kallsyms])                preempt_count_add
uname   30805 [000] 24001.058784838: ([kernel.kallsyms])                    in_lock_functions
uname   30805 [000] 24001.058784838: ([kernel.kallsyms])                preempt_count_sub
uname   30805 [000] 24001.058784838: ([kernel.kallsyms])            _copy_to_user
uname   30805 [000] 24001.058784838: ([kernel.kallsyms])        syscall_exit_to_user_mode
uname   30805 [000] 24001.058784838: ([kernel.kallsyms])            syscall_exit_work
uname   30805 [000] 24001.058784838: ([kernel.kallsyms])                perf_syscall_exit
uname   30805 [000] 24001.058784838: ([kernel.kallsyms])                    debug_smp_processor_id
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                    perf_trace_buf_alloc
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                        perf_swevent_get_recursion_context
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                            debug_smp_processor_id
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                        debug_smp_processor_id
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                    perf_tp_event
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                        perf_trace_buf_update
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                            tracing_gen_ctx_irq_test
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                        perf_swevent_event
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                            __perf_event_account_interrupt
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                                __this_cpu_preempt_check
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                            perf_event_output_forward
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                                perf_event_aux_pause
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                                    ring_buffer_get
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                                        __rcu_read_lock
uname   30805 [000] 24001.058785046: ([kernel.kallsyms])                                        __rcu_read_unlock
uname   30805 [000] 24001.058785254: ([kernel.kallsyms])                                    pt_event_stop
uname   30805 [000] 24001.058785254: ([kernel.kallsyms])                                        debug_smp_processor_id
uname   30805 [000] 24001.058785254: ([kernel.kallsyms])                                        debug_smp_processor_id
uname   30805 [000] 24001.058785254: ([kernel.kallsyms])                                        native_write_msr
uname   30805 [000] 24001.058785463: ([kernel.kallsyms])                                        native_write_msr
uname   30805 [000] 24001.058785639: 0x0

مثال بالا از tracepointها استفاده می‌کند، اما هر نوع رویداد نمونه‌برداری‌شده‌ای (sampled event) می‌تواند استفاده شود.

برای نمونه:

ردگیری میان arch_cpu_idle_enter() و arch_cpu_idle_exit() با استفاده از رویدادهای breakpoint:
$ sudo cat /proc/kallsyms | sort | grep ' arch_cpu_idle_enter\| arch_cpu_idle_exit'
ffffffffb605bf60 T arch_cpu_idle_enter
ffffffffb614d8a0 W arch_cpu_idle_exit
$ sudo perf record --kcore -a -e intel_pt/aux-action=start-paused/k -e mem:0xffffffffb605bf60:x/aux-action=resume/ -e mem:0xffffffffb614d8a0:x/aux-action=pause/ -- sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.387 MB perf.data ]
ردگیری __alloc_pages() با استفاده از kprobeها:
$ sudo perf probe --add '__alloc_pages order'
Added new event:  probe:__alloc_pages  (on __alloc_pages with order)
$ sudo perf probe --add __alloc_pages%return
Added new event:  probe:__alloc_pages__return (on __alloc_pages%return)
$ sudo perf record --kcore -aR -e intel_pt/aux-action=start-paused/k -e probe:__alloc_pages/aux-action=resume/ -e probe:__alloc_pages__return/aux-action=pause/ -- sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.490 MB perf.data ]
ردگیری با شروع از main() با استفاده از یک رویداد uprobe:
$ sudo perf probe -x /usr/bin/uname main
Added new event:  probe_uname:main     (on main in /usr/bin/uname)
$ sudo perf record -e intel_pt/-aux-action=start-paused/u -e probe_uname:main/aux-action=resume/ -- uname
Linux
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.031 MB perf.data ]
ردگیری گاه‌به‌گاه با استفاده از رویدادهای cycles با دوره‌های تناوب متفاوت:
$ perf record --kcore -a -m,64M -e intel_pt/aux-action=start-paused/k -e cycles/aux-action=pause,period=1000000/Pk -e cycles/aux-action=resume,period=10500000/Pk -- firefox
[ perf record: Woken up 19 times to write data ]
[ perf record: Captured and wrote 16.561 MB perf.data ]

مثال‌ها را می‌توان در صفحهٔ ویکی perf با عنوان “Perf tools support for Intel® Processor Trace” مشاهده کرد:

https://perf.wiki.kernel.org/index.php/Perf_tools_support_for_Intel%C2%AE_Processor_Trace

perf-record(1), perf-script(1), perf-report(1), perf-inject(1)

09/04/2026 perf