一种简单、实用的测量程序运行时间的方法
前言
平時我們可能很少去關注程序運行的時間,但是在一些情況下可能需要對程序進行一個整體的復盤、優化。
那么,程序運行的時間就是一個可以考慮的方面,可以測一下某些代碼塊、函數、算法的運行時間,然后整體考慮看看有沒有必要進行優化。
之前在某工控類項目中,我就有接到一個任務去測試程序中關鍵代碼的執行時間,并輸出報告。當時是使用一個GPIO+示波器進行測試的,也可以使用邏輯分析儀來測。
當時測量的方法很簡單:
在要測試的代碼塊/函數之前設置該GPIO的電平為高電平,在要測試的代碼塊/函數之后設置該GPIO為低電平,使用示波器測高電平的時間,就知道了這一代碼塊/函數的運行時間。
下面就通過實例來介紹一下這種簡單而有效的方法。
我這里使用邏輯分析儀來測量,使用小熊派開發板來驗證,小熊派的主控為STM32L431RCT6,系統時鐘設置為80MHz。
這里順帶提一點題外話,之前有一些初學的讀者朋友問我說邏輯分析儀貴不貴。邏輯分析儀有貴的也有便宜的,貴則上千上萬元,便宜則有幾十、幾百。我覺得無論工作、還是學習,都有必要入手一個邏輯分析儀。
本篇筆記的測試用的邏輯分析儀就是某寶上二十幾塊錢買的,可以滿足平時的學習所用。條件有限的學生朋友可以入手。有條件的可以考慮入手幾百塊錢的。
GPIO+邏輯分析儀測時間
1、測量HAL_Delay函數
STM32的HAL庫有給我們提供一個HAL_Delay延時函數,這是一個ms級延時函數。這個延時函數依賴于系統滴答定時器,所以是一個比較精確的延時函數。
這里,我們就使用GPIO+邏輯分析儀的方法來測量一下這個延時函數。為了方便測試,我們在while死循環里進行測量。
代碼:
測量結果:
可見,我們通過邏輯分析儀測出了HAL_Delay(100);運行的時間為100.4315ms,符合我們的預期。
這里高電平兩側其實就是低電平部分,只不過低電平持續的時間太短了,在這里看起來像一條豎線,我們放大來看看:
結果已經很準了,可以滿足平時的測量。這種測量很難保證百分之百的精確,小數點后面的那一部分可能是受很多不可控因素的影響,這不在我們本篇文章的討論范圍之內。
我們是想通過這個示例來介紹這種測量方法的使用及證明這種方法是可行的。下面再繼續看兩個實例。
2、測量軟件延時函數
我們以前剛開始學單片機的時候,經常有用到一些粗略的延時函數,其實現方法就是循環執行n條空語句,以達到一個延時的效果。
那么,我們怎么來構造一個us級或ms級的粗略延時函數(軟件延時函數)。我們之前看到的粗略延時函數類似這樣子:
這些函數里面需要給出一些循環的次數,這個值是怎么來確定的呢?比如上面這個函數中123這個值是怎么來確定的?我們可以使用GPIO+邏輯分析儀的方法來進行一個簡單的確定。
確定1us:
不同的處理器,結果是不一樣的。針對小熊派開發板(主控:STM32L431RCT6),循環運行15條空語句的時間實測結果是1.083us,這算是比較接近1us了。
我們就運用這個結果來構建一個us級軟件延時函數如下:
接下來我們測一下soft_delay_us(100);實際運行了多長時間:
可見,結果差不多接近我們想要的結果。構建這樣的粗略延時函數可以使用這樣的方式來確定一些循環次數的值。
3、查表法VS常規法運行時間
在之前的文章:空間換時間,查表法的經典例子《空間換時間,查表法的經典例子》中,我們有說可以適當使用查表法降低程序的執行時間。這里我們來實際測量對比一下那篇文章中查表法與常規法的優劣。
關鍵代碼:
/*?測試結果?*/ struct?test_res {unsigned?int?data;??/*?數據??????????*/unsigned?int?count;?/*?數據中1的個數?*/ };/*?============常規法============?*/ #if?1 struct?test_res?get_test_res(unsigned?int?data) {/*?保存測試結果?*/struct?test_res?res;/*?保證數據總會在0~0xf之間?*///?unsigned?int?temp?=?data?&?0xf;??unsigned?int?temp?=?data?&?0xff;??res.count?=?0;res.data?=?temp;/*?循環判斷每一位?*/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) {/*?保存測試結果?*/struct?test_res?res;/*?保證數據總會在0~0xf之間?*/unsigned?int?temp?=?data?&?0xff;??/*?獲取低4位中1的個數?*/unsigned?int?low_data?=?temp?&?0xf;unsigned?int?low_cnt?=?table[low_data];/*?獲取高4位中1的個數?*/unsigned?int?high_data?=?(temp?>>?4)?&?0xf;unsigned?int?high_cnt?=?table[high_data];/*?結果?*/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常規法程序的運行時間:
查表法程序的運行時間:
可見,這個例子中常規法程序運行時間約為2ns,而查表法程序運行時間約為500ns。查表法的程序運行之間僅為常規法的1/4,省下了3/4的時間。
隨著調用次數的增多,這里的查表法的優勢越大。比如循環計算0~31這32個數中每一個數二進制位為1的個數,則相關代碼改為:
??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);}常規法:
查表法:
可見,隨著調用次數的增多,查表法相對于常規法更省時,即查表法的優勢越大。
以上就是關于GPIO+邏輯分析儀測程序運行時間的幾個實例。下面順帶提一下使用MDK+ST-LINK測STM32程序運行時間的方法。
MDK+ST-LINK測時間
在使用MDK作為開發工具時,可以搭配一些仿真器來查看程序執行時間。這里通過實例來介紹MDK+ST-LINK測STM32程序運行時間的方法。
這里重點是設置Trace里面的系統內核時鐘,我們這里使用的是小熊派開發板(主控:STM32L431RCT6),并且配置的系統時鐘是80MHz:
所以在Trace中要設置為80MHz。這個得根據實際芯片的型號就需要根據進行修改,比如STM32F103系列默認是72MHz,STM32F429系列默認為180MHz等,根據實際進行修改。
下面我們通過在線調試、打斷點的方式看一下 HAL_Delay(1000);運行了多長時間:
可見程序運行到HAL_Delay(1000);前后的時間分別為:
前:0.00008964s 后:1.00108161s即HAL_Delay(1000);走過的時間約為1s,符合預期。
最后
以上就是本次的實踐分享,感謝閱讀與支持。如有錯誤,歡迎指出。謝謝!
若覺得文章不錯,轉發分享、在看,也是我們繼續更新的動力。
在公眾號內回復更多資源,可免費獲取嵌入式資料。期待你的關注~
? ? 推薦閱讀:
? ??專輯|Linux文章匯總
? ??專輯|程序人生
? ??專輯|C語言
嵌入式Linux
微信掃描二維碼,關注我的公眾號?
總結
以上是生活随笔為你收集整理的一种简单、实用的测量程序运行时间的方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 商业计划书-智能导盲仗
- 下一篇: 如何把几张图片合成一个pdf?