L1 캐시의 Haswell에서 최대 대역폭 확보: 62%밖에 확보하지 못함
인텔 프로세서의 다음 기능을 위해 L1 캐시에서 전체 대역폭을 얻으려고 합니다.
float triad(float *x, float *y, float *z, const int n) {
float k = 3.14159f;
for(int i=0; i<n; i++) {
z[i] = x[i] + k*y[i];
}
}
STREAM의 트라이애드 함수입니다.
이 기능을 탑재한 SandyBridge/IvyBridge 프로세서의 피크율은 약 95%입니다(NASM과의 어셈블리 사용).그러나 Haswell을 사용하면 루프를 풀지 않는 한 피크 중 62%만 달성합니다.16번 펼치면 92%가 나옵니다.저는 이것을 이해하지 못하겠어요.
조립 시에 NASM을 사용하여 기능을 쓰기로 했습니다.어셈블리의 메인 루프는 다음과 같습니다.
.L2:
vmovaps ymm1, [rdi+rax]
vfmadd231ps ymm1, ymm2, [rsi+rax]
vmovaps [rdx+rax], ymm1
add rax, 32
jne .L2
예 12.7-12.11의 Agner Fog의 Optimizing Assembly 매뉴얼에서 그는 거의 동일한 작업을 수행하는 것으로 나타났습니다(단,y[i] = y[i] +k*x[i]
Pentium M, Core 2, Sandy Bridge, FMA4, FMA3 ( )나는 그의 코드를 거의 혼자서 재현할 수 있었다(실제로 그는 방송할 때 FMA3의 예에 작은 버그가 있다).그는 FMA4 및 FMA3를 제외한 각 프로세서의 테이블에서 명령 크기 수, 퓨전 ops, 실행 포트를 제공합니다.저는 이 테이블을 FMA3용으로 직접 만들어 보았습니다.
ports
size μops-fused 0 1 2 3 4 5 6 7
vmovaps 5 1 ½ ½
vfmadd231ps 6 1 ½ ½ ½ ½
vmovaps 5 1 1 1
add 4 ½ ½
jne 2 ½ ½
--------------------------------------------------------------
total 22 4 ½ ½ 1 1 1 0 1 1
크기는 명령 길이(바이트)를 나타냅니다.의 add
★★★★★★★★★★★★★★★★★」jne
명령어에는 0.5μop이 있습니다.이것은, 1개의 매크로 op에 융합되어 있어(복수의 포토를 사용하는 μop 퓨전과는 혼동하지 말아 주세요), 포토 6과 1개의 μop만을 필요로 하는 경우입니다.명령에서는 포트 0 또는 포트 1을 사용할 수 있습니다. 포트 0을 선택했습니다. 로드는 포트 2 또는3 을 사용할 수 있습니다. 2개를 선택하고 포트 3을 사용했습니다.Agner Fog의 표와 일관성을 유지하기 위해 서로 다른 포트로 균등하게 이동할 수 있는 명령이 각 포트로 1/2씩 이동한다고 하는 것이 더 합리적이라고 생각하기 때문에 포트에 1/2을 할당했습니다.vmovaps
★★★★★★★★★★★★★★★★★」vmadd231ps
아아아아아아아아아아아아아아아아아아아아아아아아.
이 표와 모든 Core2 프로세서가 클럭사이클마다 4μops를 실행할 수 있다는 사실을 고려하면 이 루프는 클럭사이클마다 가능한 것 같습니다만, 취득할 수 없었습니다.왜 하스웰의 이 기능의 최대 대역폭에 접근하지 않고서는 접근할 수 없는지 설명해 주시겠습니까? 전개하지 않고 이것이 가능한가?해당한다면 어떻게 해야 하는가?이 기능을 위해 ILP를 최대화하려고 합니다(최대 대역폭만 원하는 것은 아닙니다).그 때문에 언롤을 하고 싶지 않습니다.
편집: Idonotexist가 IACA를 사용하여 Idonotexist가 상점들이 포트 7을 사용하지 않는다는 것을 보여주었기 때문에 다음과 같은 업데이트가 있습니다.66%의 장벽을 풀지 않고 뚫을 수 있었습니다.또한 (이론적으로) 풀지 않고 반복할 때마다 한 번의 클럭 사이클로 이 작업을 수행할 수 있었습니다.우선 가게 문제를 해결합시다.
의 Address Generation Unit(AGU; 주소 유닛은 Stephen Canon과 같은 할 수 했습니다.[base + offset]
and[base + index]
인텔 최적화 레퍼런스 매뉴얼에서 찾은 것은 포트7에 "Simple"이라는 코멘트뿐입니다.AGU"는 단순한 의미에 대한 정의가 없다.그러나 Idonotexist는 IACA의 코멘트에서 이 문제가 이미 6개월 전에 언급되었음을 알게 되었습니다.이 문제는 인텔의 직원이 2014년 3월 11일에 다음과 같이 기술했습니다.
Port7 AGU는 단순한 메모리주소(인덱스 레지스터 없음)의 스토어에서만 동작할 수 있습니다.
Stephen Canon은 "로드 오퍼랜드의 오프셋으로 스토어 주소를 사용할 것"을 제안한다.이렇게 해봤는데
vmovaps ymm1, [rdi + r9 + 32*i]
vfmadd231ps ymm1, ymm2, [rsi + r9 + 32*i]
vmovaps [r9 + 32*i], ymm1
add r9, 32*unroll
cmp r9, rcx
jne .L2
이것에 의해, 스토어는 확실히 포토 7 을 사용합니다.또 , 그는 바로 '', '먹다'입니다. 바로 이 문제가vmadd231ps
IACA는 IACA에 대응하고 있습니다.ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ.cmp
내 원래 기능이 하지 못한 명령.가게에서는 마이크로옵션을 하나 덜 쓰지만cmp
그 다음)add
그 cmp
가 「」와 합니다.jne
더 가 하나 더 필요합니다.IACA의 1.5개입니다.실제로는, 이것은 피크시의 약 57%에 지나지 않습니다.
나는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★vmadd231ps
부하와 융합하는 지침도 있습니다.이 작업은 다음과 같이 주소 지정 [absolute 32bit address + index]를 사용하는 정적 어레이에서만 수행할 수 있습니다.Evgeny Kluev 오리지널은 이것을 제안했다.
vmovaps ymm1, [src1_end + rax]
vfmadd231ps ymm1, ymm2, [src2_end + rax]
vmovaps [dst_end + rax], ymm1
add rax, 32
jl .L2
서 ★★★★★src1_end
,src2_end
, , , , 입니다.dst_end
는 스태틱 어레이의 끝 주소입니다.
이것은 제가 예상했던 4개의 마이크로옵스를 사용한 질문의 표를 재현한 것입니다.이것을 IACA에 넣으면 블록 스루풋 1.0이 보고됩니다.이론적으로는 SSE 및 AVX 버전과 마찬가지로 유효합니다.실제로는 정점의 약 72%를 차지합니다.그것은 66%의 장벽을 무너뜨리지만 내가 16번이나 굴리는 92%와는 아직 멀었다.그래서 하스웰에서 산꼭대기에 가까이 갈 수 있는 유일한 방법은 굴리는 것이다.이것은 아이비 브릿지를 통해 Core2에서는 필요하지 않지만 Haswell에서는 필요합니다.
End_edit:
C/C++ Linux를 사용합니다.NASM 의 C/C++ 의 경우,츠미야에.double frequency = 1.3;
공칭 주파수가 를 1.3으로 1.3 GHz는 사용하시는 의 동작 주파수(공칭하다(BIOS)1.3GHz).
컴파일 대상
nasm -f elf64 triad_sse_asm.asm
nasm -f elf64 triad_avx_asm.asm
nasm -f elf64 triad_fma_asm.asm
g++ -m64 -lrt -O3 -mfma tests.cpp triad_fma_asm.o -o tests_fma
g++ -m64 -lrt -O3 -mavx tests.cpp triad_avx_asm.o -o tests_avx
g++ -m64 -lrt -O3 -msse2 tests.cpp triad_sse_asm.o -o tests_sse
C/C++ 코드
#include <x86intrin.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#define TIMER_TYPE CLOCK_REALTIME
extern "C" float triad_sse_asm_repeat(float *x, float *y, float *z, const int n, int repeat);
extern "C" float triad_sse_asm_repeat_unroll16(float *x, float *y, float *z, const int n, int repeat);
extern "C" float triad_avx_asm_repeat(float *x, float *y, float *z, const int n, int repeat);
extern "C" float triad_avx_asm_repeat_unroll16(float *x, float *y, float *z, const int n, int repeat);
extern "C" float triad_fma_asm_repeat(float *x, float *y, float *z, const int n, int repeat);
extern "C" float triad_fma_asm_repeat_unroll16(float *x, float *y, float *z, const int n, int repeat);
#if (defined(__FMA__))
float triad_fma_repeat(float *x, float *y, float *z, const int n, int repeat) {
float k = 3.14159f;
int r;
for(r=0; r<repeat; r++) {
int i;
__m256 k4 = _mm256_set1_ps(k);
for(i=0; i<n; i+=8) {
_mm256_store_ps(&z[i], _mm256_fmadd_ps(k4, _mm256_load_ps(&y[i]), _mm256_load_ps(&x[i])));
}
}
}
#elif (defined(__AVX__))
float triad_avx_repeat(float *x, float *y, float *z, const int n, int repeat) {
float k = 3.14159f;
int r;
for(r=0; r<repeat; r++) {
int i;
__m256 k4 = _mm256_set1_ps(k);
for(i=0; i<n; i+=8) {
_mm256_store_ps(&z[i], _mm256_add_ps(_mm256_load_ps(&x[i]), _mm256_mul_ps(k4, _mm256_load_ps(&y[i]))));
}
}
}
#else
float triad_sse_repeat(float *x, float *y, float *z, const int n, int repeat) {
float k = 3.14159f;
int r;
for(r=0; r<repeat; r++) {
int i;
__m128 k4 = _mm_set1_ps(k);
for(i=0; i<n; i+=4) {
_mm_store_ps(&z[i], _mm_add_ps(_mm_load_ps(&x[i]), _mm_mul_ps(k4, _mm_load_ps(&y[i]))));
}
}
}
#endif
double time_diff(timespec start, timespec end)
{
timespec temp;
if ((end.tv_nsec-start.tv_nsec)<0) {
temp.tv_sec = end.tv_sec-start.tv_sec-1;
temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
} else {
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_nsec = end.tv_nsec-start.tv_nsec;
}
return (double)temp.tv_sec + (double)temp.tv_nsec*1E-9;
}
int main () {
int bytes_per_cycle = 0;
double frequency = 1.3; //Haswell
//double frequency = 3.6; //IB
//double frequency = 2.66; //Core2
#if (defined(__FMA__))
bytes_per_cycle = 96;
#elif (defined(__AVX__))
bytes_per_cycle = 48;
#else
bytes_per_cycle = 24;
#endif
double peak = frequency*bytes_per_cycle;
const int n =2048;
float* z2 = (float*)_mm_malloc(sizeof(float)*n, 64);
char *mem = (char*)_mm_malloc(1<<18,4096);
char *a = mem;
char *b = a+n*sizeof(float);
char *c = b+n*sizeof(float);
float *x = (float*)a;
float *y = (float*)b;
float *z = (float*)c;
for(int i=0; i<n; i++) {
x[i] = 1.0f*i;
y[i] = 1.0f*i;
z[i] = 0;
}
int repeat = 1000000;
timespec time1, time2;
#if (defined(__FMA__))
triad_fma_repeat(x,y,z2,n,repeat);
#elif (defined(__AVX__))
triad_avx_repeat(x,y,z2,n,repeat);
#else
triad_sse_repeat(x,y,z2,n,repeat);
#endif
while(1) {
double dtime, rate;
clock_gettime(TIMER_TYPE, &time1);
#if (defined(__FMA__))
triad_fma_asm_repeat(x,y,z,n,repeat);
#elif (defined(__AVX__))
triad_avx_asm_repeat(x,y,z,n,repeat);
#else
triad_sse_asm_repeat(x,y,z,n,repeat);
#endif
clock_gettime(TIMER_TYPE, &time2);
dtime = time_diff(time1,time2);
rate = 3.0*1E-9*sizeof(float)*n*repeat/dtime;
printf("unroll1 rate %6.2f GB/s, efficency %6.2f%%, error %d\n", rate, 100*rate/peak, memcmp(z,z2, sizeof(float)*n));
clock_gettime(TIMER_TYPE, &time1);
#if (defined(__FMA__))
triad_fma_repeat(x,y,z,n,repeat);
#elif (defined(__AVX__))
triad_avx_repeat(x,y,z,n,repeat);
#else
triad_sse_repeat(x,y,z,n,repeat);
#endif
clock_gettime(TIMER_TYPE, &time2);
dtime = time_diff(time1,time2);
rate = 3.0*1E-9*sizeof(float)*n*repeat/dtime;
printf("intrinsic rate %6.2f GB/s, efficency %6.2f%%, error %d\n", rate, 100*rate/peak, memcmp(z,z2, sizeof(float)*n));
clock_gettime(TIMER_TYPE, &time1);
#if (defined(__FMA__))
triad_fma_asm_repeat_unroll16(x,y,z,n,repeat);
#elif (defined(__AVX__))
triad_avx_asm_repeat_unroll16(x,y,z,n,repeat);
#else
triad_sse_asm_repeat_unroll16(x,y,z,n,repeat);
#endif
clock_gettime(TIMER_TYPE, &time2);
dtime = time_diff(time1,time2);
rate = 3.0*1E-9*sizeof(float)*n*repeat/dtime;
printf("unroll16 rate %6.2f GB/s, efficency %6.2f%%, error %d\n", rate, 100*rate/peak, memcmp(z,z2, sizeof(float)*n));
}
}
System V AMD64 ABI를 사용한NASM 코드
triad_fma_asm.asm:
global triad_fma_asm_repeat
;RDI x, RSI y, RDX z, RCX n, R8 repeat
;z[i] = y[i] + 3.14159*x[i]
pi: dd 3.14159
;align 16
section .text
triad_fma_asm_repeat:
shl rcx, 2
add rdi, rcx
add rsi, rcx
add rdx, rcx
vbroadcastss ymm2, [rel pi]
;neg rcx
align 16
.L1:
mov rax, rcx
neg rax
align 16
.L2:
vmovaps ymm1, [rdi+rax]
vfmadd231ps ymm1, ymm2, [rsi+rax]
vmovaps [rdx+rax], ymm1
add rax, 32
jne .L2
sub r8d, 1
jnz .L1
vzeroupper
ret
global triad_fma_asm_repeat_unroll16
section .text
triad_fma_asm_repeat_unroll16:
shl rcx, 2
add rcx, rdi
vbroadcastss ymm2, [rel pi]
.L1:
xor rax, rax
mov r9, rdi
mov r10, rsi
mov r11, rdx
.L2:
%assign unroll 32
%assign i 0
%rep unroll
vmovaps ymm1, [r9 + 32*i]
vfmadd231ps ymm1, ymm2, [r10 + 32*i]
vmovaps [r11 + 32*i], ymm1
%assign i i+1
%endrep
add r9, 32*unroll
add r10, 32*unroll
add r11, 32*unroll
cmp r9, rcx
jne .L2
sub r8d, 1
jnz .L1
vzeroupper
ret
triad_ava_asm.asm:
global triad_avx_asm_repeat
;RDI x, RSI y, RDX z, RCX n, R8 repeat
pi: dd 3.14159
align 16
section .text
triad_avx_asm_repeat:
shl rcx, 2
add rdi, rcx
add rsi, rcx
add rdx, rcx
vbroadcastss ymm2, [rel pi]
;neg rcx
align 16
.L1:
mov rax, rcx
neg rax
align 16
.L2:
vmulps ymm1, ymm2, [rdi+rax]
vaddps ymm1, ymm1, [rsi+rax]
vmovaps [rdx+rax], ymm1
add rax, 32
jne .L2
sub r8d, 1
jnz .L1
vzeroupper
ret
global triad_avx_asm_repeat2
;RDI x, RSI y, RDX z, RCX n, R8 repeat
;pi: dd 3.14159
align 16
section .text
triad_avx_asm_repeat2:
shl rcx, 2
vbroadcastss ymm2, [rel pi]
align 16
.L1:
xor rax, rax
align 16
.L2:
vmulps ymm1, ymm2, [rdi+rax]
vaddps ymm1, ymm1, [rsi+rax]
vmovaps [rdx+rax], ymm1
add eax, 32
cmp eax, ecx
jne .L2
sub r8d, 1
jnz .L1
vzeroupper
ret
global triad_avx_asm_repeat_unroll16
align 16
section .text
triad_avx_asm_repeat_unroll16:
shl rcx, 2
add rcx, rdi
vbroadcastss ymm2, [rel pi]
align 16
.L1:
xor rax, rax
mov r9, rdi
mov r10, rsi
mov r11, rdx
align 16
.L2:
%assign unroll 16
%assign i 0
%rep unroll
vmulps ymm1, ymm2, [r9 + 32*i]
vaddps ymm1, ymm1, [r10 + 32*i]
vmovaps [r11 + 32*i], ymm1
%assign i i+1
%endrep
add r9, 32*unroll
add r10, 32*unroll
add r11, 32*unroll
cmp r9, rcx
jne .L2
sub r8d, 1
jnz .L1
vzeroupper
ret
triad_sse_asm.asm:
global triad_sse_asm_repeat
;RDI x, RSI y, RDX z, RCX n, R8 repeat
pi: dd 3.14159
;align 16
section .text
triad_sse_asm_repeat:
shl rcx, 2
add rdi, rcx
add rsi, rcx
add rdx, rcx
movss xmm2, [rel pi]
shufps xmm2, xmm2, 0
;neg rcx
align 16
.L1:
mov rax, rcx
neg rax
align 16
.L2:
movaps xmm1, [rdi+rax]
mulps xmm1, xmm2
addps xmm1, [rsi+rax]
movaps [rdx+rax], xmm1
add rax, 16
jne .L2
sub r8d, 1
jnz .L1
ret
global triad_sse_asm_repeat2
;RDI x, RSI y, RDX z, RCX n, R8 repeat
;pi: dd 3.14159
;align 16
section .text
triad_sse_asm_repeat2:
shl rcx, 2
movss xmm2, [rel pi]
shufps xmm2, xmm2, 0
align 16
.L1:
xor rax, rax
align 16
.L2:
movaps xmm1, [rdi+rax]
mulps xmm1, xmm2
addps xmm1, [rsi+rax]
movaps [rdx+rax], xmm1
add eax, 16
cmp eax, ecx
jne .L2
sub r8d, 1
jnz .L1
ret
global triad_sse_asm_repeat_unroll16
section .text
triad_sse_asm_repeat_unroll16:
shl rcx, 2
add rcx, rdi
movss xmm2, [rel pi]
shufps xmm2, xmm2, 0
.L1:
xor rax, rax
mov r9, rdi
mov r10, rsi
mov r11, rdx
.L2:
%assign unroll 8
%assign i 0
%rep unroll
movaps xmm1, [r9 + 16*i]
mulps xmm1, xmm2,
addps xmm1, [r10 + 16*i]
movaps [r11 + 16*i], xmm1
%assign i i+1
%endrep
add r9, 16*unroll
add r10, 16*unroll
add r11, 16*unroll
cmp r9, rcx
jne .L2
sub r8d, 1
jnz .L1
ret
IACA 분석
IACA (인텔아키텍처 코드아나라이저)를 사용하면 매크로 운영 퓨전이 실제로 발생하고 있으며 문제가 아님을 알 수 있습니다.Mysticial이 맞습니다.문제는 그 가게가 7번 포트를 전혀 사용하지 않는다는 것입니다.
IACA는 다음을 보고합니다.
Intel(R) Architecture Code Analyzer Version - 2.1
Analyzed File - ../../../tests_fma
Binary Format - 64Bit
Architecture - HSW
Analysis Type - Throughput
Throughput Analysis Report
--------------------------
Block Throughput: 1.55 Cycles Throughput Bottleneck: FrontEnd, PORT2_AGU, PORT3_AGU
Port Binding In Cycles Per Iteration:
---------------------------------------------------------------------------------------
| Port | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 |
---------------------------------------------------------------------------------------
| Cycles | 0.5 0.0 | 0.5 | 1.5 1.0 | 1.5 1.0 | 1.0 | 0.0 | 1.0 | 0.0 |
---------------------------------------------------------------------------------------
N - port number or number of cycles resource conflict caused delay, DV - Divider pipe (on port 0)
D - Data fetch pipe (on ports 2 and 3), CP - on a critical path
F - Macro Fusion with the previous instruction occurred
* - instruction micro-ops not bound to a port
^ - Micro Fusion happened
# - ESP Tracking sync uop was issued
@ - SSE instruction followed an AVX256 instruction, dozens of cycles penalty is expected
! - instruction not supported, was not accounted in Analysis
| Num Of | Ports pressure in cycles | |
| Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 | |
---------------------------------------------------------------------------------
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [rdi+rax*1]
| 2 | 0.5 | 0.5 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [rsi+rax*1]
| 2 | | | 0.5 | 0.5 | 1.0 | | | | CP | vmovaps ymmword ptr [rdx+rax*1], ymm1
| 1 | | | | | | | 1.0 | | | add rax, 0x20
| 0F | | | | | | | | | | jnz 0xffffffffffffffec
Total Num Of Uops: 6
특히 보고된 블록 처리량(1.5)은 66%의 효율로 매우 양호합니다.
IACA의 웹사이트에 게시된 바로 그 현상에 대한 게시물Tue, 03/11/2014 - 12:39
은 인텔 이 이 .Tue, 03/11/2014 - 23:20
:
Port7 AGU는 단순한 메모리주소(인덱스 레지스터 없음)의 스토어에서만 동작할 수 있습니다.이 때문에, 상기의 분석에서는 포토 7 의 사용율이 표시되지 않습니다.
이것에 의해, 포토 7이 사용되지 않았던 이유가 확실히 해결됩니다.
내용을 보니 32배 언롤 루프unroll16
unroll32
Intel(R) Architecture Code Analyzer Version - 2.1
Analyzed File - ../../../tests_fma
Binary Format - 64Bit
Architecture - HSW
Analysis Type - Throughput
Throughput Analysis Report
--------------------------
Block Throughput: 32.00 Cycles Throughput Bottleneck: PORT2_AGU, Port2_DATA, PORT3_AGU, Port3_DATA, Port4, Port7
Port Binding In Cycles Per Iteration:
---------------------------------------------------------------------------------------
| Port | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 |
---------------------------------------------------------------------------------------
| Cycles | 16.0 0.0 | 16.0 | 32.0 32.0 | 32.0 32.0 | 32.0 | 2.0 | 2.0 | 32.0 |
---------------------------------------------------------------------------------------
N - port number or number of cycles resource conflict caused delay, DV - Divider pipe (on port 0)
D - Data fetch pipe (on ports 2 and 3), CP - on a critical path
F - Macro Fusion with the previous instruction occurred
* - instruction micro-ops not bound to a port
^ - Micro Fusion happened
# - ESP Tracking sync uop was issued
@ - SSE instruction followed an AVX256 instruction, dozens of cycles penalty is expected
! - instruction not supported, was not accounted in Analysis
| Num Of | Ports pressure in cycles | |
| Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 | |
---------------------------------------------------------------------------------
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x20]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x20]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x20], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x40]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x40]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x40], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x60]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x60]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x60], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x80]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x80]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x80], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0xa0]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0xa0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0xa0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0xc0]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0xc0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0xc0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0xe0]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0xe0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0xe0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x100]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x100]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x100], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x120]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x120]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x120], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x140]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x140]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x140], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x160]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x160]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x160], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x180]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x180]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x180], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x1a0]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x1a0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x1a0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x1c0]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x1c0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x1c0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x1e0]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x1e0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x1e0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x200]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x200]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x200], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x220]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x220]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x220], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x240]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x240]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x240], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x260]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x260]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x260], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x280]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x280]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x280], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x2a0]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x2a0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x2a0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x2c0]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x2c0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x2c0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x2e0]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x2e0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x2e0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x300]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x300]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x300], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x320]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x320]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x320], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x340]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x340]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x340], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x360]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x360]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x360], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x380]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x380]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x380], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x3a0]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x3a0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x3a0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x3c0]
| 2^ | 1.0 | | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x3c0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x3c0], ymm1
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [r9+0x3e0]
| 2^ | | 1.0 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [r10+0x3e0]
| 2^ | | | | | 1.0 | | | 1.0 | CP | vmovaps ymmword ptr [r11+0x3e0], ymm1
| 1 | | | | | | 1.0 | | | | add r9, 0x400
| 1 | | | | | | | 1.0 | | | add r10, 0x400
| 1 | | | | | | 1.0 | | | | add r11, 0x400
| 1 | | | | | | | 1.0 | | | cmp r9, rcx
| 0F | | | | | | | | | | jnz 0xfffffffffffffcaf
Total Num Of Uops: 164
여기에서는 포트 7에 대한 스토어의 마이크로 퓨전 및 올바른 스케줄링을 보여 줍니다.
수동 분석(위 편집 참조)
이제 두 번째 질문에 답할 수 있습니다.이게 풀지 않고 가능한 일인가요? 만약 그렇다면 어떻게 할 수 있을까요?대답은 '아니오'입니다.
는 배열을 채웠다.x
,y
★★★★★★★★★★★★★★★★★」z
아래 실험을 위해 충분한 버퍼를 사용하여 좌우로 이동하고 내부 루프를 다음과 같이 변경합니다.
.L2:
vmovaps ymm1, [rdi+rax] ; 1L
vmovaps ymm0, [rsi+rax] ; 2L
vmovaps [rdx+rax], ymm2 ; S1
add rax, 32 ; ADD
jne .L2 ; JMP
이것은 의도적으로 FMA(로드 및 스토어만)를 사용하지 않으며 모든 로드/스토어 명령에는 의존성이 없습니다.따라서 실행 포트로의 문제를 막는 위험은 발생하지 않습니다.
첫와 두 로드의 했습니다.1L
★★★★★★★★★★★★★★★★★」2L
( ),S1
add예: add) 및(예:A
를 종료하고 때를 참조해 주세요).J
)의 마지막에,, 「」, 「」의 가능한 모든 x
,y
★★★★★★★★★★★★★★★★★」z
바이트 의 순서 -32 바이트의 )add rax, 32
r+r
로드 또는 저장소가 잘못된 주소를 대상으로 하는 원인이 됩니다).32번2.4일가 GHz i7-4700MQ에 됨)echo '0' > /sys/devices/system/cpu/cpufreq/boost
2.4를 주파수 상수로 사용합니다.효율화 결과(최대 24개)는 다음과 같습니다.
Cases: 0 1 2 3 4 5 6 7
L1 L2 S L1 L2 S L1 L2 S L1 L2 S L1 L2 S L1 L2 S L1 L2 S L1 L2 S
-0 -0 -0 -0 -0 -32 -0 -32 -0 -0 -32 -32 -32 -0 -0 -32 -0 -32 -32 -32 -0 -32 -32 -32
________________________________________________________________________________________________
12SAJ: 65.34% 65.34% 49.63% 65.07% 49.70% 65.05% 49.22% 65.07%
12ASJ: 48.59% 64.48% 48.74% 49.69% 48.75% 49.69% 48.99% 48.60%
1A2SJ: 49.69% 64.77% 48.67% 64.06% 49.69% 49.69% 48.94% 49.69%
1AS2J: 48.61% 64.66% 48.73% 49.71% 48.77% 49.69% 49.05% 48.74%
1S2AJ: 49.66% 65.13% 49.49% 49.66% 48.96% 64.82% 49.02% 49.66%
1SA2J: 64.44% 64.69% 49.69% 64.34% 49.69% 64.41% 48.75% 64.14%
21SAJ: 65.33%* 65.34% 49.70% 65.06% 49.62% 65.07% 49.22% 65.04%
21ASJ: Hypothetically =12ASJ
2A1SJ: Hypothetically =1A2SJ
2AS1J: Hypothetically =1AS2J
2S1AJ: Hypothetically =1S2AJ
2SA1J: Hypothetically =1SA2J
S21AJ: 48.91% 65.19% 49.04% 49.72% 49.12% 49.63% 49.21% 48.95%
S2A1J: Hypothetically =S1A2J
SA21J: Hypothetically =SA12J
SA12J: 64.69% 64.93% 49.70% 64.66% 49.69% 64.27% 48.71% 64.56%
S12AJ: 48.90% 65.20% 49.12% 49.63% 49.03% 49.70% 49.21%* 48.94%
S1A2J: 49.69% 64.74% 48.65% 64.48% 49.43% 49.69% 48.66% 49.69%
A2S1J: Hypothetically =A1S2J
A21SJ: Hypothetically =A12SJ
A12SJ: 64.62% 64.45% 49.69% 64.57% 49.69% 64.45% 48.58% 63.99%
A1S2J: 49.72% 64.69% 49.72% 49.72% 48.67% 64.46% 48.95% 49.72%
AS21J: Hypothetically =AS21J
AS12J: 48.71% 64.53% 48.76% 49.69% 48.76% 49.74% 48.93% 48.69%
표에서 몇 가지 사항을 알 수 있습니다.
- 몇 가지 결과가 있지만, 두 가지 주요 결과만 있습니다: 50% 미만, 약 65%입니다.
- L1과 L2는 결과에 영향을 주지 않고 서로 자유롭게 퍼밍할 수 있다.
- 액세스 오프셋을 -32바이트로 하면 효율이 변경될 수 있습니다.
- 관심 있는 패턴(로드 1, 로드 2, 스토어 1 및 점프(주변 어디에나 Add가 적용되고 -32 오프셋이 적절히 적용됨)은 모두 동일하며 모두 상위 평원에 있습니다.
12SAJ
( 0 ( 프 0 ) 、 율 65 . 34 % ( )12ASJ
1 (이이 1 ( )S-32
.48 64.48% ( )1A2SJ
3 (제3호)2L-32
,S-32
06 % 64.06 % )A12SJ
7 (제7호)1L-32
,2L-32
,S-32
63%), 63.99효율 63.99% (표준)
- 효율이 높은 고원에서 실행할 수 있는 모든 순열에는 항상 적어도 하나의 "케이스"가 존재합니다. 1(여기서 「」는 「」1(「」)
S-32
은 이것을 하는 것 가 보증하는 것 같습니다. - 케이스 2, 4, 6은 하부 고원에서의 실행을 보증한다.이 두 가지 공통점은 저장소가 -32만큼 상쇄되지 않는 동안 둘 중 하나 또는 둘 다 -32만큼 상쇄된다는 것입니다.
- 0, 3, 5, 7의 경우 치환에 따라 달라집니다.
여기서 최소한 몇 가지 결론을 도출할 수 있습니다.
- 실행 포트 2와 3은 생성 및 로딩되는 로드 주소에 전혀 영향을 주지 않습니다.
- 퓨전 (Macro-op the macro-op fusion of the 의 macro 。
add
★★★★★★★★★★★★★★★★★」jmp
1에서는) 을 받지 않는 것처럼 @ 생각합니다 히히 ev 1 ev특 ) ev 、 @ 。의add
jne
융합에는 영향을 주지 않는 것 같습니다.이제 해스웰 ROB가 이 문제를 제대로 처리하고 있다고 확신합니다.- 본 것 from Evgeny)
12SAJ
(사례 0에서 효율이 49%인 경우)는 단순히 로드 및 저장되는 주소의 값 때문이지 추가 및 분기를 매크로로 융합할 수 없는 코어 때문은 아닙니다. - 또한 평균 루프 시간은 1.5CC이므로 매크로 운영 융합은 적어도 어느 정도 발생할 필요가 있습니다.매크로 op 퓨전이 발생하지 않으면 최소 2CC가 됩니다.
- 본 것 from Evgeny)
- 풀리지 않은 루프 내의 모든 명령의 유효 및 무효 순열을 테스트한 결과 65.34%보다 높은 것은 없었습니다.이는 풀링 없이 전체 대역폭을 사용할 수 있는지 여부에 대한 질문에 경험적으로 "아니오"라고 대답합니다.
몇 가지 가능한 설명을 가정하겠습니다.
- 서로 상대적인 주소의 값으로 인해 약간의 왜곡이 발생하고 있습니다.
- 이 때, 이 이 있다, 이 오프셋이 , 이렇게 됩니다.
x
,y
★★★★★★★★★★★★★★★★★」z
스루풋을 최대화할 수 있습니다.제 쪽에서는 빠른 무작위 테스트가 이를 지원하지 않는 것 같습니다.
- 이 때, 이 이 있다, 이 오프셋이 , 이렇게 됩니다.
루프가 원투스텝 모드로 동작하고 있습니다.루프 반복은 1개의 클럭사이클로 번갈아 실행되며, 다음으로 2개의 클럭사이클로 실행됩니다.
이는 디코더의 영향을 받는 매크로 운영 융합일 수 있습니다.Agner Fog에서:
퓨즈가 가능한 산술/논리 명령은 Sandy Bridge 및 Ivy Bridge 프로세서의 4개의 디코더 중 마지막 디코더로 디코딩할 수 없습니다.나는 이것이 Haswell에도 적용되는지 테스트하지 않았다.
- 또는 다른 클럭사이클마다 명령이 "잘못된" 포트에 발행되어 다음 반복이 1회 추가 클럭사이클 동안 차단됩니다.이러한 상황은 다음 클럭 사이클에서는 자가 수정되지만 진동 상태로 유지됩니다.
- 할 수 있는 는, 「」를 해 주세요.
UOPS_EXECUTED_PORT.PORT_[0-7]
발진이 발생하지 않으면 사용되는 모든 포트가 해당 기간 동안 균등하게 고정됩니다. 그렇지 않으면 발진이 발생하면 50% 분할됩니다.미스틱(0, 1, 6, 7)을 사용합니다.
- 할 수 있는 는, 「」를 해 주세요.
그리고 내가 생각하기에 일어나지 않는 일은 다음과 같다.
- 예측된 브런치는 포트 6에만 전송되므로 퓨전된 산술+브런치uop이 포트 0으로 이동함으로써 실행을 차단하고 있다고는 생각하지 않습니다(아래의 Agner Fog's Instruction Tables 참조).
Haswell -> Control transfer instructions
위의 루프를 몇 번 반복하면 브런치 프레딕터는 이 브런치가 루프임을 인식하고 항상 취득한 대로 예측합니다.
인텔의 퍼포먼스 카운터를 통해 해결할 수 있는 문제라고 생각합니다.
언급URL : https://stackoverflow.com/questions/25899395/obtaining-peak-bandwidth-on-haswell-in-the-l1-cache-only-getting-62
'programing' 카테고리의 다른 글
체크박스에 vue-fontawesome을 사용할 수 있습니까? (0) | 2022.07.16 |
---|---|
쉽게 컬렉션으로 변환할 수 있는 방법 (0) | 2022.07.16 |
v-model이 구성 요소의 로컬 데이터 대신 Vuex 상태를 변환하는 이유는 무엇입니까? (0) | 2022.07.16 |
mongoose 모델에서 중첩된 데이터를 쿼리하는 방법 (0) | 2022.07.16 |
C의 객체 파일이 뭐죠? (0) | 2022.07.16 |