在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux TraceEvent - 史上最長宏定義

Linux閱碼場 ? 來源:Linuxer ? 2020-06-28 09:34 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

TraceEvent是內核中一種探測的機制,據說在不使能的時候是沒有損耗的。據說使用起來挺簡單,但是要看懂著實需要花些力氣。

例子

從例子中學習,一般都是比較好的方法。內核開發者也比較nice,在內核源碼samples/trace_events目錄下就有這么一個例子。

其中文件一共有三個:

這個例子以內核模塊的形式存在,所以只要執行make就可以編譯完成。

總的來說,要定義和使用tracepoint,只要做兩點。

用TRACE_EVENT來定義一個新的tracepoint

在需要的地方,使用函數trace_XXX打印輸出

有了例子我們就要跑一跑,來看看如何使用的。

首先我們要編譯出我們的例子,這時候需要加上打開兩個編譯配置

CONFIG_SAMPLES

CONFIGSAMPLETRACE_EVENTS

編譯

make M=samples/trace_events

然后加載這個例子模塊

modprobe trace-events-sample

因為用戶接口在debugfs上,所以還要確保debugfs掛載了。

mount -t debugfs none /sys/kernel/debug/

此時我們就能在 /sys/kernel/debug/tracing/events/sample-trace/ 目錄下看到該模塊創建好的trace event了。

接下來,我們就可以打開這個探測時間,并且查看探測的輸出了。

cd /sys/kernel/debug/tracing

echo 1 > events/sample-trace/enable

cat trace

echo 0 > events/sample-trace/enable

通過cat trace觀察,可以看出系統運行時的一些狀態。

讓我們進一步再來看看events/sample-trace這個目錄:

可以看到

目錄名稱sample-trace由TRACE_SYSTEM這個宏定義,所以通過查找這個宏,就能知道有多少events的大類

每一個TRACE_EVENT都有一個自己的目錄

源文件中trace_XXX的函數就是執行探測記錄的地方了。那么這些函數是怎么定義的呢?

TRACE_EVENT定義

看完了例子,我們就該看代碼實現了。講真,這是我見過的最長的宏展開了。之前在qemu上看到的那個hmp-command和這個比起來簡直就是個小屁孩。

先來看一下例子中是如何定義一個trace event的。和其他定義不同,定義trace event的定義在頭文件,而非源文件。我把trace-events-sample.h文件做一個簡要的打開。

中間我省略了很多TRACEEVENT及其變體,每一個TRACEEVENT對應了一個trace point。

可以看到,一個trace event的定義需要涉及到起碼兩個頭文件。

史上最長宏定義

你以為就這么簡單嗎?當然不是,作為有多年閱讀c語言代碼的老司機,看到真正的定義,我都差點沒有吐出來。。。

好了,不扯淡了。怎么能很好的解釋這個宏展開的過程呢?還是用一張圖吧。倒吸一口氣,準備一次無盡的代碼閱讀。

終于完了,也不知道有沒有漏掉什么。。。大家如果真的想要看實際代碼中展開后的代碼,可以運行

make samples/trace_events/trace-events-sample.i

生成的文件是經過預處理后得到的源代碼。不過相信我,你可能不太會愿意去看這個(捂臉)

回過頭來再看這展開,讓我們來總結一下這個過程:

一共包含了兩個頭文件:linux/tracepoint.h 和 trace/define_trace.h

在trace/definetrace.h中,反復定義了TRACEEVENT且再次包含samples/trace_events/trace-events-sample.h,實現了一個宏定義多次展開的效果

究竟定義了什么?

哪怕有了上面這個圖,我想大部分人也是不會去看的。或者說,看了可能也不知道這些宏展開究竟定義了些什么?

幫人幫到底,送佛送到西

既然都幫大家做了宏展開,那我就干脆再用一張圖展示一下這么多宏定義究竟定義了些什么。

經過了一番云里霧里的宏展開,實際上就是(主要)定義出了這么一個數據結構 --traceeventcall。而且這個數據結構關聯了幾個重要的小伙伴

tracepoint

trace_event_class

trace_event

后續,我們將逐漸看到在初始化和使能的過程中,這些數據結構之間的愛恨情仇。

注冊trace_event

有了數據結構,想要使用這個功能,我們能想到的第一步就是要把相關的數據結構注冊到某個地方,這樣下次才能夠被使用到是不是?

這個秘密隱藏在了剛才宏展開的最后一次展開中,大家可以回過去搜“section("ftraceevents") &event##name;”。有內核代碼經驗的朋友可能已經猜到了,這個意思是我們把一部分的內容強制保存在了一個名為ftraceevents的section中。這些是什么呢?對了就是traceevent_call結構體的指針們。

有了這個信息,我們再來看鏈接文件的定義:

我們看到ftraceevents這個section被包含在_startftrace_events之間。那就沿著這條線繼續。

看到了么?我們依次從_start|stopftraceevents之間拿出每一個內容,再執行eventinit()。而這個類型正好是traceeventcall,和剛才的定義吻合上。

但是eventinit()里面又調用了什么call->class->rawinit(call),這是什么個鬼?別急,這個我已經給你寫好了。請跳回到剛才解釋traceeventcall的圖上找找,這個rawinit函數就是traceeventrawinit。最后這個通過registertraceevent將traceeventcall.event注冊到系統中,而這個event的類型是trace_event。

怎么樣,是不是夠刺激的?

最后我們再來展示一下trace_event注冊到系統中后的樣子吧。

trace_event結構會在兩個地方注冊:

ftraceeventlist:這個鏈表用來遍歷事件的號碼

event_hash[128]: 這個哈希表用來查找

有沒有看到其中funcs的成員第一個是之前定義的 tracerawoutput_##name?我猜這個就是最后輸出到trace文件的代碼,你覺得呢?

好了,數據結構注冊完了,接下來是什么呢?

注冊traceeventcall

在上一節中,我們看到了內核通過編譯鏈接的方法找到了traceeventcall,并且將其中的traceevent注冊到了系統中,現在我們來看看traceevent_call是如何注冊到系統中的。

這個過程就在event_init()函數下面一點。一共有兩個步驟:

添加到ftrace_events鏈表

添加到trace_array的events

第一步就在剛才的代碼片段中listadd(&call->list, &ftraceevents),而第二步則是通過函數_traceearlyaddevents()。

__trace_early_add_events() list_for_each(call, &ftrace_events, list) __trace_early_add_new_event(call, tr)

經過這次注冊,將traceeventcall和trace_array連接了起來:

創建tracefs

在使用trace工具的時候,會通過tracefs往某些文件里讀寫來控制ftrace。trace_event也不例外,所以我們要先來看一下tracefs的構建,為后續的代碼閱讀做好準備。

說起來這個過程有點繞,因為創建tracefs的地方和剛才那些注冊函數不在一個地方(系統啟動時)。

具體細節可以看源代碼,這里解釋兩點:

createeventtoplevel_files 創建了和trace event相關的根目錄的一些文件

eventcreatedir則是會對每一個tracearray->events上的traceevent_file調用,創建每個event的目錄

而這個tracearray->events則是由, 剛才看到的函數traceearlyaddnew_event()添加的。

初始化過程的梳理

到這里估計你已經暈了,沒事我自己寫得也暈了。讓我們來梳理一下整個初始化過程,明確一下這個注冊和tracefs的創建順序。

(1) 從特定的section中拿到traceeventcall數據結構,并注冊了trace_event

(2) 將traceeventcall添加到了ftrace_events鏈表

(3) 將每一個traceeventcall以traceeventfile的形式添加到trace_array.events

(4) 為每一個trace_array.events創建自己的tracefs

廢了這么大力氣我們都做了什么呢?

關聯了tracefs和traceeventfile,也就是我嗯定義的traceeventcall。

所以,每當我們操作一個tracefs文件的時候,后面就對應這相應的traceeventfile和traceeventcall了。

OK, 我們已經為tracefs的操作做好了準備,讓我們來看看打開trace event選項時的動作吧。

打開事件

在查看trace文件中的事件記錄前,我們需要使能這個事件。

echo 1 > events/sample-trace/enable

所以有個開關來控制事件。而當我們寫這個文件的時候,觸發到的內核函數就是剛才我們注冊tracefs對應的ops中的eventenablewrite。

繞暈了,其實呢就是通過某種方式設置了tracepoint結構體中的funcs成員。剛才我們在traceeventcall結構體中已經看到了tracepoint結構,這次該好好看一眼了。

主角終于登場了,經過這么一頓騷操作后,我們將之前定義好的 traceeventrawevent##name掛到了tracepoint的funcs列表中。當然我還省去了重要的一步--設置key。

輸出事件

終于到了最后了。之前說的都是定義和初始化,終于要看到調用的情況了。在例子中我們看到,當我們需要輸出一個事件時,就會調用trace_XXX()。這次該輪到它出場了。

先來看看trace_XXX這個函數的定義,它也藏在了我們剛才宏定義的展開中,這次我們仔細看一眼

每次我們調用traceXXX()函數的時候,先檢查key是否使能了,如果使能了才繼續往下走。接著我們再打開DOTRACE來看看。

聯系上上一小節的tracepoint結構體是不是能想到啥?對了,就是遍歷tracepoint->funcs數組,然后調用它們。

好了,終于完整的看完了TRACE_EVENT的定義和使用流程。小編累了,大家也累了,今天就到這里吧。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    87

    文章

    11492

    瀏覽量

    213198
  • C語言
    +關注

    關注

    180

    文章

    7630

    瀏覽量

    140933
  • 源碼
    +關注

    關注

    8

    文章

    669

    瀏覽量

    30236

原文標題:Linux TraceEvent - 我見過的史上最長宏定義

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    明電子創業板IPO獲得受理

    近日,深交所官網顯示,成都明電子股份有限公司(以下簡稱“明電子”)創業板IPO獲得受理。
    的頭像 發表于 06-06 11:16 ?446次閱讀

    如何使用Linux映像在IMX8ULP上啟用自定義logo?

    (logo_linux_clut224.ppm)帶有自定義 LOGO。 1.我已將默認徽標 logo_linux_cult224.ppm(路徑 -/home/user/Linux_
    發表于 03-31 06:30

    嵌入式學習-飛凌嵌入式ElfBoard ELF 1板卡-Linux驅動模塊之帶參數的驅動模塊

    命令行或配置文件進行配置。驅動模塊參數提供了一種動態配置和調整驅動行為的方式。 在Linux內核中,驅動模塊參數通常使用module_param進行定義和注冊。下面是一些常用的驅動模塊參數相關的
    發表于 03-13 09:52

    嵌入式學習-飛凌嵌入式ElfBoard ELF 1板卡-Linux驅動模塊之helloworld驅動

    ((alias(#init_fn))); module_init()接受一個初始化函數作為參數,并將其定義為內聯函數__initcall_##init_fn##_wrapper()。然后,它
    發表于 03-12 10:35

    飛凌嵌入式ElfBoard ELF 1板卡-Linux驅動模塊之helloworld驅動

    )));module_init()接受一個初始化函數作為參數,并將其定義為內聯函數__initcall_##init_fn##_wrapper()。然后,它使用__attribute__((alias
    發表于 03-12 10:15

    迅為RK3588開發板實時系統編譯-Preemption系統/ Xenomai系統編譯-設置屏幕配置

    。 如下圖所示: 在上圖中分別定義了不同屏幕的定義。我們如果想要連接某個屏幕,使能對應的屏幕定義即可。如果想要設置多屏顯示,請參考《【北
    發表于 01-14 16:19

    const定義的是不是常量

    C語言是如何定義常量的?const定義的算不算是常量? 常見的有這么幾種方式。 首先就是定義,使用 define 來定義
    的頭像 發表于 01-14 11:35 ?393次閱讀

    定義后面能不能加分號

    用define定義,最后需不需要加分號?
    的頭像 發表于 01-06 16:35 ?557次閱讀

    網線最長多少米不影響網速

    網線長度對網速的影響主要體現在信號衰減、帶寬限制以及電磁干擾等方面。在理論上,為了保證網絡的穩定性和數據傳輸的可靠性,網線的最長推薦傳輸距離是100米。以下是對這一結論的詳細解釋: 信號衰減:網線在
    的頭像 發表于 01-03 10:14 ?2599次閱讀

    DS92LV2421支持最長的傳輸距離只有10m嗎?

    DS92LV2421支持最長的傳輸距離只有10m嗎
    發表于 12-03 08:11

    imx6ull裸機編程,使用定義無法驅動,使用指針就可以驅動

    當我使用定義來訪問imx6ull的寄存器,控制GPIO5_IO3輸出高低電平控制LED時,程序燒錄進去后沒有反應。但是當我使用指針來訪問寄存器,LED可以正常驅動,請問這是什么原因?除了寄存器訪問
    發表于 11-04 17:59

    C語言中最常見的定義寫法

    如果讓你用C語言寫個定義,我相信大部分同學順手就能寫出define。
    的頭像 發表于 10-28 11:12 ?790次閱讀

    SV中define定義的用法

    SV中使用預處理指令`define來定義可以用來創建文本替換。根據場景不同,`define主要用來定義常量、簡化復雜的表達式或代碼段以及提高代碼的可移植性。其基本語法為:
    的頭像 發表于 10-21 14:22 ?1759次閱讀

    linux開發板與樹莓派的區別

    定義和用途 Linux開發板:Linux開發板是一種基于Linux操作系統的嵌入式開發板,通常用于工業自動化、物聯網、智能家居等領域。 樹莓派:樹莓派(Raspberry Pi)是一種
    的頭像 發表于 08-30 15:34 ?1845次閱讀

    科技擬收購APCB 100%股權

    科技近期發布重要公告,宣布其計劃通過全資子公司新加坡勝及PSL,以不超過2.787億元人民幣的現金,全面收購APCB Electronics(Thailand)Co.,Ltd.(簡稱APCB)的100%股權。此次收購標志著勝
    的頭像 發表于 08-12 15:06 ?1036次閱讀
    主站蜘蛛池模板: 两人性潮高免费视频看 | 97色在线播放 | 男男互攻h啪肉np文厉世 | 欧美一卡2卡三卡4卡5卡免费观看 | 免费午夜在线视频 | 中文字幕一区二区三区在线观看 | 欧美成人自拍视频 | 91亚洲视频| 日产乱码免费一卡二卡在线 | 精品久久久久久中文字幕欧美 | 亚洲欧美一区二区三区另类 | 2022国产情侣真实露脸在线 | 美国bj69video18视频 | 综合色图| 国产亚洲综合色就色 | 国产伦精品一区二区三区免 | 午夜国产高清精品一区免费 | 成年全黄大色大黄 | 欧美a一| 米奇777四色精品人人爽 | 精品国产_亚洲人成在线高清 | 国产欧美精品午夜在线播放 | 亚洲美女黄视频 | 久久久久久久影院 | 国产精品嫩草影院一二三区 | 好爽~~~~嗯~~~再快点明星 | 黄色录像大全 | 成人国产亚洲欧美成人综合网 | 国产全部理论片线观看 | 影院成人区精品一区二区婷婷丽春院影视 | 丁香网五月 | 一区二区中文字幕亚洲精品 | 我被黑人巨大开嫩苞在线观看 | 看片免费黄| 午夜爽爽爽 | 日韩操 | 91av成人| 两性午夜欧美高清做性 | 日韩黄色录像 | 日韩毛片 | 亚洲成人激情电影 |