<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      bcc

      bpf_prog_run_array 是 Linux 內(nèi)核用于執(zhí)行附加在某個(gè) hook(如 tracepoint/raw_tp)上的所有 BPF 程序的內(nèi)部機(jī)制。
      當(dāng) block_rq_complete tracepoint 事件發(fā)生時(shí),內(nèi)核會(huì)通過(guò) bpf_prog_run_array 依次運(yùn)行所有附加的 BPF 程序(包括你用 BCC 或 libbpf 工具加載的 biolatency 程序)。

      如果你加載的是 biolatency 的 block_rq_complete 相關(guān) BPF 程序(如 SEC("raw_tp/block_rq_complete") 或 SEC("tp_btf/block_rq_complete")),那么 bpf_prog_run_array 會(huì)執(zhí)行這些 BPF 程序體。
      這些 BPF 程序體內(nèi)部會(huì)調(diào)用 handle_block_rq_complete 函數(shù)(已編譯進(jìn) eBPF 字節(jié)碼),所以最終會(huì)執(zhí)行 handle_block_rq_complete 的邏輯。

      總結(jié):




      原理

      從內(nèi)核中獲取數(shù)據(jù)。

      整個(gè)工具的核心原理是利用 eBPF 技術(shù),在內(nèi)核中與塊設(shè)備 I/O 相關(guān)的關(guān)鍵函數(shù)上設(shè)置探針(Tracepoint),從而在幾乎無(wú)開(kāi)銷的情況下捕獲 I/O 請(qǐng)求的開(kāi)始和結(jié)束時(shí)間,計(jì)算出延遲,并將結(jié)果存入 eBPF map 中。用戶空間程序則負(fù)責(zé)讀取這個(gè) map 并將數(shù)據(jù)格式化輸出。

      我將分步為您解釋:

      1. 內(nèi)核態(tài) eBPF 程序 (biolatency.bpf.c):數(shù)據(jù)采集

      首先,我需要查看 eBPF 內(nèi)核態(tài)程序的源代碼 biolatency.bpf.c,這是數(shù)據(jù)采集的核心。

       
      \smb\save\code\bcc\bcc\libbpf-tools\biolatency.bpf.c

      好的,我們來(lái)深入分析 biolatency 的實(shí)現(xiàn)原理,詳細(xì)解釋它如何測(cè)量延遲、如何計(jì)數(shù),以及如何從內(nèi)核中獲取數(shù)據(jù)。

      整個(gè)工具的核心原理是利用 eBPF 技術(shù),在內(nèi)核中與塊設(shè)備 I/O 相關(guān)的關(guān)鍵函數(shù)上設(shè)置探針(Tracepoint),從而在幾乎無(wú)開(kāi)銷的情況下捕獲 I/O 請(qǐng)求的開(kāi)始和結(jié)束時(shí)間,計(jì)算出延遲,并將結(jié)果存入 eBPF map 中。用戶空間程序則負(fù)責(zé)讀取這個(gè) map 并將數(shù)據(jù)格式化輸出。

      1. 內(nèi)核態(tài) eBPF 程序 (biolatency.bpf.c):數(shù)據(jù)采集的核心

      這是 biolatency 的心臟,負(fù)責(zé)在內(nèi)核中直接采集數(shù)據(jù)。

      關(guān)鍵數(shù)據(jù)結(jié)構(gòu) (eBPF Maps)

      eBPF 程序使用 "maps" 作為內(nèi)核探針與用戶空間程序之間通信和存儲(chǔ)狀態(tài)的橋梁。

      • start (類型: BPF_MAP_TYPE_HASH):這是測(cè)量延遲最關(guān)鍵的 map。

        • 鍵 (Key): struct request * — 一個(gè)指向內(nèi)核 I/O 請(qǐng)求結(jié)構(gòu)體的指針。當(dāng)一個(gè) I/O 請(qǐng)求在處理過(guò)程中時(shí),這個(gè)指針是它的唯一標(biāo)識(shí)。
        • 值 (Value): u64 — 時(shí)間戳(納秒),記錄請(qǐng)求開(kāi)始的精確時(shí)間。
        • 作用: 當(dāng)一個(gè) I/O 請(qǐng)求開(kāi)始時(shí),eBPF 程序會(huì)把它的指針和當(dāng)前時(shí)間戳存入這個(gè) map。
      • hists (類型: BPF_MAP_TYPE_HASH):這個(gè) map 存儲(chǔ)最終的延遲直方圖數(shù)據(jù)。

        • 鍵 (Key): struct hist_key — 一個(gè)結(jié)構(gòu)體,可以包含設(shè)備號(hào) (dev) 或請(qǐng)求標(biāo)志 (cmd_flags)。這使得工具可以按磁盤、按操作類型(如讀 vs. 寫)分別統(tǒng)計(jì)延遲。如果用戶沒(méi)有指定分組,這個(gè)鍵就是空的,所有延遲都會(huì)被聚合到一起。
        • 值 (Value): struct hist — 一個(gè)包含名為 slots 數(shù)組的結(jié)構(gòu)體。這個(gè)數(shù)組就是直方圖本身,每個(gè)元素都是一個(gè)計(jì)數(shù)器,對(duì)應(yīng)一個(gè)特定的延遲范圍(桶)。

      追蹤 I/O 請(qǐng)求的生命周期 (探針)

      biolatency 將 eBPF 程序附加到內(nèi)核的 tracepoint 上。Tracepoint 是內(nèi)核中穩(wěn)定且高效的事件鉤子。

      • 請(qǐng)求開(kāi)始階段:

        • 探針: block_rq_insert 或 block_rq_issue
          • block_rq_insert: 當(dāng)一個(gè) I/O 請(qǐng)求被加入到調(diào)度器隊(duì)列時(shí)觸發(fā)。從這里開(kāi)始測(cè)量,會(huì)包含排隊(duì)延遲和設(shè)備處理延遲。
          • block_rq_issue: 當(dāng) I/O 調(diào)度器將請(qǐng)求發(fā)送給設(shè)備驅(qū)動(dòng)時(shí)觸發(fā)。從這里開(kāi)始測(cè)量,主要衡量設(shè)備處理延遲。這是 biolatency 的默認(rèn)行為。
        • 處理函數(shù): trace_rq_start
        • 核心操作:
          1. 獲取當(dāng)前時(shí)間戳: ts = bpf_ktime_get_ns();
          2. 使用 I/O 請(qǐng)求的指針 rq 作為鍵,將時(shí)間戳 ts 存入 start map 中: bpf_map_update_elem(&start, &rq, &ts, 0);
      • 請(qǐng)求完成階段:

        • 探針: block_rq_complete。當(dāng)塊設(shè)備完成 I/O 操作后觸發(fā)。
        • 處理函數(shù): handle_block_rq_complete
        • 核心操作:
          1. 查找開(kāi)始時(shí)間: 使用完成請(qǐng)求的指針 rq 在 start map 中查找對(duì)應(yīng)的開(kāi)始時(shí)間戳 tsp。如果找不到,說(shuō)明沒(méi)有追蹤到這個(gè)請(qǐng)求的開(kāi)始,直接忽略。
          2. 計(jì)算延遲: delta = (s64)(ts - *tsp);,其中 ts 是當(dāng)前的完成時(shí)間。delta 就是 I/O 請(qǐng)求的精確延遲(納秒)。
          3. 確定直方圖桶:
            • 首先,根據(jù)用戶指定的單位(-m 標(biāo)志),將納秒 delta 轉(zhuǎn)換為毫秒或微秒。
            • 然后,使用 slot = log2l(delta); 計(jì)算延遲應(yīng)該歸入哪個(gè)桶。這是一種高效的分組方式,可以將延遲按 2 的冪次進(jìn)行分組(例如 0-1, 2-3, 4-7, 8-15, 16-31... 微秒)。
          4. 更新計(jì)數(shù):
            • 根據(jù)設(shè)備或標(biāo)志,在 hists map 中找到對(duì)應(yīng)的直方圖。
            • 使用 __sync_fetch_and_add(&histp->slots[slot], 1); 對(duì)相應(yīng)桶的計(jì)數(shù)器執(zhí)行原子加一操作。原子操作確保了即使在多核 CPU 上有多個(gè) I/O 同時(shí)完成,計(jì)數(shù)也是準(zhǔn)確的。
          5. 清理: bpf_map_delete_elem(&start, &rq);。從 start map 中刪除已完成的請(qǐng)求,防止 map 被占滿。

      2. 用戶空間程序 (biolatency.c):數(shù)據(jù)讀取與展示

      用戶空間程序負(fù)責(zé)控制 eBPF 程序的加載、運(yùn)行,并從 map 中讀取數(shù)據(jù)進(jìn)行展示。

      • main 函數(shù)循環(huán): 在 biolatency.c 的 main 函數(shù)中,程序會(huì)設(shè)置好 eBPF 環(huán)境,然后進(jìn)入一個(gè)循環(huán)。在這個(gè)循環(huán)里,它會(huì)定期(默認(rèn)為每秒)調(diào)用 print_log2_hists 函數(shù)。

      • print_log2_hists(obj->maps.hists, ...):

        • 這個(gè)函數(shù)是你提到的關(guān)鍵。它的職責(zé)是從內(nèi)核的 hists map 中讀取數(shù)據(jù),并以人類可讀的格式打印出來(lái)。
        • obj->maps.hists 是用戶空間程序用來(lái)訪問(wèn)內(nèi)核 hists map 的文件描述符。
        • 函數(shù)會(huì)遍歷 hists map 中的所有條目。對(duì)每個(gè)條目(即每個(gè)直方圖),它會(huì):
          1. 讀取 slots 數(shù)組中的所有計(jì)數(shù)器。
          2. 遍歷這些計(jì)數(shù)器。如果某個(gè)計(jì)數(shù)器不為零,就意味著有 I/O 操作的延遲落在了這個(gè)范圍內(nèi)。
          3. 打印出該范圍對(duì)應(yīng)的延遲區(qū)間,并用一個(gè) ASCII 字符組成的條形圖來(lái)可視化該范圍內(nèi)的 I/O 操作數(shù)量。
        • 一個(gè)非常關(guān)鍵的細(xì)節(jié)是:在讀取并打印完數(shù)據(jù)后,用戶空間程序會(huì)清空內(nèi)核中 hists map 的計(jì)數(shù)器。這就是為什么你在終端上看到每隔一段時(shí)間,統(tǒng)計(jì)數(shù)據(jù)就會(huì)刷新一次。它讀取、打印,然后將計(jì)數(shù)器歸零,為下一個(gè)統(tǒng)計(jì)周期做準(zhǔn)備。

      總結(jié)流程

      1. 設(shè)置 (用戶空間): biolatency 程序解析命令行參數(shù),然后調(diào)用 biolatency_bpf__open() 和 biolatency_bpf__load() 打開(kāi)并加載 eBPF 對(duì)象文件。
      2. 附加 (用戶空間): 調(diào)用 biolatency_bpf__attach() 將 eBPF 程序附加到 block_rq_issue 和 block_rq_complete 等內(nèi)核 tracepoint 上。
      3. 記錄開(kāi)始 (內(nèi)核): 一個(gè) I/O 請(qǐng)求被調(diào)度 -> block_rq_issue 探針觸發(fā) -> trace_rq_start 函數(shù)運(yùn)行 -> 在 start map 中存入 (請(qǐng)求指針, 開(kāi)始時(shí)間)
      4. 記錄結(jié)束并計(jì)算 (內(nèi)核): I/O 請(qǐng)求完成 -> block_rq_complete 探針觸發(fā) -> handle_block_rq_complete 函數(shù)運(yùn)行:
        • 從 start map 中取出開(kāi)始時(shí)間。
        • 計(jì)算 延遲 = 完成時(shí)間 - 開(kāi)始時(shí)間
        • 通過(guò) log2(延遲) 計(jì)算出歸屬的直方圖桶。
        • 在 hists map 中為對(duì)應(yīng)的桶增加計(jì)數(shù)。
        • 從 start map 中刪除該請(qǐng)求的條目。
      5. 顯示 (用戶空間): main 函數(shù)的循環(huán)調(diào)用 print_log2_hists
        • 遍歷內(nèi)核中的 hists map。
        • 讀取每個(gè)直方圖的 slots 數(shù)組。
        • 將數(shù)據(jù)格式化為條形圖并打印到終端。
        • 將 hists map 中的計(jì)數(shù)器清零。
      6. 清理 (用戶空間): 當(dāng)用戶按下 Ctrl-C 時(shí),程序會(huì)調(diào)用 biolatency_bpf__destroy(),卸載 eBPF 程序,釋放所有資源。

      通過(guò)這個(gè)流程,biolatency 實(shí)現(xiàn)了一個(gè)高效、低開(kāi)銷的機(jī)制,能夠直接從 Linux 內(nèi)核獲取并實(shí)時(shí)展示塊設(shè)備 I/O 的延遲分布情況。



      biolatency_bpf__attach(struct biolatency_bpf *obj) { return bpf_object__attach_skeleton(obj->skeleton); } static inline void biolatency_bpf__detach(struct biolatency_bpf *obj) { bpf_object__detach_skeleton(obj->skeleton); } static inline const void *biolatency_bpf__elf_bytes(size_t *sz); static inline int biolatency_bpf__create_skeleton(struct biolatency_bpf *obj) { struct bpf_object_skeleton *s; int err; s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s)); if (!s) { err = -ENOMEM; goto err; } s->sz = sizeof(*s); s->name = "biolatency_bpf"; s->obj = &obj->obj; /* maps */ s->map_cnt = 5; s->map_skel_sz = sizeof(*s->maps); s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt, s->map_skel_sz); if (!s->maps) { err = -ENOMEM; goto err; } s->maps[0].name = "cgroup_map"; s->maps[0].map = &obj->maps.cgroup_map; s->maps[1].name = "start"; s->maps[1].map = &obj->maps.start; s->maps[2].name = "hists"; s->maps[2].map = &obj->maps.hists; s->maps[3].name = "biolaten.rodata"; s->maps[3].map = &obj->maps.rodata; s->maps[3].mmaped = (void **)&obj->rodata; s->maps[4].name = "biolaten.bss"; s->maps[4].map = &obj->maps.bss; s->maps[4].mmaped = (void **)&obj->bss; /* programs */ s->prog_cnt = 6; s->prog_skel_sz = sizeof(*s->progs); s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz); if (!s->progs) { err = -ENOMEM; goto err; } s->progs[0].name = "block_rq_insert_btf"; s->progs[0].prog = &obj->progs.block_rq_insert_btf; s->progs[0].link = &obj->links.block_rq_insert_btf; s->progs[1].name = "block_rq_issue_btf"; s->progs[1].prog = &obj->progs.block_rq_issue_btf; s->progs[1].link = &obj->links.block_rq_issue_btf; s->progs[2].name = "block_rq_complete_btf"; s->progs[2].prog = &obj->progs.block_rq_complete_btf; s->progs[2].link = &obj->links.block_rq_complete_btf; s->progs[3].name = "block_rq_insert"; s->progs[3].prog = &obj->progs.block_rq_insert; s->progs[3].link = &obj->links.block_rq_insert; s->progs[4].name = "block_rq_issue"; s->progs[4].prog = &obj->progs.block_rq_issue; s->progs[4].link = &obj->links.block_rq_issue; s->progs[5].name = "block_rq_complete"; s->progs[5].prog = &obj->progs.block_rq_complete; s->progs[5].link = &obj->links.block_rq_complete; s->data = (void *)biolatency_bpf__elf_bytes(&s->data_sz); obj->skeleton = s; return 0; err: bpf_object__destroy_skeleton(s); return err; }


      核心原理:三步測(cè)量延遲

      
      

      biolatency 的核心思想是通過(guò)在內(nèi)核中設(shè)置“起點(diǎn)”和“終點(diǎn)”兩個(gè)檢查點(diǎn)來(lái)測(cè)量 I/O 請(qǐng)求的耗時(shí)。

      
      

      1. 起點(diǎn):記錄請(qǐng)求開(kāi)始時(shí)間
      2. 終點(diǎn):記錄請(qǐng)求完成時(shí)間,并計(jì)算差值
      3. 聚合:將計(jì)算出的延遲時(shí)間存入直方圖

      
      

      這個(gè)過(guò)程完全由 biolatency.bpf.c 中的 eBPF 程序在內(nèi)核態(tài)完成,效率極高。用戶態(tài)程序 biolatency.c 只負(fù)責(zé)加載 eBPF 程序和讀取最終的統(tǒng)計(jì)結(jié)果。

      
      

      ---

      
      

      詳細(xì)實(shí)現(xiàn)步驟

      
      

      1. 如何得到內(nèi)核數(shù)據(jù):掛載追蹤點(diǎn) (Tracepoints)

      
      

      eBPF 程序通過(guò)掛載到內(nèi)核的追蹤點(diǎn)(Tracepoint)來(lái)捕獲 I/O 事件。追蹤點(diǎn)是內(nèi)核中預(yù)設(shè)的、穩(wěn)定的探測(cè)點(diǎn)。biolatency 主要使用了以下三個(gè)追蹤點(diǎn):

      
      

      * block_rq_issue: 當(dāng)一個(gè) I/O 請(qǐng)求被發(fā)送到塊設(shè)備驅(qū)動(dòng)時(shí)觸發(fā)。這是計(jì)算延遲的默認(rèn)起點(diǎn)。
      * block_rq_insert: 當(dāng)一個(gè) I/O 請(qǐng)求被插入到 I/O 調(diào)度器隊(duì)列時(shí)觸發(fā)。如果用戶使用了 -Q (queued)
      參數(shù),這個(gè)點(diǎn)會(huì)作為起點(diǎn),這樣測(cè)量的延遲就包含了請(qǐng)求在隊(duì)列中等待的時(shí)間。
      * block_rq_complete: 當(dāng)一個(gè) I/O 請(qǐng)求完成時(shí)觸發(fā)。這是所有測(cè)量的終點(diǎn)。

      
      

      在 biolatency.bpf.c 中,你可以看到如下代碼,它們將 eBPF 函數(shù)掛載到這些追蹤點(diǎn)上:

      
      

      1 SEC("tp_btf/block_rq_issue")
      2 int block_rq_issue_btf(u64 *ctx) { ... }
      3
      4 SEC("tp_btf/block_rq_insert")
      5 int block_rq_insert_btf(u64 *ctx) { ... }
      6
      7 SEC("tp_btf/block_rq_complete")
      8 int BPF_PROG(block_rq_complete_btf, struct request *rq, ...) { ... }

      
      

      2. 如何計(jì)數(shù)延遲:利用 eBPF Map

      
      

      eBPF 程序使用兩種類型的 BPF Map 來(lái)存儲(chǔ)和計(jì)算數(shù)據(jù):

      
      

      * `start` (BPF_MAP_TYPE_HASH): 這是一個(gè)哈希映射,用來(lái)臨時(shí)存儲(chǔ)一個(gè) I/O 請(qǐng)求的開(kāi)始時(shí)間。
      * Key: struct request * (指向內(nèi)核中 I/O 請(qǐng)求結(jié)構(gòu)體的指針,是每個(gè)請(qǐng)求的唯一標(biāo)識(shí))。
      * Value: u64 (納秒級(jí)的時(shí)間戳)。

      
      

      * `hists` (BPF_MAP_TYPE_HASH of HISTOGRAM): 這是一個(gè)哈希映射,其值是一個(gè)直方圖結(jié)構(gòu)體。它用來(lái)最終存儲(chǔ)延遲分布。
      * Key: struct hist_key (可以包含設(shè)備號(hào)、I/O 標(biāo)志等,用于分類統(tǒng)計(jì))。
      * Value: struct hist (一個(gè)包含多個(gè)槽位的數(shù)組,每個(gè)槽位代表一個(gè)延遲范圍的計(jì)數(shù)值)。

      
      

      延遲計(jì)數(shù)流程如下:

      
      

      1. 請(qǐng)求開(kāi)始時(shí) (觸發(fā) block_rq_issue 或 block_rq_insert):
      * eBPF 程序獲取當(dāng)前的內(nèi)核時(shí)間戳 (bpf_ktime_get_ns())。
      * 它以 I/O 請(qǐng)求的指針 struct request *rq 為鍵,時(shí)間戳為值,存入 start 哈希映射中。
      * 代碼片段: bpf_map_update_elem(&start, &rq, &ts, 0);

      
      

      2. 請(qǐng)求完成時(shí) (觸發(fā) block_rq_complete):
      * eBPF 程序再次獲取 I/O 請(qǐng)求的指針 struct request *rq。
      * 用這個(gè)指針作為鍵,去 start 哈希映射中查找對(duì)應(yīng)的開(kāi)始時(shí)間戳。
      * 代碼片段: tsp = bpf_map_lookup_elem(&start, &rq);
      * 如果找到了開(kāi)始時(shí)間戳,就計(jì)算延遲:delta = bpf_ktime_get_ns() - *tsp;。
      * 計(jì)算完成后,將該請(qǐng)求的條目從 start 映射中刪除,以防內(nèi)存泄漏。
      * 代碼片段: bpf_map_delete_elem(&start, &rq);

      
      

      3. 如何聚合數(shù)據(jù):更新直方圖

      
      

      為了避免將海量的單個(gè)延遲數(shù)據(jù)發(fā)送到用戶空間造成性能瓶頸,eBPF 程序在內(nèi)核中就地完成了數(shù)據(jù)聚合。

      
      

      1. 計(jì)算出延遲 delta (單位是納秒) 后,程序會(huì)將其轉(zhuǎn)換為微秒或毫秒,并計(jì)算它應(yīng)該落入哪個(gè)直方圖槽位 (slot)。通常使用 log2
      來(lái)實(shí)現(xiàn),這樣可以有效地覆蓋從幾微秒到幾秒的巨大范圍。
      * 代碼片段: slot = log2l(delta);
      2. 然后,程序更新 hists 映射中對(duì)應(yīng)槽位的計(jì)數(shù)器,使其加一。
      * 代碼片段: __sync_fetch_and_add(&histp->slots[slot], 1);

      
      

      4. 用戶空間的角色

      
      

      biolatency.c 中的用戶空間程序相對(duì)簡(jiǎn)單:

      
      

      1. 加載和附加:解析命令行參數(shù),打開(kāi)、加載 eBPF 對(duì)象文件 (.o),并將其中的程序附加到內(nèi)核的追蹤點(diǎn)上。
      2. 循環(huán)讀取:進(jìn)入一個(gè)循環(huán),定期 (sleep) 從內(nèi)核的 hists BPF 映射中讀取已經(jīng)聚合好的直方圖數(shù)據(jù)。
      3. 顯示結(jié)果:將直方圖數(shù)據(jù)格式化并打印到終端上,形成我們看到的延遲分布圖。
      4. 清理:當(dāng)程序退出時(shí)(例如按 Ctrl-C),它會(huì)負(fù)責(zé)分離 eBPF 程序并銷毀 BPF 對(duì)象,釋放所有資源。

      
      

      總結(jié)

      
      

      biolatency 的實(shí)現(xiàn)原理可以精煉為:

      
      

      * 數(shù)據(jù)源:通過(guò) eBPF 掛載到內(nèi)核塊設(shè)備層的追蹤點(diǎn),無(wú)侵入地獲取 I/O 請(qǐng)求的開(kāi)始和完成事件。
      * 延遲計(jì)算:利用一個(gè)哈希映射 (`start`),以 I/O 請(qǐng)求指針為鍵,來(lái)配對(duì)開(kāi)始和結(jié)束事件,并計(jì)算時(shí)間差。
      * 數(shù)據(jù)聚合:在內(nèi)核中直接使用一個(gè)直方圖映射 (`hists`) 對(duì)延遲數(shù)據(jù)進(jìn)行聚合,只將統(tǒng)計(jì)結(jié)果傳遞給用戶空間。
      * 用戶接口:用戶空間程序負(fù)責(zé)控制、參數(shù)配置

       

       

      handle_block_rq_complete 函數(shù)并不是在 C 代碼中被直接調(diào)用的,而是作為 eBPF 程序的一部分,在內(nèi)核的特定事件發(fā)生時(shí)被觸發(fā)執(zhí)行。

      具體來(lái)說(shuō),它被以下兩個(gè) eBPF 程序調(diào)用,這兩個(gè)程序都附加到了內(nèi)核的 block_rq_complete tracepoint(跟蹤點(diǎn))上:

      1. block_rq_complete_btf (使用 BTF 的版本)
      2. block_rq_complete (使用原始 tracepoint 的版本)

      您可以在 /smb/save/code/bcc/bcc/libbpf-tools/biolatency.bpf.c 文件的末尾找到這些調(diào)用點(diǎn):

      /smb/save/code/bcc/bcc/libbpf-tools/biolatency.bpf.c
       
       
       
       
       
      Apply
       
      // ... existing code ...
      SEC("tp_btf/block_rq_complete")
      int BPF_PROG(block_rq_complete_btf, struct request *rq, int error, unsigned int nr_bytes)
      {
      	return handle_block_rq_complete(rq, error, nr_bytes);
      }
      // ... existing code ...
      SEC("raw_tp/block_rq_complete")
      int BPF_PROG(block_rq_complete, struct request *rq, int error, unsigned int nr_bytes)
      {
      	return handle_block_rq_complete(rq, error, nr_bytes);
      }
      
      char LICENSE[] SEC("license") = "GPL";
      

      調(diào)用流程

      1. 當(dāng)一個(gè)塊設(shè)備(如硬盤或 SSD)完成了 I/O 操作(例如,讀或?qū)憯?shù)據(jù)完成)時(shí),Linux 內(nèi)核會(huì)觸發(fā)一個(gè)名為 block_rq_complete 的內(nèi)部事件。

      2. biolatency 工具的用戶空間部分在啟動(dòng)時(shí),會(huì)通過(guò) libbpf 庫(kù)將 block_rq_complete_btf 或 block_rq_complete 這兩個(gè) eBPF 程序中的一個(gè)附加(attach)到這個(gè)內(nèi)核事件上。選擇哪個(gè)版本取決于內(nèi)核是否支持 BTF (BPF Type Format),BTF 提供了更豐富的類型信息,是更現(xiàn)代的方式。

      3. 一旦內(nèi)核事件被觸發(fā),附加的 eBPF 程序就會(huì)被立即執(zhí)行。

      4. eBPF 程序(block_rq_complete_btf 或 block_rq_complete)的唯一任務(wù)就是調(diào)用 handle_block_rq_complete 函數(shù),并將內(nèi)核傳遞給 tracepoint 的參數(shù)(如 struct request *rq)原封不動(dòng)地傳遞給它。

      所以,handle_block_rq_complete 的調(diào)用是由內(nèi)核事件驅(qū)動(dòng)的,而不是由程序中的其他 C 函數(shù)直接調(diào)用的。這是 eBPF 工作模式的核心:將小型、高效的程序注入到內(nèi)核的特定路徑中,以響應(yīng)內(nèi)核事件。

       

      bpftool  常見(jiàn)命令

      bpftool prog list
      2: tracing name hid_tail_call tag 7cc47bbf07148bfe gpl
      loaded_at 2025-05-30T14:18:05+0800 uid 0
      xlated 56B jited 133B memlock 4096B map_ids 2
      btf_id 2
      408: cgroup_device tag 03b4eaae2f14641a gpl
      loaded_at 2025-06-30T19:57:38+0800 uid 1000
      xlated 296B jited 164B memlock 4096B map_ids 4
      435: cgroup_device tag 03b4eaae2f14641a gpl
      loaded_at 2025-06-30T21:26:06+0800 uid 1000
      xlated 296B jited 164B memlock 4096B map_ids 3
      2763: cgroup_device tag 0ecd07b7b633809f gpl

      2804: tracing name block_rq_complete_btf tag 44b7e455a95d77c2 gpl
      loaded_at 2025-10-27T17:14:24+0800 uid 0
      xlated 1072B jited 627B memlock 4096B map_ids 21,17,18,19,22
      btf_id 185

       

      bpftool prog dump xlated id 2804
      int block_rq_complete_btf(unsigned long long * ctx):
      ; int BPF_PROG(block_rq_complete_btf, struct request *rq, int error, unsigned int nr_bytes)
      0: (79) r1 = *(u64 *)(r1 +0)
      ; return handle_block_rq_complete(rq, error, nr_bytes);
      1: (85) call pc+2#bpf_prog_b1cfd2a6e8c49b0d_handle_block_rq_complete
      ; int BPF_PROG(block_rq_complete_btf, struct request *rq, int error, unsigned int nr_bytes)
      2: (b7) r0 = 0
      3: (95) exit
      int handle_block_rq_complete(struct request * rq, int error, unsigned int nr_bytes):
      ; static int handle_block_rq_complete(struct request *rq, int error, unsigned int nr_bytes)
      4: (7b) *(u64 *)(r10 -24) = r1
      ; u64 slot, *tsp, ts = bpf_ktime_get_ns();
      5: (85) call bpf_ktime_get_ns#256016
      6: (bf) r6 = r0
      7: (b7) r1 = 0
      ; struct hist_key hkey = {};
      8: (7b) *(u64 *)(r10 -32) = r1
      ; if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
      9: (18) r1 = map[id:21][0]+0
      11: (71) r1 = *(u8 *)(r1 +0)
      ; if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
      12: (bf) r2 = r10
      ;
      13: (07) r2 += -24
      ; tsp = bpf_map_lookup_elem(&start, &rq);
      14: (18) r1 = map[id:18]
      16: (85) call __htab_map_lookup_elem#296912
      17: (15) if r0 == 0x0 goto pc+1
      18: (07) r0 += 56
      ; if (!tsp)

       

       

      Linux探測(cè)工具BCC(可觀測(cè)性) - charlieroro - 博客園

      posted on 2025-10-24 17:00  文心雕蟲  閱讀(7)  評(píng)論(0)    收藏  舉報(bào)

      主站蜘蛛池模板: 妺妺窝人体色www看美女| 蜜臀av色欲a片无人一区| 最新国产AV最新国产在钱| 99在线精品视频观看免费| 亚洲永久一区二区三区在线| 激情亚洲专区一区二区三区| 黄床大片免费30分钟国产精品| 亚洲成人四虎在线播放| 日韩精品毛片一区到三区| 最新国产精品拍自在线观看| 日韩av中文字幕有码| 日韩区中文字幕在线观看| 男人j进入女人j内部免费网站| 国产一区二区一卡二卡| 男人猛躁进女人免费播放| 精品一区二区免费不卡| 亚洲av午夜福利精品一区二区 | 亚洲国产av剧一区二区三区| 亚洲VA成无码人在线观看天堂| 欧美精品人人做人人爱视频| 亚洲国产一区二区精品专| 亚洲一本二区偷拍精品| 免费萌白酱国产一区二区三区| 国产精品蜜臀av在线一区| 日韩精品有码中文字幕| 亚洲日韩乱码中文无码蜜桃臀| 国产精品美女一区二区三| 亚洲岛国成人免费av| 日本熟妇浓毛hdsex| 国产精品国语对白一区二区| 成人av午夜在线观看| 丰满人妻被黑人猛烈进入| 亚洲第一香蕉视频啪啪爽| 国产一区二区不卡在线| 国产精品成人av在线观看春天| 亚洲av成人无网码天堂| 狠狠综合久久综合88亚洲| 亚洲中文字幕无码中文字| 自拍第一区视频在线观看| 亚洲乱熟女一区二区三区| 国产欧美日韩精品丝袜高跟鞋|