Intel® PT: Intel Processor Trace is a hardware support that can track branches on Intel processors at hardware level. Afterwards, the control flow graph can be extracted with the collected outputs.
Packet | Meaning | Generation |
---|---|---|
TNT | Taken Not-Taken | On a conditional branch or compressed RET |
TIP | Target IP | Indirect branch (including un-compressed RET) |
TIP.PGE | Packet Generation Enable | Any branch instruction, control flow transfer |
Intel-pt linux kernel 4 versiyonu ile birlikte perf ile birlikte kullanılabiliyor. Bunun sayesinde herhangi ekstra bir kütüphaneye gerek kalmadan processor trace özelliğini kullanabiliyoruz. En basit örneklerden birisi:
$ sudo perf record -e intel_pt//u ls
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0,177 MB perf.data ]
Burada
//u
şeklinde verildiği zaman userspace anlamına geliyor eğer
//k
gelseydi kernel olacaktı. Intel-pt dokümanında bunlar sıralanmış:
u userspace
k kernel
h hypervisor
G guest
H host
p precise ip
Gelen veriyi parse edebilmek için perf script'i kullanabiliriz.
$ sudo perf script -i perf.data > a.txt
Gelen çıktı:
.....
.....
ls 461322 [001] 391156.010600: 1 branches:uH: 7fcc113606f0 _dl_sysdep_start+0x0 (/usr/lib/x86_64-linux-gnu/ld-2.31.so) => 0 [unknown] ([unknown])
ls 461322 [001] 391156.010602: 1 branches:uH: 7fcc11360727 _dl_sysdep_start+0x37 (/usr/lib/x86_64-linux-gnu/ld-2.31.so) => 0 [unknown] ([unknown])
ls 461322 [001] 391156.010605: 1 branches:uH: 7fcc1136080a _dl_sysdep_start+0x11a (/usr/lib/x86_64-linux-gnu/ld-2.31.so) => 0 [unknown] ([unknown])
ls 461322 [001] 391156.010608: 1 branches:uH: 7fcc11360a86 _dl_sysdep_start+0x396 (/usr/lib/x86_64-linux-gnu/ld-2.31.so) => 7fcc1135e040 __GI___tunables_init+0x0 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
.....
.....
Perf script'de alacağımız çıktıları flagler üzerinden belirleyebiliyoruz.
--itrace
üzerinden verebiliriz. Default hali
--itrace=cepwx
.
i synthesize "instructions" events
b synthesize "branches" events
x synthesize "transactions" events
w synthesize "ptwrite" events
p synthesize "power" events (incl. PSB events)
c synthesize branches events (calls only)
r synthesize branches events (returns only)
e synthesize tracing error events
d create a debug log
g synthesize a call chain (use with i or x)
G synthesize a call chain on existing event records
l synthesize last branch entries (use with i or x)
L synthesize last branch entries on existing event records
s skip initial number of events
q quicker (less detailed) decoding
Z prefer to ignore timestamps (so-called "timeless" decoding)
Aynı zamanda perf script'inde gösterilmesini istediğimiz (fields) kolonları da ayarlayabiliyoruz. Bunun için:
perf script -F pid,cpu,time
Buraya verebileceğimiz diğer parametrelerde aşağıda mevcut.
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr,symoff, srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output, brstackinsn, brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc, srccode, ipc, data_page_size, code_page_size
Bu parametrelerden
flags
parametresi ilginç eklenebilir.
Aynı zamanda eventleri gruplayabiliriz. Örneğin intel_pt ile branch_miss eventleri burada birleştiriliyor. Bununla beraber branch miss'ler için intel_pt verisi oluşturuluyor.
sudo perf record -e '{intel_pt//u,branch-misses:u}' ./prog
Çıktı:
....
a.out 480642 399271.008150: 1 branch-misses:u: 7f21e31dae78 _dl_start+0x88 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
a.out 480642 399271.008152: 1 branches:uH: tr strt 0 [unknown] ([unknown]) => 7f21e31dae78 _dl_start+0x88 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
a.out 480642 399271.008152: 1 branches:uH: jcc 7f21e31dae82 _dl_start+0x92 (/usr/lib/x86_64-linux-gnu/ld-2.31.so) => 7f21e31db070 _dl_start+0x280 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
a.out 480642 399271.008152: 1 branches:uH: jcc 7f21e31db07c _dl_start+0x28c (/usr/lib/x86_64-linux-gnu/ld-2.31.so) => 7f21e31db090 _dl_start+0x2a0 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
....