x86의 MOV가 정말 "무료"가 될 수 있습니까?왜 나는 이것을 전혀 재현할 수 없습니까?
저는 레지스터 이름 변경 때문에 x86에서 MOV 명령어가 무료가 될 수 있다고 주장하는 사람들을 계속 보고 있습니다.
저는 이것을 단 한 번의 테스트 사례에서 확인할 수 없습니다.제가 시도하는 모든 테스트 케이스는 그것을 밝혀냅니다.
예를 들어, Visual C++로 컴파일하는 코드는 다음과 같습니다.
#include <limits.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
unsigned int k, l, j;
clock_t tstart = clock();
for (k = 0, j = 0, l = 0; j < UINT_MAX; ++j)
{
++k;
k = j; // <-- comment out this line to remove the MOV instruction
l += j;
}
fprintf(stderr, "%d ms\n", (int)((clock() - tstart) * 1000 / CLOCKS_PER_SEC));
fflush(stderr);
return (int)(k + j + l);
}
이렇게 하면 루프에 대한 다음 어셈블리 코드가 생성됩니다(Visual C++이 필요하지 않으므로 원하는 대로 생성하십시오).
LOOP:
add edi,esi
mov ebx,esi
inc esi
cmp esi,FFFFFFFFh
jc LOOP
이제 이 프로그램을 여러 번 실행했는데 MOV 명령을 제거하면 상당히 일관된 2% 차이가 납니다.
Without MOV With MOV
1303 ms 1358 ms
1324 ms 1363 ms
1310 ms 1345 ms
1304 ms 1343 ms
1309 ms 1334 ms
1312 ms 1336 ms
1320 ms 1311 ms
1302 ms 1350 ms
1319 ms 1339 ms
1324 ms 1338 ms
그래서 뭐가 문제지?MOV는 왜 "무료"가 아닌가요?이 루프는 x86에 비해 너무 복잡합니까?
사람들이 주장하는 것처럼 MOV가 자유롭다는 것을 증명할 수 있는 단 하나의 예가 있습니까?
만약 그렇다면, 과연 무엇인가?그리고 만약 그렇지 않다면, 왜 모든 사람들이 MOV가 무료라고 계속 주장합니까?
프론트엔드의 경우 레지스터 복사본은 결코 무료가 아니며, 다음 CPU에서 이슈/이름 변경 단계에 따라 백엔드(지연 시간 없음)에서 실제로 실행되는 것만 제거됩니다.
- 정수가 아닌 XMM 벡터 레지스터용 AMD Buldozer 제품군.
- 정수 및 XMM 벡터 레지스터용 AMD Zen 제품군. (Zen2 이상에서는 YMM)
(BD/Zen 1에서 YMM의 로우/하이 하프에 대한 자세한 내용은 Agner Fog의 마이크로아치 가이드 참조) - 정수 및 벡터 레지스터용 Intel Ivy Bridge 이상(MMX 제외)
- Intel Goldmont 프로세서: XMM 프로세서
Lake , 제외Alder Lake E-core 정/XMM 함, YMM 제) - Intel Ice Lake가 아님: 마이크로코드 업데이트는 범용 정수 레지스터에 대해 에라타를 해결하는 작업의 일부로 레지스터 이름 바꾸기를 비활성화했습니다.XMM/YMM/ZMM 이름 변경은 계속 작동합니다.타이거 레이크도 영향을 받지만, 로켓 레이크나 올더 레이크 P-core는 아닙니다.
에 대한 uops.info 결과 - 작동하는 CPU의 지연 시간=0을 기록합니다.또한 Ice Lake 및 Tiger Lake에서 대기 시간=1이 표시되므로 마이크로코드 업데이트 후 다시 테스트했습니다.
당신의 실험
질문에서 루프의 처리량은 MOV의 지연 시간이나 (Haswell에 대한) 실행 장치를 사용하지 않을 경우의 이점에 의존하지 않습니다.
가 순서가 하는 데 4 (4 웁스의 4 웁스 ()mov
실행 장치가 필요하지 않더라도 순서가 잘못된 백엔드에 의해 추적되어야 합니다.cmp/jc
매크로를 단일 uop으로 전환).
코어 2 이후의 인텔 CPU는 클럭당 4 uops의 이슈 폭을 가지고 있었습니다.mov
Haswell에서 클럭당 하나의 반복기(근접)로 실행되는 것을 막지는 못합니다.또한 아이비브리지(이동 제거 포함)에서는 시계당 1개로 실행되지만 샌디브리지(이동 제거 없음)에서는 실행되지 않습니다.SnB에서는 1.333c 사이클당 약 1개의 반복기가 필요하며, ALU 처리량에 병목 현상이 발생합니다. (SnB/IvB에는 ALU 포트가 3개만 있고 Haswell에는 4개가 있습니다.)
이름 변경 단계에서의 특수 취급은 x87 FXCHG(스왑)의 작업이었습니다.st0
와 함께st1
더 .) MOV는 MOV보다 더 오래.아그너 포그는 FXCHG를 PPRO/PII/PIII(1세대 P6 코어)에서 대기 시간이 0인 것으로 표시합니다.
에는 두 체인 문의루는두개인있체다종습인니이속성터록의프에제")이 있습니다.add edi,esi
EDI 및 루프 카운터 ESI)에 따라 달라지므로 불완전한 스케줄링에 더욱 민감합니다.겉보기에는 관련이 없어 보이는 명령어 때문에 이론적 예측에 비해 2% 느려지는 것은 드문 일이 아니며, 명령어 순서의 작은 변화가 이러한 차이를 만들 수 있습니다.1회당 정확히 1c로 실행하려면 모든 사이클이 INC와 ADD를 실행해야 합니다.모든 INC와 ADD는 이전 반복에 종속되어 있기 때문에 순서가 잘못된 실행은 한 번의 사이클에서 두 개를 실행하여 따라잡을 수 없습니다.더 나쁜 것은, ADD가 이전 사이클의 INC에 의존한다는 것입니다. 이는 제가 의미하는 "상호 잠금"이기 때문에, INC 디프 체인에서 사이클을 잃는 것은 ADD 디프 체인도 지연시킵니다.
또한 예측된 분기는 포트 6에서만 실행될 수 있으므로 포트 6이 cmp/jc를 실행하지 않는 주기는 처리량 손실 주기입니다.이 문제는 포트 0, 1 또는 5에서 실행되는 대신 INC 또는 ADD가 포트 6에서 사이클을 훔칠 때마다 발생합니다. IDK가 원인인지, INC/ADD 디프 체인 자체의 사이클 손실이 문제인지, 아니면 둘 중 일부일 수도 있습니다.
MOV를 추가하면 100% 제거된다고 가정할 때 실행 포트 압력이 증가하지 않지만 프론트 엔드가 백엔드 실행 장치보다 먼저 실행되는 것을 방지할 수 있습니다. (루프에 있는 4개의 uop 중 3개만 실행 장치가 필요하며, Haswell CPU는 0, 1, 5, 6개의 ALU 포트 중 임의의 4개에서 INC 및 ADD를 실행할 수 있습니다.따라서 병목 현상은 다음과 같습니다.
- 클럭당 4 uops의 프론트 엔드 최대 처리량(MOV가 없는 루프는 3 uops에 불과하므로 프론트 엔드가 앞서 실행될 수 있음).
- 클럭당 1개의 테이크오버 처리량
- 관련된 종속 사슬
esi
시간 (InC 지연 시간은 1개입니다.) - 관련된 종속 사슬
edi
시간, (ADD 1번, INC에 의존함)
MOV가 없으면 프론트 엔드는 순서가 맞지 않는 백엔드가 가득 찰 때까지 클럭당 4개로 루프의 웁스 3개를 발행할 수 있습니다. (AFAICT, 루프 버퍼(루프 스트림 검출기: LSD)에서 작은 루프를 "해제"하므로 ABC 웁스가 포함된 루프는 ABC BCABC CABA CABC ... 패턴으로 발행할 수 있습니다.에 대한 성능 카운터lsd.cycles_4_uops
웁스를 발행할 때 대부분 4인 1조로 발행함을 확인합니다.)
Intel CPU는 순서가 잘못된 백엔드로 실행될 때 포트에 ops를 할당합니다.이 결정은 스케줄러(예약 스테이션, RS라고도 함)에 이미 있는 각 포트의 웁스 수를 추적하는 카운터를 기반으로 합니다.RS에 실행 대기 중인 uops가 많으면 이 작업이 잘 작동하며 일반적으로 INC 또는 ADD를 포트 6으로 예약하지 않아야 합니다.그리고 INC와 ADD의 일정을 조정하는 것도 피할 수 있을 것 같습니다. 그렇게 되면 두 디파인 중 하나로 인해 시간이 손실됩니다.그러나 RS가 비어 있거나 거의 비어 있는 경우 카운터는 ADD 또는 INC가 포트 6의 사이클을 훔치는 것을 막지 못합니다.
저는 제가 여기서 뭔가를 하고 있다고 생각했습니다만, 어떤 차선책이라도 프런트 엔드가 따라잡고 백 엔드를 꽉 채울 수 있도록 해야 합니다.작은 루프는 루프 버퍼에서 클럭당 매우 일관된 4개의 처리량으로 실행되어야 하기 때문에 프론트 엔드가 파이프라인에서 최대 처리량보다 2% 아래로 떨어지는 충분한 거품을 발생시킬 것으로 기대해서는 안 된다고 생각합니다.뭔가 다른 일이 있는 것 같아요.
의이을보는예진한정주여점의 예mov
탈락
저는 용한사를 요.lea
▁that▁has▁one▁loop다▁a▁only▁to▁construct만 있는 루프를 구성합니다.mov
클럭당 MOV 제거가 100% 또는 0%의 시간으로 성공하는 완벽한 데모를 만듭니다.mov same,same
생성되는 지연 시간 병목 현상을 보여줍니다.
매크로 융합은 루프 카운터를 포함하는 종속성 체인의 일부이기 때문에 불완전한 스케줄링은 이를 지연시킬 수 없습니다.이것은 다음과 같은 경우와는 다릅니다.cmp/jc
반복할 때마다 크리티컬 경로 종속성 체인에서 "오프"됩니다.
_start:
mov ecx, 2000000000 ; each iteration decrements by 2, so this is 1G iters
align 16 ; really align 32 makes more sense in case the uop-cache comes into play, but alignment is actually irrelevant for loops that fit in the loop buffer.
.loop:
mov eax, ecx
lea ecx, [rax-1] ; we vary these two instructions
dec ecx ; dec/jnz macro-fuses into one uop in the decoders, on Intel
jnz .loop
.end:
xor edi,edi ; edi=0
mov eax,231 ; __NR_exit_group from /usr/include/asm/unistd_64.h
syscall ; sys_exit_group(0)
Intel SnB 제품군에서는 주소 지정 모드에서 하나 또는 두 개의 구성 요소가 있는 LEA가 1c 지연 시간으로 실행됩니다(x86 태그 Wiki의 http://agner.org/optimize/, 및 기타 링크 참조).
Linux에서 정적 바이너리로 빌드하고 실행했기 때문에 전체 프로세스에 대한 사용자 공간 성능 카운터는 시작/종료 오버헤드가 거의 없는 루프만 측정합니다.(perf stat
프로그램 자체에 Perf-Counter 쿼리를 넣는 것과 비교하면 정말 쉽습니다.)
$ yasm -felf64 -Worphan-labels -gdwarf2 mov-elimination.asm && ld -o mov-elimination mov-elimination.o &&
objdump -Mintel -drwC mov-elimination &&
taskset -c 1 ocperf.py stat -etask-clock,context-switches,page-faults,cycles,instructions,branches,uops_issued.any,uops_executed.thread -r2 ./mov-elimination
Disassembly of section .text:
00000000004000b0 <_start>:
4000b0: b9 00 94 35 77 mov ecx,0x77359400
4000b5: 66 66 2e 0f 1f 84 00 00 00 00 00 data16 nop WORD PTR cs:[rax+rax*1+0x0]
00000000004000c0 <_start.loop>:
4000c0: 89 c8 mov eax,ecx
4000c2: 8d 48 ff lea ecx,[rax-0x1]
4000c5: ff c9 dec ecx
4000c7: 75 f7 jne 4000c0 <_start.loop>
00000000004000c9 <_start.end>:
4000c9: 31 ff xor edi,edi
4000cb: b8 e7 00 00 00 mov eax,0xe7
4000d0: 0f 05 syscall
perf stat -etask-clock,context-switches,page-faults,cycles,instructions,branches,cpu/event=0xe,umask=0x1,name=uops_issued_any/,cpu/event=0xb1,umask=0x1,name=uops_executed_thread/ -r2 ./mov-elimination
Performance counter stats for './mov-elimination' (2 runs):
513.242841 task-clock:u (msec) # 1.000 CPUs utilized ( +- 0.05% )
0 context-switches:u # 0.000 K/sec
1 page-faults:u # 0.002 K/sec
2,000,111,934 cycles:u # 3.897 GHz ( +- 0.00% )
4,000,000,161 instructions:u # 2.00 insn per cycle ( +- 0.00% )
1,000,000,157 branches:u # 1948.396 M/sec ( +- 0.00% )
3,000,058,589 uops_issued_any:u # 5845.300 M/sec ( +- 0.00% )
2,000,037,900 uops_executed_thread:u # 3896.865 M/sec ( +- 0.00% )
0.513402352 seconds time elapsed ( +- 0.05% )
예상대로, 루프는 1G번 실행됩니다(branches
달러), 10억 달러).를 초과하는 은 2G가 입니다. 여기에는 없는 테스트도 포함됩니다.mov
때때로 이동 제거가 실패하는 것은 아니지만 반복 횟수에 따라 확장되므로 시작 오버헤드만 발생하는 것이 아닙니다. 타이머 인터럽트 아마때 겁니다문일로이후트리눅 IIRC 스이도럽터인머타▁i.perf
인터럽트를 처리하는 동안 성능 테스트를 방해하지 않고 계속 세게 합니다.(perf
는 하드웨어 성능 카운터를 가상화하여 스레드가 CPU 간에 마이그레이션되는 경우에도 프로세스별 카운트를 얻을 수 있습니다.) 또한 동일한 물리적 코어를 공유하는 형제 논리 코어의 타이머 인터럽트는 상황을 다소 교란시킵니다.
병목 현상은 루프 카운터를 포함하는 루프 전달 종속성 체인입니다. 1Giter의 2G 주기는 반복당 2클럭 또는 감소당 1클럭입니다.이를 통해 딥 체인의 길이가 2사이클임을 확인할 수 있습니다.지연 시간이 0인 경우에만 가능합니다.(다른 병목 현상이 없다는 것을 증명하지 않는다는 것을 알고 있습니다.지연 시간이 유일한 병목 현상이라는 제 주장을 믿지 않는 경우, 지연 시간이 최대 2사이클이라는 것을 실제로 증명할 뿐입니다.이 있습니다.resource_stalls.any
counter, 할 수 않습니다
루프에는 3개의 퓨즈 도메인 웁이 있습니다.mov
,lea
거시적으로 분석합니다.3Guops_issued.any
카운트는 다음을 확인합니다.스케줄러(RS) 및 실행 장치를 제외한 디코더에서 폐기까지의 모든 파이프라인인 퓨전 도메인에서 카운트됩니다.(스냅샷 명령-스냅샷은 어디서나 단일 uop으로 유지됩니다.ROB에서 1개의 fused-domain uop이 두 개의 비fused-domain uop의 진행 상황을 추적하는 것은 스토어의 마이크로-fused 또는 ALU+load에만 해당됩니다.)
2Guops_executed.thread
( (used-domain)이 사용된다는 mov
uops가 제거되었습니다(즉, 이슈/이름 변경 단계에서 처리되고 이미 실행된 상태에서 ROB에 배치됨).여전히 문제/폐기 대역폭, uop 캐시의 공간 및 코드 크기를 차지합니다.이들은 ROB의 공간을 차지하여 순서가 잘못된 창 크기를 제한합니다.교육은 결코 무료가 아닙니다. 대기 시간 및 실행 포트 외에도 많은 마이크로 아키텍처 병목 현상이 발생할 수 있으며, 가장 중요한 것은 프런트 엔드의 4개 범위 문제율입니다.
Intel CPU의 경우 지연 시간이 0인 것은 실행 장치가 필요 없는 것보다 더 큰 문제입니다. 특히 4개의 ALU 포트가 있는 Haswell 이상에서는 더욱 그렇습니다. (그러나 그 중 3개만이 벡터 uops를 처리할 수 있으므로 제거되지 않은 벡터 이동은 더 쉽게 병목 현상이 됩니다.특히 프론트 엔드 대역폭(클럭당 4개의 퓨전 도메인 웁스)을 ALU 웁스에서 떼어내는 로드나 저장소가 많은 코드에서는 더욱 그렇습니다.또한 ops를 실행 장치로 스케줄링하는 것은 완벽하지 않습니다(가장 오래된 준비가 된 것과 유사). 따라서 중요한 경로에 있지 않은 ops는 중요한 경로에서 주기를 훔칠 수 있습니다.
우리가 만약에.nop
는또.xor edx,edx
또한 Intel SnB 제품군 CPU에서 실행되지 않는 문제도 발생합니다.
제로 레이텐시 이동 제거는 32비트에서 64비트로, 8비트에서 64비트로 제로 확장하는 데 유용합니다.movzx eax, bl
(제거됩니다.)
이동 제거 기능 없음
이동 제거를 지원하는 현재의 모든 CPU는 에 대해 지원하지 않으므로 32비트에서 64비트까지의 정수를 0으로 확장하기 위해 다른 레지스터를 선택합니다.vmovdqa xmm,xmm
필요한 경우 드물지만 YMM으로 제로 확장할 수 있습니다. (이미 등록된 레지스터에 결과가 필요하지 않은 경우)일반적으로 다른 레그로 바운스하고 뒤로 바운스하는 것이 더 나쁩니다.그리고 Intel의 경우에도 동일하게 적용됩니다.movzx eax,al
예를 들어, (AMD 라이젠은 movzx를 제거하지 않습니다.)포그의 는 아너포지표다같습과다니음는그침그의▁show▁ag다같습니를 보여줍니다.mov
라이젠에서 항상 제거되듯이, 하지만 그는 인텔에서 할 수 있는 것처럼 두 개의 다른 레그 사이에서 실패할 수 없다는 것을 의미한다고 생각합니다.
우리는 이 제한을 사용하여 의도적으로 이를 물리치는 마이크로 벤치마크를 만들 수 있습니다.
mov ecx, ecx # CPUs can't eliminate mov same,same
lea ecx, [rcx-1]
dec ecx
jnz .loop
3,000,320,972 cycles:u # 3.898 GHz ( +- 0.00% )
4,000,000,238 instructions:u # 1.33 insn per cycle ( +- 0.00% )
1,000,000,234 branches:u # 1299.225 M/sec ( +- 0.00% )
3,000,084,446 uops_issued_any:u # 3897.783 M/sec ( +- 0.00% )
3,000,058,661 uops_executed_thread:u # 3897.750 M/sec ( +- 0.00% )
종속성 체인의 길이가 이제 3주기이기 때문에 1G 반복에 3G 주기가 걸립니다.
융합 도메인 uop 카운트는 변경되지 않았고, 여전히 3G입니다.
변경된 것은 이제 비퓨즈 도메인 uop 카운트가 퓨전 도메인과 같다는 것입니다.단위가 했지만, uops에는 단위가 .mov
명령어가 제거되었기 때문에, 그들은 모두 루프 버퍼 딥 체인에 1c 지연 시간을 추가했습니다.
(마이크로퓨즈 업프가 있을 때, 예를 들면add eax, [rsi]
,uops_executed
카운트는 다음보다 높을 수 있습니다.uops_issued
하지만 우리는 그것을 가지고 있지 않습니다.)
다음을 제외하고는mov
모두:
lea ecx, [rcx-1]
dec ecx
jnz .loop
2,000,131,323 cycles:u # 3.896 GHz ( +- 0.00% )
3,000,000,161 instructions:u # 1.50 insn per cycle
1,000,000,157 branches:u # 1947.876 M/sec
2,000,055,428 uops_issued_any:u # 3895.859 M/sec ( +- 0.00% )
2,000,039,061 uops_executed_thread:u # 3895.828 M/sec ( +- 0.00% )
이제 루프 전달 DEP 체인의 대기 시간을 2사이클로 단축했습니다.
어떤 것도 제거되지 않습니다.
3.9로 테스트했습니다.GHz i7-6700k 스카이레이크.모든 성능 이벤트에 대해 Haswell i5-4210U(1G 카운트 중 40k 이내)에서 동일한 결과를 얻습니다.이는 동일한 시스템에서 다시 실행하는 것과 거의 같은 오차 범위입니다.
만약 내가 도망쳤다면,perf
근본적으로1cycles
에 cycles:u
만 해당) 3 (직후 3.(max turbo에 대한 bios-settings) 파 3.900GHz 측. ( turbo에 bios-s 설) 로 3.몇 분만 공회전시키면 GHz.Asus Z170 Pro Gaming mobo, Arch Linux 커널 4.10.11-1-ARCH. Ubuntu에서도 동일한 내용을 볼 수 있습니다. 기balance_performance
의 사람들에게/sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference
/etc/rc.local
, 지만쓰기하수정을 쓰는 balance_power
3.9도 3.9도로 .나중에 다시 GHz.)
을 실행하는 것에 더 으로: 업이트대: 실에더한나대안은.sudo perf
는 sysctl을 sysctl로 했습니다.kernel.perf_event_paranoid = 0
/etc/syctl.d/99-local.conf
AMD Ryzen을 수 있기 때문에 수 .mov
AMD Buldozer 제품군은 xmm 레지스터 복사본만 제거할 수 있습니다.(아그너 포그에 따르면,ymm
레지스터 복사본은 제거된 로우 하프와 하이 하프를 위한 ALUop입니다.)
예를 들어 AMD Buldozer와 Intel Ivybridge는 클럭당 1의 처리량을 유지할 수 있습니다.
movaps xmm0, xmm1
movaps xmm2, xmm3
movaps xmm4, xmm5
dec
jnz .loop
그러나 Intel Sandybridge는 이동을 제거할 수 없으므로 3개의 실행 포트에 대한 4개의 ALUups에서 병목 현상이 발생합니다.그랬다면pxor xmm0,xmm0
무브맵 대신 SnB는 클럭당 하나의 반복을 유지할 수 있습니다. (그러나 xor-zeroing은 레지스터의 이전 값과는 독립적이지만 AMD에서 실행 단위가 필요하기 때문에 Buldozer 계열은 그럴 수 없었습니다.또한 Buldozer 제품군은 PXOR에 대한 처리량이 0.5c에 불과합니다.)
이동 제거의 한계
연속된 두 개의 종속 MOV 명령은 Haswell과 Skylake 사이의 차이를 나타냅니다.
.loop:
mov eax, ecx
mov ecx, eax
sub ecx, 2
jnz .loop
Haswell: 사소한 실행 대 실행 변동성(1.746 - 1.749 c/iter)이지만, 이는 일반적입니다.
1,749,102,925 cycles:u # 2.690 GHz
4,000,000,212 instructions:u # 2.29 insn per cycle
1,000,000,208 branches:u # 1538.062 M/sec
3,000,079,561 uops_issued_any:u # 4614.308 M/sec
1,746,698,502 uops_executed_core:u # 2686.531 M/sec
745,676,067 lsd_cycles_4_uops:u # 1146.896 M/sec
모든 MOV 명령어가 제거되는 것은 아닙니다. 반복당 2개 중 약 0.75개가 실행 포트를 사용했습니다.제거되는 대신 실행되는 모든 MOV는 루프-캐리어된 디프 체인에 1c의 지연 시간을 추가하므로, 이는 우연이 아닙니다.uops_executed
그리고.cycles
매우 유사합니다.모든 uops는 단일 종속성 체인의 일부이므로 병렬화가 가능하지 않습니다. cycles
항상 보다더 5M 습니다보다 약 .uops_executed
Run-to-Run 변동에 상관없이, 다른 곳에서 5M 사이클만 사용되는 것 같습니다.
Skylake: HSW 결과보다 안정적이고 이동 제거 능력이 뛰어납니다. 2개 중 0.6666 MOV만 실행 장치가 필요했습니다.
1,666,716,605 cycles:u # 3.897 GHz
4,000,000,136 instructions:u # 2.40 insn per cycle
1,000,000,132 branches:u # 2338.050 M/sec
3,000,059,008 uops_issued_any:u # 7014.288 M/sec
1,666,548,206 uops_executed_thread:u # 3896.473 M/sec
666,683,358 lsd_cycles_4_uops:u # 1558.739 M/sec
하스웰에서,lsd.cycles_4_uops
uops. (0.745 * 4 ~ = 3) 되는 거의 에서 ( 따라서 uops가 실행되는 거의 모든 사이클에서 (루프 버퍼에서) 4개의 전체 그룹이 실행됩니다.그들이 어디서 왔는지 신경쓰지 않는 다른 카운터를 찾아봤어야 했어요.uops_issued.stall_cycles
uops가 발행되지 않은 주기를 계산합니다.
에서는 SKL.0.66666 * 4 = 2.66664
3보다 작기 때문에 일부 사이클에서는 프론트엔드가 4 uops 미만으로 발행되기도 합니다. (일반적으로 완전하지 않은 그룹을 발행하는 대신 완전한 4개의 그룹을 발행할 수 있는 공간이 비순차 백엔드에 있을 때까지 지연됩니다.)
이상하네요, IDK 정확한 마이크로아키텍처의 한계가 무엇인지.루프가 3 uops에 불과하기 때문에 4 uops의 각 이슈 그룹은 전체 반복 이상입니다.따라서 이슈 그룹에는 최대 3개의 종속 MOV가 포함될 수 있습니다.아마도 스카이레이크는 때때로 그것을 부수고, 더 많은 이동 제거를 허용하도록 고안된 것일까요?
업데이트: 사실 이것은 스카이레이크의 3-uop 루프에서 정상입니다. uops_issued.stall_cycles
는 HSW와 SKL이 이 루프를 발행하는 것과 동일한 방식으로 이동 제거 기능이 없는 단순한 3uop 루프를 발행하는 것을 보여줍니다.따서더나이제다는이이유다나니부입작용누는그룹을라슈로른은 ( 취해진 할 수 (문제 발생 속도에 관계없이 분기별로 클럭당 1개 이상 빠르게 실행할 수 없기 때문에 병목 현상이 아닙니다.)SKL이 왜 다른지는 아직 모르겠지만 걱정할 일은 아닌 것 같습니다.
덜 극단적인 경우 SKL과 HSW는 동일하며, 두 가지 모두 2 MOV 명령 중 0.3333을 제거하지 못합니다.
.loop:
mov eax, ecx
dec eax
mov ecx, eax
sub ecx, 1
jnz .loop
2,333,434,710 cycles:u # 3.897 GHz
5,000,000,185 instructions:u # 2.14 insn per cycle
1,000,000,181 branches:u # 1669.905 M/sec
4,000,061,152 uops_issued_any:u # 6679.720 M/sec
2,333,374,781 uops_executed_thread:u # 3896.513 M/sec
1,000,000,942 lsd_cycles_4_uops:u # 1669.906 M/sec
모든 uops 이슈는 4인 1조로 진행됩니다.4개의 uops로 구성된 연속 그룹에는 제거 후보인 정확히 2개의 MOBups가 포함됩니다.일부 주기에서 두 가지 모두 제거하는 데 분명히 성공하기 때문에 IDK는 왜 항상 그렇게 할 수 없는지를 설명합니다.
인텔의 최적화 매뉴얼에 따르면 가능한 한 빨리 이동 제거 결과를 덮어쓰면 마이크로아키텍처 리소스가 해방되어 최소한 다음 기간 동안 더 자주 성공할 수 있습니다.movzx
예 3-23을 참조하십시오. 대기 시간이 없는 MOV 지침의 효과를 개선하기 위해 순서를 다시 지정합니다.
그래서 내부적으로 제한된 크기의 ref-count 표로 추적되는 것이 아닐까요?물리적 레지스터 파일 항목이 더 이상 원래 아키텍처 레지스터의 값으로 필요하지 않을 때, 이동 대상의 값으로 여전히 필요한 경우, 해당 항목이 해제되는 것을 무언가가 차단해야 합니다.PRF 크기는 순서가 맞지 않는 창을 ROB 크기보다 작게 제한할 수 있으므로 PRF 항목을 최대한 빨리 해제하는 것이 중요합니다.
저는 해스웰과 스카이레이크의 예들을 시험해 보았는데, 이동 제거는 실제로 그렇게 할 때 훨씬 더 많은 시간을 효과적으로 사용한다는 것을 발견했습니다. 하지만 전체 주기에서는 속도가 더 빠르기보다는 약간 느리다는 것을 발견했습니다.는 IvyBridge의 으로, 의 ALU에서 병목 현상이 할 수 에만 병목 현상이 발생할 수 , IvyBridge에서 더 는 않습니다. 3개의 ALU 포트에서 병목 현상이 발생할 수 있지만 HSW/SKL은 DEP 체인에서 리소스 충돌이 발생할 경우에만 병목 현상이 발생할 수 있으며 더 많은 ALU 포트가 필요하지 않습니다.movzx
지침들.
참고 항목XCHGreg, reg 3 마이크로-op 명령이 최신 Intel 아키텍처에 대해 설명하는 이유는 무엇입니까?더 많은 연구를 위해 + 이동 제거가 어떻게 작동하는지, 그리고 그것이 작동할 수 있는지에 대한 추측.xchg eax, ecx
는)xchg reg,reg
Intel에서는 3개의 ALU uops이지만 Ryzen에서는 2개의 ALUops가 제거되었습니다.Intel이 이를 보다 효율적으로 구현할 수 있었는지 여부를 추측하는 것은 흥미로운 일입니다.
하스웰에 "", ""라는 단어를 제공하지 .uops_executed.thread
하도록 설정한 에는 하퍼스레사경우만에는하용을딩이▁uops_executed.core
다른 코어는 내가 오프라인으로 가져갔기 때문에 타이머 인터럽트도 없이 계속 유휴 상태였습니다. 안타깝게도 커널이 작동하기 전에는 이것을 수행할 수 없습니다.perf
드라이버(PAPI)가 부팅 시 HT가 활성화되어 있는지 확인하고 Dell 노트북에는 HT를 비활성화할 수 있는 BIOS 옵션이 없습니다.그래서 나는 얻을 수 없습니다.perf
시스템에서 를 한 에 모두 ://pmu 파일 이름은 PMU 파일 이름 8개입니다. :/
다음은 이동 제거에 대한 증거를 결정적으로 보여주는 두 가지 작은 테스트입니다.
__loop1:
add edx, 1
add edx, 1
add ecx, 1
jnc __loop1
대
__loop2:
mov eax, edx
add eax, 1
mov edx, eax
add edx, 1
add ecx, 1
jnc __loop2
한다면mov
종속성 체인에 사이클이 추가되었으며, 두 번째 버전은 반복당 약 4사이클이 소요될 것으로 예상됩니다.내 Haswell에서는 둘 다 반복당 약 2사이클이 소요되며, 이동 제거 없이는 이 작업이 수행될 수 없습니다.
언급URL : https://stackoverflow.com/questions/44169342/can-x86s-mov-really-be-free-why-cant-i-reproduce-this-at-all
'code' 카테고리의 다른 글
Oracle 사용자 계정 상태를 EXPIRE(GRACE)에서 OPEN으로 변경 (0) | 2023.06.17 |
---|---|
목표-C 분할()? (0) | 2023.06.17 |
여러 클래스 제거(jQuery) (0) | 2023.06.17 |
SignalR 허브에 연결된 수신기, 클라이언트 수 가져오기 (0) | 2023.06.17 |
선택 옵션을 부울 값으로 변환 (0) | 2023.06.17 |