轉自:Linux記憶體uncache區域拷貝優化 https://blog.csdn.net/u011037593/article/details/115024275
1.概述
記憶體非cache區域拷貝速度很慢,嚴重影響了系統性能,是以采用多種方法進行優化,主要有對齊拷貝、批量拷貝、減少循環次數、NEON拷貝方法。
2.進階SIMD和浮點寄存器介紹
2.NEON指令
2.1 VLDR
VLDR指令可從記憶體中将資料加載到擴充寄存器中。
VLDR{<c>}{<q>}{.64} <Dd>, [<Rn> {, #+/-<imm>}] Encoding T1/A1, immediate form
VLDR{<c>}{<q>}{.64} <Dd>, <label> Encoding T1/A1, normal literal form
VLDR{<c>}{<q>}{.64} <Dd>, [PC, #+/-<imm>] Encoding T1/A1, alternative literal form
VLDR{<c>}{<q>}{.32} <Sd>, [<Rn> {, #+/-<imm>}] Encoding T2/A2, immediate form
VLDR{<c>}{<q>}{.32} <Sd>, <label> Encoding T2/A2, normal literal form
VLDR{<c>}{<q>}{.32} <Sd>, [PC, #+/-<imm>] Encoding T2/A2, alternative literal form
<c>,<q>:是一個可選的條件代碼。
.32,.64:是一個可選的資料大小說明符。如果是單精度VFP寄存器,則必須為32;否則必須為64。
Dd:雙字(64位)加載的目标寄存器。對于NEON指令,它必須為D寄存器。對于VFP指令,它可以為D或S寄存器。
Sd:單字(32位)加載的目标寄存器。對于NEON指令,它必須為D寄存器。對于VFP指令,它可以為D或S寄存器。
Rn:存放要傳送的基址的ARM寄存器,SP可使用。
+/-:偏移量相對于基位址的運算方式,+表示基位址和偏移量相加,-表示基位址和偏移量相減,+可以省略,#0和#-0生成不同的指令。
imm:是一個可選的數值表達式。在彙編時,該表達式的值必須為一個數字常數。 該值必須是4的倍數,并在0 - 1020的範圍内。該值與基址相加得到用于傳送的位址。
label:要加載資料項的标簽。編譯器自動計算指令的Align(PC, 4)值到此标簽的偏移量。允許的值是4的倍數,在-1020到1020的範圍内。
2.2 VLDM
VLDM指令可以将連續記憶體位址中的資料加載到擴充寄存器中。
VLDM{<mode>}{<c>}{<q>}{.<size>} <Rn>{!}, <list>
<mode>:IA Increment After,連續位址的起始位址在Rn寄存器中,先加載資料,然後Rn寄存器中的位址在增大,這是預設的方式,DB Decrement Before,連續位址的起始位址在Rn寄存器中,Rn寄存器中的位址先減小,再加載資料
<c>,<q>:是一個可選的條件代碼。
<size>:是一個可選的資料大小說明符。取32或64,和<list>中寄存器的位寬一緻。
Rn:存放要傳送的基址的ARM寄存器,由ARM指令設定,SP可使用。
!:表示Rn寄存器中的内容變化時要将變化的值寫入Rn寄存器中。
<list>:加載的擴充寄存器清單。至少包含一個寄存器,如果包含了64位寄存器,最多不超過16個寄存器。
2.3 VSTR
VSTR指令将擴充寄存器中的資料儲存到記憶體中。
VSTR{<c>}{<q>}{.64} <Dd>, [<Rn>{, #+/-<imm>}] Encoding T1/A1
VSTR{<c>}{<q>}{.32} <Sd>, [<Rn>{, #+/-<imm>}] Encoding T2/A2
<c>,<q>:是一個可選的條件代碼。
.32,.64:是一個可選的資料大小說明符。如果是單精度VFP寄存器,則必須為32;否則必須為64。
Dd:雙字(64位)加載的目标寄存器。對于NEON指令,它必須為D寄存器。對于VFP指令,它可以為D或S寄存器。
Sd:但字(32位)加載的目标寄存器。對于NEON指令,它必須為D寄存器。對于VFP指令,它可以為D或S寄存器。
Rn:存放要傳送的基址的ARM寄存器,SP可使用。
+/-:偏移量相對于基位址的運算方式,+表示基位址和偏移量相加,-表示基位址和偏移量相減,+可以省略,#0和#-0生成不同的指令。
imm:是一個可選的數值表達式。在彙編時,該表達式的值必須為一個數字常數。 該值必須是4的倍數,并在0 - 1020的範圍内。該值與基址相加得到用于傳送的位址。
2.4 VSTM
VSTM指令可将擴充寄存器清單中的資料儲存到連續的記憶體中。
VSTM{<mode>}{<c>}{<q>}{.<size>} <Rn>{!}, <list>
<mode>:IA Increment After,連續位址的起始位址在Rn寄存器中,先儲存資料,然後Rn寄存器中的位址在增大,這是預設的方式,DB Decrement Before,連續位址的起始位址在Rn寄存器中,Rn寄存器中的位址先減小,再儲存資料
<c>,<q>:是一個可選的條件代碼。
<size>:是一個可選的資料大小說明符。取32或64,和<list>中寄存器的位寬一緻。
Rn:存放要傳送的基址的ARM寄存器,由ARM指令設定,SP可使用。
!:表示Rn寄存器中的内容變化時要将變化的值寫入Rn寄存器中。
<list>:儲存的擴充寄存器清單。至少包含一個寄存器,如果包含了64位寄存器,最多不超過16個寄存器。
3.ARM架構程式調用寄存器使用規則
3.1.ARM寄存器使用規則
(1)子程式間通過寄存器R0-R3傳遞參數,被調用的子程式在傳回前無須恢複寄存器R0-R3的内容,參數多餘4個時,使用棧傳遞,參數入棧的順序與參數順序相反。
(2)在子程式中,使用寄存器R4-R11儲存局部變量,如果子程式中使用了R4-R11的寄存器,則必須在使用之前儲存這些寄存器,子程式傳回之前恢複這些寄存器,在子程式中沒有使用這些寄存器,則無須儲存。
(3)寄存器R12用作子程式間的scratch寄存器,記作IP,在子程式間的連結代碼段中常有這種規則。
(4)寄存器R13用作資料棧指針,記作SP。在子程式中,寄存器R13不能用作其它用途。
(5)寄存器R14用作連接配接寄存器,記作IR。用于儲存子程式的傳回位址,如果在子程式中儲存了傳回位址,寄存器R14可用于其他用途。
(6)寄存器R15是程式計數器,記作PC。不能用作其他用途。
3.2.NEON寄存器使用規則
(1)NEON S16-S31(D8-D15,Q4-Q7)寄存器在子程式中必須儲存,S0-S15(D0-D7,Q4-Q7)和Q8-Q15在子程式中無須儲存
3.3.子程式傳回寄存器使用規則
(1)結果為一個32位整數時,可以通過寄存器R0傳回。
(2)結果為一個64位整數時,可通過寄存器R0和R1傳回,依次類推。
(3)結果為一個浮點數時,可以通過浮點運算部件的寄存器F0、D0或者S0來傳回。
(4)結果為複合型的浮點數時,可以通過寄存器F0-Fn或者D0-Dn傳回。
(5)對于位數更多的結果,需要記憶體來傳遞。
3.優化代碼
PLD為arm預加載執行的宏定義,下面彙編編寫的函數中都使用到了。
#if 1
#define PLD(code...) code
#else
#define PLD(code...)
#endif
3.1.memcpy_libc
memcpy_libc為libc的庫函數memcpy。
3.2.memcpy_1
一次循環隻拷貝一個位元組,可用于對齊拷貝和非對齊拷貝。
void *memcpy_1(void *dest, const void *src, size_t count)
{
char *tmp = dest;
const char *s = src;
while (count--)
*tmp++ = *s++;
return dest;
}
3.3.memcpy_32
memcpy_32一次循環拷貝32位元組,适用于32位元組對齊拷貝。
@ void* memcpy_32(void*, const void*, size_t);
@ 聲明符号為全局作用域
.global memcpy_32
@ 4位元組對齊
.align 4
@ 聲明memcpy_32類型為函數
.type memcpy_32, %function
memcpy_32:
@ r4-r12, lr寄存器入棧
push {r4-r11, lr}
@ memcpy的傳回值為目标存儲區域的首位址,即第一個參數值,将傳回值儲存到r3寄存器中
mov r3, r0
0:
@ 資料預取指令,會将資料提前加載到cache中
PLD( pld [r1, #128] )
@ r2為memcpy的第3個參數,表示拷貝多少個位元組數,首先減去32,
@ s:決定指令的操作是否影響CPSR的值
subs r2, r2, #32
@ r1為memcpy的第2個參數,表示源資料的位址,将源位址中的資料加載到r4-r11寄存器中
@ 每加載一個寄存器,r1中的位址增加4,總共8個寄存器,共32位元組資料
ldmia r1!, {r4-r11}
@ 将r4-r11中儲存的源資料加載到r1寄存器指向的記憶體位址,每加載一個寄存器,r1指向的位址加4
stmia r0!, {r4-r11}
@stmia r0!, {r8-r11}
@ gt為條件碼,帶符号數大于,Z=0且N=V
bgt 0b
@ 函數退出時将傳回值儲存到r0中
mov r0, r3
pop {r4-r11, pc}
.type memcpy_32, %function
@函數體的大小,.-memcpy_32中的.代表目前指令的位址,
@即點.減去标号memcpy_32,标号代表目前指令的位址
.size memcpy_32, .-memcpy_32
3.4.memcpy_64
memcpy_64一次循環拷貝64位元組,适用于64位元組對齊拷貝。
@ void* memcpy_64(void*, const void*, size_t);
.global memcpy_64
.align 4
.type memcpy_64, %function
memcpy_64:
push {r4-r11, lr}
mov r3, r0
0:
PLD( pld [r1, #256] )
subs r2, r2, #64
ldmia r1!, {r4-r11}
PLD( pld [r1, #256] )
stmia r0!, {r4-r7}
stmia r0!, {r8-r11}
ldmia r1!, {r4-r11}
stmia r0!, {r4-r7}
stmia r0!, {r8-r11}
bgt 0b
mov r0, r3
pop {r4-r11, pc}
.type memcpy_64, %function
.size memcpy_64, .-memcpy_64
3.5.memcpy_gen
memcpy_gen是通用的記憶體拷貝函數,可根據源位址和目的位址是否對齊,采用不同的拷貝方法,适用于對齊和非對齊拷貝。此代碼參考自Linux核心。
(1)判斷拷貝的位元組數是否小于4位元組,若小于4位元組,則直接進行單位元組拷貝
(2)判斷目的位址是否時按4位元組對齊,若沒有,則進入目的位址未對齊的處理邏輯
(3)判斷源位址是否按4位元組對齊,若沒有,則進入源位址未對齊的處理邏輯
(4)若目的位址和源位址按4位元組對齊,則進入目的位址和源位址對齊的處理邏輯
目的位址和源位址對齊的處理邏輯:
(1)若拷貝的位元組數大于等于32位元組,則将超過32位元組的資料進行批量拷貝,每次拷貝32位元組
(2)若剩下的資料小于32位元組,則進行4位元組拷貝
(3)若剩下的資料小于4位元組,則進行單位元組拷貝
目的位址未對齊的處理邏輯:
(1)先将未對齊的位元組進行單位元組拷貝,使目的位址按4位元組對齊
(2)若剩餘的資料小于4位元組,則進行單位元組拷貝
(3)此時若源位址也按4位元組對齊,則進入目的位址和源位址對齊的處理邏輯
(4)若源位址未按4位元組對齊,則進入源位址未對齊的處理邏輯
源位址未對齊的處理邏輯:
(1)将源位址中的資料加載的寄存器中,進行邏輯移位
(2)将低位址的源資料邏輯左移,移到寄存器的低位,将高位址的資料邏輯右移,移到寄存器的高位
(3)将兩個寄存器的資料進行或操作,實作了低位址和高位址資料在寄存器中的拼接
(4)将拼接的資料加載到目的位址中
#define LDR1W_SHIFT 0
#define STR1W_SHIFT 0
#if __BYTE_ORDER == __BIG_ENDIAN
// 大端
#define lspull lsl
#define lspush lsr
#elif __BYTE_ORDER == __LITTLE_ENDIAN
// 小端,一般都是小端
#define lspull lsr
#define lspush lsl
#else
#error "unknow byte order"
#endif
.macro ldr1w ptr reg abort
ldr \reg, [\ptr], #4
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
.endm
.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
.endm
.macro ldr1b ptr reg cond=al abort
ldr\cond\()b \reg, [\ptr], #1
.endm
.macro str1w ptr reg abort
str \reg, [\ptr], #4
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
.endm
.macro str1b ptr reg cond=al abort
str\cond\()b \reg, [\ptr], #1
.endm
.macro enter reg1 reg2
stmdb sp!, {r0, \reg1, \reg2}
.endm
.macro exit reg1 reg2
ldmfd sp!, {r0, \reg1, \reg2}
.endm
@ void* memcpy_gen(void*, const void*, size_t);
@ 聲明符号為全局作用域
.global memcpy_gen
@ 4位元組對齊
.align 4
@ 聲明memcpy_gen類型為函數
.type memcpy_gen, %function
memcpy_gen:
@ 将r0 r4 lr寄存器儲存到棧中,r0是函數的傳回值
enter r4, lr
@ 拷貝的位元組數減4并儲存到r2中,運算結果影響CPSR中的标志位
subs r2, r2, #4
@ blt:帶符号數小于
@ 如果拷貝的位元組數小于4,則跳轉到标号8處
blt 8f
@ r0儲存的是目的位址,r0和3與,判斷r0的低兩位是否是0,不是0,則是未對齊的位址
@ s:決定指令的操作是否影響CPSR的值
ands ip, r0, #3 @ 測試目的位址是否是按4位元組對齊
PLD( pld [r1, #0] )
bne 9f @ 目的位址沒有按4位元組對齊,則跳轉到标号9處
ands ip, r1, #3 @ 測試源位址是否是按4位元組對齊
bne 10f @ 源位址沒有按4位元組對齊,則跳轉到标号10處
1: subs r2, r2, #(28)
stmfd sp!, {r5 - r8}
blt 5f
PLD( pld [r1, #0] )
2: subs r2, r2, #96
PLD( pld [r1, #28] )
blt 4f
PLD( pld [r1, #60] )
PLD( pld [r1, #92] )
3: PLD( pld [r1, #124] )
4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
subs r2, r2, #32
str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
bge 3b
cmn r2, #96
bge 4b
5: ands ip, r2, #28
rsb ip, ip, #32
#if LDR1W_SHIFT > 0
lsl ip, ip, #LDR1W_SHIFT
#endif
addne pc, pc, ip @ C is always clear here
b 7f
6:
@ .rept:重複定義僞操作, 格式如下:
@ .rept 重複次數
@ 資料定義
@ .endr 結束重複定義
@ 例如:
@ .rept 3
@ .byte 0x23
@ .endr
.rept (1 << LDR1W_SHIFT)
nop
.endr
ldr1w r1, r3, abort=20f
ldr1w r1, r4, abort=20f
ldr1w r1, r5, abort=20f
ldr1w r1, r6, abort=20f
ldr1w r1, r7, abort=20f
ldr1w r1, r8, abort=20f
ldr1w r1, lr, abort=20f
#if LDR1W_SHIFT < STR1W_SHIFT
lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT
#elif LDR1W_SHIFT > STR1W_SHIFT
lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT
#endif
add pc, pc, ip
nop
.rept (1 << STR1W_SHIFT)
nop
.endr
str1w r0, r3, abort=20f
str1w r0, r4, abort=20f
str1w r0, r5, abort=20f
str1w r0, r6, abort=20f
str1w r0, r7, abort=20f
str1w r0, r8, abort=20f
str1w r0, lr, abort=20f
7: ldmfd sp!, {r5 - r8}
8: @ 處理拷貝的位元組數小于4位元組,此時r2中的值為負數,可能取值為-1 -2 -3
@ lsl 邏輯左移,将r2左移31位儲存帶r2中
movs r2, r2, lsl #31
@ ne 不相等,Z=0,r2為-1或-3時拷貝資料
ldr1b r1, r3, ne, abort=21f
@ cs 無符号數大于等于,C=1
@ 對于包含移位操作的非加/減法運算指令,C中包含最後一次被溢出的位的數值
ldr1b r1, r4, cs, abort=21f
ldr1b r1, ip, cs, abort=21f
str1b r0, r3, ne, abort=21f
str1b r0, r4, cs, abort=21f
str1b r0, ip, cs, abort=21f
exit r4, pc
9: @ 處理目的位址未按4位元組對齊的情況
@ rsb 逆向減法指令,等價于ip=4-ip,同時根據操作結果更新CPSR中相應的條件标志
@ 當rsb的運算結果為負數時,N=1,為正數或0時,N=0
@ 當rsb的運算結果符号位溢出時,V=1
rsb ip, ip, #4 @ 當位址不按4位元組對齊的時候,ip的值取值可能為1、2、3
@ 對于cmp指令,Z=1表示進行比較的兩個數大小相等
cmp ip, #2 @ cmp影響
@ gt:帶符号數大于,Z=0且N=V
ldr1b r1, r3, gt, abort=21f @ ip為3時将資料加載到r3寄存器中,同時r1=r1+1
@ ge:帶符号數大于等于,N=1且V=1或N=0且V=0
ldr1b r1, r4, ge, abort=21f @ ip為2時将資料加載到r4寄存器中,同時r1=r1+1
ldr1b r1, lr, abort=21f @ ip為1時将資料加載到lr寄存器中,同時r1=r1+1
str1b r0, r3, gt, abort=21f
str1b r0, r4, ge, abort=21f
subs r2, r2, ip @ 更新拷貝的位元組數
str1b r0, lr, abort=21f
@ 帶符号數小于,N=1且V=0或N=0且V=1
blt 8b
ands ip, r1, #3 @ 測試源位址是否是4位元組對齊的情況
@ eq 相等,Z=1,r1中的位址已按4位元組對齊,則跳轉到标号1處,否則繼續向下執行
beq 1b
10: @ 處理源位址未按4位元組對齊的情況
@ bic指令用于清除操作數1的某些位,并把結果放置到目的寄存器中
@ 将r1的低2位清0
bic r1, r1, #3
@ ip儲存了r1的低兩位,源位址的低2位與2比較
cmp ip, #2
@ 無條件執行,将r1寄存器指向的4位元組資料加載到lr寄存器中,拷貝完r1=r1+4
ldr1w r1, lr, abort=21f
@ eq 相等,Z=1
@ ip寄存器和2相等
beq 17f
@ gt:帶符号數大于,Z=0且N=V
@ ip寄存器大于2
bgt 18f
.macro forward_copy_shift pull push
@ r2寄存器減去28
subs r2, r2, #28
@ 帶符号數小于,N=1且V=0或N=0且V=1,r2小于28跳轉到14處
blt 14f
11: @ 儲存r5-r9寄存器,同時更新sp寄存器,fd:滿遞減
stmfd sp!, {r5 - r9}
PLD( pld [r1, #0] )
subs r2, r2, #96 @ r2減去96
PLD( pld [r1, #28] )
blt 13f @ 帶符号數小于,N=1且V=0或N=0且V=1,r2小于96跳轉到13處
PLD( pld [r1, #60] )
PLD( pld [r1, #92] )
12: PLD( pld [r1, #124] )
13: @ lspull(小端) = lsr:邏輯右移
@ lspush(小端) = lsr:邏輯左移
ldr4w r1, r4, r5, r6, r7, abort=19f
@ lr邏輯右移pull位并存儲到r3寄存器中
mov r3, lr, lspull #\pull
subs r2, r2, #32
ldr4w r1, r8, r9, ip, lr, abort=19f
@ r4邏輯左移push位,然後和r3或,最後将結果儲存到r3中
@ 将r4的push位儲存到r3的(32-push)位
orr r3, r3, r4, lspush #\push
mov r4, r4, lspull #\pull
orr r4, r4, r5, lspush #\push
mov r5, r5, lspull #\pull
orr r5, r5, r6, lspush #\push
mov r6, r6, lspull #\pull
orr r6, r6, r7, lspush #\push
mov r7, r7, lspull #\pull
orr r7, r7, r8, lspush #\push
mov r8, r8, lspull #\pull
orr r8, r8, r9, lspush #\push
mov r9, r9, lspull #\pull
orr r9, r9, ip, lspush #\push
mov ip, ip, lspull #\pull
orr ip, ip, lr, lspush #\push
str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
bge 12b
cmn r2, #96
bge 13b
ldmfd sp!, {r5 - r9}
14: ands ip, r2, #28
beq 16f
15: mov r3, lr, lspull #\pull
ldr1w r1, lr, abort=21f
subs ip, ip, #4
orr r3, r3, lr, lspush #\push
str1w r0, r3, abort=21f
bgt 15b
16: sub r1, r1, #(\push / 8)
b 8b
.endm
forward_copy_shift pull=8 push=24
17: forward_copy_shift pull=16 push=16
18: forward_copy_shift pull=24 push=8
.macro copy_abort_preamble
19: ldmfd sp!, {r5 - r9}
b 21f
20: ldmfd sp!, {r5 - r8}
21:
.endm
.macro copy_abort_end
ldmfd sp!, {r4, pc}
.endm
.type memcpy_gen, %function
@函數體的大小,.-memcpy_gen中的.代表目前指令的位址,
@即點.減去标号memcpy_gen,标号代表目前指令的位址
.size memcpy_gen, .-memcpy_gen
3.6.memcpy_neon_64
memcpy_neon_64使用NEON寄存器進行加速拷貝,一次拷貝64位元組,适用于64位元組的對齊拷貝。
@ void* memcpy_neon_64(void*, const void*, size_t);
@ 聲明符号為全局作用域
.global memcpy_neon_64
@ 4位元組對齊
.align 4
@ 聲明memcpy_neno類型為函數
.type memcpy_neon_64, %function
memcpy_neon_64:
@ 儲存傳回值
mov r3, r0
0:
PLD( pld [r1, #256] )
subs r2, r2, #64
vldmia.64 r1!, {d0-d7}
vstmia.64 r0!, {d0-d7}
bgt 0b
@ 函數退出時将傳回值儲存到r0中
mov r0, r3
@ 将函數的傳回位址儲存搭配pc中,退出函數
mov pc, lr
.type memcpy_neon_64, %function
@函數體的大小,.-memcpy_neon_64中的.代表目前指令的位址,
@即點.減去标号memcpy_neon_64,标号代表目前指令的位址
.size memcpy_neon_64, .-memcpy_neon_64
3.7.memcpy_neon_128
memcpy_neon_128使用NEON寄存器進行加速拷貝,一次拷貝128位元組,适用于128位元組的對齊拷貝。
@ void* memcpy_neon_128(void*, const void*, size_t);
@ 聲明符号為全局作用域
.global memcpy_neon_128
@ 4位元組對齊
.align 4
@ 聲明memcpy_neno類型為函數
.type memcpy_neon_128, %function
memcpy_neon_128:
@ 儲存neon寄存器
vpush.64 {d8-d15}
@ 儲存傳回值
mov r3, r0
0:
PLD( pld [r1, #512] )
subs r2, r2, #128
vldmia.64 r1!, {d0-d15}
vstmia.64 r0!, {d0-d15}
bgt 0b
@ 函數退出時将傳回值儲存到r0中
mov r0, r3
vpop.64 {d8-d15}
@ 将函數的傳回位址儲存搭配pc中,退出函數
mov pc, lr
.type memcpy_neon_128, %function
@函數體的大小,.-memcpy_neon_128中的.代表目前指令的位址,
@即點.減去标号memcpy_neon_128,标号代表目前指令的位址
.size memcpy_neon_128, .-memcpy_neon_128
3.速度測試
3.1.對齊拷貝測試(機關:MiB/s)
3.2.非對齊拷貝測試(機關:MiB/s)
4.影響拷貝速度的因素
(1)一次循環拷貝資料的位元組數
(2)位址是否對齊
(3)pld預取對uncache拷貝影響很小
5.結論
(1)大批量資料拷貝時,應将源位址和目的位址按32位元組、64位元組或128位元組對齊
(2)按32位元組、64位元組或128位元組對齊的資料,使用neon寄存器進行批量拷貝,若無neon寄存器,則使用arm寄存器進行批量拷貝
(3)若拷貝的位元組數小于要求的位元組數,則使用通用的方法進行拷貝
(4)uncache區域拷貝,預加載pld指令對拷貝速度的提升有限