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

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

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

如何評(píng)估CPU硬件效率?CPU硬件運(yùn)行效率介紹

dyquk4xk2p3d ? 來(lái)源:開(kāi)發(fā)內(nèi)功修煉 ? 2023-05-17 10:04 ? 次閱讀

提到CPU性能,大部分同學(xué)想到的都是CPU利用率,這個(gè)指標(biāo)確實(shí)應(yīng)該首先被關(guān)注。但是除了利用率之外,還有很容易被人忽視的指標(biāo),就是指令的運(yùn)行效率。如果運(yùn)行效率不高,那CPU利用率再忙也都是瞎忙,產(chǎn)出并不高。

這就好比人,每天都是很忙,但其實(shí)每天的效率并不一樣。有的時(shí)候一天干了很多事情,但有的時(shí)候只是瞎忙了一天,回頭一看,啥也沒(méi)干!

一、CPU 硬件運(yùn)行效率

那啥是CPU的運(yùn)行效率呢?介紹這個(gè)之前我們得先來(lái)簡(jiǎn)單回顧下CPU的構(gòu)成和工作原理。CPU在生產(chǎn)過(guò)程結(jié)束后,在硬件上就被***刻成了各種各樣的模塊。

8fb92e14-f44f-11ed-90ce-dac502259ad0.png

在上面的物理結(jié)構(gòu)圖中,可以看到每個(gè)物理核和L3 Cache的分布情況。另外就是在每個(gè)物理核中,還包括了更多組件。每個(gè)核都會(huì)集成自己獨(dú)占使用的寄存器和緩存,其中緩存包括L1 data、L1 code 和L2。

8ff6911e-f44f-11ed-90ce-dac502259ad0.png

服務(wù)程序在運(yùn)行的過(guò)程中,就是CPU核不斷地從存儲(chǔ)中獲取要執(zhí)行的指令,以及需要運(yùn)算的數(shù)據(jù)。這里所謂的存儲(chǔ)包括寄存器、L1 data緩存、L1 code緩存、L2 緩存、L3緩存,以及內(nèi)存。 當(dāng)一個(gè)服務(wù)程序被啟動(dòng)的時(shí)候,它會(huì)通過(guò)缺頁(yè)中斷的方式被加載到內(nèi)存中。當(dāng) CPU 運(yùn)行服務(wù)時(shí),它不斷從內(nèi)存讀取指令和數(shù)據(jù),進(jìn)行計(jì)算處理,然后將結(jié)果再寫(xiě)回內(nèi)存。

900aa140-f44f-11ed-90ce-dac502259ad0.png

不同的 CPU 流水線不同。在經(jīng)典的 CPU 的流水線中,每個(gè)指令周期通常包括取指、譯碼、執(zhí)行和訪存幾個(gè)階段。

在取指階段,CPU 從內(nèi)存中取出指令,將其加載到指令寄存器中。

在譯碼階段,CPU 解碼指令,確定要執(zhí)行的操作類(lèi)型,并將操作數(shù)加載到寄存器中。

在執(zhí)行階段,CPU 執(zhí)行指令,并將結(jié)果存儲(chǔ)在寄存器中。

在訪存階段,CPU 根據(jù)需要將數(shù)據(jù)從內(nèi)存寫(xiě)入寄存器中,或?qū)⒓拇嫫髦械臄?shù)據(jù)寫(xiě)回內(nèi)存。

但,內(nèi)存的訪問(wèn)速度是非常慢的。CPU一個(gè)指令周期一般只是零點(diǎn)幾個(gè)納秒,但是對(duì)于內(nèi)存來(lái)說(shuō),即使是最快的順序 IO,那也得 10 納秒左右,如果碰上隨機(jī)IO,那就是 30-40 納秒左右的開(kāi)銷(xiāo)。

所以CPU為了加速運(yùn)算,自建了臨時(shí)數(shù)據(jù)存儲(chǔ)倉(cāng)庫(kù)。就是我們上面提到的各種緩存,包括每個(gè)核都有的寄存器、L1 data、L1 code 和L2緩存,也包括整個(gè)CPU共享的L3,還包括專(zhuān)門(mén)用于虛擬內(nèi)存到物理內(nèi)存地址轉(zhuǎn)換的TLB緩存。

拿最快的寄存器來(lái)說(shuō),耗時(shí)大約是零點(diǎn)幾納秒,和CPU就工作在一個(gè)節(jié)奏下了。再往下的L1大約延遲在 2 ns 左右,L2大約 4 ns 左右,依次上漲。

但速度比較慢的存儲(chǔ)也有個(gè)好處,離CPU核更遠(yuǎn),可以把容量做到更大。所以CPU訪問(wèn)的存儲(chǔ)在邏輯上是一個(gè)金字塔的結(jié)構(gòu)。越靠近金字塔尖的存儲(chǔ),其訪問(wèn)速度越快,但容量比較小。越往下雖然速度略慢,但是存儲(chǔ)體積更大。

901ac89a-f44f-11ed-90ce-dac502259ad0.png

基本原理就介紹這么多?,F(xiàn)在我們開(kāi)始思考指令運(yùn)行效率。根據(jù)上述金字塔圖我們可以很清楚地看到,如果服務(wù)程序運(yùn)行時(shí)所需要的指令存儲(chǔ)都位于金字塔上方的話,那服務(wù)運(yùn)行的效率就高。如果程序?qū)懙牟缓?,或者?nèi)核頻繁地把進(jìn)程在不同的物理核之間遷移(不同核的L1和L2等緩存不是共享的),那上方的緩存就會(huì)命中率變低,更多的請(qǐng)求穿透到L3,甚至是更下方的內(nèi)存中訪問(wèn),程序的運(yùn)行效率就會(huì)變差。

那如何衡量指令運(yùn)行效率呢?指標(biāo)主要有以下兩類(lèi)

第一類(lèi)是CPI和IPC。

CPI全稱(chēng)是cycle per instruction,指的是平均每條指令的時(shí)鐘周期個(gè)數(shù)。IPC的全稱(chēng)是instruction per cycle,表示每時(shí)鐘周期運(yùn)行多少個(gè)指令。這兩個(gè)指標(biāo)可以幫助我們分析我們的可執(zhí)行程序運(yùn)行的快還是慢。由于這二位互為倒數(shù),所以實(shí)踐中只關(guān)注一個(gè)CPI就夠了。

CPI 指標(biāo)可以讓我們從整體上對(duì)程序的運(yùn)行速度有一個(gè)把握。假如我們的程序運(yùn)行緩存命中率高,大部分?jǐn)?shù)據(jù)都在緩存中能訪問(wèn)到,那 CPI 就會(huì)比較的低。假如說(shuō)我們的程序的局部性原理把握的不好,或者是說(shuō)內(nèi)核的調(diào)度算法有問(wèn)題,那很有可能執(zhí)行同樣的指令就需要更多的CPU周期,程序的性能也會(huì)表現(xiàn)的比較的差,CPI 指標(biāo)也會(huì)偏高。

第二類(lèi)是緩存命中率。

緩存命中率指標(biāo)分析的是程序運(yùn)行時(shí)讀取數(shù)據(jù)時(shí)有多少?zèng)]有被緩存兜住,而穿透訪問(wèn)到內(nèi)存中了。穿透到內(nèi)存中訪問(wèn)速度會(huì)慢很多。所以程序運(yùn)行時(shí)的 Cachemiss 指標(biāo)就是越低越好了。

二、如何評(píng)估CPU硬件效率

上一小節(jié)我們說(shuō)到CPU硬件工作效率的指標(biāo)主要有 CPI 和緩存命中率。那么我們?cè)撊绾潍@取這些指標(biāo)呢?

2.1 使用 perf 工具

第一個(gè)辦法是采用 Linux 默認(rèn)自帶的 perf 工具。使用 perf list 可以查看當(dāng)前系統(tǒng)上支持的硬件事件指標(biāo)。

#perflisthwcache
Listofpre-definedevents(tobeusedin-e):

branch-instructionsORbranches[Hardwareevent]
branch-misses[Hardwareevent]
bus-cycles[Hardwareevent]
cache-misses[Hardwareevent]
cache-references[Hardwareevent]
cpu-cyclesORcycles[Hardwareevent]
instructions[Hardwareevent]
ref-cycles[Hardwareevent]

L1-dcache-load-misses[Hardwarecacheevent]
L1-dcache-loads[Hardwarecacheevent]
L1-dcache-stores[Hardwarecacheevent]
L1-icache-load-misses[Hardwarecacheevent]
branch-load-misses[Hardwarecacheevent]
branch-loads[Hardwarecacheevent]
dTLB-load-misses[Hardwarecacheevent]
dTLB-loads[Hardwarecacheevent]
dTLB-store-misses[Hardwarecacheevent]
dTLB-stores[Hardwarecacheevent]
iTLB-load-misses[Hardwarecacheevent]
iTLB-loads[Hardwarecacheevent]

上述輸出中我們挑幾個(gè)重要的來(lái)解釋一下

cpu-cycles: 消耗的CPU周期

instructions: 執(zhí)行的指令計(jì)數(shù),結(jié)合cpu-cycles可以計(jì)算出CPI(每條指令需要消耗的平均周期數(shù))

L1-dcache-loads: 一級(jí)數(shù)據(jù)緩存讀取次數(shù)

L1-dcache-load-missed: 一級(jí)數(shù)據(jù)緩存讀取失敗次數(shù),結(jié)合L1-dcache-loads可以計(jì)算出L1級(jí)數(shù)據(jù)緩存命中率

dTLB-loads:dTLB緩存讀取次數(shù)

dTLB-load-misses:dTLB緩存讀取失敗次數(shù),結(jié)合dTLB-loads同樣可以算出緩存命中率

使用 perf stat 命令可以統(tǒng)計(jì)當(dāng)前系統(tǒng)或者指定進(jìn)程的上面這些指標(biāo)。直接使用 perf stat 可以統(tǒng)計(jì)到CPI。(如果要統(tǒng)計(jì)指定進(jìn)程的話只需要多個(gè) -p 參數(shù),寫(xiě)名 pid 就可以了)

#perfstatsleep5
Performancecounterstatsfor'sleep5':
......
1,758,466cycles#2.575GHz
871,474instructions#0.50insnpercycle

從上述結(jié)果 instructions 后面的注釋可以看出,當(dāng)前系統(tǒng)的 IPC 指標(biāo)是 0.50,也就是說(shuō)平均一個(gè) CPU 周期可以執(zhí)行 0.5 個(gè)指令。前面我們說(shuō)過(guò) CPI 和 IPC 互為倒數(shù),所以 1/0.5 我們可以計(jì)算出 CPI 指標(biāo)為 2。也就是說(shuō)平均一個(gè)指令需要消耗 2 個(gè)CPU周期。

我們?cè)賮?lái)看看 L1 和 dTLB 的緩存命中率情況,這次需要在 perf stat 后面跟上 -e 選項(xiàng)來(lái)指定要觀測(cè)的指標(biāo)了,因?yàn)檫@幾個(gè)指標(biāo)默認(rèn)都不輸出。

#perfstat-eL1-dcache-load-misses,L1-dcache-loads,dTLB-load-misses,dTLB-loadssleep5
Performancecounterstatsfor'sleep5':
22,578L1-dcache-load-misses#10.22%ofallL1-dcacheaccesses
220,911L1-dcache-loads
2,101dTLB-load-misses#0.95%ofalldTLBcacheaccesses
220,911dTLB-loads

上述結(jié)果中 L1-dcache-load-misses 次數(shù)為22,578,總的 L1-dcache-loads 為 220,911。可以算出 L1-dcache 的緩存訪問(wèn)失敗率大約是 10.22%。同理我們可以算出 dTLB cache 的訪問(wèn)失敗率是 0.95。這兩個(gè)指標(biāo)雖然已經(jīng)不高了,但是實(shí)踐中仍然是越低越好。

2.2 直接使用內(nèi)核提供的系統(tǒng)調(diào)用

雖然 perf 給我們提供了非常方便的用法。但是在某些業(yè)務(wù)場(chǎng)景中,你可能仍然需要自己編程實(shí)現(xiàn)數(shù)據(jù)的獲取。這時(shí)候就只能繞開(kāi) perf 直接使用內(nèi)核提供的系統(tǒng)調(diào)用來(lái)獲取這些硬件指標(biāo)了。

開(kāi)發(fā)步驟大概包含這么兩個(gè)步驟

第一步:調(diào)用 perf_event_open 創(chuàng)建 perf 文件描述符

第二步:定時(shí) read 讀取 perf 文件描述符獲取數(shù)據(jù)

其核心代碼大概如下。為了避免干擾,我只保留了主干。

intmain()
{
//第一步:創(chuàng)建perf文件描述符
structperf_event_attrattr;
attr.type=PERF_TYPE_HARDWARE;//表示監(jiān)測(cè)硬件
attr.config=PERF_COUNT_HW_INSTRUCTIONS;//標(biāo)志監(jiān)測(cè)指令數(shù)

//第一個(gè)參數(shù)pid=0表示只檢測(cè)當(dāng)前進(jìn)程
//第二個(gè)參數(shù)cpu=-1表示檢測(cè)所有cpu核
intfd=perf_event_open(&attr,0,-1,-1,0);

//第二步:定時(shí)獲取指標(biāo)計(jì)數(shù)
while(1)
{
read(fd,&instructions,sizeof(instructions));
...
}
}

在源碼中首先聲明了一個(gè)創(chuàng)建 perf 文件所需要的 perf_event_attr 參數(shù)對(duì)象。這個(gè)對(duì)象中 type 設(shè)置為 PERF_TYPE_HARDWARE 表示監(jiān)測(cè)硬件事件。config 設(shè)置為 PERF_COUNT_HW_INSTRUCTIONS 表示要監(jiān)測(cè)指令數(shù)。

然后調(diào)用 perf_event_open系統(tǒng)調(diào)用。在該系統(tǒng)調(diào)用中,除了 perf_event_attr 對(duì)象外,pid 和 cpu 這兩個(gè)參數(shù)也是非常的關(guān)鍵。其中 pid 為 -1 表示要監(jiān)測(cè)所有進(jìn)程,為 0 表示監(jiān)測(cè)當(dāng)前進(jìn)程,> 0 表示要監(jiān)測(cè)指定 pid 的進(jìn)程。對(duì)于 cpu 來(lái)說(shuō)。-1 表示要監(jiān)測(cè)所有的核,其它值表示只監(jiān)測(cè)指定的核。

內(nèi)核在分配到 perf_event 以后,會(huì)返回一個(gè)文件句柄fd。后面這個(gè)perf_event結(jié)構(gòu)可以通過(guò)read/write/ioctl/mmap通用文件接口來(lái)操作。

perf_event 編程有兩種使用方法,分別是計(jì)數(shù)和采樣。本文中的例子是最簡(jiǎn)單的技術(shù)。對(duì)于采樣場(chǎng)景,支持的功能更豐富,可以獲取調(diào)用棧,進(jìn)而渲染出火焰圖等更高級(jí)的功能。這種情況下就不能使用簡(jiǎn)單的 read ,需要給 perf_event 分配 ringbuffer 空間,然后通過(guò)mmap系統(tǒng)調(diào)用來(lái)讀取了。在 perf 中對(duì)應(yīng)的功能是 perf record/report 功能。

將完整的源碼編譯運(yùn)行后。

#gccmain.c-omain
#./main
instructions=1799
instructions=112654
instructions=123078
instructions=133505
...

三、perf內(nèi)部工作原理

你以為看到這里本文就結(jié)束了?大錯(cuò)特錯(cuò)!只講用法不講原理從來(lái)不是咱們開(kāi)發(fā)內(nèi)功修煉公眾號(hào)的風(fēng)格。

所以介紹完如何獲取硬件指標(biāo)后,咱們接下來(lái)也會(huì)展開(kāi)聊聊上層的軟件是如何和CPU硬件協(xié)同來(lái)獲取到底層的指令數(shù)、緩存命中率等指標(biāo)的。展開(kāi)聊聊底層原理。

CPU的硬件開(kāi)發(fā)者們也想到了軟件同學(xué)們會(huì)有統(tǒng)計(jì)觀察硬件指標(biāo)的需求。所以在硬件設(shè)計(jì)的時(shí)候,加了一類(lèi)專(zhuān)用的寄存器,專(zhuān)門(mén)用于系統(tǒng)性能監(jiān)視。關(guān)于這部分的描述參見(jiàn)Intel官方手冊(cè)的第18節(jié)。這個(gè)手冊(cè)你在網(wǎng)上可以搜到,我也會(huì)把它丟到我的讀者群里,還沒(méi)進(jìn)群的同學(xué)加我微信 zhangyanfei748527。

這類(lèi)寄存器的名字叫硬件性能計(jì)數(shù)器(PMC: Performance Monitoring Counter)。每個(gè)PMC寄存器都包含一個(gè)計(jì)數(shù)器和一個(gè)事件選擇器,計(jì)數(shù)器用于存儲(chǔ)事件發(fā)生的次數(shù),事件選擇器用于確定所要計(jì)數(shù)的事件類(lèi)型。例如,可以使用PMC寄存器來(lái)統(tǒng)計(jì) L1 緩存命中率或指令執(zhí)行周期數(shù)等。當(dāng)CPU執(zhí)行到 PMC 寄存器所指定的事件時(shí),硬件會(huì)自動(dòng)對(duì)計(jì)數(shù)器加1,而不會(huì)對(duì)程序的正常執(zhí)行造成任何干擾。

有了底層的支持,上層的 Linux 內(nèi)核就可以通過(guò)讀取這些 PMC 寄存器的值來(lái)獲取想要觀察的指標(biāo)了。整體的工作流程圖如下

902884e4-f44f-11ed-90ce-dac502259ad0.png

接下來(lái)我們?cè)購(gòu)脑创a的視角展開(kāi)看一下這個(gè)過(guò)程。

3.1 CPU PMU 的初始化

Linux 的 PMU (Performance Monitoring Unit)子系統(tǒng)是一種用于監(jiān)視和分析系統(tǒng)性能的機(jī)制。它將每一種要觀察的指標(biāo)都定義為了一個(gè) PMU,通過(guò) perf_pmu_register 函數(shù)來(lái)注冊(cè)到系統(tǒng)中。

其中對(duì)于 CPU 來(lái)說(shuō),定義了一個(gè)針對(duì) x86 架構(gòu) CPU 的 PMU,并在開(kāi)機(jī)啟動(dòng)的時(shí)候就會(huì)注冊(cè)到系統(tǒng)中。

//file:arch/x86/events/core.c
staticstructpmupmu={
.pmu_enable=x86_pmu_enable,
.read=x86_pmu_read,
...
}

staticint__initinit_hw_perf_events(void)
{
...
err=perf_pmu_register(&pmu,"cpu",PERF_TYPE_RAW);
}

3.2 perf_event_open 系統(tǒng)調(diào)用

在前面的實(shí)例代碼中,我們看到是通過(guò) perf_event_open 系統(tǒng)調(diào)用來(lái)創(chuàng)建了一個(gè) perf 文件。我們來(lái)看下這個(gè)創(chuàng)建過(guò)程都做了啥?

//file:kernel/events/core.c
SYSCALL_DEFINE5(perf_event_open,
structperf_event_attr__user*,attr_uptr,
pid_t,pid,int,cpu,int,group_fd,unsignedlong,flags)
{
...

//1.為調(diào)用者申請(qǐng)新文件句柄
event_fd=get_unused_fd_flags(f_flags);

...
//2.根據(jù)用戶參數(shù)attr,定位pmu對(duì)象,通過(guò)pmu初始化event
event=perf_event_alloc(&attr,cpu,task,group_leader,NULL,
NULL,NULL,cgroup_fd);
pmu=event->pmu;

//3.創(chuàng)建perf_event_contextctx對(duì)象,ctx保存了事件上下文的各種信息
ctx=find_get_context(pmu,task,event);


//4.創(chuàng)建一個(gè)文件,指定perf類(lèi)型文件的操作函數(shù)為perf_fops
event_file=anon_inode_getfile("[perf_event]",&perf_fops,event,
f_flags);

//5.把event安裝到ctx中
perf_install_in_context(ctx,event,event->cpu);

fd_install(event_fd,event_file);
returnevent_fd;
}

上面的代碼是 perf_event_open 的核心源碼。其中最關(guān)鍵的是 perf_event_alloc 的調(diào)用。在這個(gè)函數(shù)中,根據(jù)用戶傳入的 attr 來(lái)查找 pmu 對(duì)象?;貞洷疚牡膶?shí)例代碼,我們指定的是要監(jiān)測(cè)CPU硬件中的指令數(shù)。

structperf_event_attrattr;
attr.type=PERF_TYPE_HARDWARE;//表示監(jiān)測(cè)硬件
attr.config=PERF_COUNT_HW_INSTRUCTIONS;//標(biāo)志監(jiān)測(cè)指令數(shù)

所以這里就會(huì)定位到我們3.1節(jié)提到的 CPU PMU 對(duì)象,并用這個(gè) pmu 初始化 新event。接著再調(diào)用 anon_inode_getfile 創(chuàng)建一個(gè)真正的文件對(duì)象,并指定該文件的操作方法是 perf_fops。perf_fops 定義的操作函數(shù)如下:

//file:kernel/events/core.c
staticconststructfile_operationsperf_fops={
...
.read=perf_read,
.unlocked_ioctl=perf_ioctl,
.mmap=perf_mmap,
};

在創(chuàng)建完 perf 內(nèi)核對(duì)象后。還會(huì)觸發(fā)在perf_pmu_enable,經(jīng)過(guò)一系列的調(diào)用,最終會(huì)指定要監(jiān)測(cè)的寄存器。

perf_pmu_enable
->pmu_enable
->x86_pmu_enable
->x86_assign_hw_event
//file:arch/x86/events/core.c
staticinlinevoidx86_assign_hw_event(structperf_event*event,
structcpu_hw_events*cpuc,inti)
{
structhw_perf_event*hwc=&event->hw;
...
if(hwc->idx==INTEL_PMC_IDX_FIXED_BTS){
hwc->config_base=0;
hwc->event_base=0;
}elseif(hwc->idx>=INTEL_PMC_IDX_FIXED){
hwc->config_base=MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
hwc->event_base=MSR_ARCH_PERFMON_FIXED_CTR0+(hwc->idx-INTEL_PMC_IDX_FIXED);
hwc->event_base_rdpmc=(hwc->idx-INTEL_PMC_IDX_FIXED)|1<<30;
????}?else?{
????????hwc->config_base=x86_pmu_config_addr(hwc->idx);
hwc->event_base=x86_pmu_event_addr(hwc->idx);
hwc->event_base_rdpmc=x86_pmu_rdpmc_index(hwc->idx);
}
}

3.3 read 讀取計(jì)數(shù)

在實(shí)例代碼的第二步中,就是定時(shí)調(diào)用 read 系統(tǒng)調(diào)用來(lái)讀取指標(biāo)計(jì)數(shù)。在 3.2 節(jié)中我們看到了新創(chuàng)建出來(lái)的 perf 文件對(duì)象在內(nèi)核中的操作方法是 perf_read。

//file:kernel/events/core.c
staticconststructfile_operationsperf_fops={
...
.read=perf_read,
.unlocked_ioctl=perf_ioctl,
.mmap=perf_mmap,
};

perf_read 函數(shù)實(shí)際上支持可以同時(shí)讀取多個(gè)指標(biāo)出來(lái)。但為了描述起來(lái)簡(jiǎn)單,我只描述其讀取一個(gè)指標(biāo)時(shí)的工作流程。其調(diào)用鏈如下:

perf_read
__perf_read
perf_read_one
__perf_event_read_value
perf_event_read
__perf_event_read_cpu
perf_event_count

其中在 perf_event_read 中是要讀取硬件寄存器中的值。

staticintperf_event_read(structperf_event*event,boolgroup)
{
enumperf_event_statestate=READ_ONCE(event->state);
intevent_cpu,ret=0;
...

again:
//如果event正在運(yùn)行嘗試更新最新的數(shù)據(jù)
if(state==PERF_EVENT_STATE_ACTIVE){
...
data=(structperf_read_data){
.event=event,
.group=group,
.ret=0,
};
(void)smp_call_function_single(event_cpu,__perf_event_read,&data,1);
preempt_enable();
ret=data.ret;
}elseif(state==PERF_EVENT_STATE_INACTIVE){
...
}
returnret;
}

smp_call_function_single 這個(gè)函數(shù)是要在指定的 CPU 上運(yùn)行某個(gè)函數(shù)。因?yàn)榧拇嫫鞫际?CPU 專(zhuān)屬的,所以讀取寄存器應(yīng)該要指定 CPU 核。要運(yùn)行的函數(shù)就是其參數(shù)中指定的 __perf_event_read。在這個(gè)函數(shù)中,真正讀取了 x86 CPU 硬件寄存器。

__perf_event_read
->x86_pmu_read
->intel_pmu_read_event
->x86_perf_event_update

其中 __perf_event_read 調(diào)用到 x86 架構(gòu)這塊是通過(guò)函數(shù)指針指過(guò)來(lái)的。

//file:kernel/events/core.c
staticvoid__perf_event_read(void*info)
{
...
pmu->read(event);
}

在3.1中我們介紹過(guò)CPU 的這個(gè)pmu,它的read函數(shù)指針是指向 x86_pmu_read的。

//file:arch/x86/events/core.c
staticstructpmupmu={
...
.read=x86_pmu_read,
}

這樣就會(huì)執(zhí)行到 x86_pmu_read,最后就會(huì)調(diào)用到 x86_perf_event_update。在 x86_perf_event_update 中調(diào)用 rdpmcl 匯編指令來(lái)獲取寄存器中的值。

//file:arch/x86/events/core.c
u64x86_perf_event_update(structperf_event*event)
{
...
rdpmcl(hwc->event_base_rdpmc,new_raw_count);
returnnew_raw_count
}

最后返回到 perf_read_one 中會(huì)調(diào)用 copy_to_user 將值真正拷貝到用戶空間中,這樣我們的進(jìn)程就讀取到了寄存器中的硬件執(zhí)行計(jì)數(shù)了。

//file:kernel/events/core.c
staticintperf_read_one(structperf_event*event,
u64read_format,char__user*buf)
{

values[n++]=__perf_event_read_value(event,&enabled,&running);
...

copy_to_user(buf,values,n*sizeof(u64))
returnn*sizeof(u64);
}

總結(jié)

雖然內(nèi)存很快,但它的速度在 CPU 面前也只是個(gè)弟弟。所以 CPU 并不直接從內(nèi)存中獲取要運(yùn)行的指令和數(shù)據(jù),而是優(yōu)先使用自己的緩存。只有緩存不命中的時(shí)候才會(huì)請(qǐng)求內(nèi)存,性能也會(huì)變低。

那觀察 CPU 使用緩存效率高不高的指標(biāo)主要有 CPI 和緩存命中率幾個(gè)指標(biāo)。CPU 硬件在實(shí)現(xiàn)上,定義了專(zhuān)門(mén) PMU 模塊,其中包含專(zhuān)門(mén)用戶計(jì)數(shù)的寄存器。當(dāng)CPU執(zhí)行到 PMC 寄存器所指定的事件時(shí),硬件會(huì)自動(dòng)對(duì)計(jì)數(shù)器加1,而不會(huì)對(duì)程序的正常執(zhí)行造成任何干擾。有了底層的支持,上層的 Linux 內(nèi)核就可以通過(guò)讀取這些 PMC 寄存器的值來(lái)獲取想要觀察的指標(biāo)了。

我們可以使用 perf 來(lái)觀察,也可以直接使用內(nèi)核提供的 perf_event_open 系統(tǒng)調(diào)用獲取 perf 文件對(duì)象,然后自己來(lái)讀取。

902884e4-f44f-11ed-90ce-dac502259ad0.png







審核編輯:劉清

聲明:本文內(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)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5343

    瀏覽量

    120348
  • PMC
    PMC
    +關(guān)注

    關(guān)注

    0

    文章

    89

    瀏覽量

    14904
  • 光刻機(jī)
    +關(guān)注

    關(guān)注

    31

    文章

    1150

    瀏覽量

    47400
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    316

    瀏覽量

    21650
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    硬件高手實(shí)戰(zhàn)分享——提高系統(tǒng)效率的幾個(gè)誤解

    退出來(lái),后面又接踵而至,一會(huì)兒系統(tǒng)就將崩潰了。如果任務(wù)數(shù)量多但很頻繁的話,CPU的 很大精力都用在進(jìn)出中斷的開(kāi)銷(xiāo)上,系統(tǒng)效率極為低下,如果改用查詢(xún)方式反而可極大提高效率,但查詢(xún)有時(shí)不能滿足實(shí)時(shí)性要求,所以
    發(fā)表于 11-21 09:51

    提高算法驗(yàn)證以及目標(biāo)硬件實(shí)施的效率

    提高算法驗(yàn)證以及目標(biāo)硬件實(shí)施的效率
    發(fā)表于 07-16 18:05 ?12次下載

    龍芯1號(hào)CPU的網(wǎng)絡(luò)計(jì)算機(jī)硬件系統(tǒng)設(shè)計(jì)

    介紹了基于國(guó)產(chǎn)芯片的網(wǎng)絡(luò)計(jì)算機(jī)硬件系統(tǒng)設(shè)計(jì)及實(shí)現(xiàn)該 網(wǎng)絡(luò)計(jì)算機(jī) 采用我國(guó)第一款通用32 位MIPS 指令集CPU 龍芯1號(hào) CPU 硬件系統(tǒng)
    發(fā)表于 06-29 10:49 ?60次下載
    龍芯1號(hào)<b class='flag-5'>CPU</b>的網(wǎng)絡(luò)計(jì)算機(jī)<b class='flag-5'>硬件</b>系統(tǒng)設(shè)計(jì)

    ATMEL的CPU介紹

    ATMEL的CPU介紹ATMEL的CPU介紹ATMEL的CPU介紹ATMEL的
    發(fā)表于 10-30 18:08 ?5次下載

    使用智能外設(shè)提高CPU效率

    現(xiàn)代微控制器添加了一個(gè)范圍廣泛的新功能,在正確使用時(shí)可以大大提高應(yīng)用效率。特別是,可以使用獨(dú)立于CPU獨(dú)立操作的智能外設(shè)和外圍設(shè)備,允許CPU并行執(zhí)行其他任務(wù),或者進(jìn)入低功耗睡眠模式。使用這兩種技術(shù)都將提高整體處理
    發(fā)表于 06-09 14:32 ?7次下載
    使用智能外設(shè)提高<b class='flag-5'>CPU</b><b class='flag-5'>效率</b>

    Intel Graphics上提高CPU效率的DX12

    DX12提高了幀速率解鎖模式下的CPU效率,允許更多功率用于額外的圖形性能。 在幀速率鎖定模式下,額外的CPU效率可提供整體較低的CPU
    的頭像 發(fā)表于 11-07 06:03 ?3123次閱讀

    蘋(píng)果A13 Bionic芯片的CPU和GPU評(píng)述,達(dá)到最高性能狀態(tài)時(shí)的效率

    10月17日消息,英國(guó)權(quán)威硬件評(píng)測(cè)媒體Anandtech今天發(fā)布了對(duì)iPhone 11和iPhone 11 Pro的深入評(píng)估報(bào)告,其中對(duì)蘋(píng)果最新的A13 Bionic芯片的CPU和GPU部分進(jìn)行了詳細(xì)評(píng)述。
    的頭像 發(fā)表于 10-17 15:33 ?8214次閱讀

    cpu的程序是如何運(yùn)行起來(lái)的

    ,今天的第一部分就從這里說(shuō)起。 一般我們不考慮物理的硬件底層的實(shí)現(xiàn)邏輯,但是為了后續(xù)的機(jī)器碼的介紹,這里開(kāi)始介紹CPU的基本組成部分。 我們都知道現(xiàn)在的
    的頭像 發(fā)表于 09-11 09:26 ?9471次閱讀

    CPU工作過(guò)程——MCU

    的頻率來(lái)源,但是我們的目標(biāo)是讓CPU工作在168MHz的頻率,這樣才可以讓CPU工作得更快,運(yùn)行代碼更快,效率更高。當(dāng)然,如果你想讓CPU
    發(fā)表于 10-25 16:51 ?21次下載
    <b class='flag-5'>CPU</b>工作過(guò)程——MCU

    CPU利用率過(guò)高的原因是什么

    進(jìn)程來(lái)介紹CPU資源使用率為什么會(huì)達(dá)到那么高,以幫助大家排除服務(wù)器CPU使用率高的種種疑惑。 一、硬件因素 以下分別從CPU溫度,
    發(fā)表于 03-10 09:28 ?2.4w次閱讀

    信創(chuàng)基礎(chǔ)硬件CPU、GPU、存儲(chǔ)和整機(jī)

    CPU指令集(Instruction Set)是CPU中計(jì)算和控制計(jì)算機(jī)系統(tǒng)所有指令的集合。計(jì)算機(jī)的程序最終需要轉(zhuǎn)化為“指令”才能在CPU運(yùn)行。
    的頭像 發(fā)表于 12-12 11:32 ?5435次閱讀

    CPU中的特殊指令可以加速編碼效率

    依據(jù)客戶真實(shí)需求,定制下一代CPU是我們的工作之一,我們選擇做視頻轉(zhuǎn)碼的另一個(gè)原因,是為了設(shè)計(jì)更好滿足音視頻領(lǐng)域需求的下一代硬件
    的頭像 發(fā)表于 02-14 13:38 ?1807次閱讀

    CPU硬件運(yùn)行效率

    提到CPU性能,大部分同學(xué)想到的都是CPU利用率,這個(gè)指標(biāo)確實(shí)應(yīng)該首先被關(guān)注。但是除了利用率之外,還有很容易被人忽視的指標(biāo),就是指令的運(yùn)行效率。如果
    的頭像 發(fā)表于 05-17 10:48 ?1032次閱讀
    <b class='flag-5'>CPU</b>的<b class='flag-5'>硬件</b><b class='flag-5'>運(yùn)行</b><b class='flag-5'>效率</b>

    如何準(zhǔn)確評(píng)估減速電機(jī)傳動(dòng)效率

    如何準(zhǔn)確評(píng)估減速電機(jī)傳動(dòng)效率? 準(zhǔn)確評(píng)估減速電機(jī)傳動(dòng)效率是確保工業(yè)設(shè)備正常運(yùn)行和提高能源利用效率
    的頭像 發(fā)表于 12-19 10:01 ?1265次閱讀

    如何優(yōu)化智能系統(tǒng)的運(yùn)行效率

    硬件性能 :處理器速度、內(nèi)存容量和存儲(chǔ)性能是影響智能系統(tǒng)運(yùn)行效率硬件因素。 軟件架構(gòu) :軟件的設(shè)計(jì)和架構(gòu)直接影響系統(tǒng)的響應(yīng)時(shí)間和處理能力。 算法
    的頭像 發(fā)表于 10-29 10:02 ?275次閱讀