說出來不確定大家信不信,實(shí)現(xiàn)起來也就70來行算上大括號的代碼,是不是很激動人心?
言歸正傳,再小的程序,也是數(shù)據(jù)結(jié)構(gòu)+代碼。咱們先來由表及里地看看核心數(shù)據(jù)結(jié)構(gòu)的樣子。
首先,既然要從Cortex-M核在響應(yīng)中斷時(shí)自動入棧的信息采集PC,就必須了解自動入棧了些啥東東:
這里可以看出Cortex-M內(nèi)核自動壓入了8個(gè)寄存器,右二那個(gè)不起眼的pc,正是一號主角。對自動入棧不太了解的小伙伴,可以查看《Cortex-M3權(quán)威指南》第9章的介紹
(https://github.com/RockySong/cm3_def_guide_cn)
理論上pc可以是任何指令位置。不幸的是一般工程生成的指令數(shù)常常在幾萬甚至幾十萬條,難道都要記錄下來?估計(jì)天價(jià)的開發(fā)工具也不會這么做。常言說“首惡必辦,協(xié)從不問”,咱們做profiling,也沒必要統(tǒng)計(jì)出PC在所有指令上的分布密度,只要抓幾個(gè)大頭就夠了。還有個(gè)麻煩的,是一個(gè)函數(shù)可以有多個(gè)指令,函數(shù)長度可以相差巨大,而且在一個(gè)大函數(shù)里不同區(qū)域的覆蓋密度也不同。過日子還需要精打細(xì)算呀,咱們權(quán)衡打擊精度與彈藥消耗量,使用2個(gè)宏來決定配置,比如:
第1個(gè)宏P(guān)ROF_CNT決定了抓多少個(gè)大頭,第2個(gè)宏P(guān)ROF_ERR決定了網(wǎng)眼的大小——抓取的地址范圍(也就是最大誤差),在這個(gè)范圍內(nèi)的地址都計(jì)作同一個(gè)地址塊。顯然,PROF_CNT越多,PROF_ERR越小,抓取的就越多越精確,也就更接近高檔的分析工具。值得一表的是,如果PROF_ERR夠小,可以在較大的函數(shù)中抓出更消耗性能的位置。
第3個(gè)宏P(guān)ROF_MASK又是什么鬼?這其實(shí)是個(gè)工具宏,用來把地址向下對齊到誤差范圍的邊界,這也意味著PROF_ERR必須是2的整數(shù)次冪,這么做是避免消耗性能的取模運(yùn)算。
下面請出關(guān)鍵的數(shù)據(jù)結(jié)構(gòu):性能分析的PC統(tǒng)計(jì)單元:
很顯然,PROF_CNT是多少,就應(yīng)該有多少個(gè)ProfUnit_t實(shí)例。結(jié)構(gòu)中,hitCnt是關(guān)鍵的參數(shù),它統(tǒng)計(jì)了這個(gè)對齊后的PC地址”baseAddr”被采集到了多少次,”hitRatio”則是一個(gè)對人類友好的輔助變量,提供千分?jǐn)?shù)(其實(shí)是1024級)精度的CPU占用率。
此外,還有個(gè)非常有用的小細(xì)節(jié)。比如,小伙伴們可能也注意到了,CPU占用率也是有時(shí)效性的。就像一個(gè)漫長的初始化可能讓一些查詢等待的函數(shù)紅極一時(shí),但在之前越是弄得滿城風(fēng)雨,程序主體運(yùn)行后往往越是無聲無息,甚至都沒機(jī)會再運(yùn)行一遍。
而即使在正常運(yùn)行期間,不同時(shí)段開啟的功能不同,常常出現(xiàn)“皇帝輪流做,明年到我家”。因此,咱們可以加一點(diǎn)衰減處理,也就是定期對于非0的hitCnt進(jìn)行扣除一格,如果沒有后續(xù)源源不斷的再次命中,就會漸漸走下神壇直至跌出排行榜。這樣可以提高統(tǒng)計(jì)結(jié)果的實(shí)時(shí)性。衰減機(jī)制的思路也很簡單,就是輪流從hitCnt非0的各個(gè)PC樣本點(diǎn)去扣。
綜合上面的如意算盤,定義了如下統(tǒng)領(lǐng)全局的結(jié)構(gòu)體:
這個(gè)結(jié)構(gòu)里decayNdx表示下次統(tǒng)計(jì)時(shí)從誰身上扣除hitCnt,每一次扣除后就輪轉(zhuǎn)到后面的item上,以公平公正。profCnt則表示已經(jīng)做了多少次profiling統(tǒng)計(jì),用于計(jì)算命中率,而items則是上文介紹的PC樣本統(tǒng)計(jì)單元。這里也有個(gè)小細(xì)節(jié),就是在應(yīng)用衰減來扣除每個(gè)item的hitCnt時(shí),profCnt也需要扣除。
好了,有了完整的數(shù)據(jù)結(jié)構(gòu),該寫代碼了。從易到難,咱們可以先處理命中時(shí)的動作。
代碼很簡單,記錄地址,增加hitCnt,計(jì)算hitRate,再實(shí)時(shí)地“冒泡”,把最多hitCnt的item頂上去,排序的目的也是為了便于突出重點(diǎn),對人類查看友好。這里每次hitCnt加2,是為了讓衰減得沒有增加的快,“過氣”得緩慢點(diǎn),小伙伴們可以根據(jù)需要調(diào)節(jié)增加量。
再剩下的就是最復(fù)雜的主函數(shù)了——說是復(fù)雜也就不到40行的代碼。要在主函數(shù)里先應(yīng)用衰減,然后檢查這次的PC樣本是否已有記錄。如有記錄就調(diào)用上面的_ProfOnHit(),如無記錄則在一個(gè)hitCnt為0的item上記錄這個(gè)新PC樣本,也是調(diào)用_ProfOnHit()。此外,為了避免把idle函數(shù)和一些不想關(guān)心的函數(shù)也記錄下來,程序還支持一個(gè)“忽略列表”,凡是位于忽略列表地址范圍的PC樣本都不理會。
大功告成!接下來就是要使用了。使用非常簡單,只需在定時(shí)器中斷服務(wù)程序的主體中調(diào)用Profiling()并告訴它進(jìn)入定時(shí)器中斷時(shí)pc寄存器的值。為了獲取入棧的PC,這個(gè)需要一點(diǎn)Cortex-M的基礎(chǔ)知識和手寫匯編。下面給出KEIL下的匯編入口:
這個(gè)小程序先查出中斷前使用的棧指針并以作為參數(shù)傳遞給C語言主體“SysTick_C_Handler”。如果小伙伴們對這段匯編看不明白,就直接用就可以。
C語言主體的使用方式如下:
在使用的時(shí)候,咱們就進(jìn)入開發(fā)工具的調(diào)試會話,讓程序跑一會,再停下來。如果是在KEIL或IAR中,可以使用memory窗口或watch窗口觀察s_prof.items。如果使用了GDB,可以輸入命令p/a s_prof.items。查看排名靠前的item,對照map文件即可估計(jì)出函數(shù)的名字和大致位置。值得一表的是,GDB下會自動解析出地址所對應(yīng)的函數(shù)名,不用再讓咱們手動查map,非常貼心!
回顧理論篇介紹的幾個(gè)小坑,當(dāng)查到一個(gè)不合理的地址時(shí),先別激動,看看是不是小坑中的之一。如果確定不是,就有必要深入處理了。
到了這里,這期性能分析的話題的理論和實(shí)踐的故事就講完了。
等等,似乎還有什么沒交待完。試想,當(dāng)我們一一找出最耗CPU資源的函數(shù)后,倘若束手無策,那也是徒勞無功,我們必須有對付他們的辦法。其中一項(xiàng)省力而又見效快的辦法就是把它們放在執(zhí)行性能更高的位置中去,也就是前面說的VIP區(qū)。下次,咱們就介紹一下各種VIP區(qū)的特點(diǎn),以及升V的方法!敬請繼續(xù)關(guān)注!
-
mcu
+關(guān)注
關(guān)注
146文章
17979瀏覽量
366731 -
分析器
+關(guān)注
關(guān)注
0文章
93瀏覽量
12727 -
數(shù)據(jù)結(jié)構(gòu)
+關(guān)注
關(guān)注
3文章
573瀏覽量
40747
原文標(biāo)題:70行代碼來打造MCU性能分析利器!
文章出處:【微信號:mcuworld,微信公眾號:嵌入式資訊精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
9013流水燈的介紹和設(shè)計(jì)詳細(xì)資料概述

如何修改Muto軟件來運(yùn)行自己的StaseSimo Foc板的詳細(xì)資料概述

如何利用LM3447來進(jìn)行非隔離調(diào)光GU10電源的詳細(xì)資料圖解概述
如何運(yùn)用TI的LM3447來設(shè)計(jì)7W可調(diào)光LED球泡燈Demo的詳細(xì)資料概述
PID程序算法的詳細(xì)資料概述免費(fèi)下載
SV601187的詳細(xì)資料合集包括了電路圖,原理圖和介紹等詳細(xì)資料概述

如何使用萬用表簡單判斷旋轉(zhuǎn)編碼器?的詳細(xì)資料概述
數(shù)字系統(tǒng)設(shè)計(jì)與PLD應(yīng)用答案的詳細(xì)資料概述

LabVIEW串口寫入和讀取詳細(xì)資料概述

逆變器的原理和詳細(xì)資料概述

開關(guān)電源環(huán)路補(bǔ)償?shù)?b class='flag-5'>詳細(xì)資料概述

python的內(nèi)置函數(shù)詳細(xì)資料概述
CAN總線基礎(chǔ)的詳細(xì)資料概述

評論