#微控制器##嵌入式程式設計##RTOS##程式設計師#
2、量化棧使用率如何量化棧使用率,我們通常使用百分比來量化某些引數,比如考試100分滿分60分及格,這裡我們也使用百分比來量化棧使用率。量化公式如下:
棧使用率=100X歷史使用棧大小/分配棧大小
注意:下文計算棧使用率時計算單位為字而不是位元組(即四位元組為一個計量單位)。
特別規定,系統連續執行一定時間(如24小時)後“棧使用率”不超過60%為及格。要注意的是這裡我們是以不超60%為及格與考試不一樣喲,與考駕照更不一樣。要是達到90%及以上就等著系統崩潰吧。
3、堆疊的區別在大部分時候我們都是將它拿到一起說的稱之為“堆疊”以至於分開來說還有些人不明白,事實上堆與棧是兩個不同的東西,即堆就是堆,棧就是棧。
堆:想象一下地面上有一堆沙,沙越多就堆得越高,如下圖所示:
堆的類比圖
如上圖,堆形象地說就像堆沙堆一樣,其地址從低到高向上增長,越堆越高,越拿走越低/少。
棧:其地址是從高到低向下增長的。想象有一條棧道,如下圖所示:
棧的類比圖
把堆與棧合併到一起如下圖所示(以一個工程例項分配說明)
堆與棧結構圖
上圖是我一個工程堆疊分配的地址值,不同專案,或者隨著專案功能的變化其值也會變化,或者改變S檔案中堆疊大小配置項,其值也會變化。此處僅舉例接近實現情況。
補充說明:上面說的向下或向上增長,指的都是地址。
計算棧使用率
5、測試棧使用率為了測棧使用率,我定義兩個不同函式,其內部定義不同數量的區域性變數,呼叫函式前後統計棧使用率:我在配置棧總大小4096位元組,函式Test1()中定義區域性變數1000位元組(使用率約24%),函式Test1()中定義區域性變數3000位元組(使用率約73%)。如下圖所示:
6、關鍵測試程式碼如下#define APP_START_ADDRESS 0x08000000 //開始地址(棧頂地址)#define RAM_START_ADDRESS 0x20000000 //RAM開始地址#define APP_STACK_SIZE 0x1000 //棧大小(位元組數量)4KB#define APP_HEAP_SIZE 0x1000 //堆大小(位元組數量)4KB#define MCU_RAM_SIZE 0x5000 //20KB// --------------------------------------------------#define BUFF_SIZE 1024 //定義公共大小 char buff[BUFF_SIZE]; //定義公共變數int GetGloablVarSum(void){ int i,sum=0; //區域性變數 for(i=0;i<BUFF_SIZE;i++) //公共變數初始化 { buff[i]=i; sum+=buff[i]; //計算功能變數的和 } return sum; //返回計算和 }// --------------------------------------------------int GetHeapVarSum(void){ int i,sum=0; //定義公共變數 char *p1,*p2=(char*)malloc(BUFF_SIZE); //從堆區申請記憶體 p1=p2; memcpy(p2,buff,BUFF_SIZE); //將公共變數的值複製到申請的記憶體中 p1=p2; for(i=0;i<BUFF_SIZE;i++) //計算申請記憶體中值的和 { sum+=*p2++; } return sum; //返回計算和}// --------------------------------------------------void TellAboutRam(){ unsigned int StackTopAddr=(*(__IO u32*)APP_START_ADDRESS); //獲取棧頂地址 unsigned int HeapTopAddr=StackTopAddr-APP_STACK_SIZE; //獲取堆頂/棧底地址 unsigned int GlobalVarSize=HeapTopAddr-APP_HEAP_SIZE-RAM_START_ADDRESS; //計算公共變數區域大小 unsigned int RamFreeSize=MCU_RAM_SIZE-(StackTopAddr-RAM_START_ADDRESS); //計算空閒區大小 printf ("棧 頂\t=\t%08XH \n",StackTopAddr); printf ("堆 頂\t=\t%08XH \n",HeapTopAddr); printf ("未分配區\t=\t%d Byte\n",RamFreeSize); printf ("棧 區\t=\t%d Byte\n",APP_STACK_SIZE); printf ("堆 區\t=\t%d Byte\n",APP_HEAP_SIZE); printf ("公共變數區\t=\t%0d Byte\n",GlobalVarSize);}// --------------------------------------------------u8 GetMcuStackUsePercent(u8 temp){ u8 StackUsePercent=0; //棧使用百分比 u32 i; u32 StackTopAddr=0; //棧頂地址 u32 StackAddrNow=0; //棧當前地址(讀值時用) u32 StackTotalWordSize=0; //棧的字大小 u32 StackData=0; //棧中的資料 u32 StackUnuseWordSize=0; //棧中未使用字數量統計 StackTotalWordSize=APP_STACK_SIZE/4; //計算棧控制字數量 StackTopAddr=(*(__IO u32*)APP_START_ADDRESS); //讀取棧頂地址 StackAddrNow=StackTopAddr-APP_STACK_SIZE; //計算棧底地址 for(i=0;i<StackTotalWordSize;i++) { StackData=(*(__IO u32*)StackAddrNow); //讀取棧地址處的值 StackAddrNow+=4; //地址往棧頂增加 if(StackData==0) //將棧資料與初始值比較 { StackUnuseWordSize++; //棧資料==初始值 } else { break; //棧資料不等於初始值,退出統計過程 } } //計算棧使用率 StackUsePercent=100*(StackTotalWordSize-StackUnuseWordSize)/StackTotalWordSize; #if 0 printf(" ------------- %d -------------\r\n",temp); printf(" 1 APP_START_ADDRESS=%08XH \r\n",APP_START_ADDRESS); printf(" 2 Stack Addr Top=%08XH Buttom=%08XH\r\n",StackTopAddr,StackTopAddr-APP_STACK_SIZE); printf(" 3 STACK_SIZE=%04XH %d Bytes\r\n",APP_STACK_SIZE,APP_STACK_SIZE); printf(" 4 StackSize Total=%d Unuse=%d Used=%d\r\n",StackTotalWordSize,StackUnuseWordSize,StackTotalWordSize-StackUnuseWordSize); #endif return StackUsePercent; //返回棧使用率}void Test1(void){ char temp[1000]; //區域性變數(1000/4096=0.244=24%) int i,sum=0; //區域性變數 for(i=0;i<1000;i++) { temp[i]=i; sum+=temp[i]; //計算功能變數的和 }}void Test2(void){ char temp[3000]; //區域性變數(3000/4096=0.732=73.2%) int i,sum=0; //區域性變數 for(i=0;i<3000;i++) { temp[i]=i; sum+=temp[i]; //計算功能變數的和 }}int main (void) { SER_Init (); printf ("------------- Hello World ------------\n"); printf ("測試公共變數\t=\t%d \t\n",GetGloablVarSum()); printf ("測 堆區\t=\t%d \t\n",GetHeapVarSum()); TellAboutRam(); printf(" Test1前 棧使用率=%d%%\r\n",GetMcuStackUsePercent(1)); Test1(); printf(" Test1後 棧使用率=%d%%\r\n",GetMcuStackUsePercent(1)); Test2(); printf(" Test2後 棧使用率=%d%%\r\n",GetMcuStackUsePercent(1)); while (1) { DelayMs(1000); } }
7、模擬測試測試結果如下圖
模擬測試棧使用百分比
最新評論