[英]Optimizing ARM Cortex M3 code
我有一個C函數,它試圖將幀緩沖區復制到FSMC RAM。
這些函數將游戲循環的幀速率降低到10FPS。 我想知道如何分析反匯編函數,我應該計算每個指令周期嗎? 我想知道CPU在哪里花費時間,在哪一部分。 我確定算法也是一個問題,因為它的O(N ^ 2)
C函數是:
void LCD_Flip()
{
u8 i,j;
LCD_SetCursor(0x00, 0x0000);
LCD_WriteRegister(0x0050,0x00);//GRAM horizontal start position
LCD_WriteRegister(0x0051,239);//GRAM horizontal end position
LCD_WriteRegister(0x0052,0);//Vertical GRAM Start position
LCD_WriteRegister(0x0053,319);//Vertical GRAM end position
LCD_WriteIndex(0x0022);
for(j=0;j<fbHeight;j++)
{
for(i=0;i<240;i++)
{
u16 color = frameBuffer[i+j*fbWidth];
LCD_WriteData(color);
}
}
}
拆卸功能:
08000fd0 <LCD_Flip>:
8000fd0: b580 push {r7, lr}
8000fd2: b082 sub sp, #8
8000fd4: af00 add r7, sp, #0
8000fd6: 2000 movs r0, #0
8000fd8: 2100 movs r1, #0
8000fda: f7ff fde9 bl 8000bb0 <LCD_SetCursor>
8000fde: 2050 movs r0, #80 ; 0x50
8000fe0: 2100 movs r1, #0
8000fe2: f7ff feb5 bl 8000d50 <LCD_WriteRegister>
8000fe6: 2051 movs r0, #81 ; 0x51
8000fe8: 21ef movs r1, #239 ; 0xef
8000fea: f7ff feb1 bl 8000d50 <LCD_WriteRegister>
8000fee: 2052 movs r0, #82 ; 0x52
8000ff0: 2100 movs r1, #0
8000ff2: f7ff fead bl 8000d50 <LCD_WriteRegister>
8000ff6: 2053 movs r0, #83 ; 0x53
8000ff8: f240 113f movw r1, #319 ; 0x13f
8000ffc: f7ff fea8 bl 8000d50 <LCD_WriteRegister>
8001000: 2022 movs r0, #34 ; 0x22
8001002: f7ff fe87 bl 8000d14 <LCD_WriteIndex>
8001006: 2300 movs r3, #0
8001008: 71bb strb r3, [r7, #6]
800100a: e01b b.n 8001044 <LCD_Flip+0x74>
800100c: 2300 movs r3, #0
800100e: 71fb strb r3, [r7, #7]
8001010: e012 b.n 8001038 <LCD_Flip+0x68>
8001012: 79f9 ldrb r1, [r7, #7]
8001014: 79ba ldrb r2, [r7, #6]
8001016: 4613 mov r3, r2
8001018: 011b lsls r3, r3, #4
800101a: 1a9b subs r3, r3, r2
800101c: 011b lsls r3, r3, #4
800101e: 1a9b subs r3, r3, r2
8001020: 18ca adds r2, r1, r3
8001022: 4b0b ldr r3, [pc, #44] ; (8001050 <LCD_Flip+0x80>)
8001024: f833 3012 ldrh.w r3, [r3, r2, lsl #1]
8001028: 80bb strh r3, [r7, #4]
800102a: 88bb ldrh r3, [r7, #4]
800102c: 4618 mov r0, r3
800102e: f7ff fe7f bl 8000d30 <LCD_WriteData>
8001032: 79fb ldrb r3, [r7, #7]
8001034: 3301 adds r3, #1
8001036: 71fb strb r3, [r7, #7]
8001038: 79fb ldrb r3, [r7, #7]
800103a: 2bef cmp r3, #239 ; 0xef
800103c: d9e9 bls.n 8001012 <LCD_Flip+0x42>
800103e: 79bb ldrb r3, [r7, #6]
8001040: 3301 adds r3, #1
8001042: 71bb strb r3, [r7, #6]
8001044: 79bb ldrb r3, [r7, #6]
8001046: 2b63 cmp r3, #99 ; 0x63
8001048: d9e0 bls.n 800100c <LCD_Flip+0x3c>
800104a: 3708 adds r7, #8
800104c: 46bd mov sp, r7
800104e: bd80 pop {r7, pc}
不完全回答你的問題,但我看到你渴望快速執行循環。
以下是本書的一些提示:“ARM系統開發人員指南:設計和優化系統軟件(計算機體系結構和設計中的Morgan Kaufmann系列)” http://www.amazon.com/ARM-System-Developers-Guide-Architecture / DP / 1558608745
第5章包含名為“C循環結構”的部分。 以下是該部分的摘要:
有效地編寫循環
根據摘要,您的內部循環可能如下所示。
uinsigned int i = 240/4; // Use unsigned loop counters by default
// and the continuation condition i!=0
do
{
// Unroll important loops to reduce the loop overhead
LCD_WriteData( (u16)frameBuffer[ (i--) + (j*fbWidth) ] );
LCD_WriteData( (u16)frameBuffer[ (i--) + (j*fbWidth) ] );
LCD_WriteData( (u16)frameBuffer[ (i--) + (j*fbWidth) ] );
LCD_WriteData( (u16)frameBuffer[ (i--) + (j*fbWidth) ] );
}
while ( i != 0 ) // Use do-while loops rather than for
// loops when you know the loop will
// iterate at least once
您可能還想嘗試使用'pragma',例如:
#pragma Otime
http://www.keil.com/support/man/docs/armcc/armcc_chr1359124989673.htm
#pragma unroll(n)
http://www.keil.com/support/man/docs/armcc/armcc_chr1359124992247.htm
因為它是Cortex-M3試圖找出MCU硬件是否有機會安排代碼/數據以利用其哈佛架構 (我的速度提高了30%)。
也許並非所有內容都適用於您的應用程序(以相反的順序填充緩沖區)。 我只是想提請你注意這本書以及可能的優化要點。
您應該首先在啟用速度優化的情況下編譯C代碼。 您提供的反匯編代碼似乎是在堆棧中存儲i
和j
計數器,這會向內部循環添加3個加載/存儲操作。 您可能LCD_WriteData
在內部循環中內聯LCD_WriteData
。
另一方面,如果您真的在內循環中寫入LCD,那么性能可能會受到該接口的限制。
只是為了純粹減少循環操作的數量,你可以這樣做。 我確實做了一些可能不准確的假設:你有一個從i=0:239
開始的循環,我假設fbWidth
與240
相同。 如果不是這樣,那么循環必須更復雜。
void LCD_Flip()
{
u16 i,limit = fbHeight+fbWidth;
// We will use a precalculated limit and one single loop
LCD_SetCursor(0x00, 0x0000);
LCD_WriteRegister(0x0050,0x00);//GRAM horizontal start position
LCD_WriteRegister(0x0051,239);//GRAM horizontal end position
LCD_WriteRegister(0x0052,0);//Vertical GRAM Start position
LCD_WriteRegister(0x0053,319);//Vertical GRAM end position
LCD_WriteIndex(0x0022);
// Single loop from 0:limit-1 takes care of having to do an
// x,y conversion each iteration.
for(i=0;i<limit;j++)
{
u16 color = frameBuffer[i];
LCD_WriteData(color);
}
}
這剝離了兩個循環,有利於單個for循環,每次迭代只有一個條件測試。 最重要的是,對frameBuffer
的索引現在是線性的,因此我們不需要將寬度乘以從x,y到線性存儲。 你的循環迭代不會減少(即它仍然是O(N)
, N = height*width
),但指令的數量應該減少。
正如@Joe Hass在他的回答中指出的那樣,如果你真的受到LCD界面的限制,這實際上可能根本沒有幫助。 根據您使用的STM32,FSMC可能不會特別快,我無法想象LCD控制器也會非常快。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.