一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

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

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

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

Linux TraceEvent - 史上最長(zhǎng)宏定義

Linux閱碼場(chǎng) ? 來(lái)源:Linuxer ? 2020-06-28 09:34 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

TraceEvent是內(nèi)核中一種探測(cè)的機(jī)制,據(jù)說(shuō)在不使能的時(shí)候是沒(méi)有損耗的。據(jù)說(shuō)使用起來(lái)挺簡(jiǎn)單,但是要看懂著實(shí)需要花些力氣。

例子

從例子中學(xué)習(xí),一般都是比較好的方法。內(nèi)核開(kāi)發(fā)者也比較nice,在內(nèi)核源碼samples/trace_events目錄下就有這么一個(gè)例子。

其中文件一共有三個(gè):

這個(gè)例子以內(nèi)核模塊的形式存在,所以只要執(zhí)行make就可以編譯完成。

總的來(lái)說(shuō),要定義和使用tracepoint,只要做兩點(diǎn)。

用TRACE_EVENT來(lái)定義一個(gè)新的tracepoint

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

有了例子我們就要跑一跑,來(lái)看看如何使用的。

首先我們要編譯出我們的例子,這時(shí)候需要加上打開(kāi)兩個(gè)編譯配置

CONFIG_SAMPLES

CONFIGSAMPLETRACE_EVENTS

編譯

make M=samples/trace_events

然后加載這個(gè)例子模塊

modprobe trace-events-sample

因?yàn)橛脩?a target="_blank">接口在debugfs上,所以還要確保debugfs掛載了。

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

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

接下來(lái),我們就可以打開(kāi)這個(gè)探測(cè)時(shí)間,并且查看探測(cè)的輸出了。

cd /sys/kernel/debug/tracing

echo 1 > events/sample-trace/enable

cat trace

echo 0 > events/sample-trace/enable

通過(guò)cat trace觀察,可以看出系統(tǒng)運(yùn)行時(shí)的一些狀態(tài)。

讓我們進(jìn)一步再來(lái)看看events/sample-trace這個(gè)目錄:

可以看到

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

每一個(gè)TRACE_EVENT都有一個(gè)自己的目錄

源文件中trace_XXX的函數(shù)就是執(zhí)行探測(cè)記錄的地方了。那么這些函數(shù)是怎么定義的呢?

TRACE_EVENT定義

看完了例子,我們就該看代碼實(shí)現(xiàn)了。講真,這是我見(jiàn)過(guò)的最長(zhǎng)的宏展開(kāi)了。之前在qemu上看到的那個(gè)hmp-command和這個(gè)比起來(lái)簡(jiǎn)直就是個(gè)小屁孩。

先來(lái)看一下例子中是如何定義一個(gè)trace event的。和其他定義不同,定義trace event的定義在頭文件,而非源文件。我把trace-events-sample.h文件做一個(gè)簡(jiǎn)要的打開(kāi)。

中間我省略了很多TRACEEVENT及其變體,每一個(gè)TRACEEVENT對(duì)應(yīng)了一個(gè)trace point。

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

史上最長(zhǎng)宏定義

你以為就這么簡(jiǎn)單嗎?當(dāng)然不是,作為有多年閱讀c語(yǔ)言代碼的老司機(jī),看到真正的定義,我都差點(diǎn)沒(méi)有吐出來(lái)。。。

好了,不扯淡了。怎么能很好的解釋這個(gè)宏展開(kāi)的過(guò)程呢?還是用一張圖吧。倒吸一口氣,準(zhǔn)備一次無(wú)盡的代碼閱讀。

終于完了,也不知道有沒(méi)有漏掉什么。。。大家如果真的想要看實(shí)際代碼中展開(kāi)后的代碼,可以運(yùn)行

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

生成的文件是經(jīng)過(guò)預(yù)處理后得到的源代碼。不過(guò)相信我,你可能不太會(huì)愿意去看這個(gè)(捂臉)

回過(guò)頭來(lái)再看這展開(kāi),讓我們來(lái)總結(jié)一下這個(gè)過(guò)程:

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

在trace/definetrace.h中,反復(fù)定義了TRACEEVENT且再次包含samples/trace_events/trace-events-sample.h,實(shí)現(xiàn)了一個(gè)宏定義多次展開(kāi)的效果

究竟定義了什么?

哪怕有了上面這個(gè)圖,我想大部分人也是不會(huì)去看的。或者說(shuō),看了可能也不知道這些宏展開(kāi)究竟定義了些什么?

幫人幫到底,送佛送到西

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

經(jīng)過(guò)了一番云里霧里的宏展開(kāi),實(shí)際上就是(主要)定義出了這么一個(gè)數(shù)據(jù)結(jié)構(gòu) --traceeventcall。而且這個(gè)數(shù)據(jù)結(jié)構(gòu)關(guān)聯(lián)了幾個(gè)重要的小伙伴

tracepoint

trace_event_class

trace_event

后續(xù),我們將逐漸看到在初始化和使能的過(guò)程中,這些數(shù)據(jù)結(jié)構(gòu)之間的愛(ài)恨情仇。

注冊(cè)trace_event

有了數(shù)據(jù)結(jié)構(gòu),想要使用這個(gè)功能,我們能想到的第一步就是要把相關(guān)的數(shù)據(jù)結(jié)構(gòu)注冊(cè)到某個(gè)地方,這樣下次才能夠被使用到是不是?

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

有了這個(gè)信息,我們?cè)賮?lái)看鏈接文件的定義:

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

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

但是eventinit()里面又調(diào)用了什么call->class->rawinit(call),這是什么個(gè)鬼?別急,這個(gè)我已經(jīng)給你寫(xiě)好了。請(qǐng)?zhí)氐絼偛沤忉宼raceeventcall的圖上找找,這個(gè)rawinit函數(shù)就是traceeventrawinit。最后這個(gè)通過(guò)registertraceevent將traceeventcall.event注冊(cè)到系統(tǒng)中,而這個(gè)event的類型是trace_event。

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

最后我們?cè)賮?lái)展示一下trace_event注冊(cè)到系統(tǒng)中后的樣子吧。

trace_event結(jié)構(gòu)會(huì)在兩個(gè)地方注冊(cè):

ftraceeventlist:這個(gè)鏈表用來(lái)遍歷事件的號(hào)碼

event_hash[128]: 這個(gè)哈希表用來(lái)查找

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

好了,數(shù)據(jù)結(jié)構(gòu)注冊(cè)完了,接下來(lái)是什么呢?

注冊(cè)traceeventcall

在上一節(jié)中,我們看到了內(nèi)核通過(guò)編譯鏈接的方法找到了traceeventcall,并且將其中的traceevent注冊(cè)到了系統(tǒng)中,現(xiàn)在我們來(lái)看看traceevent_call是如何注冊(cè)到系統(tǒng)中的。

這個(gè)過(guò)程就在event_init()函數(shù)下面一點(diǎn)。一共有兩個(gè)步驟:

添加到ftrace_events鏈表

添加到trace_array的events

第一步就在剛才的代碼片段中l(wèi)istadd(&call->list, &ftraceevents),而第二步則是通過(guò)函數(shù)_traceearlyaddevents()。

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

經(jīng)過(guò)這次注冊(cè),將traceeventcall和trace_array連接了起來(lái):

創(chuàng)建tracefs

在使用trace工具的時(shí)候,會(huì)通過(guò)tracefs往某些文件里讀寫(xiě)來(lái)控制ftrace。trace_event也不例外,所以我們要先來(lái)看一下tracefs的構(gòu)建,為后續(xù)的代碼閱讀做好準(zhǔn)備。

說(shuō)起來(lái)這個(gè)過(guò)程有點(diǎn)繞,因?yàn)閯?chuàng)建tracefs的地方和剛才那些注冊(cè)函數(shù)不在一個(gè)地方(系統(tǒng)啟動(dòng)時(shí))。

具體細(xì)節(jié)可以看源代碼,這里解釋兩點(diǎn):

createeventtoplevel_files 創(chuàng)建了和trace event相關(guān)的根目錄的一些文件

eventcreatedir則是會(huì)對(duì)每一個(gè)tracearray->events上的traceevent_file調(diào)用,創(chuàng)建每個(gè)event的目錄

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

初始化過(guò)程的梳理

到這里估計(jì)你已經(jīng)暈了,沒(méi)事我自己寫(xiě)得也暈了。讓我們來(lái)梳理一下整個(gè)初始化過(guò)程,明確一下這個(gè)注冊(cè)和tracefs的創(chuàng)建順序。

(1) 從特定的section中拿到traceeventcall數(shù)據(jù)結(jié)構(gòu),并注冊(cè)了trace_event

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

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

(4) 為每一個(gè)trace_array.events創(chuàng)建自己的tracefs

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

關(guān)聯(lián)了tracefs和traceeventfile,也就是我嗯定義的traceeventcall。

所以,每當(dāng)我們操作一個(gè)tracefs文件的時(shí)候,后面就對(duì)應(yīng)這相應(yīng)的traceeventfile和traceeventcall了。

OK, 我們已經(jīng)為tracefs的操作做好了準(zhǔn)備,讓我們來(lái)看看打開(kāi)trace event選項(xiàng)時(shí)的動(dòng)作吧。

打開(kāi)事件

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

echo 1 > events/sample-trace/enable

所以有個(gè)開(kāi)關(guān)來(lái)控制事件。而當(dāng)我們寫(xiě)這個(gè)文件的時(shí)候,觸發(fā)到的內(nèi)核函數(shù)就是剛才我們注冊(cè)tracefs對(duì)應(yīng)的ops中的eventenablewrite。

繞暈了,其實(shí)呢就是通過(guò)某種方式設(shè)置了tracepoint結(jié)構(gòu)體中的funcs成員。剛才我們?cè)趖raceeventcall結(jié)構(gòu)體中已經(jīng)看到了tracepoint結(jié)構(gòu),這次該好好看一眼了。

主角終于登場(chǎng)了,經(jīng)過(guò)這么一頓騷操作后,我們將之前定義好的 traceeventrawevent##name掛到了tracepoint的funcs列表中。當(dāng)然我還省去了重要的一步--設(shè)置key。

輸出事件

終于到了最后了。之前說(shuō)的都是定義和初始化,終于要看到調(diào)用的情況了。在例子中我們看到,當(dāng)我們需要輸出一個(gè)事件時(shí),就會(huì)調(diào)用trace_XXX()。這次該輪到它出場(chǎng)了。

先來(lái)看看trace_XXX這個(gè)函數(shù)的定義,它也藏在了我們剛才宏定義的展開(kāi)中,這次我們仔細(xì)看一眼

每次我們調(diào)用traceXXX()函數(shù)的時(shí)候,先檢查key是否使能了,如果使能了才繼續(xù)往下走。接著我們?cè)俅蜷_(kāi)DOTRACE來(lái)看看。

聯(lián)系上上一小節(jié)的tracepoint結(jié)構(gòu)體是不是能想到啥?對(duì)了,就是遍歷tracepoint->funcs數(shù)組,然后調(diào)用它們。

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

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(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)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11508

    瀏覽量

    213558
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7632

    瀏覽量

    141439
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    671

    瀏覽量

    30295

原文標(biāo)題:Linux TraceEvent - 我見(jiàn)過(guò)的史上最長(zhǎng)宏定義

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

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

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    明電子創(chuàng)業(yè)板IPO獲得受理

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

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

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

    嵌入式學(xué)習(xí)-飛凌嵌入式ElfBoard ELF 1板卡-Linux驅(qū)動(dòng)模塊之帶參數(shù)的驅(qū)動(dòng)模塊

    命令行或配置文件進(jìn)行配置。驅(qū)動(dòng)模塊參數(shù)提供了一種動(dòng)態(tài)配置和調(diào)整驅(qū)動(dòng)行為的方式。 在Linux內(nèi)核中,驅(qū)動(dòng)模塊參數(shù)通常使用module_param進(jìn)行定義和注冊(cè)。下面是一些常用的驅(qū)動(dòng)模塊參數(shù)相關(guān)的
    發(fā)表于 03-13 09:52

    嵌入式學(xué)習(xí)-飛凌嵌入式ElfBoard ELF 1板卡-Linux驅(qū)動(dòng)模塊之helloworld驅(qū)動(dòng)

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

    飛凌嵌入式ElfBoard ELF 1板卡-Linux驅(qū)動(dòng)模塊之helloworld驅(qū)動(dòng)

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

    迅為RK3588開(kāi)發(fā)板實(shí)時(shí)系統(tǒng)編譯-Preemption系統(tǒng)/ Xenomai系統(tǒng)編譯-設(shè)置屏幕配置

    。 如下圖所示: 在上圖中分別定義了不同屏幕的定義。我們?nèi)绻胍B接某個(gè)屏幕,使能對(duì)應(yīng)的屏幕定義即可。如果想要設(shè)置多屏顯示,請(qǐng)參考《【北
    發(fā)表于 01-14 16:19

    const定義的是不是常量

    C語(yǔ)言是如何定義常量的?const定義的算不算是常量? 常見(jiàn)的有這么幾種方式。 首先就是定義,使用 define 來(lái)定義。
    的頭像 發(fā)表于 01-14 11:35 ?419次閱讀

    定義后面能不能加分號(hào)

    用define定義,最后需不需要加分號(hào)?
    的頭像 發(fā)表于 01-06 16:35 ?573次閱讀

    網(wǎng)線最長(zhǎng)多少米不影響網(wǎng)速

    網(wǎng)線長(zhǎng)度對(duì)網(wǎng)速的影響主要體現(xiàn)在信號(hào)衰減、帶寬限制以及電磁干擾等方面。在理論上,為了保證網(wǎng)絡(luò)的穩(wěn)定性和數(shù)據(jù)傳輸?shù)目煽啃?,網(wǎng)線的最長(zhǎng)推薦傳輸距離是100米。以下是對(duì)這一結(jié)論的詳細(xì)解釋: 信號(hào)衰減:網(wǎng)線在
    的頭像 發(fā)表于 01-03 10:14 ?2764次閱讀

    DS92LV2421支持最長(zhǎng)的傳輸距離只有10m嗎?

    DS92LV2421支持最長(zhǎng)的傳輸距離只有10m嗎
    發(fā)表于 12-03 08:11

    imx6ull裸機(jī)編程,使用定義無(wú)法驅(qū)動(dòng),使用指針就可以驅(qū)動(dòng)

    當(dāng)我使用定義來(lái)訪問(wèn)imx6ull的寄存器,控制GPIO5_IO3輸出高低電平控制LED時(shí),程序燒錄進(jìn)去后沒(méi)有反應(yīng)。但是當(dāng)我使用指針來(lái)訪問(wèn)寄存器,LED可以正常驅(qū)動(dòng),請(qǐng)問(wèn)這是什么原因?除了寄存器訪問(wèn)
    發(fā)表于 11-04 17:59

    C語(yǔ)言中最常見(jiàn)的定義寫(xiě)法

    如果讓你用C語(yǔ)言寫(xiě)個(gè)定義,我相信大部分同學(xué)順手就能寫(xiě)出define。
    的頭像 發(fā)表于 10-28 11:12 ?821次閱讀

    SV中define定義的用法

    SV中使用預(yù)處理指令`define來(lái)定義,可以用來(lái)創(chuàng)建文本替換。根據(jù)場(chǎng)景不同,`define主要用來(lái)定義常量、簡(jiǎn)化復(fù)雜的表達(dá)式或代碼段以及提高代碼的可移植性。其基本語(yǔ)法為:
    的頭像 發(fā)表于 10-21 14:22 ?1863次閱讀

    linux開(kāi)發(fā)板與樹(shù)莓派的區(qū)別

    定義和用途 Linux開(kāi)發(fā)板:Linux開(kāi)發(fā)板是一種基于Linux操作系統(tǒng)的嵌入式開(kāi)發(fā)板,通常用于工業(yè)自動(dòng)化、物聯(lián)網(wǎng)、智能家居等領(lǐng)域。 樹(shù)莓派:樹(shù)莓派(Raspberry Pi)是一種
    的頭像 發(fā)表于 08-30 15:34 ?1932次閱讀

    科技擬收購(gòu)APCB 100%股權(quán)

    科技近期發(fā)布重要公告,宣布其計(jì)劃通過(guò)全資子公司新加坡勝及PSL,以不超過(guò)2.787億元人民幣的現(xiàn)金,全面收購(gòu)APCB Electronics(Thailand)Co.,Ltd.(簡(jiǎn)稱APCB)的100%股權(quán)。此次收購(gòu)標(biāo)志著勝
    的頭像 發(fā)表于 08-12 15:06 ?1084次閱讀