搞汽車(chē)嵌入式開(kāi)發(fā)的小伙伴,似乎對(duì)編程語(yǔ)言要求不高。只要能用,程序能動(dòng),咱們就縫縫補(bǔ)補(bǔ)又三年。雖然是這么說(shuō),但是,作為一名開(kāi)發(fā)者,咱們還是要有上進(jìn)心的。畢竟汽車(chē)級(jí)MCU資源不是那么豐富,能在代碼上做一些優(yōu)化,提升產(chǎn)品性能,也算咱們的feature。本文,聊一聊提升程序效率的一種方式:減少for循環(huán),提升執(zhí)行效率。問(wèn)題描述:對(duì)地址范圍0x200000~0x2FFFFF的數(shù)據(jù)進(jìn)行加密計(jì)算,每次只能輸入16 Byte字節(jié)(一個(gè)Block)進(jìn)行計(jì)算,上一次的計(jì)算結(jié)果參與下一次計(jì)算。熟悉CMAC加密的同學(xué)應(yīng)該看出來(lái),這就是一個(gè)典型的CMAC計(jì)算。常規(guī)編碼,我們會(huì)怎么寫(xiě)呢?示意如下:for (; CmacData.leftDataLen > 16; ) { AesCmac_Cal128BitLen(addressIn); addressIn += 16U; CmacData.leftDataLen -= 16U; } 如果覺(jué)得別扭,可以改造成如下while格式:
while (CmacData.leftDataLen > 16) { AesCmac_Cal128BitLen(addressIn); addressIn += 16U; CmacData.leftDataLen -= 16U; } 初始長(zhǎng)度CmacData.leftDataLen = 0x100000,也就是1 MBytes。那么,這樣的寫(xiě)法會(huì)消耗多少時(shí)間呢?本文用Timer(定時(shí)器)統(tǒng)計(jì),用時(shí)統(tǒng)計(jì),示意如下:TimeArr[0] = OsTimer0_GetTicks(); for (; CmacData.leftDataLen > 16; ) { AesCmac_Cal128BitLen(addressIn); addressIn += 16U; CmacData.leftDataLen -= 16U; } TimeArr[1] = OsTimer0_GetTicks() - TimeArr[0]; for寫(xiě)法平均用時(shí)8567044Ticks,while寫(xiě)法平均用時(shí)8569820Ticks。其中,Timer主頻60MHz,換算下來(lái),兩者分別用時(shí):142.784ms、142.830ms。能否優(yōu)化上述的寫(xiě)法呢?答:可以。優(yōu)化思路:如上的循環(huán)中,每16 Bytes進(jìn)行一次判斷,而且每次運(yùn)算,均需要進(jìn)行address的累加和長(zhǎng)度的遞減。所以,如果把字節(jié)提高到64 Bytes執(zhí)行一次判斷,可以減少3次address的累加和長(zhǎng)度的遞減,即:適當(dāng)增加判斷的顆粒度。
while (CmacData.leftDataLen > 64) { AesCmac_Cal128BitLen(addressIn); AesCmac_Cal128BitLen(addressIn+16); AesCmac_Cal128BitLen(addressIn+32); AesCmac_Cal128BitLen(addressIn+48); addressIn += 64U; CmacData.leftDataLen -= 64U; }
用時(shí):7586131Ticks,即:126.436ms。 修改for代碼如下所示: for (;CmacData.leftDataLen > 64;) { AesCmac_Cal128BitLen(addressIn); AesCmac_Cal128BitLen(addressIn+16); AesCmac_Cal128BitLen(addressIn+32); AesCmac_Cal128BitLen(addressIn+48); addressIn += 64U; CmacData.leftDataLen -= 64U; }
用時(shí):7585583Ticks,即:126.426ms。 統(tǒng)計(jì)對(duì)比如下:

所以,遇到for循環(huán)時(shí),可以適當(dāng)放大判斷的顆粒度。
|