1. 程式人生 > >Linux bpf 2.1、bcc的實現

Linux bpf 2.1、bcc的實現

bcc全稱為(BPF Compiler Collection),它是模仿gcc(GNU Compiler Collection)的命名風格。

BPF是執行在核心態的一種虛擬機器語言,我們在使用者態可以通過Clang+LLVM把c語言編譯成BPF目標碼,然後通過載入器loader(bcc/perf/iproute2)將BPF目標碼通過bpf()系統呼叫載入到核心當中,最後通過perf的ioctl命令PERF_EVENT_IOC_SET_BPF將載入到核心中的BPF程式和對應子模組(tracing/networking)的鉤子繫結起來。(具體參考3.2、BPF and XDP Reference Guide

)

bcc把上述使用者態編譯、載入、繫結的功能都集成了起來,方便使用者使用,對使用者的介面更友好。它使用了(python + lua + c++)的混合架構,底層操作封裝到c++ 庫中,lua提供一些輔助功能,對使用者的介面使用python提供,python和c++之間的呼叫使用ctypes連線。因為使用了python,所有抓回來的資料分析和資料呈現也都非常方便。

有了bcc以後使用者就不需要一步步手工的寫c程式碼、編譯、載入、繫結、資料分析、資料呈現,只要按照bcc的規則編寫一個python檔案,bcc幫你一鍵搞定。

1、背景介紹

說到bcc,就不得不提到Brendan Gregg,他是perfermance屆的大神。他開發了很多perf相關的工具和指令碼:

perf_eventsperf-toolsbccFlame Graphs。相關的文件都可以在他的部落格上找到,本文bcc的文件也引用自它的部落格。

2、bcc安裝

首先確保你的核心版本是4.1或者以上的版本(推薦4.9以上),並且打開了以下配置:(檢視/proc/config.gz or /boot/config-)

CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
# [optional, for tc filters]
CONFIG_NET_CLS_BPF=m
# [optional, for tc actions]
CONFIG_NET_ACT_BPF=m
CONFIG_BPF_JIT=y
CONFIG_HAVE_BPF_JIT=y
# [optional, for kprobes]
CONFIG_BPF_EVENTS=y

如果執行bcc網路示例需要開啟一些可選的核心選項:

CONFIG_NET_SCH_SFQ=m
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
CONFIG_DUMMY=m
CONFIG_VXLAN=m

在ubuntu環境下,我們可以使用以下簡單的命令來安裝bcc工具:

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
echo "deb https://repo.iovisor.org/apt/xenial xenial main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r)

3、bcc的使用入門

安裝完bcc以後,我們可以進入"/usr/share/bcc/tools"和"/usr/share/bcc/examples/tracing"路徑下執行bcc已經提供的效能分析命令,關於命令的基本使用可以參考上面的入門指導。

/usr/share/bcc/tools$ ls
argdist              doc             mdflush         pythonflow   tcpconnlat
bashreadline         execsnoop       memleak         pythongc     tcpdrop
biolatency           ext4dist        mountsnoop      pythonstat   tcplife
biosnoop             ext4slower      mysqld_qslower  reset-trace  tcpretrans
biotop               filelife        nfsdist         rubycalls    tcpstates
bitesize             fileslower      nfsslower       rubyflow     tcpsubnet
bpflist              filetop         nodegc          rubygc       tcptop
btrfsdist            funccount       nodestat        rubyobjnew   tcptracer
btrfsslower          funclatency     offcputime      rubystat     tplist
cachestat            funcslower      offwaketime     runqlat      trace
cachetop             gethostlatency  old             runqlen      ttysnoop
capable              hardirqs        oomkill         runqslower   vfscount
cobjnew              inject          opensnoop       slabratetop  vfsstat
cpudist              javacalls       perlcalls       softirqs     wakeuptime
cpuunclaimed         javaflow        perlflow        solisten     xfsdist
criticalstat         javagc          perlstat        sslsniff     xfsslower
dbslower             javaobjnew      phpcalls        stackcount   zfsdist
dbstat               javastat        phpflow         statsnoop    zfsslower
dcsnoop              javathreads     phpstat         syncsnoop
dcstat               killsnoop       pidpersec       syscount
deadlock_detector    lib             profile         tcpaccept
deadlock_detector.c  llcstat         pythoncalls     tcpconnect

/usr/share/bcc/examples/tracing$ ls
bitehist_example.txt            strlen_count.py
bitehist.py                     strlen_hist.py
CMakeLists.txt                  strlen_snoop.py
disksnoop_example.txt           sync_timing.py
disksnoop.py                    task_switch.py
hello_fields.py                 tcpv4connect_example.txt
hello_perf_output.py            tcpv4connect.py
kvm_hypercall.py                trace_fields.py
kvm_hypercall.txt               trace_perf_output.py
mallocstacks.py                 urandomread_example.txt
mysqld_query_example.txt        urandomread-explicit.py
mysqld_query.py                 urandomread.py
nodejs_http_server_example.txt  vfsreadlat.c
nodejs_http_server.py           vfsreadlat_example.txt
stacksnoop_example.txt          vfsreadlat.py
stacksnoop.py

如果bcc提供的專用命令不能滿足你,bcc還提供了幾個通用自定義命令:trace、argdist、funccount。可以詳細看一下這幾個命令的用法。

4、bcc python指令碼的編寫

如果bcc自帶指令碼不能滿足你,你可以仿照bcc的語法規則自己開發python指令碼,自定義自己要採集的資料,自定義自己的資料處理和呈現規則。因為是python介面,我們可以進行二次開發把資料進行更詳盡的分析、用圖形呈現等等。

5、bcc原始碼結構

我們也可以從github上下載bcc的原始碼進行分析和除錯。

我們在配置pycharm工程的時候需要注意:

  • 1、bcc的指令碼需要以root的許可權來執行:參考
  • 2、需要把bcc/src/python的路徑加入到python庫的搜尋路徑中,工程才能正確執行:參考

我們檢視cc的python指令碼,核心部分是BPF python庫:

bcc/examples$ cat hello_world.py 
#!/usr/bin/env python
# Copyright (c) PLUMgrid, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")

# run in project examples directory with:
# sudo ./hello_world.py"
# see trace_fields.py for a longer example

from bcc import BPF

# This may not work for 4.17 on x64, you need replace kprobe__sys_clone with kprobe____x64_sys_clone
BPF(text='int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; }').trace_print()

BPF python庫是在路徑bcc/src/python/bcc/中實現的,在libbcc.py中通過ctypes匯入了libbcc.so.0:

bcc/src/python/bcc$ cat libbcc.py
# Copyright 2015 PLUMgrid
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import ctypes as ct

lib = ct.CDLL("libbcc.so.0", use_errno=True)

# keep in sync with bpf_common.h
lib.bpf_module_create_b.restype = ct.c_void_p
lib.bpf_module_create_b.argtypes = [ct.c_char_p, ct.c_char_p, ct.c_uint]
lib.bpf_module_create_c.restype = ct.c_void_p

libbcc.so.0是c++的底層實現,原始碼在bcc/src/cc路徑下。

本來是想寫一篇bcc核心程式碼分析的文章,後來發現整個程式碼規模太大,還是分析個大致框架有問題再追蹤修改吧。