一種簡(jiǎn)單、實(shí)用的測(cè)量程序運(yùn)行時(shí)間的方法
掃描二維碼
隨時(shí)隨地手機(jī)看文章
點(diǎn)擊上方「嵌入式大雜燴」,選擇「置頂公眾號(hào)」第一時(shí)間查看嵌入式筆記!
前言
平時(shí)我們可能很少去關(guān)注程序運(yùn)行的時(shí)間,但是在一些情況下可能需要對(duì)程序進(jìn)行一個(gè)整體的復(fù)盤、優(yōu)化。
那么,程序運(yùn)行的時(shí)間就是一個(gè)可以考慮的方面,可以測(cè)一下某些代碼塊、函數(shù)、算法的運(yùn)行時(shí)間,然后整體考慮看看有沒(méi)有必要進(jìn)行優(yōu)化。
之前在某工控類項(xiàng)目中,我就有接到一個(gè)任務(wù)去測(cè)試程序中關(guān)鍵代碼的執(zhí)行時(shí)間,并輸出報(bào)告。當(dāng)時(shí)是使用一個(gè)GPIO+示波器
進(jìn)行測(cè)試的,也可以使用邏輯分析儀來(lái)測(cè)。
當(dāng)時(shí)測(cè)量的方法很簡(jiǎn)單:
在要測(cè)試的代碼塊/函數(shù)之前設(shè)置該GPIO的電平為高電平,在要測(cè)試的代碼塊/函數(shù)之后設(shè)置該GPIO為低電平,使用示波器測(cè)高電平的時(shí)間,就知道了這一代碼塊/函數(shù)的運(yùn)行時(shí)間。
下面就通過(guò)實(shí)例來(lái)介紹一下這種簡(jiǎn)單而有效的方法。
我這里使用邏輯分析儀來(lái)測(cè)量,使用小熊派開發(fā)板
來(lái)驗(yàn)證,小熊派的主控為STM32L431RCT6
,系統(tǒng)時(shí)鐘設(shè)置為80MHz
。
這里順帶提一點(diǎn)題外話,之前有一些初學(xué)的讀者朋友問(wèn)我說(shuō)邏輯分析儀貴不貴。邏輯分析儀有貴的也有便宜的,貴則上千上萬(wàn)元,便宜則有幾十、幾百。我覺(jué)得無(wú)論工作、還是學(xué)習(xí),都有必要入手一個(gè)邏輯分析儀。
本篇筆記的測(cè)試用的邏輯分析儀就是某寶上二十幾塊錢買的,可以滿足平時(shí)的學(xué)習(xí)所用。條件有限的學(xué)生朋友可以入手。有條件的可以考慮入手幾百塊錢的。
GPIO+邏輯分析儀測(cè)時(shí)間
1、測(cè)量HAL_Delay函數(shù)
STM32的HAL庫(kù)有給我們提供一個(gè)HAL_Delay
延時(shí)函數(shù),這是一個(gè)ms級(jí)延時(shí)函數(shù)。這個(gè)延時(shí)函數(shù)依賴于系統(tǒng)滴答定時(shí)器,所以是一個(gè)比較精確的延時(shí)函數(shù)。
這里,我們就使用GPIO+邏輯分析儀
的方法來(lái)測(cè)量一下這個(gè)延時(shí)函數(shù)。為了方便測(cè)試,我們?cè)趙hile死循環(huán)里進(jìn)行測(cè)量。
代碼:
測(cè)量結(jié)果:
可見,我們通過(guò)邏輯分析儀測(cè)出了HAL_Delay(100);
運(yùn)行的時(shí)間為100.4315ms
,符合我們的預(yù)期。
這里高電平兩側(cè)其實(shí)就是低電平部分,只不過(guò)低電平持續(xù)的時(shí)間太短了,在這里看起來(lái)像一條豎線,我們放大來(lái)看看:
結(jié)果已經(jīng)很準(zhǔn)了,可以滿足平時(shí)的測(cè)量。這種測(cè)量很難保證百分之百的精確,小數(shù)點(diǎn)后面的那一部分可能是受很多不可控因素的影響,這不在我們本篇文章的討論范圍之內(nèi)。
我們是想通過(guò)這個(gè)示例來(lái)介紹這種測(cè)量方法的使用及證明這種方法是可行的。下面再繼續(xù)看兩個(gè)實(shí)例。
2、測(cè)量軟件延時(shí)函數(shù)
我們以前剛開始學(xué)單片機(jī)的時(shí)候,經(jīng)常有用到一些粗略的延時(shí)函數(shù),其實(shí)現(xiàn)方法就是循環(huán)執(zhí)行n條空語(yǔ)句,以達(dá)到一個(gè)延時(shí)的效果。
那么,我們?cè)趺磥?lái)構(gòu)造一個(gè)us級(jí)或ms級(jí)的粗略延時(shí)函數(shù)(軟件延時(shí)函數(shù))。我們之前看到的粗略延時(shí)函數(shù)類似這樣子:
這些函數(shù)里面需要給出一些循環(huán)的次數(shù),這個(gè)值是怎么來(lái)確定的呢?比如上面這個(gè)函數(shù)中123這個(gè)值是怎么來(lái)確定的?我們可以使用GPIO+邏輯分析儀的方法
來(lái)進(jìn)行一個(gè)簡(jiǎn)單的確定。
確定1us:
不同的處理器,結(jié)果是不一樣的。針對(duì)小熊派開發(fā)板(主控:STM32L431RCT6),循環(huán)運(yùn)行15條空語(yǔ)句的時(shí)間實(shí)測(cè)結(jié)果是1.083us
,這算是比較接近1us了。
我們就運(yùn)用這個(gè)結(jié)果來(lái)構(gòu)建一個(gè)us級(jí)軟件延時(shí)函數(shù)如下:
接下來(lái)我們測(cè)一下soft_delay_us(100);
實(shí)際運(yùn)行了多長(zhǎng)時(shí)間:
可見,結(jié)果差不多接近我們想要的結(jié)果。構(gòu)建這樣的粗略延時(shí)函數(shù)可以使用這樣的方式來(lái)確定一些循環(huán)次數(shù)的值。
3、查表法VS常規(guī)法運(yùn)行時(shí)間
在之前的文章:空間換時(shí)間,查表法的經(jīng)典例子《空間換時(shí)間,查表法的經(jīng)典例子》中,我們有說(shuō)可以適當(dāng)使用查表法降低程序的執(zhí)行時(shí)間。這里我們來(lái)實(shí)際測(cè)量對(duì)比一下那篇文章中查表法與常規(guī)法的優(yōu)劣。
關(guān)鍵代碼:
/* 測(cè)試結(jié)果 */
struct test_res
{
unsigned int data; /* 數(shù)據(jù) */
unsigned int count; /* 數(shù)據(jù)中1的個(gè)數(shù) */
};
/* ============常規(guī)法============ */
#if 1
struct test_res get_test_res(unsigned int data)
{
/* 保存測(cè)試結(jié)果 */
struct test_res res;
/* 保證數(shù)據(jù)總會(huì)在0~0xf之間 */
// unsigned int temp = data & 0xf;
unsigned int temp = data & 0xff;
res.count = 0;
res.data = temp;
/* 循環(huán)判斷每一位 */
for (int i = 0; i < 16; i++)
{
if (temp & 0x01)
{
res.count++;
}
temp >>= 1;
}
return res;
}
#else
/* ============查表法============ */
int table[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
struct test_res get_test_res(unsigned int data)
{
/* 保存測(cè)試結(jié)果 */
struct test_res res;
/* 保證數(shù)據(jù)總會(huì)在0~0xf之間 */
unsigned int temp = data & 0xff;
/* 獲取低4位中1的個(gè)數(shù) */
unsigned int low_data = temp & 0xf;
unsigned int low_cnt = table[low_data];
/* 獲取高4位中1的個(gè)數(shù) */
unsigned int high_data = (temp >> 4) & 0xf;
unsigned int high_cnt = table[high_data];
/* 結(jié)果 */
res.count = low_cnt + high_cnt;
res.data = temp;
return res;
}
int main(void)
{
/* USER CODE BEGIN 1 */
struct test_res res = {0};
/* 省略部分代碼。。。。。。。。。 */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
res = get_test_res(30);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
}
/* USER CODE END 3 */
}
#endif
常規(guī)法程序的運(yùn)行時(shí)間:
查表法程序的運(yùn)行時(shí)間:
可見,這個(gè)例子中常規(guī)法程序運(yùn)行時(shí)間約為2ns,而查表法程序運(yùn)行時(shí)間約為500ns。查表法的程序運(yùn)行之間僅為常規(guī)法的1/4,省下了3/4的時(shí)間。
隨著調(diào)用次數(shù)的增多,這里的查表法的優(yōu)勢(shì)越大。比如循環(huán)計(jì)算0~31這32個(gè)數(shù)中每一個(gè)數(shù)二進(jìn)制位為1的個(gè)數(shù),則相關(guān)代碼改為:
int i;
while (1)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
for (i = 0; i < 32; i++)
{
res = get_test_res(i);
}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
}
常規(guī)法:
查表法:
可見,隨著調(diào)用次數(shù)的增多,查表法相對(duì)于常規(guī)法更省時(shí),即查表法的優(yōu)勢(shì)越大。
以上就是關(guān)于GPIO+邏輯分析儀測(cè)程序運(yùn)行時(shí)間
的幾個(gè)實(shí)例。下面順帶提一下使用MDK+ST-LINK
測(cè)STM32程序運(yùn)行時(shí)間的方法。
MDK+ST-LINK測(cè)時(shí)間
在使用MDK作為開發(fā)工具時(shí),可以搭配一些仿真器來(lái)查看程序執(zhí)行時(shí)間。這里通過(guò)實(shí)例來(lái)介紹MDK+ST-LINK
測(cè)STM32程序運(yùn)行時(shí)間的方法。
這里重點(diǎn)是設(shè)置Trace
里面的系統(tǒng)內(nèi)核時(shí)鐘,我們這里使用的是小熊派開發(fā)板(主控:STM32L431RCT6),并且配置的系統(tǒng)時(shí)鐘是80MHz:
所以在Trace
中要設(shè)置為80MHz。這個(gè)得根據(jù)實(shí)際芯片的型號(hào)就需要根據(jù)進(jìn)行修改,比如STM32F103系列默認(rèn)是72MHz,STM32F429系列默認(rèn)為180MHz等,根據(jù)實(shí)際進(jìn)行修改。
下面我們通過(guò)在線調(diào)試、打斷點(diǎn)的方式看一下 HAL_Delay(1000);
運(yùn)行了多長(zhǎng)時(shí)間:
可見程序運(yùn)行到HAL_Delay(1000);
前后的時(shí)間分別為:
前:0.00008964s
后:1.00108161s
即HAL_Delay(1000);
走過(guò)的時(shí)間約為1s,符合預(yù)期。
最后
以上就是本次的實(shí)踐分享,感謝閱讀與支持。如有錯(cuò)誤,歡迎指出。謝謝!
若覺(jué)得文章不錯(cuò),轉(zhuǎn)發(fā)分享、在看,也是我們繼續(xù)更新的動(dòng)力。
在公眾號(hào)內(nèi)回復(fù)更多資源,可免費(fèi)獲取嵌入式資料。期待你的關(guān)注~
猜你喜歡
C語(yǔ)言、嵌入式應(yīng)用:TCP通信實(shí)例分析
一些不可不知的計(jì)算機(jī)網(wǎng)絡(luò)基礎(chǔ)
AT指令測(cè)試ESP8266通信模組并獲取天氣數(shù)據(jù)
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!