0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于ebpf的性能工具-bpftrace腳本語法

Rice嵌入式開發(fā)技術(shù)分享 ? 來源:Rice 嵌入式開發(fā)技術(shù)分享 ? 作者:Rice 嵌入式開發(fā)技 ? 2023-09-04 16:04 ? 次閱讀

bpftrace 通過高度抽象的封裝來使用 eBPF,大多數(shù)功能只需要寥寥幾筆就可以運(yùn)行起來,可以很快讓我們搞清楚 eBPF 是什么樣的,而暫時(shí)不關(guān)心 eBPF 復(fù)雜的內(nèi)部機(jī)理。由于 bpftrace 深受 AWK 和 c 的影響,bpftrace 使用起來于 AWK 非常相似,那些內(nèi)核 hook 注入點(diǎn)幾乎可以按普通字符串匹配來理解,非常容易上手。

前面我們介紹了如何部署bpftrace工具,并且介紹了如何運(yùn)行bpftrace腳本,這篇文章將介紹bpftrace腳本的語法。

基于ubuntu22.04-深入淺出 eBPF

基于ebpf的性能工具-bpftrace

bpftrace腳本語法

腳本格式

  • bpftrace腳本基本格式如下:
probe{
actions;
}
  • bpftrace語法深受AWK的影響,{前的部分相當(dāng)于AWK的condition,{}中的部分相當(dāng)于AWK的action。只不過bpftrace執(zhí)行actions的條件是觸發(fā)probe名稱指定的事件。
  • probe是探針的名稱,我們知道內(nèi)核中函數(shù)非常多,為了方便,內(nèi)核對(duì)probe做了namespace處理,這里的probe通常是以冒號(hào):分割的一組名稱,比如:
tracepointtick_stop
kprobe:do_sys_open
  • 顯然,最后一部分表示的是函數(shù)名稱,其他部分則是namespace,這樣做有兩點(diǎn)好處:①便于查找函數(shù);②便于定位不同模塊中的同名函數(shù)。

  • bpftrace除了可以監(jiān)聽指定的probe事件,還有兩個(gè)特殊的probe:BEGIN,END。這與AWK類似,它們分別在bpftrace程序執(zhí)行開始、結(jié)束時(shí),無條件的執(zhí)行一些操作,比如完成一些初始化、清理工作等。

BEGIN{
print("helloworld.n");
}

END{
print("byeworld.n");
}
  • filter是可選的,有時(shí)候我們只需要探測(cè)特定條件下函數(shù)的行為,比如參數(shù)為某個(gè)值的時(shí)候,就可以用到filter,這需要了解bpftrace如何訪問probe的變量,我們稍晚再說。

prbbe參數(shù)

ebpf支持的probe:hardware,iter,kfunc,kprobe,software,tracepoint,uprobe。

9c747342-4af9-11ee-bb52-92fbcf53809c.png
  1. dynamic tracing
  • ebpf提供了內(nèi)核和應(yīng)用的動(dòng)態(tài)trace,分別用于探測(cè)函數(shù)入口處和函數(shù)返回(ret)處的信息

    • ①面向內(nèi)核的 kprobe/kretprobe,k = kernel
    • ②面向應(yīng)用的 uprobe/uretprobe,u = user land
  • kprobe/kretprobe 可以探測(cè)內(nèi)核大部分函數(shù),出于安全考慮,有部分內(nèi)核函數(shù)不允許安裝探針,另外也可以配合 offset 探測(cè)函數(shù)中任意位置的信息。

  • uprobe/uretprobe 則可以為應(yīng)用的任意函數(shù)安裝探針。

  • 動(dòng)態(tài) trace 技術(shù)依賴內(nèi)核和應(yīng)用的符號(hào)表,對(duì)于那些 inline 或者 static 函數(shù)則無法直接安裝探針,需要自行通過 offset 實(shí)現(xiàn)??梢越柚?nm 或者 strings 指令查看應(yīng)用的符號(hào)表。

  • 這兩種動(dòng)態(tài) trace 技術(shù)的原理與 GDB 類似,當(dāng)對(duì)某段代碼安裝探針,內(nèi)核會(huì)將目標(biāo)位置指令復(fù)制一份,并替換為 int3 中斷, 執(zhí)行流跳轉(zhuǎn)到用戶指定的探針 handler,再執(zhí)行備份的指令,如果此時(shí)也指定了 ret 探針,也會(huì)被執(zhí)行,最后再跳轉(zhuǎn)回原來的指令序列。

  • kprobe 和 uprobe 可以通過 arg0、arg1... ... 訪問所有參數(shù);kretprobe 和 uretprobe 通過 retval 訪問函數(shù)的返回值。除了基本類型:char、int 等,字符串需通過 str() 函數(shù)才能訪問。

  1. static tracing
  • 靜態(tài) trace,所謂 “靜態(tài)” 是指探針的位置、名稱都是在代碼中硬編碼的,編譯時(shí)就確定了。靜態(tài) trace 的實(shí)現(xiàn)原理類似 callback,當(dāng)被激活時(shí)執(zhí)行,關(guān)閉時(shí)不執(zhí)行,性能比動(dòng)態(tài) trace 高一些。

    • ① 內(nèi)核中的靜態(tài)trace:tracepoint
    • ② 應(yīng)用中的靜態(tài)trace: usdt = Userland Statically Defined Tracing
  • 靜態(tài) trace 已經(jīng)在內(nèi)核和應(yīng)用中飽含了探針參數(shù)信息,可以直接通過 args->參數(shù)名 訪問函數(shù)參數(shù)。tracepoint 的 參數(shù) format 信息可以通過 bpftrace -v probe 查看:

youyeetoo@youyeetoo:~$bpftrace-lvtracepointsys_exit
tracepointsys_exit
longid
longret
youyeetoo@youyeetoo:~$
  • 或者訪問debugfs:
youyeetoo@youyeetoo:~$cat/sys/kernel/debug/tracing/events/raw_syscalls/sys_exit/format
name:sys_exit
ID:348
format:
field:unsignedshortcommon_type;offset:0;size:2;signed:0;
field:unsignedcharcommon_flags;offset:2;size:1;signed:0;
field:unsignedcharcommon_preempt_count;offset:3;size:1;signed:0;
field:intcommon_pid;offset:4;size:4;signed:1;

field:longid;offset:8;size:8;signed:1;
field:longret;offset:16;size:8;signed:1;

printfmt:"NR%ld=%ld",REC->id,REC->ret
youyeetoo@youyeetoo:~$

內(nèi)置變量

無論 Dynamic tracing 或者 Static tracing,它們的目的都是監(jiān)聽特定函數(shù)調(diào)用事件,這些函數(shù)即可以在內(nèi)核中,也可以在用戶態(tài)的應(yīng)用或者 lib 中。獲知這些函數(shù)調(diào)用時(shí)的參數(shù)、返回值就已經(jīng)實(shí)現(xiàn)了開發(fā)者大半目標(biāo)。除此之外,bpfstrace 還內(nèi)置了一些變量,用戶訪獲得探測(cè)對(duì)象自身信息。這些變量在 bpftrace 中直接訪問即可,如下:

  • pid / tid:Bpftrace或者說eBPF工作在內(nèi)核,因此這些變量都與內(nèi)核中進(jìn)程表示有關(guān)。先說tid,內(nèi)核中線程與進(jìn)程沒做作明確區(qū)分,它們都是相同的調(diào)度對(duì)象task_sruct。tid是thread id的縮寫,由于歷史原因,在task中的成員是task_sruct.pid。所以對(duì)于Linux內(nèi)核,線程=輕量級(jí)進(jìn)程。而pid實(shí)際上指的是內(nèi)核中進(jìn)程組,由task中的task_sruct.tgid成員表示。也就是說,進(jìn)程=線程組。
  • uid / gid:執(zhí)行函數(shù)的用戶ID、組ID。
  • nsecs:時(shí)間戳,納秒。
  • elapsed:ebpfs 啟動(dòng)后的納秒數(shù)。
  • numaid:NUMA = Non-Uniform Memory Access,與多核 CPU 的內(nèi)存訪問相關(guān)。
  • cpu:當(dāng)前 cpu 編號(hào),從 0 開始。
  • comm:進(jìn)程名稱,通常為進(jìn)程可執(zhí)行文件名。
  • kstack:內(nèi)核棧。
  • ustack: 用戶棧。
  • arg0, arg1, ..., argN:函數(shù)參數(shù)。
  • sarg0, sarg1, ..., sargN:函數(shù)參數(shù)(棧中)。
  • retval:返回值。
  • func:函數(shù)名,可以在可執(zhí)行文件的符號(hào)表中這個(gè)函數(shù)名。
  • probe:探針的完整名稱,也就是 bpftrace 中 形如 'kprobe:do_nanosleep'
  • curtask:當(dāng)前 task struct。
  • rand:一個(gè)無符號(hào) 32 位隨機(jī)數(shù)。
  • cgroup:當(dāng)前進(jìn)程的 Cgroup,內(nèi)核資源組,類似 namespace,docker 等虛擬化技術(shù)即基于內(nèi)核提供的這一基礎(chǔ)設(shè)施。
  • cpid:子進(jìn)程 pid,bpftrace 允許通過 -c 指定一個(gè) cmd 運(yùn)行,然后在該進(jìn)程上安裝 probe。
  • 2, ..., #:bpftrace 程序自身的位置參數(shù)

全局變量

  • 全局變量@name,所謂的全局變量:①對(duì)所有的probe actions可見,②bpftrace生命周期內(nèi)可見。

  • bpftrace支持兩種變量形式:

    • ① 簡單變量,@name = value;簡單變量就是單純的變量名和值,很容易理解,你可以在腳本中創(chuàng)建任意數(shù)量的簡單變量。
    • ② Map,@name[key] = value;Map非常接近Python中的Dict,或者C中的數(shù)組,但數(shù)組索引可以是數(shù)字、字符串等。例如借助內(nèi)置變量tid可以為每個(gè)線程記錄獨(dú)立的數(shù)值。
  • 測(cè)試?yán)樱?/p>

kprobe:do_nanosleep{
@start[tid]=nsecs;
}

kretprobe:do_nanosleep/@start[tid]!=0/{
printf("sleptfor%dmsn",(nsecs-@start[tid])/1000000);
delete(@start[tid]);
}
  • 運(yùn)行效果:
youyeetoo@youyeetoo:~$bpftracebpf_test.bt
Attaching2probes...
sleptfor0ms
sleptfor0ms
sleptfor0ms
sleptfor0ms
sleptfor0ms
sleptfor0ms
sleptfor0ms

臨時(shí)變量

$name, 只在當(dāng)前action中有效,超出action的{}不具備記憶能力。

內(nèi)置函數(shù)

bpftrace無法自定義函數(shù),但提供了約36個(gè)內(nèi)置函數(shù),可以在bpftrace腳本的任意位置調(diào)用它們。完整的列表可以參考官方文檔:(https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md)。

bpftrace的函數(shù)非常有限,原因是bpftrace腳本會(huì)編譯為bytecode,交由內(nèi)核中的eBPF VM執(zhí)行,出于安全和效率考慮,eBPF VM不能允許用戶執(zhí)行任意函數(shù),僅允許執(zhí)行限定的函數(shù),或缺有限的數(shù)據(jù)。

  1. printf -- printf(fmt, ...)bpftrace的printf函數(shù)行為與C語言基本一致,區(qū)別在于它只支持有限的格式化字符,不如C語言支持的那么多。
BEGIN{
print("helloworld.n");
}

END{
print("byeworld.n");
}
  1. time -- time(fmt)time函數(shù)用于打印當(dāng)前時(shí)間,可以通過參數(shù)中的格式化字符串指定,如果沒有指定格式化字符串,那么默認(rèn)格式是%H:%M:%Sn。time函數(shù)完全兼容strftime的格式化字符,下面列出一些常用項(xiàng):
  • %S 秒,00-60;
  • %M 分鐘,00-59;
  • %I 小時(shí),01-12;%H 小時(shí),00-23;
  • %d 每月的第幾天,01-31;
  • %w 星期,0-6, 0 指 星期日;
  • %m 月份,01-12;
  • %y 年份,00-99;%Y 完整的年份;

「注意:格式化字符結(jié)尾不要忘記換行,否則不會(huì)自動(dòng)清空緩沖區(qū)到標(biāo)準(zhǔn)輸出,就看不到輸出了?!?/strong>

youyeetoo@youyeetoo:~$bpftrace-e'interval1{time("%Y%H:%M:%Sn");}'
Attaching1probe...
202316:35:30
202316:35:31
202316:35:32
^C
  1. system該函數(shù)可以調(diào)用 shell,用于 probe 觸發(fā)其他用戶態(tài)可執(zhí)行程序非常有用。下面是一個(gè)簡單的例子,定時(shí)調(diào)用 `ps. 查看當(dāng)前進(jìn)程:
youyeetoo@youyeetoo:~$bpftrace--unsafe-e'kprobe:do_nanosleep{system("ps-p%dn",pid);}'
Attaching1probe...
PIDTTYTIMECMD
933?00:00:00cron
^C
  1. ustack當(dāng)使用 uprobe 時(shí),很可能需要關(guān)注用戶進(jìn)程的 stack 情況,ustack 函數(shù)接受 2 個(gè)參數(shù),這兩個(gè)參數(shù)可以同時(shí)使用,或者只用 1 個(gè)。
  • mode,stack 模式,可選 bpftrace、perf;
  • limit,一個(gè)整數(shù),獲取 stack 的最大深度;
youyeetoo@youyeetoo:~$bpftrace-e'uprobereadline{printf("%sn",ustack(perf,3));}'
stdin:1:1-21:WARNING:attachingtouprobetargetfile'/usr/bin/bash'butmatched2binaries
uprobereadline{printf("%sn",ustack(perf,3));}
~~~~~~~~~~~~~~~~~~~~
Attaching1probe...

56440bb42690readline+0(/usr/bin/bash)
56440bb42690readline+0(/usr/bin/bash)
56440bb42690readline+0(/usr/bin/bash)

控制語句

bpftrace 也提供了常見的流程控制語句:① 條件語句 ② 循環(huán)語句

  1. 條件語句
  • bpftrace的條件語句用法與C語言完全一樣:
if(condition){
statements;//A
}else{
statements;//B
}
  • 當(dāng)滿足條件時(shí)執(zhí)行 A 處語句,否則執(zhí)行 B 處語句。當(dāng)然也可能有以下更簡單的形式,沒有 else 部分,條件滿足時(shí)執(zhí)行 A 處語句,然后執(zhí)行 B 處語句,否則跳過 A 處語句:
if(condition){
statements;//A
}

statements;//B
  • 多個(gè) if-else 也可能連接在一起:
if(condition){
statements;//A
}elseif(condition){
statements;//B
}elseif(condition){
statements;//C
}else{
statements;//D
}
  • 測(cè)試樣例:
BEGIN{
$num=$1;
if($num>=10){
$result="A";
}elseif($num>=5){
$result="B";
}else{
$result="C"
}
printf("result:%sn",$result);
exit();
}
  • 測(cè)試樣例結(jié)果:
youyeetoo@youyeetoo:~$bpftracebpf_test.bt15
Attaching1probe...
result:A

youyeetoo@youyeetoo:~$bpftracebpf_test.bt8
Attaching1probe...
result:B

youyeetoo@youyeetoo:~$bpftracebpf_test.bt3
Attaching1probe...
result:C

youyeetoo@youyeetoo:~$
  1. 循環(huán)語句
while(condition){
//dosomething
}
  • 測(cè)試樣例:
BEGIN{
$i=0;
while($i10){
printf("i=%dn",$i);
$i++
}
exit();
}

  • 測(cè)試樣例結(jié)果:
youyeetoo@youyeetoo:~$bpftracebpf_test.bt
Attaching1probe...
i=0
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9

審核編輯 黃宇


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5052

    文章

    18909

    瀏覽量

    300740
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4256

    瀏覽量

    62224
  • 語法
    +關(guān)注

    關(guān)注

    0

    文章

    41

    瀏覽量

    9749
  • 腳本
    +關(guān)注

    關(guān)注

    1

    文章

    383

    瀏覽量

    14792
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    解構(gòu)內(nèi)核源碼eBPF樣例編譯過程

    了解和掌握純c語言的ebpf編譯和使用,有助于我們加深對(duì)于eBPF技術(shù)原理的進(jìn)一步掌握,也有助于開發(fā)符合自己業(yè)務(wù)需求的高性能ebpf程序。
    的頭像 發(fā)表于 04-17 14:05 ?1464次閱讀

    Linux跟蹤工具bpftrace的原理和使用

    這篇文章介紹一個(gè)基于ebpf技術(shù)的強(qiáng)大工具--bpftrace
    發(fā)表于 09-01 15:10 ?1735次閱讀
    Linux跟蹤<b class='flag-5'>工具</b><b class='flag-5'>bpftrace</b>的原理和使用

    如何在 Shell 腳本中執(zhí)行語法檢查調(diào)試模式

    LCTT 原創(chuàng)編譯,Linux中國 榮譽(yù)推出我們開啟了 Shell 腳本調(diào)試系列文章,先是解釋了不同的調(diào)試選項(xiàng),下面介紹如何啟用 Shell 調(diào)試模式。寫完腳本后,建議在運(yùn)行腳本之前先檢查
    發(fā)表于 12-31 11:04

    總結(jié)linux腳本語法和正則表達(dá)式的應(yīng)用

    每日學(xué)一點(diǎn)之linux腳本語法以及正則表達(dá)式基礎(chǔ)
    發(fā)表于 11-08 09:23

    Makefile腳本語法簡介

    宏定義LEDS_CTL 的使用Makefile腳本語法簡介Makefile測(cè)試
    發(fā)表于 12-22 06:39

    openEuler 倡議建立 eBPF 軟件發(fā)布標(biāo)準(zhǔn)

    eBPF 被廣泛應(yīng)用在云原生、可觀測(cè)、性能調(diào)優(yōu)、安全、硬件加速等領(lǐng)域,并且其應(yīng)用場(chǎng)景還在快速擴(kuò)展,各種場(chǎng)景基于 eBPF 技術(shù)的創(chuàng)新 idea 呈現(xiàn)井噴現(xiàn)象,eBPF 的時(shí)代已經(jīng)來臨
    發(fā)表于 12-23 16:21

    服務(wù)器端腳本與動(dòng)態(tài)網(wǎng)頁設(shè)計(jì),下載

    服務(wù)器端腳本與動(dòng)態(tài)網(wǎng)頁設(shè)計(jì) 1. 了解服務(wù)器端腳本和動(dòng)態(tài)網(wǎng)頁的有關(guān)概念 ; 2. 了解ASP、PHP的基本語法和基本功能 ; 3. 熟練掌握J(rèn)SP的基本語法和基本
    發(fā)表于 04-28 16:44 ?0次下載

    強(qiáng)勁的Linux Trace工具 bpftrace for Linux 2018

    本文主要是Brendan Gregg在介紹 bpftrace在2018年的開發(fā)進(jìn)展,以及對(duì)bpftrace的介紹和對(duì)Dtrace的區(qū)別介紹。
    的頭像 發(fā)表于 06-04 15:44 ?1.2w次閱讀
    強(qiáng)勁的Linux Trace<b class='flag-5'>工具</b> <b class='flag-5'>bpftrace</b> for Linux 2018

    eBPF是什么以及eBPF能干什么

    一、eBPF是什么 eBPF是extended BPF的縮寫,而BPF是Berkeley Packet Filter的縮寫。對(duì)linux網(wǎng)絡(luò)比較熟悉的伙伴對(duì)BPF應(yīng)該比較了解,它通過特定的語法
    的頭像 發(fā)表于 07-05 15:17 ?1.1w次閱讀
    <b class='flag-5'>eBPF</b>是什么以及<b class='flag-5'>eBPF</b>能干什么

    基于ebpf性能工具-bpftrace

    運(yùn)行情況對(duì)于診斷問題、優(yōu)化性能以及進(jìn)行安全監(jiān)控至關(guān)重要。bpftrace作為一款強(qiáng)大的跟蹤工具,為開發(fā)人員和系統(tǒng)管理員提供了一種獨(dú)特的方式來監(jiān)視和分析Linux系統(tǒng)的內(nèi)部運(yùn)行。本文描述bpft
    的頭像 發(fā)表于 09-04 16:02 ?609次閱讀
    基于<b class='flag-5'>ebpf</b>的<b class='flag-5'>性能</b><b class='flag-5'>工具</b>-<b class='flag-5'>bpftrace</b>

    ebpf的快速開發(fā)工具--libbpf-bootstrap

    基于ubuntu22.04-深入淺出 eBPF 基于ebpf性能工具-bpftrace 基于ebpf
    的頭像 發(fā)表于 09-25 09:04 ?812次閱讀
    <b class='flag-5'>ebpf</b>的快速開發(fā)<b class='flag-5'>工具</b>--libbpf-bootstrap

    基于ebpf性能工具應(yīng)用

    曾利用Valgrind工具成功地發(fā)現(xiàn)并解決了一個(gè)隱藏在軟件中的bug,這充分體現(xiàn)了工具在開發(fā)過程中的重要性。 然而,同樣強(qiáng)大的bpftrace工具同樣具備簡潔而直觀的特點(diǎn),能夠協(xié)助我們
    的頭像 發(fā)表于 11-08 16:19 ?358次閱讀
    基于<b class='flag-5'>ebpf</b>的<b class='flag-5'>性能</b><b class='flag-5'>工具</b>應(yīng)用

    腳本錯(cuò)誤scripterror怎么解決

    腳本錯(cuò)誤”(Script Error)通常是在運(yùn)行或嘗試運(yùn)行一段腳本或程序時(shí)出現(xiàn)的錯(cuò)誤。這種錯(cuò)誤可能源于許多不同的原因,包括語法錯(cuò)誤、運(yùn)行環(huán)境問題、依賴庫缺失等。解決腳本錯(cuò)誤需要針對(duì)
    的頭像 發(fā)表于 11-26 14:46 ?7084次閱讀

    腳本調(diào)試工具有哪些?腳本調(diào)試工具怎么用?

    腳本調(diào)試是軟件開發(fā)過程中非常重要的一環(huán),它能幫助開發(fā)者快速定位并解決代碼中的錯(cuò)誤。大多數(shù)編程語言都提供了各種各樣的腳本調(diào)試工具,本文將介紹一些常見的腳本調(diào)試
    的頭像 發(fā)表于 12-01 14:40 ?733次閱讀

    Shell腳本檢查工具ShellCheck介紹

    ShellCheck是一個(gè)用于bash/sh shell腳本的靜態(tài)分析工具,可以輔助檢查腳本語法錯(cuò)誤,給出建議增強(qiáng)腳本健壯性。
    的頭像 發(fā)表于 12-27 13:43 ?1803次閱讀
    Shell<b class='flag-5'>腳本</b>檢查<b class='flag-5'>工具</b>ShellCheck介紹