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

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

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

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

科技綠洲 ? 來(lái)源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-08 16:19 ? 次閱讀

在實(shí)際的軟件開發(fā)過(guò)程中,內(nèi)存問(wèn)題常常是耗費(fèi)大量時(shí)間進(jìn)行分析的挑戰(zhàn)之一。為了更有效地定位和解決與內(nèi)存相關(guān)的難題,一系列輔助工具應(yīng)運(yùn)而生,其中備受贊譽(yù)的Valgrind工具便是其中之一。事實(shí)上,筆者本人曾利用Valgrind工具成功地發(fā)現(xiàn)并解決了一個(gè)隱藏在軟件中的bug,這充分體現(xiàn)了工具在開發(fā)過(guò)程中的重要性。

然而,同樣強(qiáng)大的bpftrace工具同樣具備簡(jiǎn)潔而直觀的特點(diǎn),能夠協(xié)助我們高效地追蹤內(nèi)存泄漏問(wèn)題。在這方面,bpftrace提供了一種更加精細(xì)的、實(shí)時(shí)的分析方式,幫助開發(fā)人員準(zhǔn)確地定位代碼中可能存在的內(nèi)存泄漏情況。

構(gòu)建樣例

我們編寫一個(gè)程序--mem_check.c,代碼中包含正確的申請(qǐng)內(nèi)存和釋放內(nèi)存的邏輯,同時(shí)包含存在內(nèi)存泄露的代碼代碼。。

#include
#include

int main(){
char *p1 = NULL;
char *p2 = NULL;

for(int i = 0; i < 5; i++)
{
p1 = malloc(16);
}

for(int i = 0; i < 5; i++)
{
p2 = malloc(32);
free(p2);
}
getchar();
return 0;
}

上面的代碼非常簡(jiǎn)單,我們申請(qǐng)了5次16個(gè)字節(jié)的內(nèi)存,沒(méi)有釋放,存在內(nèi)存泄露。申請(qǐng)5次32個(gè)字節(jié)的內(nèi)存,有釋放,沒(méi)存在內(nèi)存泄露。那么我們?nèi)绾瓮ㄟ^(guò)bpftrace定位呢?

我們通過(guò)bpftrace對(duì)mem_check.c進(jìn)行動(dòng)態(tài)的統(tǒng)計(jì)內(nèi)存的申請(qǐng)和釋放,定位內(nèi)存泄露的問(wèn)題。我們需要對(duì)關(guān)鍵的兩個(gè)接口進(jìn)行probe--malloc和free,這兩個(gè)接口的實(shí)現(xiàn)在libc中。

編譯mem_check.c文件,生成可執(zhí)行文件:

gcc mem_check.c -o mem_check

探測(cè)mem_ckeck可執(zhí)行文件

bpftrace可以對(duì)內(nèi)核態(tài)進(jìn)行探測(cè)也可以對(duì)用戶態(tài)進(jìn)行探測(cè),其中探針如下:

  • 內(nèi)核態(tài)探針:kprobe/kretprobe
  • 用戶態(tài)探針:uprobe/uretprobe

mem_check.c是一個(gè)應(yīng)用程序,顯然我們需要使用用戶態(tài)探針:uprobe/uretprobe

通過(guò)uprobe探測(cè)mem_check.c中的malloc函數(shù),我們單行指令驗(yàn)證,參數(shù)格式是 uprobe:可執(zhí)行文件:函數(shù)名:

圖片

理論是沒(méi)有沒(méi)有問(wèn)題,但實(shí)際發(fā)生錯(cuò)誤:No probes to attach。原因:可執(zhí)行文件mem_check中找不到符號(hào):malloc,我們可以通過(guò)nm命令確定一下:

圖片

我們發(fā)現(xiàn)malloc是一個(gè)鏈接自GLIBC_2.2.5的符號(hào),并不是mem_ckeck自身的符號(hào),所以我們探測(cè)的符號(hào)修改libc庫(kù)中malloc符號(hào),系統(tǒng)中可能存在多個(gè)c庫(kù),我們需要找到mem_ckeck程序使用的C庫(kù),通過(guò)ldd命令查看:

圖片

mem_check可執(zhí)行文件使用的C庫(kù)為:/lib/x86_64-linux-gnu/libc.so.6,我們將可以執(zhí)行文件替換為/lib/x86_64-linux-gnu/libc.so.6。再次執(zhí)行,會(huì)出現(xiàn)大量?jī)?nèi)容,顯然是其他進(jìn)程調(diào)用了malloc引起的,而我們的mem_ckeck還沒(méi)有運(yùn)行,顯然還沒(méi)有探測(cè)我們的可執(zhí)行程序。

bpftrace -e 'uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc {printf("malloc calln")}'

我們需要進(jìn)行過(guò)濾,增加filter只保留我們關(guān)心的應(yīng)用程序的調(diào)用探測(cè)。bpftrace提供了系統(tǒng)變量comm表示可執(zhí)行文件名 (進(jìn)程名),只需要在上述指令中增加 filter,只處理comm=="mem_check"的malloc調(diào)用事件。左邊終端執(zhí)行探測(cè),右邊終端執(zhí)行可執(zhí)行文件。每調(diào)用一次malloc函數(shù),就能探測(cè)到一次:

圖片

使用bpftrace腳本進(jìn)一步探測(cè)

將上面的單行命令變?yōu)閎pftrace腳本--bpf_test.bt

BEGIN {
printf("start proben");
}

uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{
printf("malloc calln");
}

END {
printf("end proben");
}

探測(cè)mem_check中malloc的內(nèi)存空間大小。

malloc的原型:

void *malloc(size_t size);

bpftrace的uprobe和kprobe可以通過(guò)內(nèi)置變量arg0、arg1 ··· ··· 訪問(wèn)函數(shù)參數(shù),對(duì)bpf_test.bt修改就可以打印malloc申請(qǐng)內(nèi)存的大小:

BEGIN {
printf("start proben");
}

uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{
printf("malloc size: %dn", arg0);
}

END {
printf("end proben");
}

如下圖可以看到mem_check中申請(qǐng)內(nèi)存的情況,最后一個(gè)malloc size 1024是mem_check自動(dòng)創(chuàng)建輸出緩沖區(qū)申請(qǐng)的內(nèi)存,不用理會(huì)。

圖片

探測(cè)mem_check中malloc的返回值

malloc的返回值是地址,需借助uretprobe進(jìn)行探測(cè),函數(shù)返回值可通過(guò)內(nèi)置變量retval訪問(wèn)。uretprobe的filter與malloc參數(shù)探測(cè)時(shí)類似,腳本修改為:

BEGIN {
printf("start proben");
}

uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{
printf("malloc size: %dn", arg0);
}

uretprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{
printf("addr = %pn", retval);
}

END {
printf("end proben");
}

運(yùn)行結(jié)果:

圖片

探測(cè)mem_check中free

我們已經(jīng)探測(cè)到mem_check的malloc的內(nèi)存大小,內(nèi)存的地址,我們通過(guò)探測(cè)free,然后匹配malloc和free的情況就可以查找內(nèi)存的泄漏點(diǎn)。腳本修改為:

BEGIN {
printf("start proben");
}

uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{
printf("malloc size: %dn", arg0);
}

uretprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{
printf("addr = %pn", retval);
}

uprobe:/lib/x86_64-linux-gnu/libc.so.6:free /comm == "mem_check"/{
printf("free addr = %pn", arg0);
}

END {
printf("end proben");
}

運(yùn)行結(jié)果:

圖片

探測(cè)內(nèi)存泄露

上面我們已經(jīng)探測(cè)到了mem_check中的malloc,free情況。我們可以通過(guò)malloc和free的地址集合差,就可以得到內(nèi)存泄露的地址位置。

bpftrace底層使用的是eBPF的map作為存儲(chǔ)結(jié)構(gòu),可以簡(jiǎn)單的看作K-V存儲(chǔ),我們可以利用map來(lái)統(tǒng)計(jì)地址集合差,步驟如下:

  1. 定義一個(gè)map變量@mem:保存malloc返回的內(nèi)存地址。
  2. 當(dāng)探測(cè)到free調(diào)用時(shí),將@mem對(duì)應(yīng)地址刪除。
  3. 最后@mem剩下的就是內(nèi)存泄露的地址。

內(nèi)存泄露檢測(cè)腳本如下:

BEGIN {
printf("start proben");
}

uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{
printf("malloc size: %dn", arg0);
@size = arg0;
}

uretprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /comm == "mem_check"/{
printf("addr = %pn", retval);
@mem[retval] = @size;

}

uprobe:/lib/x86_64-linux-gnu/libc.so.6:free /comm == "mem_check"/{
printf("free addr = %pn", arg0);
delete(@mem[arg0]);
}

END {
printf("end proben");
}

運(yùn)行結(jié)果:

圖片

如上圖,紅色框中就是沒(méi)有釋放的內(nèi)存和內(nèi)存大小。

總結(jié)

通過(guò)編寫一些簡(jiǎn)單的bpftrace腳本,我們就可以監(jiān)視應(yīng)用程序的內(nèi)存分配和釋放事件,捕獲內(nèi)存泄漏的跡象。這種直接的實(shí)時(shí)監(jiān)控方式,使得開發(fā)者能夠在問(wèn)題出現(xiàn)時(shí)即刻獲得反饋,從而更加迅速地解決潛在的內(nèi)存問(wèn)題,提升軟件的穩(wěn)定性和性能。

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

    關(guān)注

    8

    文章

    3025

    瀏覽量

    74054
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4788

    瀏覽量

    68616
  • Valgrind
    +關(guān)注

    關(guān)注

    0

    文章

    9

    瀏覽量

    6811
收藏 人收藏

    評(píng)論

    相關(guān)推薦

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

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

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

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

    基于ebpf性能工具-bpftrace腳本語(yǔ)法

    ,并且介紹了如何運(yùn)行bpftrace腳本,這篇文章將介紹bpftrace腳本的語(yǔ)法。 基于ubuntu22.04-深入淺出 eBPF 基于ebpf性能工具
    的頭像 發(fā)表于 09-04 16:04 ?1038次閱讀
    基于<b class='flag-5'>ebpf</b>的<b class='flag-5'>性能</b><b class='flag-5'>工具</b>-bpftrace腳本語(yǔ)法

    關(guān)于 eBPF 安全可觀測(cè)性,你需要知道的那些事兒

    非常復(fù)雜的話題,牽一發(fā)而動(dòng)全身,防御機(jī)制、加固配置、漏洞利用等等挑戰(zhàn)性的技術(shù)。在進(jìn)行加固防御的過(guò)程中,又會(huì)產(chǎn)生性能或者系統(tǒng)穩(wěn)定性相關(guān)的影響。從 eBPF + LSM 的角度可以更加可視化、數(shù)據(jù)豐富的觀測(cè)內(nèi)核
    發(fā)表于 09-08 15:31

    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)來(lái)臨
    發(fā)表于 12-23 16:21

    eBPF是什么以及eBPF能干什么

    規(guī)則使用基于寄存器的虛擬機(jī)來(lái)描述包過(guò)濾的行為。比較常用的功能是通過(guò)過(guò)濾來(lái)統(tǒng)計(jì)流量,tcpdump工具就是基于BPF實(shí)現(xiàn)的。而eBPF對(duì)它進(jìn)行了擴(kuò)展來(lái)實(shí)現(xiàn)更多的功能。 主要區(qū)別如下: 1)允許使用C 語(yǔ)言編寫
    的頭像 發(fā)表于 07-05 15:17 ?1.2w次閱讀
    <b class='flag-5'>eBPF</b>是什么以及<b class='flag-5'>eBPF</b>能干什么

    eBPF深入理解和實(shí)現(xiàn)原理

    簡(jiǎn)單來(lái)說(shuō),wBPF 是一個(gè)在硬件上直接執(zhí)行 eBPF 程序的系統(tǒng)。
    的頭像 發(fā)表于 06-14 09:25 ?3604次閱讀

    介紹eBPF針對(duì)可觀測(cè)場(chǎng)景的應(yīng)用

    隨著eBPF推出,由于具有高性能、高擴(kuò)展、安全性等優(yōu)勢(shì),目前已經(jīng)在網(wǎng)絡(luò)、安全、可觀察等領(lǐng)域廣泛應(yīng)用,同時(shí)也誕生了許多優(yōu)秀的開源項(xiàng)目,如Cilium、Pixie等,而iLogtail 作為阿里內(nèi)外千萬(wàn)實(shí)例可觀測(cè)數(shù)據(jù)的采集器,eBPF
    的頭像 發(fā)表于 08-11 09:10 ?1592次閱讀

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

    eBPF 是一個(gè)能夠在內(nèi)核運(yùn)行沙箱程序的技術(shù),提供了一種在內(nèi)核事件和用戶程序事件發(fā)生時(shí)安全注入代碼的機(jī)制,使得非內(nèi)核開發(fā)人員也可以對(duì)內(nèi)核進(jìn)行控制。隨著內(nèi)核的發(fā)展,eBPF 逐步從最初的數(shù)據(jù)包過(guò)濾
    的頭像 發(fā)表于 12-06 10:29 ?565次閱讀

    Linux 內(nèi)核:eBPF優(yōu)勢(shì)和eBPF潛力總結(jié)

    Express Data Path (XDP):網(wǎng)絡(luò)驅(qū)動(dòng)程序是最早可以附加 XDP BPF 鉤子的點(diǎn)。當(dāng)收到一個(gè)數(shù)據(jù)包時(shí),eBPF 程序就會(huì)被觸發(fā)運(yùn)行。
    發(fā)表于 01-10 11:37 ?3175次閱讀

    什么是eBPFeBPF為何備受追捧?

    用云杉網(wǎng)絡(luò) VP 向陽(yáng)的話來(lái)說(shuō):“ eBPF 最重要(沒(méi)有之一)的特點(diǎn)是安全性” 。他表示,以往必須編寫內(nèi)核模塊才能做到的工作現(xiàn)在基本都能做到。
    的頭像 發(fā)表于 05-06 11:41 ?2274次閱讀

    eBPF的前世今生?eBPF在使用中遇到的問(wèn)題有哪些?

    在介紹eBPF (Extended Berkeley Packet Filter)之前,我們先來(lái)了解一下它的前身-BPF (Berkeley Packet Filter)伯克利數(shù)據(jù)包過(guò)濾器。
    的頭像 發(fā)表于 08-12 15:10 ?1624次閱讀
    <b class='flag-5'>eBPF</b>的前世今生?<b class='flag-5'>eBPF</b>在使用中遇到的問(wèn)題有哪些?

    基于ebpf性能工具-bpftrace

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

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

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

    eBPF動(dòng)手實(shí)踐系列三:基于原生libbpf庫(kù)的eBPF編程改進(jìn)方案簡(jiǎn)析

    在上一篇文章《eBPF動(dòng)手實(shí)踐系列二:構(gòu)建基于純C語(yǔ)言的eBPF項(xiàng)目》中,我們初步實(shí)現(xiàn)了脫離內(nèi)核源碼進(jìn)行純C語(yǔ)言eBPF項(xiàng)目的構(gòu)建。libbpf庫(kù)在早期和內(nèi)核源碼結(jié)合的比較緊密,如今的libbpf庫(kù)更加成熟,已經(jīng)完全脫離內(nèi)核源碼
    的頭像 發(fā)表于 03-19 14:19 ?831次閱讀
    <b class='flag-5'>eBPF</b>動(dòng)手實(shí)踐系列三:基于原生libbpf庫(kù)的<b class='flag-5'>eBPF</b>編程改進(jìn)方案簡(jiǎn)析