2017-04-15 65 views
2

我最近使用了一個板(LPCXpresso 5411x)做一些計算,我們試圖減少週期,只要我們能夠節省我們的特定需求的運行時間,所以我需要對cortex-m4指令的成本週期進行一些研究。我發現很多奇怪的東西(不能用我在互聯網上找到的東西解釋)用手臂皮質m4週期計數奇怪的東西

我用DWT-> CYCCNT來計算我想測試的函數所消耗的週期數。

int start_cycle, end_cycle; 

__asm volatile (
    "LDR %[s1], [%[a]], #0\n\t" 
    :[s1] "=&r"(start_cycle): [a] "r"(&(DWT->CYCCNT)):); 

AddrSumTest(); 
__asm volatile (
    "LDR %[s1], [%[a]], #0\n\t" 
    :[s1] "=&r"(end_cycle): [a] "r"(&(DWT->CYCCNT)):); 

printf("inside the func() cycles: %d\n",end_cycle - start_cycle); 

這裏是我的功能是如何定義的:

__attribute__((always_inline)) static inline void AddrSumTest(){ 
    uint32_t x, y, i, q; 

    __asm volatile (
     "nop\n\t" 
     :[x] "=r" (x), [y] "=r" (y), [i] "=r" (i), [q] "=r" (q):); 
    } 
} 
  • Arm Infocenter,指令MOV應該花費一個週期,但我發現,

以下指令需要8個週期(不是3個,因爲需要額外的週期來讀取DWT-> CYCC NT

"nop\n\t" 
    "MOV %[x], #2\n\t" 
    "nop\n\t" 

添加另一MOV指令之後,需要10個循環以下循環(爲什麼不9個週期)

"nop\n\t" 
    "MOV %[x], #2\n\t" 
    "MOV %[y], #3\n\t" 
    "nop\n\t" 

和組裝編碼後一種情況是

4000578: f853 4b00 ldr.w r4, [r3], #0 
400057c: bf00  nop 
400057e: f04f 0502 mov.w r5, #2 
4000582: f04f 0603 mov.w r6, #3 
4000586: bf00  nop 
4000588: f853 1b00 ldr.w r1, [r3], #0 
400058c: 4805  ldr r0, [pc, #20] ;(40005a4<test_AddrSum+0x30>) 
400058e: 1b09  subs r1, r1, r4 
4000590: f000 f80e bl 40005b0 <__printf_veneer> 

這兩個ldrs正在從DWT-> CYCCNT讀取,另外,爲什麼這會花費10個週期,我估計是2(來自ldr)+ 4 = 6

順便說一句,板沒有任何緩存,並且我將代碼存儲在sramx中,並且堆棧在sram2中。

我錯過了什麼,它有什麼辦法可以弄清楚每個週期如何消耗?此外,我也對cortex-m4的數據依賴性感到困惑。

+0

如果沒有任何緩存,您可能不得不爲循環獲取指令提取額外的費用。另請注意,您計算的週期時間只包含讀取DWT-> CYCCNT的兩條LDR指令之一,而不是兩條指令。推測它們在執行兩條指令時(例如在開始時)在相同的相對點處讀取循環計數。要包含這兩者,循環次數必須在第一個LDR指令開始時和第二個LDR指令結束時。 –

+0

我同意你的意見,但你的意思是每個指令fetche的週期額外成本 –

+0

每個指令獲取,但我不知道如何Cortex-M4指令提取。例如,它可能會在每個提取中獲取32位字,因此並非每條指令都會支付它。 –

回答

1

採取變化,我沒有那個芯片,但有其他人。在這種情況下使用ti cortex-m4。 st部分在閃存前面有這個緩存,我不認爲你可以關閉並且(按照設計)影響性能。

00000082 <test>: 
    82: f3bf 8f4f dsb sy 
    86: f3bf 8f6f isb sy 
    8a: 6802  ldr r2, [r0, #0] 
    8c: 46c0  nop   ; (mov r8, r8) 
    8e: 46c0  nop   ; (mov r8, r8) 
    90: 46c0  nop   ; (mov r8, r8) 
    92: 46c0  nop   ; (mov r8, r8) 
    94: 46c0  nop   ; (mov r8, r8) 
    96: 46c0  nop   ; (mov r8, r8) 
    98: f240 0102 movw r1, #2 
    9c: f240 0103 movw r1, #3 
    a0: 46c0  nop   ; (mov r8, r8) 
    a2: 46c0  nop   ; (mov r8, r8) 
    a4: 46c0  nop   ; (mov r8, r8) 
    a6: 46c0  nop   ; (mov r8, r8) 
    a8: 46c0  nop   ; (mov r8, r8) 
    aa: 46c0  nop   ; (mov r8, r8) 
    ac: 46c0  nop   ; (mov r8, r8) 
    ae: 6803  ldr r3, [r0, #0] 
    b0: 1ad0  subs r0, r2, r3 
    b2: 4770  bx lr 

因此,沒有第二MOVW需要閃光燈爲0x11的時鐘,並根據對準在RAM爲0x10和0×11之間。當thumb2指令在字邊界上對齊時,它比未對齊時需要更長的時鐘。

使用Thumb指令爲0x2102

00000000 20001016 00000010 
00000002 20001018 00000010 
00000004 2000101A 00000010 
00000006 2000101C 00000010 

使用的Thumb2擴展0xf240,0x0102

00000000 20001016 00000010 
00000002 20001018 00000011 
00000004 2000101A 00000010 
00000006 2000101C 00000011 

使用的Thumb2擴展0xf240,0x0102,0xf240,0x0103

00000000 20001016 00000012 
00000002 20001018 00000013 
00000004 2000101A 00000012 
00000006 2000101C 00000013 

這並不是一個驚喜,可能與提取有關。這些微控制器比全尺寸手臂簡單得多。完整大小將獲取每條提取8條指令,並且取決於獲取線中的東西會影響性能,更重要的還有循環以及分支位於獲取線的位置(緩存打開或關閉無關緊要)。分支也有可以打開和關閉的分支預測器,並且可以在設計上有所不同。

這個特殊的芯片說40Mhz以上它可以提取一個字的預取,意味着在它下面會提取一個半字(總線可能是一個字寬,所以兩次讀取相同的地址以獲得兩條指令...)爲什麼?)

其他芯片(cortex-ms以及其他芯片)你必須控制閃存上的等待狀態,有時閃存速度是內存速度的一半,相同的代碼,相同的機器代碼,運行速度更快即使在低速情況下也可以在內存上運行,並且隨着您增加時鐘和增加閃存上的等待狀態數量而變得更糟,以保持其速度。

特別是ST家族有一些營銷術語,用於預取緩存,它們放在你不能禁用的東西。您可以在測試剛代碼之前做DSB/ISB和例如見等待狀態爲單次的影響,但如果做一個測試循環

test_loop: sub r3,#1 
bne test_loop 

並運行它的時候有很多的幾個時鐘在開始時會反映出來,但很小,就像使用緩存一樣,但如果處理器讓您看到這些緩存,您仍應該看到對緩存的獲取線效果。

某些芯片具有可以啓用或禁用的閃存預取功能,尤其是循環可能會損害性能,而不是幫助您將事情正確對齊,以便預取程序在循環結束時讀取良好。 ARM的IP在內核邊緣(AXI,AMBA,AHB,APB,無論什麼)的邊界總線上停止,一般情況下,你可能有一個L2緩存的ARM IP(不是這些微控制器中的一個),而你可能會購買一些arm ip來幫助你的總線,但是最終該芯片具有芯片特定的東西,該芯片與芯片供應商和芯片供應商沒有任何關係,特別是閃存和sram接口。如上所示,首先沒有理由期望使用流水線處理器獲得可預測的結果,並且真正容易用兩個指令循環顯示,由於單獨對齊,相同的機器代碼在性能上可能差別很大,而且還您直接或間接控制的因素,閃光燈等待狀態,時鐘與閃光燈的相對速度。如果我們設備上的N和N + 1等待狀態之間的邊界爲24Mhz,那麼在N + 1個等待狀態下,N個等待狀態下的24Mhz比24Mhz快得多。在N + 1等待狀態下,28Mhz(N + 1等待狀態)比24Mhz快,但最終cpu時鐘可能會克服等待狀態,你可以發現CPU速度超過24Mhz n + 1等待狀態,時鐘定時性能,而不是計數CPU時鐘,如果受到閃存等待狀態的影響,CPU時鐘應該始終受到閃存等待狀態的影響。

srams通常不會有等待狀態,運行速度與CPU一樣快,但可能有例外情況。毫無疑問,性能有限制,許多供應商都有關於外設時鐘的規則,儘管該部分達到了48位,但仍然不能超過32mhz,所以訪問外設的基準測試將採用不同數量的cpu時鐘在不同的CPU /系統速度設置。

您也可以在處理器中配置選項,基本上編譯時間選項。 cortex-m4不會做廣告,但cortex-m0 +可以配置爲16或32位指令取指寬度。我沒有那個源代碼的可見性,所以它可能是必須是編譯時間的東西,或者如果你選擇你可以設置一個控制寄存器並使其可以運行時配置,或者可能有邏輯說明如果pll設置是這樣的強迫一種方式,其他方式,等等。所以,即使你有兩個來自不同廠商的芯片具有相同的rev和型號的cpu核心,這並不意味着它們會表現相同。更不用說芯片供應商擁有源代碼並且可以進行修改。

因此,試圖預測系統中流水線處理器的循環計數,這種情況不會發生。您將有時間添加一個額外的nop,並且它會變得更快,您添加一個的時間會減少,並且會變得更慢,正如您期望的那樣,以及它不會更改的時間。如果一個nop可以做到這一點,那麼任何其他的指令也可以。

更不用說與管道本身搞混了,這些cortex-ms真的很短管道,所以我們被告知如此迫使一系列帶有很多依賴關係的指令與類似的順序沒有不會有太大的影響。

以相同的機器碼進行測試在不同供應商的幾個cortex-m4上運行它(甚至是cortex-m3s和cortex-m7s),使用不同設置的閃存和RAM,並且不應該有驚喜在cpu ticks中的執行時間會有所不同。

+0

如果您正在使用內聯彙編以獲得某些手工彙編性能,那是另一個會影響性能的未知數,或者會因編譯而異(在此處添加一行,在其他位置刪除一行)該程序)。 –

+0

非常感謝,我也注意到指令對齊會影響性能。我會閱讀你以後認真說過的話。 –

+0

您正處於理解的正確軌道。或者根本不瞭解情況。你應該能夠像你一樣做實驗,並看到相同的機器代碼可以有不同的表現。爲什麼我們可以推測它並且非常接近,但是沒有獲得邏輯和模擬的確實知道。 –